gui_session: provide mode info as XML

In multi-monitor scenarios, the mode is no longer a single rectangular
area but a panorama with potentially many captured rectangles. This
patch replaces the former 'mode' and 'mode_sigh' RPC by a new 'info'
ROM accessor.

Issue #5353
This commit is contained in:
Norman Feske 2024-10-01 14:56:18 +02:00 committed by Christian Helmuth
parent d29cb0a15d
commit 318d641266
31 changed files with 639 additions and 412 deletions

View File

@ -47,6 +47,8 @@ struct Backdrop::Main
Gui::Connection _gui { _env, "backdrop" }; Gui::Connection _gui { _env, "backdrop" };
Gui::Rect _gui_win { };
struct Buffer struct Buffer
{ {
Gui::Connection &gui; Gui::Connection &gui;
@ -112,7 +114,7 @@ struct Backdrop::Main
using Command = Gui::Session::Command; using Command = Gui::Session::Command;
_gui.enqueue<Command::Background>(_view_id); _gui.enqueue<Command::Background>(_view_id);
Gui::Rect rect(Gui::Point(), _buffer->size()); Gui::Rect rect(_gui_win.at, _buffer->size());
_gui.enqueue<Command::Geometry>(_view_id, rect); _gui.enqueue<Command::Geometry>(_view_id, rect);
_gui.enqueue<Command::Back>(_view_id); _gui.enqueue<Command::Back>(_view_id);
_gui.execute(); _gui.execute();
@ -139,8 +141,7 @@ struct Backdrop::Main
{ {
_gui.view(_view_id, { }); _gui.view(_view_id, { });
_gui.mode_sigh(_config_handler); _gui.info_sigh(_config_handler);
_config.sigh(_config_handler); _config.sigh(_config_handler);
_handle_config(); _handle_config();
@ -307,12 +308,14 @@ void Backdrop::Main::_handle_config()
{ {
_config.update(); _config.update();
Framebuffer::Mode const phys_mode = _gui.mode(); _gui_win = _gui.window().convert<Gui::Rect>(
Framebuffer::Mode const mode { [&] (Gui::Rect rect) { return rect; },
.area = { _config.xml().attribute_value("width", phys_mode.area.w), [&] (Gui::Undefined) { return Gui::Rect { { }, { 640, 480 } }; });
_config.xml().attribute_value("height", phys_mode.area.h) },
.alpha = false _gui_win.area = { _config.xml().attribute_value("width", _gui_win.w()),
}; _config.xml().attribute_value("height", _gui_win.h()) };
Framebuffer::Mode const mode { .area = _gui_win.area, .alpha = false };
_buffer.construct(_env, _gui, mode); _buffer.construct(_env, _gui, mode);

View File

@ -56,9 +56,12 @@ struct Decorator::Main : Window_factory_base
struct Canvas struct Canvas
{ {
Framebuffer::Mode const mode; Env &_env;
Attached_dataspace fb_ds; Gui::Connection &_gui;
Decorator::Canvas<Pixel_rgb888> canvas;
Gui::Area const scr_area = _gui.panorama().convert<Gui::Area>(
[&] (Gui::Rect rect) { return rect.area; },
[&] (Gui::Undefined) { return Gui::Area { 1, 1 }; });
/* /*
* The GUI connection's buffer is split into two parts. The upper * The GUI connection's buffer is split into two parts. The upper
@ -66,24 +69,24 @@ struct Decorator::Main : Window_factory_base
* whereas the lower part contains the back buffer targeted by * whereas the lower part contains the back buffer targeted by
* the Decorator::Canvas. * the Decorator::Canvas.
*/ */
static Framebuffer::Mode _doubled(Framebuffer::Mode const mode) Dataspace_capability _buffer_ds() const
{ {
return { .area = { .w = mode.area.w, .h = mode.area.h*2 }, _gui.buffer({ .area = { .w = scr_area.w, .h = scr_area.h*2 },
.alpha = mode.alpha }; .alpha = false });
return _gui.framebuffer.dataspace();
} }
Attached_dataspace fb_ds { _env.rm(), _buffer_ds() };
Pixel_rgb888 *_canvas_pixels_ptr() Pixel_rgb888 *_canvas_pixels_ptr()
{ {
return fb_ds.local_addr<Pixel_rgb888>() + mode.area.count(); return fb_ds.local_addr<Pixel_rgb888>() + scr_area.count();
} }
Canvas(Env &env, Gui::Connection &gui) Decorator::Canvas<Pixel_rgb888> canvas {
: _canvas_pixels_ptr(), scr_area, _env.ram(), _env.rm() };
mode(gui.mode()),
fb_ds(env.rm(), Canvas(Env &env, Gui::Connection &gui) : _env(env), _gui(gui) { }
(gui.buffer(_doubled(mode)), gui.framebuffer.dataspace())),
canvas(_canvas_pixels_ptr(), mode.area, env.ram(), env.rm())
{ }
}; };
Reconstructible<Canvas> _canvas { _env, _gui }; Reconstructible<Canvas> _canvas { _env, _gui };
@ -93,7 +96,7 @@ struct Decorator::Main : Window_factory_base
if (!_canvas.constructed()) if (!_canvas.constructed())
return; return;
Rect const canvas_rect { { }, _canvas->mode.area }; Rect const canvas_rect { { }, _canvas->scr_area };
dirty.flush([&] (Rect const &r) { dirty.flush([&] (Rect const &r) {
@ -110,9 +113,7 @@ struct Decorator::Main : Window_factory_base
{ {
_canvas.construct(_env, _gui); _canvas.construct(_env, _gui);
Area const canvas_area = _canvas->mode.area; _window_stack.mark_as_dirty(Rect(Point(0, 0), _canvas->scr_area));
_window_stack.mark_as_dirty(Rect(Point(0, 0), canvas_area));
Dirty_rect dirty = _window_stack.draw(_canvas->canvas); Dirty_rect dirty = _window_stack.draw(_canvas->canvas);
@ -195,7 +196,7 @@ struct Decorator::Main : Window_factory_base
_config.sigh(_config_handler); _config.sigh(_config_handler);
_handle_config(); _handle_config();
_gui.mode_sigh(_mode_handler); _gui.info_sigh(_mode_handler);
_window_layout.sigh(_window_layout_handler); _window_layout.sigh(_window_layout_handler);
_pointer.sigh(_pointer_handler); _pointer.sigh(_pointer_handler);

View File

@ -2007,7 +2007,7 @@ struct Sculpt::Main : Input_event_handler,
_drivers.update_soc(_soc); _drivers.update_soc(_soc);
_gui.input.sigh(_input_handler); _gui.input.sigh(_input_handler);
_gui.mode_sigh(_gui_mode_handler); _gui.info_sigh(_gui_mode_handler);
_handle_gui_mode(); _handle_gui_mode();
_system_config.with_manual_config([&] (Xml_node const &system) { _system_config.with_manual_config([&] (Xml_node const &system) {
@ -2078,12 +2078,6 @@ void Sculpt::Main::_update_window_layout(Xml_node const &decorator_margins,
return Area(win.attribute_value("width", 0U), return Area(win.attribute_value("width", 0U),
win.attribute_value("height", 0U)); }; win.attribute_value("height", 0U)); };
Framebuffer::Mode const mode = _gui.mode();
/* suppress intermediate boot-time states before the framebuffer driver is up */
if (mode.area.count() <= 1)
return;
_window_layout.generate([&] (Xml_generator &xml) { _window_layout.generate([&] (Xml_generator &xml) {
auto gen_window = [&] (Xml_node win, Rect rect) { auto gen_window = [&] (Xml_node win, Rect rect) {
@ -2105,8 +2099,8 @@ void Sculpt::Main::_update_window_layout(Xml_node const &decorator_margins,
Area const size = win_size(win); Area const size = win_size(win);
Point const pos = _touch_keyboard.visible Point const pos = _touch_keyboard.visible
? Point(0, int(mode.area.h) - int(size.h)) ? Point(0, int(_screen_size.h) - int(size.h))
: Point(0, int(mode.area.h)); : Point(0, int(_screen_size.h));
gen_window(win, Rect(pos, size)); gen_window(win, Rect(pos, size));
}); });
@ -2122,16 +2116,19 @@ void Sculpt::Main::_update_window_layout(Xml_node const &decorator_margins,
void Sculpt::Main::_handle_gui_mode() void Sculpt::Main::_handle_gui_mode()
{ {
Framebuffer::Mode const mode = _gui.mode(); auto const panorama = _gui.panorama();
_screensaver.display_driver_ready(mode.area.count() > 1); _screensaver.display_driver_ready(panorama.ok());
if (mode.area.count() > 1) panorama.with_result(
_gui_mode_ready = true; [&] (Gui::Rect const rect) {
_gui_mode_ready = true;
_screen_size = mode.area; _screen_size = rect.area;
_main_view.min_width = _screen_size.w; _main_view.min_width = _screen_size.w;
_main_view.min_height = _screen_size.h; _main_view.min_height = _screen_size.h;
},
[&] (Gui::Undefined) { }
);
generate_runtime_config(); generate_runtime_config();
_update_window_layout(); _update_window_layout();

View File

@ -145,11 +145,8 @@ struct Gui::Session_component : Rpc_object<Gui::Session>
void execute() override { void execute() override {
_gui_session.execute(); } _gui_session.execute(); }
Framebuffer::Mode mode() override { Info_result info() override {
return _gui_session.mode(); } return _gui_session.info(); }
void mode_sigh(Signal_context_capability sigh) override {
_gui_session.mode_sigh(sigh); }
Buffer_result buffer(Framebuffer::Mode mode) override { Buffer_result buffer(Framebuffer::Mode mode) override {
return _gui_session.buffer(mode); } return _gui_session.buffer(mode); }

View File

@ -104,7 +104,10 @@ struct Sculpt::Main : Input_event_handler,
Gui::Connection _gui { _env, "input" }; Gui::Connection _gui { _env, "input" };
bool _gui_mode_ready = false; /* becomes true once the graphics driver is up */ Gui::Connection::Panorama_result _panorama = Gui::Undefined { };
/* becomes true once the graphics driver is up */
bool _gui_mode_ready() const { return _panorama.ok(); };
Gui::Root _gui_root { _env, _heap, *this, _global_input_seq_number }; Gui::Root _gui_root { _env, _heap, *this, _global_input_seq_number };
@ -953,8 +956,10 @@ struct Sculpt::Main : Input_event_handler,
ev.handle_wheel([&] (int, int y) { dy = y*32; }); ev.handle_wheel([&] (int, int y) { dy = y*32; });
if (ev.key_press(Input::KEY_PAGEUP)) dy = int(_gui.mode().area.h / 3); int const vscroll_step = int(_screen_size.h) / 3;
if (ev.key_press(Input::KEY_PAGEDOWN)) dy = -int(_gui.mode().area.h / 3);
if (ev.key_press(Input::KEY_PAGEUP)) dy = vscroll_step;
if (ev.key_press(Input::KEY_PAGEDOWN)) dy = -vscroll_step;
if (dy != 0) { if (dy != 0) {
scroll_ypos += dy; scroll_ypos += dy;
@ -1647,7 +1652,7 @@ struct Sculpt::Main : Input_event_handler,
{ {
_drivers.update_soc(_soc); _drivers.update_soc(_soc);
_gui.input.sigh(_input_handler); _gui.input.sigh(_input_handler);
_gui.mode_sigh(_gui_mode_handler); _gui.info_sigh(_gui_mode_handler);
_handle_gui_mode(); _handle_gui_mode();
_fb_config.trigger_update(); _fb_config.trigger_update();
@ -1680,7 +1685,7 @@ void Sculpt::Main::_update_window_layout(Xml_node const &decorator_margins,
Xml_node const &window_list) Xml_node const &window_list)
{ {
/* skip window-layout handling (and decorator activity) while booting */ /* skip window-layout handling (and decorator activity) while booting */
if (!_gui_mode_ready) if (!_gui_mode_ready())
return; return;
struct Decorator_margins struct Decorator_margins
@ -1726,18 +1731,16 @@ void Sculpt::Main::_update_window_layout(Xml_node const &decorator_margins,
if (panel_height == 0) if (panel_height == 0)
return; return;
Framebuffer::Mode const mode = _gui.mode();
/* suppress intermediate boot-time states before the framebuffer driver is up */ /* suppress intermediate boot-time states before the framebuffer driver is up */
if (mode.area.count() <= 1) if (!_screen_size.valid())
return; return;
/* area reserved for the panel */ /* area reserved for the panel */
Rect const panel = Rect(Point(0, 0), Area(mode.area.w, panel_height)); Rect const panel = Rect(Point(0, 0), Area(_screen_size.w, panel_height));
/* available space on the right of the menu */ /* available space on the right of the menu */
Rect avail = Rect::compound(Point(0, panel.h()), Rect avail = Rect::compound(Point(0, panel.h()),
Point(mode.area.w - 1, mode.area.h - 1)); Point(_screen_size.w - 1, _screen_size.h - 1));
Point const log_offset = _log_visible Point const log_offset = _log_visible
? Point(0, 0) ? Point(0, 0)
@ -1745,8 +1748,8 @@ void Sculpt::Main::_update_window_layout(Xml_node const &decorator_margins,
Point const log_p1(avail.x2() - log_min_w - margins.right + 1 + log_offset.x, Point const log_p1(avail.x2() - log_min_w - margins.right + 1 + log_offset.x,
avail.y1() + margins.top); avail.y1() + margins.top);
Point const log_p2(mode.area.w - margins.right - 1 + log_offset.x, Point const log_p2(_screen_size.w - margins.right - 1 + log_offset.x,
mode.area.h - margins.bottom - 1); _screen_size.h - margins.bottom - 1);
/* position of the inspect window */ /* position of the inspect window */
Point const inspect_p1(avail.x1() + margins.left, avail.y1() + margins.top); Point const inspect_p1(avail.x1() + margins.left, avail.y1() + margins.top);
@ -1812,7 +1815,7 @@ void Sculpt::Main::_update_window_layout(Xml_node const &decorator_margins,
Area const size = win_size(win); Area const size = win_size(win);
Point const pos = _network_visible Point const pos = _network_visible
? Point(log_p1.x - size.w, avail.y1()) ? Point(log_p1.x - size.w, avail.y1())
: Point(mode.area.w, avail.y1()); : Point(_screen_size.w, avail.y1());
gen_window(win, Rect(pos, size)); gen_window(win, Rect(pos, size));
}); });
@ -1918,7 +1921,7 @@ void Sculpt::Main::_update_window_layout(Xml_node const &decorator_margins,
_with_window(window_list, logo_label, [&] (Xml_node const &win) { _with_window(window_list, logo_label, [&] (Xml_node const &win) {
Area const size = win_size(win); Area const size = win_size(win);
Point const pos(mode.area.w - size.w, mode.area.h - size.h); Point const pos(_screen_size.w - size.w, _screen_size.h - size.h);
gen_window(win, Rect(pos, size)); gen_window(win, Rect(pos, size));
}); });
}); });
@ -1945,10 +1948,11 @@ void Sculpt::Main::_update_window_layout(Xml_node const &decorator_margins,
void Sculpt::Main::_handle_gui_mode() void Sculpt::Main::_handle_gui_mode()
{ {
Framebuffer::Mode const mode = _gui.mode(); _panorama = _gui.panorama();
if (mode.area.count() > 1) _screen_size = _panorama.convert<Gui::Area>(
_gui_mode_ready = true; [&] (Gui::Rect rect) { return rect.area; },
[&] (Gui::Undefined) { return Gui::Area { 1024, 768 }; });
_update_window_layout(); _update_window_layout();
@ -1956,7 +1960,7 @@ void Sculpt::Main::_handle_gui_mode()
if (!_settings.manual_fonts_config) { if (!_settings.manual_fonts_config) {
_font_size_px = (double)mode.area.h / 60.0; _font_size_px = (double)_screen_size.h / 60.0;
if (_settings.font_size == Settings::Font_size::SMALL) _font_size_px *= 0.85; if (_settings.font_size == Settings::Font_size::SMALL) _font_size_px *= 0.85;
if (_settings.font_size == Settings::Font_size::LARGE) _font_size_px *= 1.35; if (_settings.font_size == Settings::Font_size::LARGE) _font_size_px *= 1.35;
@ -2011,7 +2015,6 @@ void Sculpt::Main::_handle_gui_mode()
}); });
} }
_screen_size = mode.area;
_panel_dialog.min_width = _screen_size.w; _panel_dialog.min_width = _screen_size.w;
unsigned const menu_width = max((unsigned)(_font_size_px*21.0), 320u); unsigned const menu_width = max((unsigned)(_font_size_px*21.0), 320u);
_diag_dialog.min_width = menu_width; _diag_dialog.min_width = menu_width;

View File

@ -325,9 +325,9 @@ struct Window_layouter::Main : Operations,
void _handle_mode_change() void _handle_mode_change()
{ {
/* determine maximized window geometry */ /* determine maximized window geometry */
Framebuffer::Mode const mode = _gui.mode(); _screen_size = _gui.panorama().convert<Gui::Area>(
[&] (Gui::Rect rect) { return rect.area; },
_screen_size = mode.area; [&] (Gui::Undefined) { return Gui::Area { 1, 1 }; });
_update_window_layout(); _update_window_layout();
} }
@ -373,7 +373,7 @@ struct Window_layouter::Main : Operations,
*/ */
Main(Env &env) : _env(env) Main(Env &env) : _env(env)
{ {
_gui.mode_sigh(_mode_change_handler); _gui.info_sigh(_mode_change_handler);
_handle_mode_change(); _handle_mode_change();
_drop_timer.sigh(_drop_timer_handler); _drop_timer.sigh(_drop_timer_handler);

View File

@ -150,11 +150,8 @@ struct Sandboxed_runtime::Gui_session : Session_object<Gui::Session>
void execute() override { void execute() override {
_gui_session.execute(); } _gui_session.execute(); }
Framebuffer::Mode mode() override { Info_result info() override {
return _gui_session.mode(); } return _gui_session.info(); }
void mode_sigh(Signal_context_capability sigh) override {
_gui_session.mode_sigh(sigh); }
Buffer_result buffer(Framebuffer::Mode mode) override { Buffer_result buffer(Framebuffer::Mode mode) override {
return _gui_session.buffer(mode); } return _gui_session.buffer(mode); }

View File

@ -455,15 +455,7 @@ class Gui_fader::Gui_session_component
return _gui.execute(); return _gui.execute();
} }
Framebuffer::Mode mode() override Info_result info() override { return _gui.info_rom_cap(); }
{
return _gui.mode();
}
void mode_sigh(Genode::Signal_context_capability sigh) override
{
_gui.mode_sigh(sigh);
}
Buffer_result buffer(Framebuffer::Mode mode) override Buffer_result buffer(Framebuffer::Mode mode) override
{ {

View File

@ -100,9 +100,16 @@ struct Terminal::Main : Character_consumer
Signal_handler<Main> _config_handler { Signal_handler<Main> _config_handler {
_env.ep(), *this, &Main::_handle_config }; _env.ep(), *this, &Main::_handle_config };
Gui::Rect _gui_window_rect()
{
return _gui.window().convert<Gui::Rect>(
[&] (Gui::Rect rect) { return rect; },
[&] (Gui::Undefined) { return Gui::Rect { { }, { 1, 1 } }; });
}
void _handle_mode_change() void _handle_mode_change()
{ {
_fb_mode = _gui.mode(); _win_rect = _gui_window_rect();
_handle_config(); _handle_config();
} }
@ -114,7 +121,7 @@ struct Terminal::Main : Character_consumer
Constructible<Attached_dataspace> _fb_ds { }; Constructible<Attached_dataspace> _fb_ds { };
Framebuffer::Mode _fb_mode { }; Gui::Rect _win_rect { };
Gui::View_id _view { }; Gui::View_id _view { };
@ -143,7 +150,7 @@ struct Terminal::Main : Character_consumer
bool _flush_scheduled = false; bool _flush_scheduled = false;
Framebuffer::Mode _flushed_fb_mode { }; Gui::Rect _flushed_win_rect { };
void _handle_flush() void _handle_flush()
{ {
@ -151,7 +158,7 @@ struct Terminal::Main : Character_consumer
if (_text_screen_surface.constructed() && _fb_ds.constructed()) { if (_text_screen_surface.constructed() && _fb_ds.constructed()) {
Surface<PT> surface(_fb_ds->local_addr<PT>(), _fb_mode.area); Surface<PT> surface(_fb_ds->local_addr<PT>(), _win_rect.area);
Rect const dirty = _text_screen_surface->redraw(surface); Rect const dirty = _text_screen_surface->redraw(surface);
@ -159,14 +166,14 @@ struct Terminal::Main : Character_consumer
} }
/* update view geometry after mode change */ /* update view geometry after mode change */
if (_fb_mode.area != _flushed_fb_mode.area) { if (_win_rect != _flushed_win_rect) {
using Command = Gui::Session::Command; using Command = Gui::Session::Command;
_gui.enqueue<Command::Geometry>(_view, Rect(Point(0, 0), _fb_mode.area)); _gui.enqueue<Command::Geometry>(_view, _win_rect);
_gui.enqueue<Command::Front>(_view); _gui.enqueue<Command::Front>(_view);
_gui.execute(); _gui.execute();
_flushed_fb_mode = _fb_mode; _flushed_win_rect = _win_rect;
} }
} }
@ -215,14 +222,14 @@ struct Terminal::Main : Character_consumer
_config.sigh(_config_handler); _config.sigh(_config_handler);
_gui.input.sigh(_input_handler); _gui.input.sigh(_input_handler);
_gui.mode_sigh(_mode_change_handler); _gui.info_sigh(_mode_change_handler);
_fb_mode = { .area = _gui.mode().area, .alpha = false }; _win_rect = _gui_window_rect();
/* apply initial size from config, if provided */ /* apply initial size from config, if provided */
_config.xml().with_optional_sub_node("initial", [&] (Xml_node const &initial) { _config.xml().with_optional_sub_node("initial", [&] (Xml_node const &initial) {
_fb_mode.area = Area(initial.attribute_value("width", _fb_mode.area.w), _win_rect.area = { initial.attribute_value("width", _win_rect.w()),
initial.attribute_value("height", _fb_mode.area.h)); initial.attribute_value("height", _win_rect.h()) };
}); });
_handle_config(); _handle_config();
@ -259,9 +266,9 @@ void Terminal::Main::_handle_config()
/* /*
* Adapt terminal to font or framebuffer mode changes * Adapt terminal to font or framebuffer mode changes
*/ */
_gui.buffer(_fb_mode); _gui.buffer({ .area = _win_rect.area, .alpha = false });
if (_fb_mode.area.count() > 0) if (_win_rect.valid())
_fb_ds.construct(_env.rm(), _gui.framebuffer.dataspace()); _fb_ds.construct(_env.rm(), _gui.framebuffer.dataspace());
/* /*
@ -276,7 +283,7 @@ void Terminal::Main::_handle_config()
*/ */
try { try {
Text_screen_surface<PT>::Geometry const new_geometry(_font->font(), _fb_mode.area); Text_screen_surface<PT>::Geometry const new_geometry(_font->font(), _win_rect.area);
bool const reconstruct = !_text_screen_surface.constructed() || bool const reconstruct = !_text_screen_surface.constructed() ||
_text_screen_surface->size() != new_geometry.size(); _text_screen_surface->size() != new_geometry.size();
@ -307,7 +314,7 @@ void Terminal::Main::_handle_config()
: Position(); : Position();
_text_screen_surface.construct(_heap, _font->font(), _text_screen_surface.construct(_heap, _font->font(),
_color_palette, _fb_mode.area); _color_palette, _win_rect.area);
if (snapshot.constructed()) if (snapshot.constructed())
_text_screen_surface->import(*snapshot); _text_screen_surface->import(*snapshot);

View File

@ -222,6 +222,11 @@ struct Wm::Decorator_gui_session : Session_object<Gui::Session>,
return _dummy_input_component_cap; return _dummy_input_component_cap;
} }
Info_result info() override
{
return _real_gui.session.info();
}
View_result view(View_id id, View_attr const &attr) override View_result view(View_id id, View_attr const &attr) override
{ {
/* /*
@ -316,21 +321,6 @@ struct Wm::Decorator_gui_session : Session_object<Gui::Session>,
_real_gui.execute(); _real_gui.execute();
} }
Framebuffer::Mode mode() override
{
return _real_gui.session.mode();
}
void mode_sigh(Signal_context_capability sigh) override
{
/*
* Remember signal-context capability to keep NOVA from revoking
* transitive delegations of the capability.
*/
_mode_sigh = sigh;
_real_gui.session.mode_sigh(sigh);
}
Buffer_result buffer(Framebuffer::Mode mode) override Buffer_result buffer(Framebuffer::Mode mode) override
{ {
return _real_gui.session.buffer(mode); return _real_gui.session.buffer(mode);

View File

@ -104,14 +104,9 @@ class Wm::Direct_gui_session : public Session_object<Gui::Session>
_session.execute(); _session.execute();
} }
Framebuffer::Mode mode() override Info_result info() override
{ {
return _session.mode(); return _session.info();
}
void mode_sigh(Signal_context_capability sigh) override
{
_session.mode_sigh(sigh);
} }
Buffer_result buffer(Framebuffer::Mode mode) override Buffer_result buffer(Framebuffer::Mode mode) override

View File

@ -19,6 +19,7 @@
#include <gui_session/connection.h> #include <gui_session/connection.h>
#include <input_session/capability.h> #include <input_session/capability.h>
#include <input/component.h> #include <input/component.h>
#include <os/dynamic_rom_session.h>
/* local includes */ /* local includes */
#include <window_registry.h> #include <window_registry.h>
@ -494,8 +495,16 @@ class Wm::Gui::Child_view : public View, private List<Child_view>::Element
class Wm::Gui::Session_component : public Session_object<Gui::Session>, class Wm::Gui::Session_component : public Session_object<Gui::Session>,
private List<Session_component>::Element, private List<Session_component>::Element,
private Input_origin_changed_handler, private Input_origin_changed_handler,
private Upgradeable private Upgradeable,
private Dynamic_rom_session::Xml_producer
{ {
public:
struct Action : Interface
{
virtual void gen_screen_area_info(Xml_generator &) const = 0;
};
private: private:
friend class List<Session_component>; friend class List<Session_component>;
@ -531,7 +540,8 @@ class Wm::Gui::Session_component : public Session_object<Gui::Session>,
} }
}; };
Env &_env; Env &_env;
Action &_action;
Constrained_ram_allocator _ram { Constrained_ram_allocator _ram {
_env.ram(), _ram_quota_guard(), _cap_quota_guard() }; _env.ram(), _ram_quota_guard(), _cap_quota_guard() };
@ -561,15 +571,39 @@ class Wm::Gui::Session_component : public Session_object<Gui::Session>,
Input_session _input_session { _env, _ram }; Input_session _input_session { _env, _ram };
Click_handler &_click_handler; Click_handler &_click_handler;
Signal_context_capability _mode_sigh { };
Area _requested_size { }; struct Info_rom_session : Dynamic_rom_session
bool _resize_requested = false; {
bool _has_alpha = false; Session_component &_session;
Pointer::State _pointer_state;
Point const _initial_pointer_pos { -1, -1 }; Info_rom_session(Session_component &session, auto &&... args)
Point _pointer_pos = _initial_pointer_pos; : Dynamic_rom_session(args...), _session(session) { }
Point _virtual_pointer_pos { };
unsigned _key_cnt = 0; void sigh(Signal_context_capability sigh) override
{
Dynamic_rom_session::sigh(sigh);
/*
* We consider a window as resizable if the client shows interest
* in mode-change notifications.
*/
_session._resizeable = sigh.valid();
for (Top_level_view *v = _session._top_level_views.first(); v; v = v->next())
v->resizeable(_session._resizeable);
}
};
Constructible<Info_rom_session> _info_rom { };
bool _resizeable = false;
Area _requested_size { };
bool _resize_requested = false;
bool _has_alpha = false;
Pointer::State _pointer_state;
Point const _initial_pointer_pos { -1, -1 };
Point _pointer_pos = _initial_pointer_pos;
Point _virtual_pointer_pos { };
unsigned _key_cnt = 0;
auto _with_view(View_id id, auto const &fn, auto const &missing_fn) auto _with_view(View_id id, auto const &fn, auto const &missing_fn)
-> decltype(missing_fn()) -> decltype(missing_fn())
@ -601,9 +635,6 @@ class Wm::Gui::Session_component : public Session_object<Gui::Session>,
Signal_handler<Session_component> _input_handler { Signal_handler<Session_component> _input_handler {
_env.ep(), *this, &Session_component::_handle_input }; _env.ep(), *this, &Session_component::_handle_input };
Signal_handler<Session_component> _mode_handler {
_env.ep(), *this, &Session_component::_handle_mode_change };
Point _input_origin() const Point _input_origin() const
{ {
if (Top_level_view const *v = _top_level_views.first()) if (Top_level_view const *v = _top_level_views.first())
@ -714,14 +745,42 @@ class Wm::Gui::Session_component : public Session_object<Gui::Session>,
} }
} }
void _handle_mode_change() /**
* Dynamic_rom_session::Xml_producer interface
*/
void produce_xml(Xml_generator &xml) override
{ {
/* _action.gen_screen_area_info(xml);
* Inform a viewless client about the upstream
* mode change. auto virtual_capture_area = [&]
*/ {
if (_mode_sigh.valid() && !_top_level_views.first()) /*
Signal_transmitter(_mode_sigh).submit(); * While resizing the window, return requested window size as
* mode
*/
if (_resize_requested)
return _requested_size;
/*
* If the first top-level view has a defined size, use it
* as the size of the virtualized GUI session.
*/
if (Top_level_view const *v = _top_level_views.first())
if (v->size().valid())
return v->size();
return Area { };
};
auto gen_attr = [&] (Area const area)
{
if (area.valid()) {
xml.attribute("width", area.w);
xml.attribute("height", area.h);
}
};
xml.node("capture", [&] { gen_attr(virtual_capture_area()); });
} }
/** /**
@ -827,6 +886,7 @@ class Wm::Gui::Session_component : public Session_object<Gui::Session>,
public: public:
Session_component(Env &env, Session_component(Env &env,
Action &action,
Resources const &resources, Resources const &resources,
Label const &label, Label const &label,
Diag const diag, Diag const diag,
@ -835,13 +895,13 @@ class Wm::Gui::Session_component : public Session_object<Gui::Session>,
Click_handler &click_handler) Click_handler &click_handler)
: :
Session_object<Gui::Session>(env.ep(), resources, label, diag), Session_object<Gui::Session>(env.ep(), resources, label, diag),
_env(env), Xml_producer("panorama"),
_env(env), _action(action),
_window_registry(window_registry), _window_registry(window_registry),
_click_handler(click_handler), _click_handler(click_handler),
_pointer_state(pointer_tracker) _pointer_state(pointer_tracker)
{ {
_gui_input.sigh(_input_handler); _gui_input.sigh(_input_handler);
_real_gui.session.mode_sigh(_mode_handler);
_input_session.event_queue().enabled(true); _input_session.event_queue().enabled(true);
} }
@ -933,8 +993,8 @@ class Wm::Gui::Session_component : public Session_object<Gui::Session>,
_resize_requested = true; _resize_requested = true;
/* notify client */ /* notify client */
if (_mode_sigh.valid()) if (_info_rom.constructed())
Signal_transmitter(_mode_sigh).submit(); _info_rom->trigger_update();
} }
void hidden(bool hidden) void hidden(bool hidden)
@ -953,6 +1013,12 @@ class Wm::Gui::Session_component : public Session_object<Gui::Session>,
*/ */
Capability<Session> session() { return _real_gui.connection.cap(); } Capability<Session> session() { return _real_gui.connection.cap(); }
void propagate_mode_change()
{
if (_info_rom.constructed())
_info_rom->trigger_update();
}
/*************************** /***************************
** GUI session interface ** ** GUI session interface **
@ -1048,7 +1114,7 @@ class Wm::Gui::Session_component : public Session_object<Gui::Session>,
}); });
if (result == View_result::OK && view_ptr) { if (result == View_result::OK && view_ptr) {
view_ptr->resizeable(_mode_sigh.valid()); view_ptr->resizeable(_resizeable);
_top_level_views.insert(view_ptr); _top_level_views.insert(view_ptr);
} }
return result; return result;
@ -1161,45 +1227,35 @@ class Wm::Gui::Session_component : public Session_object<Gui::Session>,
_window_registry.flush(); _window_registry.flush();
} }
Framebuffer::Mode mode() override Info_result info() override
{ {
Framebuffer::Mode const real_mode = _real_gui.session.mode(); if (!_info_rom.constructed()) {
Cap_quota const needed_caps { 2 };
if (!_cap_quota_guard().have_avail(needed_caps)) {
_starved_for_caps = true;
return Info_error::OUT_OF_CAPS;
}
/* Ram_quota const needed_ram { 8*1024 };
* While resizing the window, return requested window size as if (!_ram_quota_guard().have_avail(needed_ram)) {
* mode _starved_for_ram = true;
*/ return Info_error::OUT_OF_RAM;
if (_resize_requested) }
return Framebuffer::Mode { .area = _requested_size,
.alpha = real_mode.alpha };
/* try {
* If the first top-level view has a defined size, use it Dynamic_rom_session::Content_producer &rom_producer = *this;
* as the size of the virtualized GUI session. _info_rom.construct(*this, _env.ep(), _ram, _env.rm(), rom_producer);
*/ _info_rom->dataspace(); /* eagerly consume RAM and caps */
if (Top_level_view const *v = _top_level_views.first()) }
if (v->size().valid()) catch (Out_of_ram) { _starved_for_ram = true; }
return Framebuffer::Mode { .area = v->size(), catch (Out_of_caps) { _starved_for_caps = true; }
.alpha = real_mode.alpha};
/* if (_starved_for_ram || _starved_for_caps) {
* If top-level view has yet been defined, return the real mode. if (_starved_for_ram) return Info_error::OUT_OF_RAM;
*/ if (_starved_for_caps) return Info_error::OUT_OF_CAPS;
return real_mode; }
} }
return _info_rom->cap();
void mode_sigh(Signal_context_capability sigh) override
{
_mode_sigh = sigh;
/*
* We consider a window as resizable if the client shows interest
* in mode-change notifications.
*/
bool const resizeable = _mode_sigh.valid();
for (Top_level_view *v = _top_level_views.first(); v; v = v->next())
v->resizeable(resizeable);
} }
Buffer_result buffer(Framebuffer::Mode mode) override Buffer_result buffer(Framebuffer::Mode mode) override
@ -1238,6 +1294,8 @@ class Wm::Gui::Root : public Rpc_object<Typed_root<Gui::Session> >,
Env &_env; Env &_env;
Session_component::Action &_action;
Attached_rom_dataspace _config { _env, "config" }; Attached_rom_dataspace _config { _env, "config" };
Sliced_heap _sliced_heap { _env.ram(), _env.rm() }; Sliced_heap _sliced_heap { _env.ram(), _env.rm() };
@ -1292,11 +1350,12 @@ class Wm::Gui::Root : public Rpc_object<Typed_root<Gui::Session> >,
/** /**
* Constructor * Constructor
*/ */
Root(Env &env, Window_registry &window_registry, Root(Env &env, Session_component::Action &action,
Window_registry &window_registry,
Pointer::Tracker &pointer_tracker, Pointer::Tracker &pointer_tracker,
Gui::Connection &focus_gui_session) Gui::Connection &focus_gui_session)
: :
_env(env), _env(env), _action(action),
_pointer_tracker(pointer_tracker), _pointer_tracker(pointer_tracker),
_window_registry(window_registry), _window_registry(window_registry),
_focus_gui_session(focus_gui_session) _focus_gui_session(focus_gui_session)
@ -1376,7 +1435,6 @@ class Wm::Gui::Root : public Rpc_object<Typed_root<Gui::Session> >,
1 + /* Input_session events dataspace (_input_session) */ 1 + /* Input_session events dataspace (_input_session) */
1 + /* Command buffer (_command_buffer) */ 1 + /* Command buffer (_command_buffer) */
1 + /* Input signal handler (_input_handler) */ 1 + /* Input signal handler (_input_handler) */
1 + /* Mode signal handler (_mode_handler) */
1; /* Content-view capability */ 1; /* Content-view capability */
if (resources.cap_quota.value < needed_caps) if (resources.cap_quota.value < needed_caps)
@ -1390,7 +1448,7 @@ class Wm::Gui::Root : public Rpc_object<Typed_root<Gui::Session> >,
case ROLE_REGULAR: case ROLE_REGULAR:
try { try {
Session_component &session = *new (_sliced_heap) Session_component &session = *new (_sliced_heap)
Session_component(_env, resources, label, diag, Session_component(_env, _action, resources, label, diag,
_window_registry, _window_registry,
_pointer_tracker, _pointer_tracker,
_click_handler); _click_handler);
@ -1586,6 +1644,12 @@ class Wm::Gui::Root : public Rpc_object<Typed_root<Gui::Session> >,
if (s->has_win_id(win_id)) if (s->has_win_id(win_id))
return s->request_resize(size); return s->request_resize(size);
} }
void propagate_mode_change()
{
for (Session_component *s = _sessions.first(); s; s = s->next())
s->propagate_mode_change();
}
}; };
#endif /* _GUI_H_ */ #endif /* _GUI_H_ */

View File

@ -33,8 +33,6 @@ struct Wm::Layouter_gui_session : Session_object<Gui::Session>
*/ */
Gui::Connection _mode_sigh_gui; Gui::Connection _mode_sigh_gui;
Signal_context_capability _mode_sigh { };
Attached_ram_dataspace _command_ds; Attached_ram_dataspace _command_ds;
Layouter_gui_session(Env &env, Layouter_gui_session(Env &env,
@ -63,6 +61,11 @@ struct Wm::Layouter_gui_session : Session_object<Gui::Session>
return _input_session_cap; return _input_session_cap;
} }
Info_result info() override
{
return _mode_sigh_gui.info_rom_cap();
}
View_result view(Gui::View_id, View_attr const &) override View_result view(Gui::View_id, View_attr const &) override
{ {
return View_result::OK; return View_result::OK;
@ -94,19 +97,6 @@ struct Wm::Layouter_gui_session : Session_object<Gui::Session>
void execute() override { } void execute() override { }
Framebuffer::Mode mode() override { return _mode_sigh_gui.mode(); }
void mode_sigh(Signal_context_capability sigh) override
{
/*
* Remember signal-context capability to keep NOVA from revoking
* transitive delegations of the capability.
*/
_mode_sigh = sigh;
_mode_sigh_gui.mode_sigh(sigh);
}
Buffer_result buffer(Framebuffer::Mode) override { return Buffer_result::OK; } Buffer_result buffer(Framebuffer::Mode) override { return Buffer_result::OK; }
void focus(Capability<Gui::Session>) override { } void focus(Capability<Gui::Session>) override { }

View File

@ -24,7 +24,7 @@
namespace Wm { class Main; } namespace Wm { class Main; }
struct Wm::Main : Pointer::Tracker struct Wm::Main : Pointer::Tracker, Gui::Session_component::Action
{ {
Env &_env; Env &_env;
@ -46,7 +46,28 @@ struct Wm::Main : Pointer::Tracker
Gui::Connection _focus_gui_session { _env }; Gui::Connection _focus_gui_session { _env };
Gui::Root _gui_root { _env, _window_registry, *this, _focus_gui_session }; Gui::Area _screen_area { };
Signal_handler<Main> _mode_handler {
_env.ep(), *this, &Main::_handle_mode };
void _handle_mode()
{
_focus_gui_session.with_info([&] (Xml_node const &info) {
_screen_area = Area::from_xml(info); });
_gui_root.propagate_mode_change();
}
/**
* Gui::Session_component::Action interface
*/
void gen_screen_area_info(Xml_generator &xml) const override
{
xml.attribute("width", _screen_area.w);
xml.attribute("height", _screen_area.h);
}
Gui::Root _gui_root { _env, *this, _window_registry, *this, _focus_gui_session };
static void _with_win_id_from_xml(Xml_node const &window, auto const &fn) static void _with_win_id_from_xml(Xml_node const &window, auto const &fn)
{ {
@ -117,6 +138,8 @@ struct Wm::Main : Pointer::Tracker
_focus_rom.sigh(_focus_handler); _focus_rom.sigh(_focus_handler);
_resize_request_rom.sigh(_resize_request_handler); _resize_request_rom.sigh(_resize_request_handler);
_focus_gui_session.info_sigh(_mode_handler);
_handle_mode();
} }
}; };

View File

@ -91,13 +91,21 @@ class Pdf_view
Gui::Connection _gui { _env }; Gui::Connection _gui { _env };
Framebuffer::Mode _nit_mode = _gui.mode(); Gui::Rect _gui_window()
Framebuffer::Mode _fb_mode {}; {
return _gui.window().convert<Gui::Rect>(
[&] (Gui::Rect rect) { return rect; },
[&] (Gui::Undefined) { return Gui::Rect { { }, { 512, 512 } }; });
}
Gui::Rect _win_rect = _gui_window();
Framebuffer::Mode _fb_mode {};
Genode::Constructible<Genode::Attached_dataspace> _fb_ds { }; Genode::Constructible<Genode::Attached_dataspace> _fb_ds { };
Genode::Signal_handler<Pdf_view> _nit_mode_handler { Genode::Signal_handler<Pdf_view> _gui_mode_handler {
_env.ep(), *this, &Pdf_view::_handle_nit_mode }; _env.ep(), *this, &Pdf_view::_handle_gui_mode };
Genode::Signal_handler<Pdf_view> _input_handler { Genode::Signal_handler<Pdf_view> _input_handler {
_env.ep(), *this, &Pdf_view::_handle_input_events }; _env.ep(), *this, &Pdf_view::_handle_input_events };
@ -110,10 +118,10 @@ class Pdf_view
{ {
using namespace Gui; using namespace Gui;
_nit_mode = _gui.mode(); _win_rect = _gui_window();
unsigned max_x = Genode::max(_nit_mode.area.w, _fb_mode.area.w); unsigned max_x = Genode::max(_win_rect.area.w, _fb_mode.area.w);
unsigned max_y = Genode::max(_nit_mode.area.h, _fb_mode.area.h); unsigned max_y = Genode::max(_win_rect.area.h, _fb_mode.area.h);
if (max_x > _fb_mode.area.w || max_y > _fb_mode.area.h) { if (max_x > _fb_mode.area.w || max_y > _fb_mode.area.h) {
_fb_mode = Mode { .area = { max_x, max_y }, .alpha = false }; _fb_mode = Mode { .area = { max_x, max_y }, .alpha = false };
@ -123,8 +131,8 @@ class Pdf_view
_fb_ds.construct(_env.rm(), _gui.framebuffer.dataspace()); _fb_ds.construct(_env.rm(), _gui.framebuffer.dataspace());
} }
_pdfapp.scrw = _nit_mode.area.w; _pdfapp.scrw = _win_rect.area.w;
_pdfapp.scrh = _nit_mode.area.h; _pdfapp.scrh = _win_rect.area.h;
/* /*
* XXX replace heuristics with a meaningful computation * XXX replace heuristics with a meaningful computation
@ -132,17 +140,17 @@ class Pdf_view
* The magic values are hand-tweaked manually to accommodating the * The magic values are hand-tweaked manually to accommodating the
* use case of showing slides. * use case of showing slides.
*/ */
_pdfapp.resolution = Genode::min(_nit_mode.area.w/5, _pdfapp.resolution = Genode::min(_win_rect.area.w/5,
_nit_mode.area.h/4); _win_rect.area.h/4);
_view.area(_nit_mode.area); _view.area(_win_rect.area);
_view.front(); _view.front();
} }
void _handle_nit_mode() void _handle_gui_mode()
{ {
_rebuffer(); _rebuffer();
pdfapp_onresize(&_pdfapp, _nit_mode.area.w, _nit_mode.area.h); pdfapp_onresize(&_pdfapp, _win_rect.area.w, _win_rect.area.h);
} }
pdfapp_t _pdfapp { }; pdfapp_t _pdfapp { };
@ -218,7 +226,7 @@ class Pdf_view
*/ */
Pdf_view(Genode::Env &env) : _env(env) Pdf_view(Genode::Env &env) : _env(env)
{ {
_gui.mode_sigh(_nit_mode_handler); _gui.info_sigh(_gui_mode_handler);
_gui.input.sigh(_input_handler); _gui.input.sigh(_input_handler);
pdfapp_init(&_pdfapp); pdfapp_init(&_pdfapp);
@ -291,12 +299,12 @@ void Pdf_view::show()
int const tweaked_y_max = y_max - 2; int const tweaked_y_max = y_max - 2;
/* center vertically if the dst buffer is higher than the image */ /* center vertically if the dst buffer is higher than the image */
if ((unsigned)_pdfapp.image->h < _nit_mode.area.h) if ((unsigned)_pdfapp.image->h < _win_rect.area.h)
dst_line += dst_line_width*((_nit_mode.area.h - _pdfapp.image->h)/2); dst_line += dst_line_width*((_win_rect.area.h - _pdfapp.image->h)/2);
/* center horizontally if the dst buffer is wider than the image */ /* center horizontally if the dst buffer is wider than the image */
if ((unsigned)_pdfapp.image->w < _nit_mode.area.w) if ((unsigned)_pdfapp.image->w < _win_rect.area.w)
dst_line += (_nit_mode.area.w - _pdfapp.image->w)/2; dst_line += (_win_rect.area.w - _pdfapp.image->w)/2;
for (int y = 0; y < tweaked_y_max; y++) { for (int y = 0; y < tweaked_y_max; y++) {
copy_line_rgba(src_line, dst_line, x_max); copy_line_rgba(src_line, dst_line, x_max);
@ -304,7 +312,7 @@ void Pdf_view::show()
dst_line += dst_line_width; dst_line += dst_line_width;
} }
_gui.framebuffer.refresh({ { 0, 0 }, _nit_mode.area }); _gui.framebuffer.refresh({ { 0, 0 }, _win_rect.area });
} }

View File

@ -30,6 +30,9 @@ struct Gui::Session_client : Rpc_client<Session>
Input::Session_capability input() override { Input::Session_capability input() override {
return call<Rpc_input>(); } return call<Rpc_input>(); }
Info_result info() override {
return call<Rpc_info>(); }
[[nodiscard]] View_result view(View_id id, View_attr const &attr) override { [[nodiscard]] View_result view(View_id id, View_attr const &attr) override {
return call<Rpc_view>(id, attr); } return call<Rpc_view>(id, attr); }
@ -53,12 +56,6 @@ struct Gui::Session_client : Rpc_client<Session>
void execute() override { call<Rpc_execute>(); } void execute() override { call<Rpc_execute>(); }
Framebuffer::Mode mode() override {
return call<Rpc_mode>(); }
void mode_sigh(Signal_context_capability sigh) override {
call<Rpc_mode_sigh>(sigh); }
[[nodiscard]] Buffer_result buffer(Framebuffer::Mode mode) override { [[nodiscard]] Buffer_result buffer(Framebuffer::Mode mode) override {
return call<Rpc_buffer>(mode); } return call<Rpc_buffer>(mode); }

View File

@ -17,6 +17,7 @@
#include <gui_session/client.h> #include <gui_session/client.h>
#include <framebuffer_session/client.h> #include <framebuffer_session/client.h>
#include <input_session/client.h> #include <input_session/client.h>
#include <rom_session/client.h>
#include <base/connection.h> #include <base/connection.h>
namespace Gui { namespace Gui {
@ -52,6 +53,43 @@ class Gui::Connection : private Genode::Connection<Session>
static constexpr Ram_quota _RAM_QUOTA { 96*1024 }; static constexpr Ram_quota _RAM_QUOTA { 96*1024 };
static constexpr Cap_quota _CAP_QUOTA { Session::CAP_QUOTA + 9 }; static constexpr Cap_quota _CAP_QUOTA { Session::CAP_QUOTA + 9 };
Constructible<Rom_session_client> _info_rom { };
Constructible<Attached_dataspace> _info_ds { };
Rom_session_capability _info_rom_capability()
{
for (;;) {
using Error = Session::Info_error;
auto const result = _client.info();
if (result == Error::OUT_OF_RAM) { upgrade_ram(8*1024); continue; }
if (result == Error::OUT_OF_CAPS) { upgrade_caps(2); continue; }
return result.convert<Rom_session_capability>(
[&] (Rom_session_capability cap) { return cap; },
[&] (auto) /* handled above */ { return Rom_session_capability(); });
}
}
void _with_info_rom(auto const &fn)
{
if (!_info_ds.constructed())
_info_rom.construct(_info_rom_capability());
fn(*_info_rom);
}
void _with_info_xml(auto const &fn)
{
_with_info_rom([&] (Rom_session_client &rom) {
if (!_info_ds.constructed() || rom.update() == false)
_info_ds.construct(_env.rm(), rom.dataspace());
try {
Xml_node xml(_info_ds->local_addr<char>(), _info_ds->size());
fn(xml); }
catch (Xml_node::Invalid_syntax) {
warning("Gui::info has invalid XML syntax"); }
});
}
public: public:
View_ids view_ids { }; View_ids view_ids { };
@ -199,14 +237,71 @@ class Gui::Connection : private Genode::Connection<Session>
} }
/** /**
* Return physical screen mode * Call 'fn' with mode information as 'Xml_node const &' argument
*/ */
Framebuffer::Mode mode() { return _client.mode(); } void with_info(auto const &fn) { _with_info_xml(fn); }
Capability<Rom_session> info_rom_cap()
{
Capability<Rom_session> result { };
_with_info_rom([&] (Rom_session_client &rom) { result = rom.rpc_cap(); });
return result;
}
using Panorama_result = Attempt<Gui::Rect, Gui::Undefined>;
/**
* Return geometry of the total panorama
*
* The retured rectangle may be undefined for a client of the nitpicker
* GUI server in the absence of any capture client.
*/
Panorama_result panorama()
{
Gui::Rect result { };
_with_info_xml([&] (Xml_node const &info) {
result = Rect::from_xml(info); });
return result.valid() ? Panorama_result { result }
: Panorama_result { Undefined { } };
}
using Window_result = Attempt<Rect, Gui::Undefined>;
/**
* Return suitable geometry of top-level view
*
* For nitpicker clients, the window is the bounding box of all capture
* clients. For window-manager clients, returned rectangle corresponds
* to the window size as defined by the layouter.
*
* The returned rectangle may be undefined when a client of the window
* manager has not defined a top-level view yet.
*/
Window_result window()
{
Rect result { };
_with_info_xml([&] (Xml_node const &info) {
Rect bb { }; /* bounding box of all captured rects */
unsigned count = 0;
info.for_each_sub_node("capture", [&] (Xml_node const &capture) {
bb = Rect::compound(bb, Rect::from_xml(capture));
count++;
});
result = (count == 1) ? bb : Rect::from_xml(info);
});
return result.valid() ? Window_result { result }
: Window_result { Undefined { } };
}
/** /**
* Register signal handler to be notified about mode changes * Register signal handler to be notified about mode changes
*/ */
void mode_sigh(Signal_context_capability sigh) { _client.mode_sigh(sigh); } void info_sigh(Signal_context_capability sigh)
{
_with_info_rom([&] (Rom_session_client &rom) { rom.sigh(sigh); });
if (sigh.valid())
Signal_transmitter(sigh).submit();
}
void focus(Capability<Session> focused) { _client.focus(focused); } void focus(Capability<Session> focused) { _client.focus(focused); }
}; };

View File

@ -19,6 +19,7 @@
#include <os/surface.h> #include <os/surface.h>
#include <framebuffer_session/capability.h> #include <framebuffer_session/capability.h>
#include <input_session/capability.h> #include <input_session/capability.h>
#include <rom_session/rom_session.h>
namespace Gui { namespace Gui {
@ -44,6 +45,8 @@ namespace Gui {
using Rect = Surface_base::Rect; using Rect = Surface_base::Rect;
using Point = Surface_base::Point; using Point = Surface_base::Point;
using Area = Surface_base::Area; using Area = Surface_base::Area;
struct Undefined { };
} }
@ -171,6 +174,14 @@ struct Gui::Session : Genode::Session
*/ */
virtual Input::Session_capability input() = 0; virtual Input::Session_capability input() = 0;
enum class Info_error { OUT_OF_RAM, OUT_OF_CAPS };
using Info_result = Attempt<Capability<Rom_session>, Info_error>;
/**
* Request ROM session containing the mode information
*/
virtual Info_result info() = 0;
struct View_attr struct View_attr
{ {
Title title; Title title;
@ -233,16 +244,6 @@ struct Gui::Session : Genode::Session
*/ */
virtual void execute() = 0; virtual void execute() = 0;
/**
* Return physical screen mode
*/
virtual Framebuffer::Mode mode() = 0;
/**
* Register signal handler to be notified about mode changes
*/
virtual void mode_sigh(Signal_context_capability) = 0;
enum class Buffer_result { OK, OUT_OF_RAM, OUT_OF_CAPS }; enum class Buffer_result { OK, OUT_OF_RAM, OUT_OF_CAPS };
/** /**
@ -284,6 +285,7 @@ struct Gui::Session : Genode::Session
GENODE_RPC(Rpc_framebuffer, Framebuffer::Session_capability, framebuffer); GENODE_RPC(Rpc_framebuffer, Framebuffer::Session_capability, framebuffer);
GENODE_RPC(Rpc_input, Input::Session_capability, input); GENODE_RPC(Rpc_input, Input::Session_capability, input);
GENODE_RPC(Rpc_info, Info_result, info);
GENODE_RPC(Rpc_view, View_result, view, View_id, View_attr const &); GENODE_RPC(Rpc_view, View_result, view, View_id, View_attr const &);
GENODE_RPC(Rpc_child_view, Child_view_result, child_view, View_id, View_id, View_attr const &); GENODE_RPC(Rpc_child_view, Child_view_result, child_view, View_id, View_id, View_attr const &);
GENODE_RPC(Rpc_destroy_view, void, destroy_view, View_id); GENODE_RPC(Rpc_destroy_view, void, destroy_view, View_id);
@ -293,16 +295,13 @@ struct Gui::Session : Genode::Session
GENODE_RPC(Rpc_command_dataspace, Dataspace_capability, command_dataspace); GENODE_RPC(Rpc_command_dataspace, Dataspace_capability, command_dataspace);
GENODE_RPC(Rpc_execute, void, execute); GENODE_RPC(Rpc_execute, void, execute);
GENODE_RPC(Rpc_background, int, background, View_capability); GENODE_RPC(Rpc_background, int, background, View_capability);
GENODE_RPC(Rpc_mode, Framebuffer::Mode, mode);
GENODE_RPC(Rpc_mode_sigh, void, mode_sigh, Signal_context_capability);
GENODE_RPC(Rpc_focus, void, focus, Capability<Session>); GENODE_RPC(Rpc_focus, void, focus, Capability<Session>);
GENODE_RPC(Rpc_buffer, Buffer_result, buffer, Framebuffer::Mode); GENODE_RPC(Rpc_buffer, Buffer_result, buffer, Framebuffer::Mode);
GENODE_RPC_INTERFACE(Rpc_framebuffer, Rpc_input, GENODE_RPC_INTERFACE(Rpc_framebuffer, Rpc_input, Rpc_info,
Rpc_view, Rpc_child_view, Rpc_destroy_view, Rpc_associate, Rpc_view, Rpc_child_view, Rpc_destroy_view, Rpc_associate,
Rpc_view_capability, Rpc_release_view_id, Rpc_view_capability, Rpc_release_view_id,
Rpc_command_dataspace, Rpc_execute, Rpc_mode, Rpc_command_dataspace, Rpc_execute, Rpc_buffer, Rpc_focus);
Rpc_mode_sigh, Rpc_buffer, Rpc_focus);
}; };
#endif /* _INCLUDE__GUI_SESSION__GUI_SESSION_H_ */ #endif /* _INCLUDE__GUI_SESSION__GUI_SESSION_H_ */

View File

@ -44,14 +44,16 @@ struct Status_bar::Buffer
Gui::Connection &_gui; Gui::Connection &_gui;
Framebuffer::Mode const _nit_mode { _gui.mode() }; Gui::Area const _scr_area = _gui.panorama().convert<Gui::Area>(
[&] (Gui::Rect rect) { return rect.area; },
[&] (Gui::Undefined) { return Gui::Area { 1, 1 }; });
/* /*
* Dimension nitpicker buffer depending on nitpicker's screen size. * Dimension nitpicker buffer depending on nitpicker's screen size.
* The status bar is as wide as nitpicker's screen and has a fixed * The status bar is as wide as nitpicker's screen and has a fixed
* height. * height.
*/ */
Framebuffer::Mode const _mode { .area = { _nit_mode.area.w, HEIGHT }, Framebuffer::Mode const _mode { .area = { _scr_area.w, HEIGHT },
.alpha = false }; .alpha = false };
Dataspace_capability _init_buffer() Dataspace_capability _init_buffer()
@ -198,7 +200,7 @@ struct Status_bar::Main
{ {
/* register signal handlers */ /* register signal handlers */
_focus_ds.sigh(_focus_handler); _focus_ds.sigh(_focus_handler);
_gui.mode_sigh(_mode_handler); _gui.info_sigh(_mode_handler);
/* import initial state */ /* import initial state */
_handle_mode(); _handle_mode();

View File

@ -263,6 +263,15 @@ struct Gui_fb::Main : View_updater
Attached_dataspace _input_ds { _env.rm(), _gui.input.dataspace() }; Attached_dataspace _input_ds { _env.rm(), _gui.input.dataspace() };
Gui::Rect _gui_window()
{
return _gui.window().convert<Gui::Rect>(
[&] (Gui::Rect rect) { return rect; },
[&] (Gui::Undefined) { return _gui.panorama().convert<Gui::Rect>(
[&] (Gui::Rect rect) { return rect; },
[&] (Gui::Undefined) { return Gui::Rect { { }, { 1, 1 } }; }); });
}
struct Initial_size struct Initial_size
{ {
long const _width { 0 }; long const _width { 0 };
@ -276,18 +285,18 @@ struct Gui_fb::Main : View_updater
_height(config.attribute_value("initial_height", 0L)) _height(config.attribute_value("initial_height", 0L))
{ } { }
unsigned width(Framebuffer::Mode const &mode) const unsigned width(Gui::Area const &gui_area) const
{ {
if (_width > 0) return (unsigned)_width; if (_width > 0) return (unsigned)_width;
if (_width < 0) return (unsigned)(mode.area.w + _width); if (_width < 0) return (unsigned)(gui_area.w + _width);
return mode.area.w; return gui_area.w;
} }
unsigned height(Framebuffer::Mode const &mode) const unsigned height(Gui::Area const &gui_area) const
{ {
if (_height > 0) return (unsigned)_height; if (_height > 0) return (unsigned)_height;
if (_height < 0) return (unsigned)(mode.area.h + _height); if (_height < 0) return (unsigned)(gui_area.h + _height);
return mode.area.h; return gui_area.h;
} }
bool valid() const { return _width != 0 && _height != 0; } bool valid() const { return _width != 0 && _height != 0; }
@ -296,9 +305,10 @@ struct Gui_fb::Main : View_updater
Framebuffer::Mode _initial_mode() Framebuffer::Mode _initial_mode()
{ {
Gui::Area const gui_area = _gui_window().area;
return { return {
.area = { _initial_size.width (_gui.mode()), .area = { _initial_size.width (gui_area),
_initial_size.height(_gui.mode()) }, _initial_size.height(gui_area) },
.alpha = false .alpha = false
}; };
} }
@ -348,7 +358,7 @@ struct Gui_fb::Main : View_updater
/** /**
* Return screen-coordinate origin, depening on the config and screen mode * Return screen-coordinate origin, depening on the config and screen mode
*/ */
static Point _coordinate_origin(Framebuffer::Mode mode, Xml_node config) static Point _coordinate_origin(Gui::Area gui_area, Xml_node config)
{ {
char const * const attr = "origin"; char const * const attr = "origin";
@ -359,9 +369,9 @@ struct Gui_fb::Main : View_updater
Value const value = config.attribute_value(attr, Value()); Value const value = config.attribute_value(attr, Value());
if (value == "top_left") return Point(0, 0); if (value == "top_left") return Point(0, 0);
if (value == "top_right") return Point(mode.area.w, 0); if (value == "top_right") return Point(gui_area.w, 0);
if (value == "bottom_left") return Point(0, mode.area.h); if (value == "bottom_left") return Point(0, gui_area.h);
if (value == "bottom_right") return Point(mode.area.w, mode.area.h); if (value == "bottom_right") return Point(gui_area.w, gui_area.h);
warning("unsupported ", attr, " attribute value '", value, "'"); warning("unsupported ", attr, " attribute value '", value, "'");
return Point(0, 0); return Point(0, 0);
@ -371,9 +381,9 @@ struct Gui_fb::Main : View_updater
{ {
Xml_node const config = _config_rom.xml(); Xml_node const config = _config_rom.xml();
Framebuffer::Mode const gui_mode = _gui.mode(); Gui::Area const gui_area = _gui_window().area;
_position = _coordinate_origin(gui_mode, config) + Point::from_xml(config); _position = _coordinate_origin(gui_area, config) + Point::from_xml(config);
bool const attr = config.has_attribute("width") || bool const attr = config.has_attribute("width") ||
config.has_attribute("height"); config.has_attribute("height");
@ -384,15 +394,12 @@ struct Gui_fb::Main : View_updater
_initial_size.set = true; _initial_size.set = true;
} }
unsigned const gui_width = gui_mode.area.w; long width = config.attribute_value("width", long(gui_area.w)),
unsigned const gui_height = gui_mode.area.h; height = config.attribute_value("height", long(gui_area.h));
long width = config.attribute_value("width", (long)gui_mode.area.w),
height = config.attribute_value("height", (long)gui_mode.area.h);
if (!_initial_size.set && _initial_size.valid()) { if (!_initial_size.set && _initial_size.valid()) {
width = _initial_size.width (gui_mode); width = _initial_size.width (gui_area);
height = _initial_size.height(gui_mode); height = _initial_size.height(gui_area);
_initial_size.set = true; _initial_size.set = true;
} else { } else {
@ -401,8 +408,8 @@ struct Gui_fb::Main : View_updater
* If configured width / height values are negative, the effective * If configured width / height values are negative, the effective
* width / height is deduced from the screen size. * width / height is deduced from the screen size.
*/ */
if (width < 0) width = gui_width + width; if (width < 0) width = gui_area.w + width;
if (height < 0) height = gui_height + height; if (height < 0) height = gui_area.h + height;
} }
_fb_session.size(Area((unsigned)width, (unsigned)height)); _fb_session.size(Area((unsigned)width, (unsigned)height));
@ -466,7 +473,7 @@ struct Gui_fb::Main : View_updater
* Register signal handlers * Register signal handlers
*/ */
_config_rom.sigh(_config_update_handler); _config_rom.sigh(_config_update_handler);
_gui.mode_sigh(_mode_update_handler); _gui.info_sigh(_mode_update_handler);
_gui.input.sigh(_input_handler); _gui.input.sigh(_input_handler);
} }
}; };

View File

@ -86,15 +86,6 @@ class Nitpicker::Capture_session : public Session_object<Capture::Session>
} }
}; };
static void gen_attr(Xml_generator &xml, Rect const rect)
{
if (rect.x1()) xml.attribute("xpos", rect.x1());
if (rect.y1()) xml.attribute("ypos", rect.y1());
xml.attribute("width", rect.w());
xml.attribute("height", rect.h());
}
private: private:
Env &_env; Env &_env;
@ -185,6 +176,19 @@ class Nitpicker::Capture_session : public Session_object<Capture::Session>
void apply_policy(Policy const &policy) { _policy = policy; } void apply_policy(Policy const &policy) { _policy = policy; }
void gen_capture_attr(Xml_generator &xml) const
{
xml.attribute("name", label());
gen_attr(xml, bounding_box());
unsigned const w_mm = _policy.w_mm.or_default(_buffer_attr.mm.w),
h_mm = _policy.h_mm.or_default(_buffer_attr.mm.h);
if (w_mm) xml.attribute("width_mm", w_mm);
if (h_mm) xml.attribute("height_mm", h_mm);
}
/******************************* /*******************************
** Capture session interface ** ** Capture session interface **

View File

@ -99,7 +99,7 @@ class Nitpicker::Domain_registry
return pos + _corner(panorama) + _offset; return pos + _corner(panorama) + _offset;
} }
Rect screen_rect(Area screen_area) const Rect screen_rect(Rect const panorama) const
{ {
/* align value to zero or to limit, depending on its sign */ /* align value to zero or to limit, depending on its sign */
auto aligned = [&] (unsigned limit, int v) auto aligned = [&] (unsigned limit, int v)
@ -107,9 +107,9 @@ class Nitpicker::Domain_registry
return unsigned((v > 0) ? v : max(0, int(limit) + v)); return unsigned((v > 0) ? v : max(0, int(limit) + v));
}; };
return { .at = _offset, return { .at = _offset + panorama.at,
.area = { .w = aligned(screen_area.w, _area.x), .area = { .w = aligned(panorama.w(), _area.x),
.h = aligned(screen_area.h, _area.y) } }; .h = aligned(panorama.h(), _area.y) } };
} }
}; };

View File

@ -375,20 +375,6 @@ void Gui_session::execute()
} }
Framebuffer::Mode Gui_session::mode()
{
Rect const screen = screen_rect(_view_stack.bounding_box().area);
/*
* Return at least a size of 1x1 to spare the clients the need to handle
* the special case of 0x0, which can happen at boot time before the
* framebuffer driver is running.
*/
return { .area = { max(screen.w(), 1u), max(screen.h(), 1u) },
.alpha = uses_alpha() };
}
Gui_session::Buffer_result Gui_session::buffer(Framebuffer::Mode mode) Gui_session::Buffer_result Gui_session::buffer(Framebuffer::Mode mode)
{ {
/* check if the session quota suffices for the specified mode */ /* check if the session quota suffices for the specified mode */
@ -472,3 +458,13 @@ Dataspace_capability Gui_session::realloc_buffer(Framebuffer::Mode mode)
return _texture.dataspace(); return _texture.dataspace();
} }
void Gui_session::produce_xml(Xml_generator &xml)
{
Rect const domain_panorama =
_domain ? _domain->screen_rect(_view_stack.bounding_box())
: Rect { };
_action.gen_capture_info(xml, domain_panorama);
}

View File

@ -20,6 +20,7 @@
#include <base/heap.h> #include <base/heap.h>
#include <os/session_policy.h> #include <os/session_policy.h>
#include <os/reporter.h> #include <os/reporter.h>
#include <os/dynamic_rom_session.h>
#include <gui_session/gui_session.h> #include <gui_session/gui_session.h>
/* local includes */ /* local includes */
@ -42,8 +43,19 @@ namespace Nitpicker {
class Nitpicker::Gui_session : public Session_object<Gui::Session>, class Nitpicker::Gui_session : public Session_object<Gui::Session>,
public View_owner, public View_owner,
public Buffer_provider, public Buffer_provider,
private Session_list::Element private Session_list::Element,
private Dynamic_rom_session::Xml_producer
{ {
public:
struct Action : Interface
{
/*
* \param rect domain-specific panorama rectangle
*/
virtual void gen_capture_info(Xml_generator &xml, Rect rect) const = 0;
};
private: private:
struct View_ref : Gui::View_ref struct View_ref : Gui::View_ref
@ -85,7 +97,8 @@ class Nitpicker::Gui_session : public Session_object<Gui::Session>,
Gui_session(Gui_session const &); Gui_session(Gui_session const &);
Gui_session &operator = (Gui_session const &); Gui_session &operator = (Gui_session const &);
Env &_env; Env &_env;
Action &_action;
Constrained_ram_allocator _ram; Constrained_ram_allocator _ram;
@ -110,7 +123,7 @@ class Nitpicker::Gui_session : public Session_object<Gui::Session>,
Focus_updater &_focus_updater; Focus_updater &_focus_updater;
Hover_updater &_hover_updater; Hover_updater &_hover_updater;
Signal_context_capability _mode_sigh { }; Constructible<Dynamic_rom_session> _info_rom { };
View &_pointer_origin; View &_pointer_origin;
@ -183,9 +196,15 @@ class Nitpicker::Gui_session : public Session_object<Gui::Session>,
[&] /* ID does not exist */ { return missing_fn(); }); [&] /* ID does not exist */ { return missing_fn(); });
} }
/**
* Dynamic_rom_session::Xml_producer interface
*/
void produce_xml(Xml_generator &) override;
public: public:
Gui_session(Env &env, Gui_session(Env &env,
Action &action,
Resources const &resources, Resources const &resources,
Label const &label, Label const &label,
Diag const &diag, Diag const &diag,
@ -198,7 +217,8 @@ class Nitpicker::Gui_session : public Session_object<Gui::Session>,
Reporter &focus_reporter) Reporter &focus_reporter)
: :
Session_object(env.ep(), resources, label, diag), Session_object(env.ep(), resources, label, diag),
_env(env), Xml_producer("panorama"),
_env(env), _action(action),
_ram(env.ram(), _ram_quota_guard(), _cap_quota_guard()), _ram(env.ram(), _ram_quota_guard(), _cap_quota_guard()),
_session_alloc(_ram, env.rm()), _session_alloc(_ram, env.rm()),
_framebuffer_session_component(env.ep(), view_stack, *this, *this), _framebuffer_session_component(env.ep(), view_stack, *this, *this),
@ -319,14 +339,6 @@ class Nitpicker::Gui_session : public Session_object<Gui::Session>,
*/ */
void visible(bool visible) { _visible = visible; } void visible(bool visible) { _visible = visible; }
/**
* Return session-local screen geometry
*/
Rect screen_rect(Area screen_area) const
{
return _domain ? _domain->screen_rect(screen_area) : Rect { };
}
void reset_domain() { _domain = nullptr; } void reset_domain() { _domain = nullptr; }
/** /**
@ -344,8 +356,8 @@ class Nitpicker::Gui_session : public Session_object<Gui::Session>,
*/ */
void notify_mode_change() void notify_mode_change()
{ {
if (_mode_sigh.valid()) if (_info_rom.constructed())
Signal_transmitter(_mode_sigh).submit(); _info_rom->trigger_update();
} }
/** /**
@ -375,6 +387,30 @@ class Nitpicker::Gui_session : public Session_object<Gui::Session>,
Input::Session_capability input() override { Input::Session_capability input() override {
return _input_session_component.cap(); } return _input_session_component.cap(); }
Info_result info() override
{
if (!_info_rom.constructed()) {
Cap_quota const needed_caps { 2 };
if (!try_withdraw(needed_caps))
return Info_error::OUT_OF_CAPS;
bool out_of_caps = false, out_of_ram = false;
try {
Dynamic_rom_session::Content_producer &rom_producer = *this;
_info_rom.construct(_env.ep(), _ram, _env.rm(), rom_producer);
}
catch (Out_of_ram) { out_of_ram = true; }
catch (Out_of_caps) { out_of_caps = true; }
if (out_of_ram || out_of_ram) {
replenish(needed_caps);
if (out_of_ram) return Info_error::OUT_OF_RAM;
if (out_of_caps) return Info_error::OUT_OF_CAPS;
}
}
return _info_rom->cap();
}
View_result view(View_id, View_attr const &attr) override; View_result view(View_id, View_attr const &attr) override;
Child_view_result child_view(View_id, View_id, View_attr const &attr) override; Child_view_result child_view(View_id, View_id, View_attr const &attr) override;
@ -391,10 +427,6 @@ class Nitpicker::Gui_session : public Session_object<Gui::Session>,
void execute() override; void execute() override;
Framebuffer::Mode mode() override;
void mode_sigh(Signal_context_capability sigh) override { _mode_sigh = sigh; }
Buffer_result buffer(Framebuffer::Mode) override; Buffer_result buffer(Framebuffer::Mode) override;
void focus(Capability<Gui::Session>) override; void focus(Capability<Gui::Session>) override;

View File

@ -90,6 +90,7 @@ class Nitpicker::Gui_root : public Root_component<Gui_session>
private: private:
Env &_env; Env &_env;
Gui_session::Action &_action;
Attached_rom_dataspace const &_config; Attached_rom_dataspace const &_config;
Session_list &_session_list; Session_list &_session_list;
Domain_registry const &_domain_registry; Domain_registry const &_domain_registry;
@ -118,7 +119,7 @@ class Nitpicker::Gui_root : public Root_component<Gui_session>
resources.cap_quota.value -= 2; resources.cap_quota.value -= 2;
Gui_session *session = new (md_alloc()) Gui_session *session = new (md_alloc())
Gui_session(_env, Gui_session(_env, _action,
resources, label, resources, label,
session_diag_from_args(args), _view_stack, session_diag_from_args(args), _view_stack,
_focus_updater, _hover_updater, _pointer_origin, _focus_updater, _hover_updater, _pointer_origin,
@ -170,6 +171,7 @@ class Nitpicker::Gui_root : public Root_component<Gui_session>
* Constructor * Constructor
*/ */
Gui_root(Env &env, Gui_root(Env &env,
Gui_session::Action &action,
Attached_rom_dataspace const &config, Attached_rom_dataspace const &config,
Session_list &session_list, Session_list &session_list,
Domain_registry const &domain_registry, Domain_registry const &domain_registry,
@ -184,7 +186,7 @@ class Nitpicker::Gui_root : public Root_component<Gui_session>
Hover_updater &hover_updater) Hover_updater &hover_updater)
: :
Root_component<Gui_session>(&env.ep().rpc_ep(), &md_alloc), Root_component<Gui_session>(&env.ep().rpc_ep(), &md_alloc),
_env(env), _config(config), _session_list(session_list), _env(env), _action(action), _config(config), _session_list(session_list),
_domain_registry(domain_registry), _global_keys(global_keys), _domain_registry(domain_registry), _global_keys(global_keys),
_view_stack(view_stack), _user_state(user_state), _view_stack(view_stack), _user_state(user_state),
_pointer_origin(pointer_origin), _pointer_origin(pointer_origin),
@ -346,14 +348,11 @@ class Nitpicker::Capture_root : public Root_component<Capture_session>
session.mark_as_damaged(rect); }); session.mark_as_damaged(rect); });
} }
void report_displays(Xml_generator &xml) const void report_displays(Xml_generator &xml, Rect const domain_panorama) const
{ {
Capture_session::gen_attr(xml, _view_stack.bounding_box()); gen_attr(xml, domain_panorama);
_sessions.for_each([&] (Capture_session const &capture) { _sessions.for_each([&] (Capture_session const &capture) {
xml.node("capture", [&] { xml.node("capture", [&] { capture.gen_capture_attr(xml); }); });
xml.attribute("name", capture.label());
Capture_session::gen_attr(xml, capture.bounding_box()); }); });
} }
}; };
@ -411,7 +410,8 @@ struct Nitpicker::Main : Focus_updater, Hover_updater,
Capture_session::Handler, Capture_session::Handler,
Event_session::Handler, Event_session::Handler,
Capture_root::Action, Capture_root::Action,
User_state::Action User_state::Action,
Gui_session::Action
{ {
Env &_env; Env &_env;
@ -613,11 +613,19 @@ struct Nitpicker::Main : Focus_updater, Hover_updater,
Constructible<Attached_rom_dataspace> _focus_rom { }; Constructible<Attached_rom_dataspace> _focus_rom { };
Gui_root _gui_root { _env, _config_rom, _session_list, *_domain_registry, Gui_root _gui_root { _env, *this, _config_rom, _session_list, *_domain_registry,
_global_keys, _view_stack, _user_state, _pointer_origin, _global_keys, _view_stack, _user_state, _pointer_origin,
_builtin_background, _sliced_heap, _builtin_background, _sliced_heap,
_focus_reporter, *this, *this }; _focus_reporter, *this, *this };
/**
* Gui_session::Action interface
*/
void gen_capture_info(Xml_generator &xml, Rect const domain_panorama) const override
{
_capture_root.report_displays(xml, domain_panorama);
}
Capture_root _capture_root { _env, *this, _sliced_heap, _view_stack, *this }; Capture_root _capture_root { _env, *this, _sliced_heap, _view_stack, *this };
Event_root _event_root { _env, _sliced_heap, *this }; Event_root _event_root { _env, _sliced_heap, *this };
@ -1041,7 +1049,7 @@ void Nitpicker::Main::_report_displays()
if (_fb_screen.constructed()) if (_fb_screen.constructed())
xml.node("display", [&] { gen_attr(xml, _fb_screen->_rect); }); xml.node("display", [&] { gen_attr(xml, _fb_screen->_rect); });
_capture_root.report_displays(xml); _capture_root.report_displays(xml, _view_stack.bounding_box());
}); });
} }

View File

@ -43,15 +43,15 @@ void Vmm::Virtio_gpu_queue::notify(Virtio_gpu_device & dev)
void Vmm::Virtio_gpu_control_request::_get_display_info() void Vmm::Virtio_gpu_control_request::_get_display_info()
{ {
Framebuffer::Mode mode = _device.resize(); Gui::Area const mode = _device.resize();
Display_info_response dir { _desc_range(1) }; Display_info_response dir { _desc_range(1) };
memset((void*)dir.base(), 0, Display_info_response::SIZE); memset((void*)dir.base(), 0, Display_info_response::SIZE);
dir.write<Control_header::Type>(Control_header::Type::OK_DISPLAY_INFO); dir.write<Control_header::Type>(Control_header::Type::OK_DISPLAY_INFO);
dir.write<Display_info_response::X>(0); dir.write<Display_info_response::X>(0);
dir.write<Display_info_response::Y>(0); dir.write<Display_info_response::Y>(0);
dir.write<Display_info_response::Width>(mode.area.w); dir.write<Display_info_response::Width>(mode.w);
dir.write<Display_info_response::Height>(mode.area.h); dir.write<Display_info_response::Height>(mode.h);
dir.write<Display_info_response::Enabled>(1); dir.write<Display_info_response::Enabled>(1);
dir.write<Display_info_response::Flags>(0); dir.write<Display_info_response::Flags>(0);
} }
@ -195,9 +195,9 @@ void Vmm::Virtio_gpu_control_request::_resource_flush()
uint32_t x = rf.read<Resource_flush::X>(); uint32_t x = rf.read<Resource_flush::X>();
uint32_t y = rf.read<Resource_flush::Y>(); uint32_t y = rf.read<Resource_flush::Y>();
uint32_t w = min(rf.read<Resource_flush::Width>(), uint32_t w = min(rf.read<Resource_flush::Width>(),
_device._fb_mode.area.w - x); _device._gui_win.area.w - x);
uint32_t h = min(rf.read<Resource_flush::Height>(), uint32_t h = min(rf.read<Resource_flush::Height>(),
_device._fb_mode.area.h - y); _device._gui_win.area.h - y);
enum { BYTES_PER_PIXEL = Virtio_gpu_device::BYTES_PER_PIXEL }; enum { BYTES_PER_PIXEL = Virtio_gpu_device::BYTES_PER_PIXEL };
@ -218,9 +218,9 @@ void Vmm::Virtio_gpu_control_request::_resource_flush()
(res.area.w * y + x) * BYTES_PER_PIXEL); (res.area.w * y + x) * BYTES_PER_PIXEL);
void * dst = void * dst =
(void*)((addr_t)_device._fb_ds->local_addr<void>() + (void*)((addr_t)_device._fb_ds->local_addr<void>() +
(_device._fb_mode.area.w * y + x) * BYTES_PER_PIXEL); (_device._gui_win.area.w * y + x) * BYTES_PER_PIXEL);
uint32_t line_src = res.area.w * BYTES_PER_PIXEL; uint32_t line_src = res.area.w * BYTES_PER_PIXEL;
uint32_t line_dst = _device._fb_mode.area.w * BYTES_PER_PIXEL; uint32_t line_dst = _device._gui_win.area.w * BYTES_PER_PIXEL;
blit(src, line_src, dst, line_dst, w*BYTES_PER_PIXEL, h); blit(src, line_src, dst, line_dst, w*BYTES_PER_PIXEL, h);
_device._gui.framebuffer.refresh({ { int(x), int(y) }, { w, h } }); _device._gui.framebuffer.refresh({ { int(x), int(y) }, { w, h } });

View File

@ -296,8 +296,16 @@ class Vmm::Virtio_gpu_device : public Virtio_device<Virtio_gpu_queue, 2>
Gui::Connection & _gui; Gui::Connection & _gui;
Cpu::Signal_handler<Virtio_gpu_device> _handler; Cpu::Signal_handler<Virtio_gpu_device> _handler;
Constructible<Attached_dataspace> _fb_ds { }; Constructible<Attached_dataspace> _fb_ds { };
Framebuffer::Mode _fb_mode { _gui.mode() };
Gui::Top_level_view _view { _gui, { { }, _fb_mode.area } }; Gui::Rect _request_gui_window()
{
return _gui.window().convert<Gui::Rect>(
[&] (Gui::Rect rect) { return rect; },
[&] (Gui::Undefined) { return Gui::Rect { { }, { 640, 480 } }; });
}
Gui::Rect _gui_win = _request_gui_window();
Gui::Top_level_view _view { _gui, _gui_win };
using Area = Genode::Area<>; using Area = Genode::Area<>;
using Rect = Genode::Rect<>; using Rect = Genode::Rect<>;
@ -446,7 +454,7 @@ class Vmm::Virtio_gpu_device : public Virtio_device<Virtio_gpu_queue, 2>
_env(env), _heap(heap), _ram_ds(ram_ds), _gui(gui), _env(env), _heap(heap), _ram_ds(ram_ds), _gui(gui),
_handler(cpu, env.ep(), *this, &Virtio_gpu_device::_mode_change) _handler(cpu, env.ep(), *this, &Virtio_gpu_device::_mode_change)
{ {
_gui.mode_sigh(_handler); _gui.info_sigh(_handler);
} }
void buffer_notification() void buffer_notification()
@ -454,21 +462,21 @@ class Vmm::Virtio_gpu_device : public Virtio_device<Virtio_gpu_queue, 2>
_buffer_notification(); _buffer_notification();
} }
Framebuffer::Mode resize() Gui::Area resize()
{ {
_fb_ds.destruct(); _fb_ds.destruct();
_fb_mode = _gui.mode(); _gui_win = _request_gui_window();
_gui.buffer(_fb_mode); _gui.buffer({ .area = _gui_win.area, .alpha = false });
if (_fb_mode.area.count() > 0) if (_gui_win.valid())
_fb_ds.construct(_env.rm(), _gui.framebuffer.dataspace()); _fb_ds.construct(_env.rm(), _gui.framebuffer.dataspace());
using Command = Gui::Session::Command; using Command = Gui::Session::Command;
_gui.enqueue<Command::Geometry>(_view.id(), Rect(Point(0, 0), _fb_mode.area)); _gui.enqueue<Command::Geometry>(_view.id(), _gui_win);
_gui.enqueue<Command::Front>(_view.id()); _gui.enqueue<Command::Front>(_view.id());
_gui.execute(); _gui.execute();
return _gui.mode(); return _gui_win.area;
} }
}; };

View File

@ -291,7 +291,13 @@ void GenodeConsole::_handle_mode_change()
Genodefb *fb = dynamic_cast<Genodefb *>(pFramebuffer); Genodefb *fb = dynamic_cast<Genodefb *>(pFramebuffer);
fb->update_mode(_gui.mode()); Gui::Rect const gui_win = _gui.window().convert<Gui::Rect>(
[&] (Gui::Rect rect) { return rect; },
[&] (Gui::Undefined) { return _gui.panorama().convert<Gui::Rect>(
[&] (Gui::Rect rect) { return rect; },
[&] (Gui::Undefined) { return Gui::Rect { { }, { 800, 600 } }; }); });
fb->update_mode(gui_win);
update_video_mode(); update_video_mode();
} }
@ -340,7 +346,7 @@ void GenodeConsole::init_backends(IKeyboard * gKeyboard, IMouse * gMouse)
HRESULT rc = i_getDisplay()->QueryFramebuffer(0, &pFramebuffer); HRESULT rc = i_getDisplay()->QueryFramebuffer(0, &pFramebuffer);
Assert(SUCCEEDED(rc) && pFramebuffer); Assert(SUCCEEDED(rc) && pFramebuffer);
_gui.mode_sigh(_mode_change_signal_dispatcher); _gui.info_sigh(_mode_change_signal_dispatcher);
_handle_mode_change(); _handle_mode_change();
} }

View File

@ -34,13 +34,13 @@ class Genodefb :
Genode::Env &_env; Genode::Env &_env;
Gui::Connection &_gui; Gui::Connection &_gui;
Gui::Top_level_view _view { _gui }; Gui::Top_level_view _view { _gui };
Fb_Genode::Mode _fb_mode { .area = { 1024, 768 } }; Gui::Rect _gui_win { .at = { }, .area = { 1024, 768 } };
/* /*
* The mode currently used by the VM. Can be smaller than the * The mode currently used by the VM. Can be smaller than the
* framebuffer mode. * framebuffer mode.
*/ */
Fb_Genode::Mode _virtual_fb_mode; Gui::Area _virtual_fb_mode;
void *_attach() void *_attach()
{ {
@ -64,23 +64,23 @@ class Genodefb :
{ {
if (!_fb_base) return; if (!_fb_base) return;
size_t const max_h = Genode::min(_fb_mode.area.h, _virtual_fb_mode.area.h); size_t const max_h = Genode::min(_gui_win.area.h, _virtual_fb_mode.h);
size_t const num_pixels = _fb_mode.area.w * max_h; size_t const num_pixels = _gui_win.area.w * max_h;
memset(_fb_base, 0, num_pixels * sizeof(Genode::Pixel_rgb888)); memset(_fb_base, 0, num_pixels * sizeof(Genode::Pixel_rgb888));
_gui.framebuffer.refresh({ { 0, 0 }, _virtual_fb_mode.area }); _gui.framebuffer.refresh({ _gui_win.at, _virtual_fb_mode });
} }
void _adjust_buffer() void _adjust_buffer()
{ {
_gui.buffer(_fb_mode); _gui.buffer({ .area = _gui_win.area, .alpha = false });
_view.area(_fb_mode.area); _view.geometry(_gui_win);
} }
Fb_Genode::Mode _initial_setup() Gui::Area _initial_setup()
{ {
_adjust_buffer(); _adjust_buffer();
_view.front(); _view.front();
return _fb_mode; return _gui_win.area;
} }
public: public:
@ -96,14 +96,14 @@ class Genodefb :
Assert(rc == VINF_SUCCESS); Assert(rc == VINF_SUCCESS);
} }
int w() const { return _fb_mode.area.w; } int w() const { return _gui_win.area.w; }
int h() const { return _fb_mode.area.h; } int h() const { return _gui_win.area.h; }
void update_mode(Fb_Genode::Mode mode) void update_mode(Gui::Rect const gui_win)
{ {
Lock(); Lock();
_fb_mode = mode; _gui_win = gui_win;
if (_fb_base) if (_fb_base)
_env.rm().detach(Genode::addr_t(_fb_base)); _env.rm().detach(Genode::addr_t(_fb_base));
@ -135,32 +135,32 @@ class Genodefb :
/* save the new bitmap reference */ /* save the new bitmap reference */
_display->QuerySourceBitmap(screen, _display_bitmap.asOutParam()); _display->QuerySourceBitmap(screen, _display_bitmap.asOutParam());
bool const ok = (w <= (ULONG)_fb_mode.area.w) && bool const ok = (w <= (ULONG)_gui_win.area.w) &&
(h <= (ULONG)_fb_mode.area.h); (h <= (ULONG)_gui_win.area.h);
bool const changed = (w != (ULONG)_virtual_fb_mode.area.w) || bool const changed = (w != (ULONG)_virtual_fb_mode.w) ||
(h != (ULONG)_virtual_fb_mode.area.h); (h != (ULONG)_virtual_fb_mode.h);
if (ok && changed) { if (ok && changed) {
Genode::log("fb resize : [", screen, "] ", Genode::log("fb resize : [", screen, "] ",
_virtual_fb_mode.area, " -> ", _virtual_fb_mode, " -> ",
w, "x", h, w, "x", h,
" (host: ", _fb_mode.area, ")"); " (host: ", _gui_win.area, ")");
if ((w < (ULONG)_fb_mode.area.w) || if ((w < (ULONG)_gui_win.area.w) ||
(h < (ULONG)_fb_mode.area.h)) { (h < (ULONG)_gui_win.area.h)) {
/* clear the old content around the new, smaller area. */ /* clear the old content around the new, smaller area. */
_clear_screen(); _clear_screen();
} }
_virtual_fb_mode = Fb_Genode::Mode { .area = { w, h } }; _virtual_fb_mode = { w, h };
result = S_OK; result = S_OK;
} else if (changed) { } else if (changed) {
Genode::log("fb resize : [", screen, "] ", Genode::log("fb resize : [", screen, "] ",
_virtual_fb_mode.area, " -> ", _virtual_fb_mode, " -> ",
w, "x", h, " ignored" w, "x", h, " ignored"
" (host: ", _fb_mode.area, ")"); " (host: ", _gui_win.area, ")");
} }
Unlock(); Unlock();
@ -213,8 +213,8 @@ class Genodefb :
&ulBytesPerLine, &ulBytesPerLine,
&bitmapFormat); &bitmapFormat);
Gui::Area const area_fb = Gui::Area(_fb_mode.area.w, Gui::Area const area_fb = Gui::Area(_gui_win.area.w,
_fb_mode.area.h); _gui_win.area.h);
Gui::Area const area_vm = Gui::Area(ulWidth, ulHeight); Gui::Area const area_vm = Gui::Area(ulWidth, ulHeight);
using namespace Genode; using namespace Genode;
@ -251,7 +251,7 @@ class Genodefb :
Lock(); Lock();
Gui::Area const area_fb = _fb_mode.area; Gui::Area const area_fb = _gui_win.area;
Gui::Area const area_vm = Gui::Area(width, height); Gui::Area const area_vm = Gui::Area(width, height);
using namespace Genode; using namespace Genode;
@ -290,8 +290,8 @@ class Genodefb :
if (!supported) if (!supported)
return E_POINTER; return E_POINTER;
*supported = ((width <= (ULONG)_fb_mode.area.w) && *supported = ((width <= (ULONG)_gui_win.area.w) &&
(height <= (ULONG)_fb_mode.area.h)); (height <= (ULONG)_gui_win.area.h));
return S_OK; return S_OK;
} }

View File

@ -33,13 +33,13 @@ class Genodefb :
Genode::Env &_env; Genode::Env &_env;
Gui::Connection &_gui; Gui::Connection &_gui;
Gui::Top_level_view _view { _gui }; Gui::Top_level_view _view { _gui };
Fb_Genode::Mode _fb_mode { .area = { 1024, 768 } }; Gui::Rect _gui_win { { }, { 1024, 768 } };
/* /*
* The mode currently used by the VM. Can be smaller than the * The mode currently used by the VM. Can be smaller than the
* framebuffer mode. * framebuffer mode.
*/ */
Fb_Genode::Mode _virtual_fb_mode; Gui::Area _virtual_fb_mode;
void *_attach() void *_attach()
{ {
@ -62,23 +62,23 @@ class Genodefb :
{ {
if (!_fb_base) return; if (!_fb_base) return;
size_t const max_h = Genode::min(_fb_mode.area.h, _virtual_fb_mode.area.h); size_t const max_h = Genode::min(_gui_win.area.h, _virtual_fb_mode.h);
size_t const num_pixels = _fb_mode.area.w * max_h; size_t const num_pixels = _gui_win.area.w * max_h;
memset(_fb_base, 0, num_pixels * sizeof(Genode::Pixel_rgb888)); memset(_fb_base, 0, num_pixels * sizeof(Genode::Pixel_rgb888));
_gui.framebuffer.refresh({ { 0, 0 }, _virtual_fb_mode.area }); _gui.framebuffer.refresh({ _gui_win.at, _virtual_fb_mode });
} }
void _adjust_buffer() void _adjust_buffer()
{ {
_gui.buffer(_fb_mode); _gui.buffer({ .area = _gui_win.area, .alpha = false });
_view.area(_fb_mode.area); _view.area(_gui_win.area);
} }
Fb_Genode::Mode _initial_setup() Gui::Area _initial_setup()
{ {
_adjust_buffer(); _adjust_buffer();
_view.front(); _view.front();
return _fb_mode; return _gui_win.area;
} }
public: public:
@ -98,14 +98,14 @@ class Genodefb :
virtual ~Genodefb() { } virtual ~Genodefb() { }
int w() const { return _fb_mode.area.w; } int w() const { return _gui_win.area.w; }
int h() const { return _fb_mode.area.h; } int h() const { return _gui_win.area.h; }
void update_mode(Fb_Genode::Mode mode) void update_mode(Gui::Rect gui_win)
{ {
Lock(); Lock();
_fb_mode = mode; _gui_win = gui_win;
if (_fb_base) if (_fb_base)
_env.rm().detach(Genode::addr_t(_fb_base)); _env.rm().detach(Genode::addr_t(_fb_base));
@ -137,32 +137,32 @@ class Genodefb :
/* save the new bitmap reference */ /* save the new bitmap reference */
_display->QuerySourceBitmap(screen, _display_bitmap.asOutParam()); _display->QuerySourceBitmap(screen, _display_bitmap.asOutParam());
bool const ok = (w <= (ULONG)_fb_mode.area.w) && bool const ok = (w <= (ULONG)_gui_win.area.w) &&
(h <= (ULONG)_fb_mode.area.h); (h <= (ULONG)_gui_win.area.h);
bool const changed = (w != (ULONG)_virtual_fb_mode.area.w) || bool const changed = (w != (ULONG)_virtual_fb_mode.w) ||
(h != (ULONG)_virtual_fb_mode.area.h); (h != (ULONG)_virtual_fb_mode.h);
if (ok && changed) { if (ok && changed) {
Genode::log("fb resize : [", screen, "] ", Genode::log("fb resize : [", screen, "] ",
_virtual_fb_mode.area, " -> ", _virtual_fb_mode, " -> ",
w, "x", h, w, "x", h,
" (host: ", _fb_mode.area, ")"); " (host: ", _gui_win.area, ")");
if ((w < (ULONG)_fb_mode.area.w) || if ((w < (ULONG)_gui_win.area.w) ||
(h < (ULONG)_fb_mode.area.h)) { (h < (ULONG)_gui_win.area.h)) {
/* clear the old content around the new, smaller area. */ /* clear the old content around the new, smaller area. */
_clear_screen(); _clear_screen();
} }
_virtual_fb_mode = Fb_Genode::Mode { .area = { w, h } }; _virtual_fb_mode = { w, h };
result = S_OK; result = S_OK;
} else if (changed) { } else if (changed) {
Genode::log("fb resize : [", screen, "] ", Genode::log("fb resize : [", screen, "] ",
_virtual_fb_mode.area, " -> ", _virtual_fb_mode, " -> ",
w, "x", h, " ignored" w, "x", h, " ignored"
" (host: ", _fb_mode.area, ")"); " (host: ", _gui_win.area, ")");
} }
Unlock(); Unlock();
@ -215,8 +215,8 @@ class Genodefb :
&ulBytesPerLine, &ulBytesPerLine,
&bitmapFormat); &bitmapFormat);
Gui::Area const area_fb = Gui::Area(_fb_mode.area.w, Gui::Area const area_fb = Gui::Area(_gui_win.area.w,
_fb_mode.area.h); _gui_win.area.h);
Gui::Area const area_vm = Gui::Area(ulWidth, ulHeight); Gui::Area const area_vm = Gui::Area(ulWidth, ulHeight);
using namespace Genode; using namespace Genode;
@ -253,7 +253,7 @@ class Genodefb :
Lock(); Lock();
Gui::Area const area_fb = _fb_mode.area; Gui::Area const area_fb = _gui_win.area;
Gui::Area const area_vm = Gui::Area(width, height); Gui::Area const area_vm = Gui::Area(width, height);
using namespace Genode; using namespace Genode;
@ -292,8 +292,8 @@ class Genodefb :
if (!supported) if (!supported)
return E_POINTER; return E_POINTER;
*supported = ((width <= (ULONG)_fb_mode.area.w) && *supported = ((width <= (ULONG)_gui_win.area.w) &&
(height <= (ULONG)_fb_mode.area.h)); (height <= (ULONG)_gui_win.area.h));
return S_OK; return S_OK;
} }

View File

@ -302,7 +302,7 @@ struct Main : Event_handler
Gui::Connection &gui = *new Registered<Gui::Connection>(_gui_connections, _env, label.string()); Gui::Connection &gui = *new Registered<Gui::Connection>(_gui_connections, _env, label.string());
gui.input.sigh(_input_handler); gui.input.sigh(_input_handler);
gui.mode_sigh(_fb_mode_handler); gui.info_sigh(_fb_mode_handler);
Genodefb *fb = new Genodefb(_env, gui, _idisplay); Genodefb *fb = new Genodefb(_env, gui, _idisplay);
@ -438,7 +438,13 @@ void Main::_handle_fb_mode()
Genodefb *fb = dynamic_cast<Genodefb *>(pFramebuffer); Genodefb *fb = dynamic_cast<Genodefb *>(pFramebuffer);
fb->update_mode(gui.mode()); Gui::Rect const gui_win = gui.window().convert<Gui::Rect>(
[&] (Gui::Rect rect) { return rect; },
[&] (Gui::Undefined) { return gui.panorama().convert<Gui::Rect>(
[&] (Gui::Rect rect) { return rect; },
[&] (Gui::Undefined) { return Gui::Rect { { }, { 800, 600 } }; }); });
fb->update_mode(gui_win);
if ((fb->w() <= 1) && (fb->h() <= 1)) { if ((fb->w() <= 1) && (fb->h() <= 1)) {
/* interpret a size of 0x0 as indication to quit VirtualBox */ /* interpret a size of 0x0 as indication to quit VirtualBox */