genode/repos/os/src/app/status_bar/main.cc

260 lines
6.9 KiB
C++

/*
* \brief Minimalistic status bar for nitpicker
* \author Norman Feske
* \date 2014-07-08
*/
/*
* Copyright (C) 2014-2017 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.
*/
#include <util/reconstructible.h>
#include <util/xml_node.h>
#include <util/color.h>
#include <base/component.h>
#include <base/attached_rom_dataspace.h>
#include <os/pixel_rgb565.h>
#include <nitpicker_session/connection.h>
#include <nitpicker_gfx/box_painter.h>
#include <nitpicker_gfx/tff_font.h>
namespace Status_bar {
using namespace Genode;
typedef String<128> Domain_name;
typedef String<128> Label;
typedef Surface_base::Area Area;
typedef Surface_base::Point Point;
typedef Surface_base::Rect Rect;
struct Buffer;
struct Main;
}
extern char _binary_default_tff_start;
struct Status_bar::Buffer
{
enum { HEIGHT = 18, LABEL_GAP = 15 };
Nitpicker::Connection &_nitpicker;
Framebuffer::Mode const _nit_mode { _nitpicker.mode() };
/*
* Dimension nitpicker buffer depending on nitpicker's screen size.
* The status bar is as wide as nitpicker's screen and has a fixed
* height.
*/
Framebuffer::Mode const _mode { _nit_mode.width(), HEIGHT, _nit_mode.format() };
Dataspace_capability _init_buffer()
{
_nitpicker.buffer(_mode, false);
return _nitpicker.framebuffer()->dataspace();
}
Attached_dataspace _fb_ds;
Tff_font::Static_glyph_buffer<4096> _glyph_buffer { };
Tff_font _font { &_binary_default_tff_start, _glyph_buffer };
Buffer(Region_map &rm, Nitpicker::Connection &nitpicker)
:
_nitpicker(nitpicker), _fb_ds(rm, _init_buffer())
{ }
template <typename PT>
void _draw_outline(Surface<PT> &surface, Point pos, char const *s)
{
for (int j = -1; j <= 1; j++)
for (int i = -1; i <= 1; i++)
if (i || j)
Text_painter::paint(surface,
Text_painter::Position(pos.x() + i, pos.y() + j),
_font, Color(0, 0, 0), s);
}
template <typename PT>
void _draw_label(Surface<PT> &surface, Point pos,
Domain_name const &domain_name, Label const &label,
Color color)
{
Color const label_text_color((color.r + 255)/2,
(color.g + 255)/2,
(color.b + 255)/2);
Color const domain_text_color(255, 255, 255);
pos = pos + Point(1, 1);
_draw_outline(surface, pos, domain_name.string());
Text_painter::paint(surface, Text_painter::Position(pos.x(), pos.y()),
_font, domain_text_color, domain_name.string());
pos = pos + Point(_font.string_width(domain_name.string()).decimal() + LABEL_GAP, 0);
_draw_outline(surface, pos, label.string());
Text_painter::paint(surface, Text_painter::Position(pos.x(), pos.y()),
_font, label_text_color, label.string());
}
Area _label_size(Domain_name const &domain_name, Label const &label) const
{
return Area(_font.string_width(domain_name.string()).decimal() + LABEL_GAP
+ _font.string_width(label.string()).decimal() + 2,
_font.bounding_box().h() + 2);
}
void draw(Domain_name const &, Label const &, Color);
Framebuffer::Mode mode() const { return _mode; }
};
void Status_bar::Buffer::draw(Domain_name const &domain_name,
Label const &label,
Color color)
{
if (_mode.format() != Framebuffer::Mode::RGB565) {
error("pixel format not supported");
return;
}
typedef Pixel_rgb565 PT;
Area const area(_mode.width(), _mode.height());
Surface<PT> surface(_fb_ds.local_addr<PT>(), area);
Rect const view_rect(Point(0, 0), area);
int r = color.r, g = color.g, b = color.b;
/* dim session color a bit to improve the contrast of the label */
r = (r + 100)/2, g = (g + 100)/2, b = (b + 100)/2;
/* highlight first line with slightly brighter color */
Box_painter::paint(surface,
Rect(Point(0, 0), Area(view_rect.w(), 1)),
Color(r + (r / 2), g + (g / 2), b + (b / 2)));
/* draw slightly shaded background */
for (unsigned i = 1; i < area.h() - 1; i++) {
r -= r > 3 ? 4 : 0;
g -= g > 3 ? 4 : 0;
b -= b > 4 ? 4 : 0;
Box_painter::paint(surface,
Rect(Point(0, i), Area(view_rect.w(), 1)),
Color(r, g, b));
}
/* draw last line darker */
Box_painter::paint(surface,
Rect(Point(0, view_rect.h() - 1), Area(view_rect.w(), 1)),
Color(r / 4, g / 4, b / 4));
_draw_label(surface, view_rect.center(_label_size(domain_name, label)),
domain_name, label, color);
_nitpicker.framebuffer()->refresh(0, 0, area.w(), area.h());
}
struct Status_bar::Main
{
Env &_env;
Attached_rom_dataspace _focus_ds { _env, "focus" };
void _handle_focus();
Signal_handler<Main> _focus_handler {
_env.ep(), *this, &Main::_handle_focus };
void _handle_mode();
Signal_handler<Main> _mode_handler {
_env.ep(), *this, &Main::_handle_mode };
Nitpicker::Connection _nitpicker { _env, "status_bar" };
/* status-bar attributes */
Domain_name _domain_name { };
Label _label { };
Color _color { };
Reconstructible<Buffer> _buffer { _env.rm(), _nitpicker };
Nitpicker::Session::View_handle const _view { _nitpicker.create_view() };
void _draw_status_bar()
{
_buffer->draw(_domain_name, _label, _color);
}
Main(Env &env) : _env(env)
{
/* register signal handlers */
_focus_ds.sigh(_focus_handler);
_nitpicker.mode_sigh(_mode_handler);
/* schedule initial view-stacking command, needed only once */
typedef Nitpicker::Session::View_handle View_handle;
_nitpicker.enqueue<Nitpicker::Session::Command::To_front>(_view, View_handle());
/* import initial state */
_handle_mode();
_handle_focus();
}
};
void Status_bar::Main::_handle_focus()
{
/* fetch new content of the focus ROM module */
_focus_ds.update();
if (!_focus_ds.valid())
return;
/* reset status-bar properties */
_label = Label();
_domain_name = Domain_name();
_color = Color(0, 0, 0);
/* read new focus information from nitpicker's focus report */
try {
Xml_node node(_focus_ds.local_addr<char>());
_label = node.attribute_value("label", Label());
_domain_name = node.attribute_value("domain", Domain_name());
_color = node.attribute_value("color", Color(0, 0, 0));
}
catch (...) {
warning("could not parse focus report"); }
_draw_status_bar();
}
void Status_bar::Main::_handle_mode()
{
_buffer.construct(_env.rm(), _nitpicker);
_draw_status_bar();
Rect const geometry(Point(0, 0), Area(_buffer->mode().width(),
_buffer->mode().height()));
_nitpicker.enqueue<Nitpicker::Session::Command::Geometry>(_view, geometry);
_nitpicker.execute();
}
void Component::construct(Genode::Env &env) { static Status_bar::Main main { env }; }