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

260 lines
6.9 KiB
C++
Raw Normal View History

/*
* \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 */
Follow practices suggested by "Effective C++" The patch adjust the code of the base, base-<kernel>, and os repository. To adapt existing components to fix violations of the best practices suggested by "Effective C++" as reported by the -Weffc++ compiler argument. The changes follow the patterns outlined below: * A class with virtual functions can no longer publicly inherit base classed without a vtable. The inherited object may either be moved to a member variable, or inherited privately. The latter would be used for classes that inherit 'List::Element' or 'Avl_node'. In order to enable the 'List' and 'Avl_tree' to access the meta data, the 'List' must become a friend. * Instead of adding a virtual destructor to abstract base classes, we inherit the new 'Interface' class, which contains a virtual destructor. This way, single-line abstract base classes can stay as compact as they are now. The 'Interface' utility resides in base/include/util/interface.h. * With the new warnings enabled, all member variables must be explicitly initialized. Basic types may be initialized with '='. All other types are initialized with braces '{ ... }' or as class initializers. If basic types and non-basic types appear in a row, it is nice to only use the brace syntax (also for basic types) and align the braces. * If a class contains pointers as members, it must now also provide a copy constructor and assignment operator. In the most cases, one would make them private, effectively disallowing the objects to be copied. Unfortunately, this warning cannot be fixed be inheriting our existing 'Noncopyable' class (the compiler fails to detect that the inheriting class cannot be copied and still gives the error). For now, we have to manually add declarations for both the copy constructor and assignment operator as private class members. Those declarations should be prepended with a comment like this: /* * Noncopyable */ Thread(Thread const &); Thread &operator = (Thread const &); In the future, we should revisit these places and try to replace the pointers with references. In the presence of at least one reference member, the compiler would no longer implicitly generate a copy constructor. So we could remove the manual declaration. Issue #465
2017-12-21 15:42:15 +01:00
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 */
Follow practices suggested by "Effective C++" The patch adjust the code of the base, base-<kernel>, and os repository. To adapt existing components to fix violations of the best practices suggested by "Effective C++" as reported by the -Weffc++ compiler argument. The changes follow the patterns outlined below: * A class with virtual functions can no longer publicly inherit base classed without a vtable. The inherited object may either be moved to a member variable, or inherited privately. The latter would be used for classes that inherit 'List::Element' or 'Avl_node'. In order to enable the 'List' and 'Avl_tree' to access the meta data, the 'List' must become a friend. * Instead of adding a virtual destructor to abstract base classes, we inherit the new 'Interface' class, which contains a virtual destructor. This way, single-line abstract base classes can stay as compact as they are now. The 'Interface' utility resides in base/include/util/interface.h. * With the new warnings enabled, all member variables must be explicitly initialized. Basic types may be initialized with '='. All other types are initialized with braces '{ ... }' or as class initializers. If basic types and non-basic types appear in a row, it is nice to only use the brace syntax (also for basic types) and align the braces. * If a class contains pointers as members, it must now also provide a copy constructor and assignment operator. In the most cases, one would make them private, effectively disallowing the objects to be copied. Unfortunately, this warning cannot be fixed be inheriting our existing 'Noncopyable' class (the compiler fails to detect that the inheriting class cannot be copied and still gives the error). For now, we have to manually add declarations for both the copy constructor and assignment operator as private class members. Those declarations should be prepended with a comment like this: /* * Noncopyable */ Thread(Thread const &); Thread &operator = (Thread const &); In the future, we should revisit these places and try to replace the pointers with references. In the presence of at least one reference member, the compiler would no longer implicitly generate a copy constructor. So we could remove the manual declaration. Issue #465
2017-12-21 15:42:15 +01:00
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 }; }