diff --git a/repos/os/run/demo.run b/repos/os/run/demo.run index bfc6922dc..cbed7e6f3 100644 --- a/repos/os/run/demo.run +++ b/repos/os/run/demo.run @@ -5,10 +5,11 @@ set build_components { core init drivers/timer - server/nitpicker app/pointer + server/nitpicker app/pointer app/status_bar server/liquid_framebuffer app/launchpad app/scout test/nitpicker server/nitlog drivers/framebuffer drivers/pci drivers/input + server/report_rom } lappend_if [have_spec usb] build_components drivers/usb @@ -116,15 +117,27 @@ append config { + + + + + + + + + + - + + - - + + + @@ -136,6 +149,13 @@ append config { + + + + + + + @@ -170,7 +190,7 @@ close $launchpad_config_fd set boot_modules { core init timer - nitpicker pointer liquid_fb launchpad scout + nitpicker pointer status_bar report_rom liquid_fb launchpad scout testnit nitlog launchpad.config } diff --git a/repos/os/src/app/status_bar/main.cc b/repos/os/src/app/status_bar/main.cc new file mode 100644 index 000000000..761dc50ff --- /dev/null +++ b/repos/os/src/app/status_bar/main.cc @@ -0,0 +1,282 @@ +/* + * \brief Minimalistic status bar for nitpicker + * \author Norman Feske + * \date 2014-07-08 + */ + +/* + * Copyright (C) 2014 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 +#include +#include +#include +#include +#include +#include +#include + +typedef Genode::Color Color; +typedef Genode::String<128> Domain_name; +typedef Genode::String<128> Label; +typedef Genode::Surface_base::Area Area; +typedef Genode::Surface_base::Point Point; +typedef Genode::Surface_base::Rect Rect; +typedef Genode::size_t size_t; + + +/*************** + ** Utilities ** + ***************/ + +template +static Genode::String read_string_attribute(Genode::Xml_node node, char const *attr, + Genode::String default_value) +{ + try { + char buf[N]; + node.attribute(attr).value(buf, sizeof(buf)); + return Genode::String(buf); + } + catch (...) { + return default_value; } +} + +extern char _binary_default_tff_start; + + +/****************** + ** Main program ** + ******************/ + +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() }; + + Genode::Dataspace_capability init_buffer() + { + nitpicker.buffer(mode, false); + return nitpicker.framebuffer()->dataspace(); + } + + Genode::Attached_dataspace fb_ds { init_buffer() }; + + Text_painter::Font const font { &_binary_default_tff_start }; + + Status_bar_buffer(Nitpicker::Connection &nitpicker) + : + nitpicker(nitpicker) + { } + + template + void _draw_outline(Genode::Surface &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, pos + Point(i, j), font, + Color(0, 0, 0), s); + } + + template + void _draw_label(Genode::Surface &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, pos, font, domain_text_color, + domain_name.string()); + + pos = pos + Point(font.str_w(domain_name.string()) + LABEL_GAP, 0); + + _draw_outline(surface, pos, label.string()); + Text_painter::paint(surface, pos, font, label_text_color, label.string()); + } + + Area _label_size(Domain_name const &domain_name, Label const &label) const + { + return Area(font.str_w(domain_name.string()) + LABEL_GAP + + font.str_w(label.string()) + 2, + font.str_h(domain_name.string()) + 2); + } + + void draw(Domain_name const &, Label const &, Color); +}; + + +void Status_bar_buffer::draw(Domain_name const &domain_name, + Label const &label, + Color color) +{ + if (mode.format() != Framebuffer::Mode::RGB565) { + PERR("pixel format not supported"); + return; + } + + typedef Genode::Pixel_rgb565 PT; + + Area const area(mode.width(), mode.height()); + + Genode::Surface surface(fb_ds.local_addr(), 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 Main +{ + Genode::Attached_rom_dataspace focus_ds { "focus" }; + + Genode::Signal_receiver sig_rec; + + void handle_focus(unsigned); + + Genode::Signal_dispatcher
focus_signal_dispatcher { + sig_rec, *this, &Main::handle_focus }; + + void handle_mode(unsigned); + + Genode::Signal_dispatcher
mode_signal_dispatcher { + sig_rec, *this, &Main::handle_mode }; + + Nitpicker::Connection nitpicker; + + /* status-bar attributes */ + Domain_name domain_name; + Label label; + Color color; + + Genode::Volatile_object status_bar_buffer { nitpicker }; + + Nitpicker::Session::View_handle const view { nitpicker.create_view() }; + + void draw_status_bar() + { + status_bar_buffer->draw(domain_name, label, color); + } + + Main() + { + /* register signal handlers */ + focus_ds.sigh(focus_signal_dispatcher); + nitpicker.mode_sigh(mode_signal_dispatcher); + + /* schedule initial view-stacking command, needed only once */ + nitpicker.enqueue(view); + + /* import initial state */ + handle_mode(0); + handle_focus(0); + } +}; + + +void Main::handle_focus(unsigned) +{ + /* fetch new content of the focus ROM module */ + focus_ds.update(); + + /* 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 { + Genode::Xml_node node(focus_ds.local_addr()); + + label = read_string_attribute(node, "label", Label()); + domain_name = read_string_attribute(node, "domain", Domain_name()); + color = node.attribute_value("color", Color(0, 0, 0)); + } + catch (...) { + PWRN("could not parse focus report"); } + + draw_status_bar(); +} + + +void Main::handle_mode(unsigned) +{ + status_bar_buffer.construct(nitpicker); + + draw_status_bar(); + + Rect const geometry(Point(0, 0), Area(status_bar_buffer->mode.width(), + status_bar_buffer->mode.height())); + + nitpicker.enqueue(view, geometry); + nitpicker.execute(); +} + + +int main(int, char **) +{ + static Main main; + + /* dispatch signals */ + for (;;) { + + Genode::Signal sig = main.sig_rec.wait_for_signal(); + Genode::Signal_dispatcher_base *dispatcher = + dynamic_cast(sig.context()); + + if (dispatcher) + dispatcher->dispatch(sig.num()); + } + + return 0; +} diff --git a/repos/os/src/app/status_bar/target.mk b/repos/os/src/app/status_bar/target.mk new file mode 100644 index 000000000..f66e445d6 --- /dev/null +++ b/repos/os/src/app/status_bar/target.mk @@ -0,0 +1,6 @@ +TARGET = status_bar +SRC_CC = main.cc +LIBS += base +SRC_BIN = default.tff + +vpath %.tff $(REP_DIR)/src/server/nitpicker diff --git a/repos/os/src/server/nitpicker/chunky_menubar.h b/repos/os/src/server/nitpicker/chunky_menubar.h deleted file mode 100644 index a3e2cc0ec..000000000 --- a/repos/os/src/server/nitpicker/chunky_menubar.h +++ /dev/null @@ -1,111 +0,0 @@ -/* - * \brief Chunky-pixel-based menubar - * \author Norman Feske - * \date 2006-08-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 _CHUNKY_MENUBAR_ -#define _CHUNKY_MENUBAR_ - -#include -#include - -#include "menubar.h" - - -template -class Chunky_menubar : public Texture, - public Session, - public Menubar, - public View -{ - private: - - Canvas _canvas; - - public: - - Chunky_menubar(PT *pixels, Area size) - : - Texture(pixels, 0, size), - Session(Genode::Session_label("")), - View(*this, View::NOT_TRANSPARENT, View::NOT_BACKGROUND, 0), - _canvas(pixels, size) - { - View::geometry(Rect(Point(0, 0), size)); - Session::texture(this, false); - } - - - /*********************** - ** Session interface ** - ***********************/ - - void submit_input_event(Input::Event) override { } - void submit_sync() override { } - - - /******************** - ** View interface ** - ********************/ - - int frame_size(Mode const &mode) const override { return 0; } - void frame(Canvas_base &canvas, Mode const &mode) const override { } - void draw(Canvas_base &canvas, Mode const &mode) const override - { - Clip_guard clip_guard(canvas, geometry()); - - /* draw menubar content */ - canvas.draw_texture(abs_position(), *this, Texture_painter::SOLID, BLACK, false); - } - - - /*********************** - ** Menubar interface ** - ***********************/ - - void state(Menubar_state const state) override - { - *static_cast(this) = state; - - /* choose base color dependent on the Nitpicker state */ - int r = (mode.kill()) ? 200 : (mode.xray()) ? session_color.r : (session_color.r + 100) >> 1; - int g = (mode.kill()) ? 70 : (mode.xray()) ? session_color.g : (session_color.g + 100) >> 1; - int b = (mode.kill()) ? 70 : (mode.xray()) ? session_color.b : (session_color.b + 100) >> 1; - - Rect const view_rect = abs_geometry(); - - /* highlight first line with slightly brighter color */ - _canvas.draw_box(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 < view_rect.h() - 1; i++) { - r -= r > 3 ? 4 : 0; - g -= g > 3 ? 4 : 0; - b -= b > 4 ? 4 : 0; - _canvas.draw_box(Rect(Point(0, i), Area(view_rect.w(), 1)), Color(r, g, b)); - } - - /* draw last line darker */ - _canvas.draw_box(Rect(Point(0, view_rect.h() - 1), Area(view_rect.w(), 1)), - Color(r / 4, g / 4, b / 4)); - - /* draw label */ - draw_label(_canvas, view_rect.center(label_size(session_label.string(), "")), - session_label.string(), WHITE, "", session_color); - } - - View &view() override { return *this; } - - using Menubar::state; -}; - -#endif diff --git a/repos/os/src/server/nitpicker/main.cc b/repos/os/src/server/nitpicker/main.cc index 2f0fd9aae..afb753c67 100644 --- a/repos/os/src/server/nitpicker/main.cc +++ b/repos/os/src/server/nitpicker/main.cc @@ -37,7 +37,6 @@ #include "background.h" #include "clip_guard.h" #include "pointer_origin.h" -#include "chunky_menubar.h" #include "domain_registry.h" namespace Input { class Session_component; } @@ -98,6 +97,20 @@ static void report_focus(Genode::Reporter &reporter, Session *focused_session) } +static void report_kill_focus(Genode::Reporter &reporter) +{ + if (!reporter.is_enabled()) + return; + + Genode::Reporter::Xml_generator xml(reporter, [&] () + { + xml.attribute("label", ""); + xml.attribute("domain", ""); + xml.attribute("color", "#ff4444"); + }); +} + + /* * Font initialization */ @@ -1043,11 +1056,10 @@ struct Nitpicker::Main typedef Pixel_rgb565 PT; /* physical pixel type */ /* - * Initialize framebuffer and menu bar + * Initialize framebuffer * - * The framebuffer and menubar are encapsulated in a volatile object to - * allow their reconstruction at runtime as a response to resolution - * changes. + * The framebuffer is encapsulated in a volatile object to allow its + * reconstruction at runtime as a response to resolution changes. */ struct Framebuffer_screen { @@ -1059,28 +1071,10 @@ struct Nitpicker::Main Screen screen = { fb_ds.local_addr(), Area(mode.width(), mode.height()) }; - enum { MENUBAR_HEIGHT = 16 }; - - /** - * Size of menubar pixel buffer in bytes - */ - size_t const menubar_size = sizeof(PT)*mode.width()*MENUBAR_HEIGHT; - - PT *menubar_pixels = - (PT *)env()->heap()->alloc(menubar_size); - - Chunky_menubar menubar = - { menubar_pixels, Area(mode.width(), MENUBAR_HEIGHT) }; - /** * Constructor */ Framebuffer_screen(Framebuffer::Session &fb) : framebuffer(fb) { } - - /** - * Destructor - */ - ~Framebuffer_screen() { env()->heap()->free(menubar_pixels, menubar_size); } }; Genode::Volatile_object fb_screen = { framebuffer }; @@ -1103,7 +1097,7 @@ struct Nitpicker::Main Genode::Volatile_object domain_registry { *env()->heap(), Genode::Xml_node("") }; - User_state user_state = { global_keys, fb_screen->screen.size(), fb_screen->menubar }; + User_state user_state = { global_keys, fb_screen->screen.size() }; /* * Create view stack with default elements @@ -1151,12 +1145,9 @@ struct Nitpicker::Main { // tmp_fb = &framebuffer; - fb_screen->menubar.state(Menubar_state(user_state, "", BLACK)); - user_state.default_background(background); user_state.stack(pointer_origin); user_state.stack(background); - user_state.stack(fb_screen->menubar); config()->sigh(config_dispatcher); Signal_transmitter(config_dispatcher).submit(); @@ -1185,6 +1176,7 @@ void Nitpicker::Main::handle_input(unsigned) do { Point const old_pointer_pos = user_state.pointer_pos(); ::Session * const old_focused_session = user_state.Mode::focused_session(); + bool const old_kill_mode = user_state.kill(); /* handle batch of pending events */ if (input.is_pending()) @@ -1192,6 +1184,7 @@ void Nitpicker::Main::handle_input(unsigned) Point const new_pointer_pos = user_state.pointer_pos(); ::Session * const new_focused_session = user_state.Mode::focused_session(); + bool const new_kill_mode = user_state.kill(); /* report mouse-position updates */ if (pointer_reporter.is_enabled() && old_pointer_pos != new_pointer_pos) { @@ -1207,6 +1200,24 @@ void Nitpicker::Main::handle_input(unsigned) if (old_focused_session != new_focused_session) report_focus(focus_reporter, new_focused_session); + /* report kill mode */ + if (old_kill_mode != new_kill_mode) { + + if (new_kill_mode) + report_kill_focus(focus_reporter); + + if (!new_kill_mode) + report_focus(focus_reporter, new_focused_session); + } + + /* + * Continuously redraw the whole screen when kill mode is active. + * Otherwise client updates (e.g., the status bar) would stay invisible + * because we do not dispatch the RPC interface during kill mode. + */ + if (new_kill_mode) + user_state.update_all_views(); + /* update mouse cursor */ if (old_pointer_pos != new_pointer_pos) user_state.geometry(pointer_origin, Rect(new_pointer_pos, Area())); @@ -1290,24 +1301,12 @@ void Nitpicker::Main::handle_config(unsigned) void Nitpicker::Main::handle_fb_mode(unsigned) { - /* save state of menu bar */ - Menubar_state menubar_state = fb_screen->menubar.state(); - - /* remove old version of menu bar from view stack */ - user_state.remove_view(fb_screen->menubar, false); - /* reconstruct framebuffer screen and menu bar */ fb_screen.construct(framebuffer); /* let the view stack use the new size */ user_state.size(Area(fb_screen->mode.width(), fb_screen->mode.height())); - /* load original state into new menu bar */ - fb_screen->menubar.state(menubar_state); - - /* re-insert menu bar behind mouse cursor */ - user_state.stack(fb_screen->menubar, &pointer_origin); - /* redraw */ user_state.update_all_views(); diff --git a/repos/os/src/server/nitpicker/menubar.h b/repos/os/src/server/nitpicker/menubar.h deleted file mode 100644 index eeaaf9d0c..000000000 --- a/repos/os/src/server/nitpicker/menubar.h +++ /dev/null @@ -1,50 +0,0 @@ -/* - * \brief Nitpicker menubar interface - * \author Norman Feske - * \date 2006-08-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 _MENUBAR_H_ -#define _MENUBAR_H_ - -#include "view.h" -#include "draw_label.h" -#include "mode.h" - -struct Menubar_state -{ - Genode::String<128> session_label; - Mode mode; - Color session_color; - - Menubar_state(Mode mode, char const *session_label, Color session_color) - : - session_label(session_label), mode(mode), session_color(session_color) - { } - - Menubar_state() : session_color(BLACK) { } -}; - - -struct Menubar : Menubar_state -{ - virtual ~Menubar() { } - - /** - * Set state that is displayed in the trusted menubar - */ - virtual void state(Menubar_state) = 0; - - Menubar_state state() const { return *this; } - - virtual View &view() = 0; -}; - -#endif diff --git a/repos/os/src/server/nitpicker/user_state.cc b/repos/os/src/server/nitpicker/user_state.cc index ec80c395d..ebc68518e 100644 --- a/repos/os/src/server/nitpicker/user_state.cc +++ b/repos/os/src/server/nitpicker/user_state.cc @@ -35,30 +35,14 @@ static inline bool _mouse_button(Keycode keycode) { ** User state interface ** **************************/ -User_state::User_state(Global_keys &global_keys, Area view_stack_size, Menubar &menubar) +User_state::User_state(Global_keys &global_keys, Area view_stack_size) : - View_stack(view_stack_size, *this), _global_keys(global_keys), _menubar(menubar) + View_stack(view_stack_size, *this), _global_keys(global_keys) { } -void User_state::_update_menubar() -{ - Menubar_state state(*this, "", BLACK); - - if (_input_receiver) - state = Menubar_state(*this, - _input_receiver->label().string(), - _input_receiver->color()); - - _menubar.state(state); - - refresh_view(_menubar.view(), _menubar.view().abs_geometry()); -} - - void User_state::_update_all() { - _update_menubar(); update_all_views(); } @@ -283,6 +267,4 @@ void User_state::focused_session(::Session *session) if (!_global_key_sequence) _input_receiver = session; - - _update_menubar(); } diff --git a/repos/os/src/server/nitpicker/user_state.h b/repos/os/src/server/nitpicker/user_state.h index d59ac8b8f..642b481f4 100644 --- a/repos/os/src/server/nitpicker/user_state.h +++ b/repos/os/src/server/nitpicker/user_state.h @@ -19,7 +19,6 @@ #define _USER_STATE_H_ #include "mode.h" -#include "menubar.h" #include "view_stack.h" #include "global_keys.h" @@ -32,13 +31,6 @@ class User_state : public Mode, public View_stack */ Global_keys &_global_keys; - /* - * Menubar to display trusted labeling information - * according to the current Mitpicker mode and the - * focused session. - */ - Menubar &_menubar; - /* * Current pointer position */ @@ -59,7 +51,6 @@ class User_state : public Mode, public View_stack */ bool _global_key_sequence = false; - void _update_menubar(); void _update_all(); public: @@ -67,7 +58,7 @@ class User_state : public Mode, public View_stack /** * Constructor */ - User_state(Global_keys &, Area view_stack_size, Menubar &); + User_state(Global_keys &, Area view_stack_size); /** * Handle input event