Move repositories to 'repos/' subdirectory

This patch changes the top-level directory layout as a preparatory
step for improving the tools for managing 3rd-party source codes.
The rationale is described in the issue referenced below.

Issue #1082
This commit is contained in:
Norman Feske
2014-05-07 11:48:19 +02:00
parent 1f9890d635
commit ca971bbfd8
3943 changed files with 454 additions and 430 deletions

View File

@ -0,0 +1,39 @@
Liquid frame buffer is an implementation of the frame buffer interface
running as a client of the Nitpicker GUI server. It supports the
following configuration options. The example shows the default
values.
! <config
!
! <!-- enable the animated background,
! valid values are 'on' and 'off' -->
! animate="on"
!
! <!-- the initial window position and
! size of the virtual frame buffer -->
! xpos="400"
! ypos="270"
! width="500"
! height="400"
!
! <!-- set the window title -->
! title="Liquid Framebuffer"
!
! <!-- show a resize handle,
! valid values are 'on' and 'off' -->
! resize_handle="off"
!
! <!-- show window decoration (title bar and borders),
! valid values are 'on' and 'off' -->
! decoration="on"
!
! />
Because Liquid frame buffer creates the virtual frame-buffer window at
start time, not at session-creation time, sufficient memory resources must
be provided when starting the program. Consequently, the client does not
need to donate memory for the frame buffer backing store.
Liquid frame buffer supports only one client. If multiple
virtual frame buffers are needed, multiple instances of the
program should be used.

View File

@ -0,0 +1,231 @@
/*
* \brief Window with holding a fixed-size content element
* \author Norman Feske
* \date 2006-09-21
*/
/*
* Copyright (C) 2006-2013 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU General Public License version 2.
*/
#ifndef _FRAMEBUFFER_WINDOW_H_
#define _FRAMEBUFFER_WINDOW_H_
#include <scout/window.h>
#include "titlebar.h"
#include "sky_texture.h"
#include "fade_icon.h"
#define TITLEBAR_RGBA _binary_titlebar_rgba_start
#define SIZER_RGBA _binary_sizer_rgba_start
extern unsigned char TITLEBAR_RGBA[];
extern unsigned char SIZER_RGBA[];
template <typename PT>
class Framebuffer_window : public Scout::Window
{
private:
/**
* Constants
*/
enum { _TH = 32 }; /* height of title bar */
/**
* Widgets
*/
Scout::Titlebar<PT> _titlebar;
Scout::Sky_texture<PT, 512, 512> _bg_texture;
int _bg_offset;
Scout::Fade_icon<PT, 32, 32> _sizer;
Scout::Element *_content;
bool _config_alpha;
bool _config_resize_handle;
bool _config_decoration;
public:
/**
* Constructor
*/
Framebuffer_window(Scout::Graphics_backend &gfx_backend,
Scout::Element *content,
Scout::Point position,
Scout::Area size,
Scout::Area max_size,
char const *name,
bool config_alpha,
bool config_resize_handle,
bool config_decoration)
:
Scout::Window(gfx_backend, position,
Scout::Area(content->min_size().w() + 2,
content->min_size().h() + 1 + _TH),
max_size, false),
_bg_offset(0), _content(content), _config_alpha(config_alpha),
_config_resize_handle(config_resize_handle),
_config_decoration(config_decoration)
{
/* titlebar */
_titlebar.rgba(TITLEBAR_RGBA);
_titlebar.text(name);
_titlebar.event_handler(new Scout::Mover_event_handler(this));
/* resize handle */
_sizer.rgba(SIZER_RGBA);
_sizer.event_handler(new Scout::Sizer_event_handler(this));
_sizer.alpha(100);
if (config_decoration)
append(&_titlebar);
append(_content);
if (config_resize_handle)
append(&_sizer);
unsigned const BORDER = 1, TITLE = _TH, RESIZER = 32;
_min_size = Scout::Area(BORDER + RESIZER + BORDER,
BORDER + TITLE + RESIZER + BORDER);
}
/**
* Set the window title
*/
void name(const char *name)
{
_titlebar.text(name);
}
/**
* Set the alpha config option
*/
void config_alpha(bool alpha)
{
_config_alpha = alpha;
}
/**
* Set the resize_handle config option
*/
void config_resize_handle(bool resize_handle)
{
if (!_config_resize_handle && resize_handle)
append(&_sizer);
else if (_config_resize_handle && !resize_handle)
remove(&_sizer);
_config_resize_handle = resize_handle;
}
/**
* Set the decoration config option
*/
void config_decoration(bool decoration)
{
_config_decoration = decoration;
}
/**
* Move window to new position
*/
void vpos(int x, int y)
{
Window::vpos(x, y);
format(_size);
}
/**
* Resize the window according to the new content size
*/
void content_geometry(int x, int y, int w, int h)
{
if (_config_decoration) {
x -= 1; /* border */
y -= _TH; /* title bar */
}
Window::vpos(x, y);
format(Scout::Area(w + 2, h + 1 + _TH));
}
/**
* Window interface
*/
void format(Scout::Area size)
{
using namespace Scout;
unsigned w = size.w();
unsigned h = size.h();
/* limit window size to valid values */
w = max(w, min_size().w());
h = max(h, min_size().h());
w = min(w, max_size().w());
h = min(h, max_size().h());
_size = Scout::Area(w, h);
int y = 0;
if (_config_decoration) {
_titlebar.format_fixed_width(w);
_titlebar.geometry(Rect(Point(1, y),
Area(_titlebar.min_size().w(),
_titlebar.min_size().h())));
y += _titlebar.min_size().h();
}
int const content_h = ((int)h > y + 1) ? (h - y - 1) : 0;
int const content_x = _config_decoration ? 1 : 0;
int const content_w = w - 2;
_content->format_fixed_size(Area(content_w, content_h));
_content->geometry(Rect(Point(content_x, y),
Area(content_w, content_h)));
_sizer.geometry(Rect(Point(_size.w() - 32, _size.h() - 32), Area(32, 32)));
if (_config_decoration)
Window::format(_size);
else
Window::format(Area(_size.w() - 2, _size.h() - 1 - _TH));
refresh();
}
/**
* Configure background texture offset (for background animation)
*/
void bg_offset(int bg_offset) { _bg_offset = bg_offset; }
/**
* Element interface
*/
void draw(Scout::Canvas_base &canvas, Scout::Point abs_position)
{
using namespace Scout;
if (_config_alpha)
_bg_texture.draw(canvas, Point(0, - _bg_offset));
Parent_element::draw(canvas, abs_position);
/* border */
Color color(0, 0, 0);
canvas.draw_box(0, 0, _size.w(), 1, color);
if (_config_decoration)
canvas.draw_box(0, _TH, _size.w(), 1, color);
canvas.draw_box(0, _size.h() - 1, _size.w(), 1, color);
canvas.draw_box(0, 1, 1, _size.h() - 2, color);
canvas.draw_box(_size.w() - 1, 1, 1, _size.h() - 2, color);
};
};
#endif

View File

@ -0,0 +1,327 @@
/*
* \brief Nitpicker-based virtual framebuffer
* \author Norman Feske
* \date 2006-09-21
*/
/*
* Copyright (C) 2006-2013 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU General Public License version 2.
*/
#include <base/rpc_server.h>
#include <base/signal.h>
#include <cap_session/connection.h>
#include <os/config.h>
#include <scout/user_state.h>
#include <scout/nitpicker_graphics_backend.h>
#include "framebuffer_window.h"
#include "services.h"
/**
* Runtime configuration
*/
namespace Scout { namespace Config
{
int iconbar_detail = 1;
int background_detail = 1;
int mouse_cursor = 1;
int browser_attr = 0;
} }
void Scout::Launcher::launch() { }
class Background_animator : public Scout::Tick
{
private:
Framebuffer_window<Scout::Pixel_rgb565> *_fb_win;
int _bg_offset;
public:
/**
* Constructor
*/
Background_animator(Framebuffer_window<Scout::Pixel_rgb565> *fb_win):
_fb_win(fb_win), _bg_offset(0) {
schedule(20); }
/**
* Tick interface
*/
int on_tick()
{
_fb_win->bg_offset(_bg_offset);
_bg_offset += 2;
_fb_win->refresh();
/* schedule next tick */
return 1;
}
};
/**
* Animated background
*/
static bool config_animate = true;
static bool config_alpha = true;
/**
* Size and position of virtual frame buffer
*/
static long config_fb_width = 500;
static long config_fb_height = 400;
static long config_fb_x = 400;
static long config_fb_y = 260;
/**
* Window title
*/
static const char *config_title = "Liquid Framebuffer";
/**
* Resize handle
*/
static bool config_resize_handle = false;
/**
* Window decoration
*/
static bool config_decoration = true;
/**
* Parse configuration
*/
static void read_config()
{
using namespace Genode;
Xml_node config_node = config()->xml_node();
try {
char buf[16];
config_node.attribute("animate").value(buf, sizeof(buf));
if (!strcmp("off", buf)) config_animate = false;
else if (!strcmp("on", buf)) config_animate = true;
else
Genode::printf("Warning: invalid value for animate declaration,\n"
" valid values are 'on', 'off.\n'");
} catch (Xml_node::Nonexistent_attribute) { }
config_alpha = config_animate;
try { config_node.attribute("xpos").value(&config_fb_x); }
catch (Xml_node::Nonexistent_attribute) { }
try { config_node.attribute("ypos").value(&config_fb_y); }
catch (Xml_node::Nonexistent_attribute) { }
try { config_node.attribute("width").value(&config_fb_width); }
catch (Xml_node::Nonexistent_attribute) { }
try { config_node.attribute("height").value(&config_fb_height); }
catch (Xml_node::Nonexistent_attribute) { }
try {
static char buf[64];
config_node.attribute("title").value(buf, sizeof(buf));
config_title = buf;
} catch (Xml_node::Nonexistent_attribute) { }
try {
char buf[16];
config_node.attribute("decoration").value(buf, sizeof(buf));
if (!strcmp("off", buf)) config_decoration = false;
else if (!strcmp("on", buf)) config_decoration = true;
else
Genode::printf("Warning: invalid value for decoration declaration,\n"
" valid values are 'on', 'off.\n'");
} catch (Xml_node::Nonexistent_attribute) { }
try {
char buf[16];
config_node.attribute("resize_handle").value(buf, sizeof(buf));
if (!strcmp("off", buf)) config_resize_handle = false;
else if (!strcmp("on", buf)) config_resize_handle = true;
else
Genode::printf("Warning: invalid value for resize_handle declaration,\n"
" valid values are 'on', 'off.\n'");
} catch (Xml_node::Nonexistent_attribute) { }
}
/*******************
** Input handler **
*******************/
struct Input_handler
{
GENODE_RPC(Rpc_handle_input, void, handle, Scout::Event&);
GENODE_RPC_INTERFACE(Rpc_handle_input);
};
class Input_handler_component : public Genode::Rpc_object<Input_handler,
Input_handler_component>
{
private:
Scout::Platform &_pf;
Scout::User_state &_user_state;
Framebuffer_window<Genode::Pixel_rgb565> &_fb_win;
Genode::Signal_receiver &_sig_rec;
unsigned long _curr_time, _old_time;
public:
Input_handler_component(Scout::Platform &pf,
Scout::User_state &user_state,
Framebuffer_window<Genode::Pixel_rgb565> &fb_win,
Genode::Signal_receiver &sig_rec)
:
_pf(pf),
_user_state(user_state),
_fb_win(fb_win),
_sig_rec(sig_rec)
{
_curr_time = _old_time = _pf.timer_ticks();
}
void handle(Scout::Event &ev)
{
using Scout::Event;
if (ev.type != Event::WHEEL)
ev.mouse_position = ev.mouse_position - _user_state.view_position();
/* direct all keyboard events to the window content */
if ((ev.type == Event::PRESS || ev.type == Event::RELEASE)
&& (ev.code != Event::BTN_LEFT))
window_content()->handle_event(ev);
else
_user_state.handle_event(ev);
if (ev.type == Event::TIMER) {
Scout::Tick::handle(_pf.timer_ticks());
/* check for configuration changes */
if (_sig_rec.pending()) {
_sig_rec.wait_for_signal();
Genode::config()->reload();
/* keep the current values by default */
config_fb_x = _fb_win.view_x();
config_fb_y = _fb_win.view_y();
config_fb_width = _fb_win.view_w();
config_fb_height = _fb_win.view_h();
try { read_config(); } catch (...) { }
_fb_win.name(config_title);
_fb_win.config_alpha(config_alpha);
_fb_win.config_resize_handle(config_resize_handle);
_fb_win.config_decoration(config_decoration);
/* must get called after 'config_decoration()' */
_fb_win.content_geometry(config_fb_x, config_fb_y,
config_fb_width, config_fb_height);
_user_state.update_view_offset();
}
}
/* perform periodic redraw */
_curr_time = _pf.timer_ticks();
if (!_pf.event_pending() && ((_curr_time - _old_time > 20) || (_curr_time < _old_time))) {
_old_time = _curr_time;
_fb_win.process_redraw();
}
}
};
/**
* Main program
*/
int main(int argc, char **argv)
{
using namespace Scout;
try { read_config(); } catch (...) { }
/*
* Register signal handler for config changes
*/
static Genode::Signal_receiver sig_rec;
static Genode::Signal_context sig_ctx;
try { Genode::config()->sigh(sig_rec.manage(&sig_ctx)); } catch (...) { }
/* heuristic for allocating the double-buffer backing store */
enum { WINBORDER_WIDTH = 10, WINBORDER_HEIGHT = 40 };
/* init platform */
static Nitpicker::Connection nitpicker;
static Platform pf(*nitpicker.input());
Area const max_size(config_fb_width + WINBORDER_WIDTH,
config_fb_height + WINBORDER_HEIGHT);
Point const initial_position(config_fb_x, config_fb_y);
Area const initial_size = max_size;
static Nitpicker_graphics_backend
graphics_backend(nitpicker, max_size, initial_position, initial_size);
/* initialize our window content */
init_window_content(config_fb_width, config_fb_height, config_alpha);
/* create instance of browser window */
static Framebuffer_window<Pixel_rgb565>
fb_win(graphics_backend, window_content(),
initial_position, initial_size, max_size,
config_title, config_alpha,
config_resize_handle, config_decoration);
if (config_animate) {
static Background_animator fb_win_bg_anim(&fb_win);
}
/* create user state manager */
static User_state user_state(&fb_win, &fb_win,
initial_position.x(), initial_position.y());
fb_win.parent(&user_state);
fb_win.content_geometry(config_fb_x, config_fb_y,
config_fb_width, config_fb_height);
/* initialize server entry point */
enum { STACK_SIZE = 2*1024*sizeof(Genode::addr_t) };
static Genode::Cap_connection cap;
static Genode::Rpc_entrypoint ep(&cap, STACK_SIZE, "liquid_fb_ep");
/* initialize public services */
init_services(ep);
/* create local input handler service */
static Input_handler_component input_handler(pf, user_state, fb_win,
sig_rec);
Genode::Capability<Input_handler> input_handler_cap = ep.manage(&input_handler);
/* enter main loop */
for (;;) {
Event ev = pf.get_event();
input_handler_cap.call<Input_handler::Rpc_handle_input>(ev);
if (ev.type == Event::QUIT)
break;
}
return 0;
}

View File

@ -0,0 +1,361 @@
/*
* \brief Implementation of Framebuffer and Input services
* \author Norman Feske
* \date 2006-09-22
*/
/*
* Copyright (C) 2006-2013 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU General Public License version 2.
*/
#include <base/env.h>
#include <base/semaphore.h>
#include <base/rpc_server.h>
#include <framebuffer_session/framebuffer_session.h>
#include <input/component.h>
#include <nitpicker_gfx/texture_painter.h>
#include <os/pixel_rgb565.h>
#include "services.h"
typedef Genode::Texture<Genode::Pixel_rgb565> Texture_rgb565;
/*****************
** Event queue **
*****************/
class Event_queue
{
private:
enum { QUEUE_SIZE = 1024 };
Input::Event _queue[QUEUE_SIZE];
int _head;
int _tail;
Genode::Semaphore _sem;
public:
/**
* Constructor
*/
Event_queue(): _head(0), _tail(0)
{
Scout::memset(_queue, 0, sizeof(_queue));
}
void post(Input::Event ev)
{
if ((_head + 1)%QUEUE_SIZE != _tail) {
_queue[_head] = ev;
_head = (_head + 1)%QUEUE_SIZE;
_sem.up();
}
}
Input::Event get()
{
_sem.down();
Input::Event dst_ev = _queue[_tail];
_tail = (_tail + 1)%QUEUE_SIZE;
return dst_ev;
}
int pending() { return _head != _tail; }
} _ev_queue;
/***************************
** Input service backend **
***************************/
namespace Input {
void event_handling(bool enable) { }
bool event_pending() { return _ev_queue.pending(); }
Event get_event() { return _ev_queue.get(); }
}
class Window_content : public Scout::Element
{
private:
class Content_event_handler : public Scout::Event_handler
{
private:
Event_queue *_ev_queue;
Scout::Point _old_mouse_position;
Element *_element;
public:
Content_event_handler(Event_queue *ev_queue,
Scout::Element *element)
:
_ev_queue(ev_queue), _element(element) { }
void handle(Scout::Event &ev)
{
using namespace Scout;
Point mouse_position = ev.mouse_position - _element->abs_position();
int code = 0;
if (ev.type == Event::PRESS || ev.type == Event::RELEASE)
code = ev.code;
Input::Event::Type type;
type = (ev.type == Event::MOTION) ? Input::Event::MOTION
: (ev.type == Event::PRESS) ? Input::Event::PRESS
: (ev.type == Event::RELEASE) ? Input::Event::RELEASE
: Input::Event::INVALID;
if (type != Input::Event::INVALID)
_ev_queue->post(Input::Event(type, code, mouse_position.x(),
mouse_position.y(),
mouse_position.x() - _old_mouse_position.x(),
mouse_position.y() - _old_mouse_position.y()));
_old_mouse_position = mouse_position;
}
};
struct Fb_texture
{
unsigned w, h;
Genode::Attached_ram_dataspace ds;
Genode::Pixel_rgb565 *pixel;
unsigned char *alpha;
Genode::Texture<Genode::Pixel_rgb565> texture;
Fb_texture(unsigned w, unsigned h, bool config_alpha)
:
w(w), h(h),
ds(Genode::env()->ram_session(), w*h*sizeof(Genode::Pixel_rgb565)),
pixel(ds.local_addr<Genode::Pixel_rgb565>()),
alpha((unsigned char *)Genode::env()->heap()->alloc(w*h)),
texture(pixel, alpha, Scout::Area(w, h))
{
int alpha_min = config_alpha ? 0 : 255;
/* init alpha channel */
for (unsigned y = 0; y < h; y++)
for (unsigned x = 0; x < w; x++) {
int v = (x * y + (w*h)/4) / w;
v = v + (x + y)/2;
int a = v & 0xff;
if (v & 0x100)
a = 255 - a;
a += (Genode::Dither_matrix::value(x, y) - 127) >> 4;
alpha[y*w + x] = Genode::max(alpha_min, Genode::min(a, 255));
}
}
~Fb_texture()
{
Genode::env()->heap()->free(alpha, w*h);
}
};
bool _config_alpha;
Content_event_handler _ev_handler;
Fb_texture *_fb;
/**
* Size of the framebuffer handed out by the next call of 'dataspace'
*/
Scout::Area _next_size;
/**
* Most current designated size of the framebuffer as defined by the
* user.
*
* The '_designated_size' may be updated any time when the user drags
* the resize handle of the window. It is propagated to '_next_size'
* not before the framebuffer client requests the current mode. Once
* the mode information is passed to the client, it is locked until
* the client requests the mode again.
*/
Scout::Area _designated_size;
Genode::Signal_context_capability _mode_sigh;
public:
Window_content(unsigned fb_w, unsigned fb_h, Event_queue *ev_queue,
bool config_alpha)
:
_config_alpha(config_alpha),
_ev_handler(ev_queue, this),
_fb(new (Genode::env()->heap()) Fb_texture(fb_w, fb_h, _config_alpha)),
_next_size(fb_w, fb_h),
_designated_size(_next_size)
{
_min_size = Scout::Area(_fb->w, _fb->h);
event_handler(&_ev_handler);
}
Genode::Dataspace_capability fb_ds_cap() { return _fb->ds.cap(); }
unsigned fb_w() { return _fb->w; }
unsigned fb_h() { return _fb->h; }
Scout::Area mode_size()
{
_next_size = _designated_size;
return _next_size;
}
void mode_sigh(Genode::Signal_context_capability sigh)
{
_mode_sigh = sigh;
}
void realloc_framebuffer()
{
/* skip reallocation if size has not changed */
if (_next_size.w() == _fb->w && _next_size.h() == _fb->h)
return;
Genode::destroy(Genode::env()->heap(), _fb);
_fb = new (Genode::env()->heap())
Fb_texture(_next_size.w(), _next_size.h(), _config_alpha);
}
/**
* Element interface
*/
void draw(Scout::Canvas_base &canvas, Scout::Point abs_position)
{
canvas.draw_texture(abs_position + _position, _fb->texture);
}
void format_fixed_size(Scout::Area size)
{
_designated_size = size;
/* notify framebuffer client about mode change */
if (_mode_sigh.valid())
Genode::Signal_transmitter(_mode_sigh).submit();
}
};
static Window_content *_window_content;
Scout::Element *window_content() { return _window_content; }
/***********************************************
** Implementation of the framebuffer service **
***********************************************/
namespace Framebuffer
{
class Session_component : public Genode::Rpc_object<Session>
{
private:
Window_content &_window_content;
Genode::Signal_context_capability _sync_sigh;
public:
Session_component(Window_content &window_content)
: _window_content(window_content) { }
Genode::Dataspace_capability dataspace() override
{
_window_content.realloc_framebuffer();
return _window_content.fb_ds_cap();
}
Mode mode() const override
{
return Mode(_window_content.mode_size().w(),
_window_content.mode_size().h(), Mode::RGB565);
}
void mode_sigh(Genode::Signal_context_capability sigh) override {
_window_content.mode_sigh(sigh); }
void sync_sigh(Genode::Signal_context_capability sigh) override {
_sync_sigh = sigh; }
void refresh(int x, int y, int w, int h) override
{
_window_content.redraw_area(x, y, w, h);
if (_sync_sigh.valid())
Genode::Signal_transmitter(_sync_sigh).submit();
}
};
class Root : public Genode::Root_component<Session_component>
{
private:
Window_content &_window_content;
protected:
Session_component *_create_session(const char *args) override {
return new (md_alloc()) Session_component(_window_content); }
public:
Root(Genode::Rpc_entrypoint *session_ep,
Genode::Allocator *md_alloc,
Window_content &window_content)
:
Genode::Root_component<Session_component>(session_ep, md_alloc),
_window_content(window_content)
{ }
};
}
void init_window_content(unsigned fb_w, unsigned fb_h, bool config_alpha)
{
static Window_content content(fb_w, fb_h, &_ev_queue, config_alpha);
_window_content = &content;
}
void init_services(Genode::Rpc_entrypoint &ep)
{
using namespace Genode;
/*
* Let the entry point serve the framebuffer and input root interfaces
*/
static Framebuffer::Root fb_root(&ep, env()->heap(), *_window_content);
static Input::Root input_root(&ep, env()->heap());
/*
* Now, the root interfaces are ready to accept requests.
* This is the right time to tell mummy about our services.
*/
env()->parent()->announce(ep.manage(&fb_root));
env()->parent()->announce(ep.manage(&input_root));
}

View File

@ -0,0 +1,28 @@
/*
* \brief Fb_nit-internal service interface
* \author Norman Feske
* \date 2006-09-22
*/
/*
* Copyright (C) 2006-2013 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU General Public License version 2.
*/
#ifndef _SERVICES_H_
#define _SERVICES_H_
#include <base/rpc_server.h>
#include <scout/canvas.h>
#include "elements.h"
extern Scout::Element *window_content();
extern void init_window_content(unsigned fb_w, unsigned fb_h, bool config_alpha);
extern void init_services(Genode::Rpc_entrypoint &ep);
extern void lock_window_content();
extern void unlock_window_content();
#endif

View File

@ -0,0 +1,5 @@
TARGET = liquid_fb
LIBS = scout_widgets config
SRC_CC = main.cc services.cc
INC_DIR += $(REP_DIR)/src/app/scout \
$(REP_DIR)/src/server/framebuffer/sdl

View File

@ -0,0 +1,466 @@
/*
* \brief Nitpicker-based logging service
* \author Norman Feske
* \date 2006-09-18
*/
/*
* Copyright (C) 2006-2013 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU General Public License version 2.
*/
#include <util/arg_string.h>
#include <base/env.h>
#include <base/sleep.h>
#include <base/lock.h>
#include <base/snprintf.h>
#include <base/rpc_server.h>
#include <root/component.h>
#include <cap_session/connection.h>
#include <log_session/log_session.h>
#include <nitpicker_session/connection.h>
#include <nitpicker_view/client.h>
#include <timer_session/connection.h>
#include <input/event.h>
#include <os/pixel_rgb565.h>
/*
* Nitpicker's graphics backend
*/
#include <nitpicker_gfx/text_painter.h>
#include <nitpicker_gfx/box_painter.h>
enum { LOG_W = 80 }; /* number of visible characters per line */
enum { LOG_H = 25 }; /* number of lines of log window */
typedef Text_painter::Font Font;
typedef Genode::Surface_base::Point Point;
typedef Genode::Surface_base::Area Area;
typedef Genode::Surface_base::Rect Rect;
typedef Genode::Color Color;
/*
* Font initialization
*/
extern char _binary_mono_tff_start;
Font default_font(&_binary_mono_tff_start);
/**
* Pixel-type-independent interface to graphics backend
*/
struct Canvas_base
{
virtual void draw_string(Point, Font const &, Color, char const *) = 0;
virtual void draw_box(Rect, Color) = 0;
};
/**
* Pixel-type-specific graphics backend
*/
template <typename PT>
class Canvas : public Canvas_base
{
private:
Genode::Surface<PT> _surface;
public:
Canvas(PT *base, Area size) : _surface(base, size) { }
void clip(Rect rect) { _surface.clip(rect); }
void draw_string(Point p, Font const &font, Color color,
char const *sstr)
{
Text_painter::paint(_surface, p, font, color, sstr);
}
void draw_box(Rect rect, Color color)
{
Box_painter::paint(_surface, rect, color);
}
};
class Log_entry
{
private:
typedef Genode::Color Color;
char _label[64];
char _text[LOG_W];
char _attr[LOG_W];
Color _color;
int _label_len;
int _text_len;
int _id;
public:
/**
* Constructors
*
* The default constructor is used to build an array of log entries.
*/
Log_entry() { }
Log_entry(Genode::Color color, const char *label, const char *log_text, const char *log_attr, int id):
_color(color), _id(id)
{
Genode::strncpy(_label, label, sizeof(_label));
Genode::strncpy(_text, log_text, sizeof(_text));
_label_len = Genode::strlen(_label);
_text_len = Genode::strlen(_text);
/* replace line feed at the end of the text with a blank */
if (_text_len > 0 && _text[_text_len - 1] == '\n')
_text[_text_len - 1] = ' ';
Genode::memcpy(_attr, log_attr, _text_len);
}
/**
* Draw entry
*
* An entry consists of a label and text. The argument 'new_section'
* marks a transition of output from one session to another. This
* information is used to separate sessions visually.
*/
void draw(Canvas_base &canvas, int y, int new_section = false)
{
Color label_fgcol = Color(Genode::min(255, _color.r + 200),
Genode::min(255, _color.g + 200),
Genode::min(255, _color.b + 200));
Color label_bgcol = Color(_color.r, _color.g, _color.b);
Color text_fgcol = Color(180, 180, 180);
Color text_bgcol = Color(_color.r / 2, _color.g / 2, _color.b / 2);
/* calculate label dimensions */
int label_w = default_font.str_w(_label);
int label_h = default_font.str_h(_label);
if (new_section) {
canvas.draw_box(Rect(Point(1, y), Area(label_w + 2, label_h - 1)), label_bgcol);
canvas.draw_string(Point(1, y - 1), default_font, label_fgcol, _label);
canvas.draw_box(Rect(Point(1, y + label_h - 1), Area(label_w + 2, 1)), Color(0, 0, 0));
canvas.draw_box(Rect(Point(label_w + 2, y), Area(1, label_h - 1)), _color);
canvas.draw_box(Rect(Point(label_w + 3, y), Area(1, label_h - 1)), Color(0, 0, 0));
canvas.draw_box(Rect(Point(label_w + 4, y), Area(1000, label_h)), text_bgcol);
canvas.draw_box(Rect(Point(label_w + 4, y), Area(1000, 1)), Color(0, 0, 0));
} else
canvas.draw_box(Rect(Point(1, y), Area(1000, label_h)), text_bgcol);
/* draw log text */
canvas.draw_string(Point(label_w + 6, y), default_font, text_fgcol, _text);
}
/**
* Accessors
*/
int label_len() { return _label_len; }
int id() { return _id; }
};
class Log_window
{
private:
Canvas_base &_canvas;
Log_entry _entries[LOG_H]; /* log entries */
int _dst_entry; /* destination entry for next write */
int _view_pos; /* current view port on the entry array */
bool _scroll; /* scroll mode (when text hits bottom) */
char _attr[LOG_W]; /* character attribute buffer */
bool _dirty; /* schedules the log window for a redraw */
Genode::Lock _dirty_lock;
public:
/**
* Constructor
*/
Log_window(Canvas_base &canvas)
: _canvas(canvas), _dst_entry(0), _view_pos(0), _dirty(true)
{ }
/**
* Write log entry
*
* \param color base color for highlighting the session.
* \param sid unique ID of the log session. This ID is used to
* determine section transitions in the log output.
*/
void write(Genode::Color color, const char *label,
const char *log_text, int sid)
{
_entries[_dst_entry] = Log_entry(color, label, log_text, _attr, sid);
if (_scroll)
_view_pos++;
/* cycle through log entries */
_dst_entry = (_dst_entry + 1) % LOG_H;
/* start scrolling when the dst entry wraps for the first time */
if (_dst_entry == 0)
_scroll = true;
/* schedule log window for redraw */
Genode::Lock::Guard lock_guard(_dirty_lock);
_dirty |= 1;
}
/**
* Draw log window
*
* \retval true drawing operations had been performed
*/
bool draw()
{
{
Genode::Lock::Guard lock_guard(_dirty_lock);
if (!_dirty) return false;
_dirty = false;
}
int line_h = default_font.str_h(" ");
int curr_session_id = -1;
for (int i = 0, y = 0; i < LOG_H; i++, y += line_h) {
Log_entry *le = &_entries[(i + _view_pos) % LOG_H];
le->draw(_canvas, y, curr_session_id != le->id());
curr_session_id = le->id();
}
return true;
}
};
class Log_session_component : public Genode::Rpc_object<Genode::Log_session>
{
public:
enum { LABEL_LEN = 64 };
private:
Genode::Color _color;
Log_window *_log_window;
char _label[LABEL_LEN];
int _id;
static int _bit(int v, int bit_num) { return (v >> bit_num) & 1; }
public:
/**
* Constructor
*/
Log_session_component(const char *label, Log_window *log_window)
: _color(0, 0, 0), _log_window(log_window)
{
static int cnt;
_id = cnt++;
const int scale = 32;
const int offset = 64;
/* compute session color */
int r = (_bit(_id, 3) + 2*_bit(_id, 0))*scale + offset;
int g = (_bit(_id, 4) + 2*_bit(_id, 1))*scale + offset;
int b = (_bit(_id, 5) + 2*_bit(_id, 2))*scale + offset;
_color = Genode::Color(r, g, b);
Genode::strncpy(_label, label, sizeof(_label));
}
/***************************
** Log session interface **
***************************/
Genode::size_t write(String const &log_text)
{
if (!log_text.is_valid_string()) {
PERR("corrupted string");
return 0;
}
_log_window->write(_color, _label, log_text.string(), _id);
return Genode::strlen(log_text.string());
}
};
class Log_root_component : public Genode::Root_component<Log_session_component>
{
private:
Log_window *_log_window;
protected:
Log_session_component *_create_session(const char *args)
{
PINF("create log session (%s)", args);
char label_buf[Log_session_component::LABEL_LEN];
Genode::Arg label_arg = Genode::Arg_string::find_arg(args, "label");
label_arg.string(label_buf, sizeof(label_buf), "");
return new (md_alloc()) Log_session_component(label_buf, _log_window);
}
public:
/**
* Constructor
*/
Log_root_component(Genode::Rpc_entrypoint *ep,
Genode::Allocator *md_alloc,
Log_window *log_window)
:
Genode::Root_component<Log_session_component>(ep, md_alloc),
_log_window(log_window) { }
};
class Log_view
{
private:
Nitpicker::View_capability _cap;
int _x, _y, _w, _h;
public:
Log_view(Nitpicker::Session *nitpicker,
int x, int y, int w, int h)
:
_x(x), _y(y), _w(w), _h(h)
{
using namespace Nitpicker;
_cap = nitpicker->create_view();
View_client(_cap).viewport(_x, _y, _w, _h, 0, 0, true);
View_client(_cap).stack(Nitpicker::View_capability(), true, true);
}
void top()
{
Nitpicker::View_client(_cap).stack(Nitpicker::View_capability(), true, true);
}
void move(int x, int y)
{
_x = x, _y = y;
Nitpicker::View_client(_cap).viewport(_x, _y, _w, _h, 0, 0, true);
}
/**
* Accessors
*/
int x() { return _x; }
int y() { return _y; }
};
int main(int argc, char **argv)
{
using namespace Genode;
/* make sure that we connect to LOG before providing this service by ourself */
printf("--- nitlog ---\n");
/* calculate size of log view in pixels */
int log_win_w = default_font.str_w(" ") * LOG_W + 2;
int log_win_h = default_font.str_h(" ") * LOG_H + 2;
/* init sessions to the required external services */
static Nitpicker::Connection nitpicker;
static Timer::Connection timer;
nitpicker.buffer(Framebuffer::Mode(log_win_w, log_win_h,
Framebuffer::Mode::RGB565), false);
/* initialize entry point that serves the root interface */
enum { STACK_SIZE = 4096 };
static Cap_connection cap;
static Rpc_entrypoint ep(&cap, STACK_SIZE, "nitlog_ep");
/*
* Use sliced heap to allocate each session component at a separate
* dataspace.
*/
static Sliced_heap sliced_heap(env()->ram_session(), env()->rm_session());
/* create log window */
void *addr = env()->rm_session()->attach(nitpicker.framebuffer()->dataspace());
static Canvas<Pixel_rgb565> canvas((Pixel_rgb565 *)addr,
::Area(log_win_w, log_win_h));
static Log_window log_window(canvas);
/*
* We clip a border of one pixel off the canvas. This way, the
* border remains unaffected by the drawing operations and
* acts as an outline for the log window.
*/
canvas.clip(::Rect(::Point(1, 1), ::Area(log_win_w - 2, log_win_h - 2)));
/* create view for log window */
Log_view log_view(&nitpicker, 20, 20, log_win_w, log_win_h);
/* create root interface for service */
static Log_root_component log_root(&ep, &sliced_heap, &log_window);
/* announce service at our parent */
env()->parent()->announce(ep.manage(&log_root));
/* handle input events */
Input::Event *ev_buf = env()->rm_session()->attach(nitpicker.input()->dataspace());
int omx = 0, omy = 0, key_cnt = 0;
while (1) {
while (!nitpicker.input()->is_pending()) {
if (log_window.draw())
nitpicker.framebuffer()->refresh(0, 0, log_win_w, log_win_h);
timer.msleep(20);
}
for (int i = 0, num_ev = nitpicker.input()->flush(); i < num_ev; i++) {
Input::Event *ev = &ev_buf[i];
if (ev->type() == Input::Event::PRESS) key_cnt++;
if (ev->type() == Input::Event::RELEASE) key_cnt--;
/* move view */
if (ev->type() == Input::Event::MOTION && key_cnt > 0)
log_view.move(log_view.x() + ev->ax() - omx,
log_view.y() + ev->ay() - omy);
/* find selected view and bring it to front */
if (ev->type() == Input::Event::PRESS && key_cnt == 1)
log_view.top();
omx = ev->ax(); omy = ev->ay();
}
}
return 0;
}

Binary file not shown.

View File

@ -0,0 +1,5 @@
TARGET = nitlog
LIBS = base blit
SRC_CC = main.cc
SRC_BIN = mono.tff
INC_DIR = $(REP_DIR)/src/server/nitpicker/include