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

View File

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

View File

@ -2007,7 +2007,7 @@ struct Sculpt::Main : Input_event_handler,
_drivers.update_soc(_soc);
_gui.input.sigh(_input_handler);
_gui.mode_sigh(_gui_mode_handler);
_gui.info_sigh(_gui_mode_handler);
_handle_gui_mode();
_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),
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) {
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);
Point const pos = _touch_keyboard.visible
? Point(0, int(mode.area.h) - int(size.h))
: Point(0, int(mode.area.h));
? Point(0, int(_screen_size.h) - int(size.h))
: Point(0, int(_screen_size.h));
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()
{
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)
_gui_mode_ready = true;
_screen_size = mode.area;
_main_view.min_width = _screen_size.w;
_main_view.min_height = _screen_size.h;
panorama.with_result(
[&] (Gui::Rect const rect) {
_gui_mode_ready = true;
_screen_size = rect.area;
_main_view.min_width = _screen_size.w;
_main_view.min_height = _screen_size.h;
},
[&] (Gui::Undefined) { }
);
generate_runtime_config();
_update_window_layout();

View File

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

View File

@ -104,7 +104,10 @@ struct Sculpt::Main : Input_event_handler,
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 };
@ -953,8 +956,10 @@ struct Sculpt::Main : Input_event_handler,
ev.handle_wheel([&] (int, int y) { dy = y*32; });
if (ev.key_press(Input::KEY_PAGEUP)) dy = int(_gui.mode().area.h / 3);
if (ev.key_press(Input::KEY_PAGEDOWN)) dy = -int(_gui.mode().area.h / 3);
int const vscroll_step = int(_screen_size.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) {
scroll_ypos += dy;
@ -1647,7 +1652,7 @@ struct Sculpt::Main : Input_event_handler,
{
_drivers.update_soc(_soc);
_gui.input.sigh(_input_handler);
_gui.mode_sigh(_gui_mode_handler);
_gui.info_sigh(_gui_mode_handler);
_handle_gui_mode();
_fb_config.trigger_update();
@ -1680,7 +1685,7 @@ void Sculpt::Main::_update_window_layout(Xml_node const &decorator_margins,
Xml_node const &window_list)
{
/* skip window-layout handling (and decorator activity) while booting */
if (!_gui_mode_ready)
if (!_gui_mode_ready())
return;
struct Decorator_margins
@ -1726,18 +1731,16 @@ void Sculpt::Main::_update_window_layout(Xml_node const &decorator_margins,
if (panel_height == 0)
return;
Framebuffer::Mode const mode = _gui.mode();
/* suppress intermediate boot-time states before the framebuffer driver is up */
if (mode.area.count() <= 1)
if (!_screen_size.valid())
return;
/* 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 */
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(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,
avail.y1() + margins.top);
Point const log_p2(mode.area.w - margins.right - 1 + log_offset.x,
mode.area.h - margins.bottom - 1);
Point const log_p2(_screen_size.w - margins.right - 1 + log_offset.x,
_screen_size.h - margins.bottom - 1);
/* position of the inspect window */
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);
Point const pos = _network_visible
? 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));
});
@ -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) {
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));
});
});
@ -1945,10 +1948,11 @@ void Sculpt::Main::_update_window_layout(Xml_node const &decorator_margins,
void Sculpt::Main::_handle_gui_mode()
{
Framebuffer::Mode const mode = _gui.mode();
_panorama = _gui.panorama();
if (mode.area.count() > 1)
_gui_mode_ready = true;
_screen_size = _panorama.convert<Gui::Area>(
[&] (Gui::Rect rect) { return rect.area; },
[&] (Gui::Undefined) { return Gui::Area { 1024, 768 }; });
_update_window_layout();
@ -1956,7 +1960,7 @@ void Sculpt::Main::_handle_gui_mode()
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::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;
unsigned const menu_width = max((unsigned)(_font_size_px*21.0), 320u);
_diag_dialog.min_width = menu_width;

View File

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

View File

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

View File

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

View File

@ -100,9 +100,16 @@ struct Terminal::Main : Character_consumer
Signal_handler<Main> _config_handler {
_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()
{
_fb_mode = _gui.mode();
_win_rect = _gui_window_rect();
_handle_config();
}
@ -114,7 +121,7 @@ struct Terminal::Main : Character_consumer
Constructible<Attached_dataspace> _fb_ds { };
Framebuffer::Mode _fb_mode { };
Gui::Rect _win_rect { };
Gui::View_id _view { };
@ -143,7 +150,7 @@ struct Terminal::Main : Character_consumer
bool _flush_scheduled = false;
Framebuffer::Mode _flushed_fb_mode { };
Gui::Rect _flushed_win_rect { };
void _handle_flush()
{
@ -151,7 +158,7 @@ struct Terminal::Main : Character_consumer
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);
@ -159,14 +166,14 @@ struct Terminal::Main : Character_consumer
}
/* 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;
_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.execute();
_flushed_fb_mode = _fb_mode;
_flushed_win_rect = _win_rect;
}
}
@ -215,14 +222,14 @@ struct Terminal::Main : Character_consumer
_config.sigh(_config_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 */
_config.xml().with_optional_sub_node("initial", [&] (Xml_node const &initial) {
_fb_mode.area = Area(initial.attribute_value("width", _fb_mode.area.w),
initial.attribute_value("height", _fb_mode.area.h));
_win_rect.area = { initial.attribute_value("width", _win_rect.w()),
initial.attribute_value("height", _win_rect.h()) };
});
_handle_config();
@ -259,9 +266,9 @@ void Terminal::Main::_handle_config()
/*
* 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());
/*
@ -276,7 +283,7 @@ void Terminal::Main::_handle_config()
*/
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() ||
_text_screen_surface->size() != new_geometry.size();
@ -307,7 +314,7 @@ void Terminal::Main::_handle_config()
: Position();
_text_screen_surface.construct(_heap, _font->font(),
_color_palette, _fb_mode.area);
_color_palette, _win_rect.area);
if (snapshot.constructed())
_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;
}
Info_result info() override
{
return _real_gui.session.info();
}
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();
}
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
{
return _real_gui.session.buffer(mode);

View File

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

View File

@ -19,6 +19,7 @@
#include <gui_session/connection.h>
#include <input_session/capability.h>
#include <input/component.h>
#include <os/dynamic_rom_session.h>
/* local includes */
#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>,
private List<Session_component>::Element,
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:
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 {
_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 };
Click_handler &_click_handler;
Signal_context_capability _mode_sigh { };
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;
struct Info_rom_session : Dynamic_rom_session
{
Session_component &_session;
Info_rom_session(Session_component &session, auto &&... args)
: Dynamic_rom_session(args...), _session(session) { }
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)
-> decltype(missing_fn())
@ -601,9 +635,6 @@ class Wm::Gui::Session_component : public Session_object<Gui::Session>,
Signal_handler<Session_component> _input_handler {
_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
{
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
{
/*
* Inform a viewless client about the upstream
* mode change.
*/
if (_mode_sigh.valid() && !_top_level_views.first())
Signal_transmitter(_mode_sigh).submit();
_action.gen_screen_area_info(xml);
auto virtual_capture_area = [&]
{
/*
* 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:
Session_component(Env &env,
Action &action,
Resources const &resources,
Label const &label,
Diag const diag,
@ -835,13 +895,13 @@ class Wm::Gui::Session_component : public Session_object<Gui::Session>,
Click_handler &click_handler)
:
Session_object<Gui::Session>(env.ep(), resources, label, diag),
_env(env),
Xml_producer("panorama"),
_env(env), _action(action),
_window_registry(window_registry),
_click_handler(click_handler),
_pointer_state(pointer_tracker)
{
_gui_input.sigh(_input_handler);
_real_gui.session.mode_sigh(_mode_handler);
_input_session.event_queue().enabled(true);
}
@ -933,8 +993,8 @@ class Wm::Gui::Session_component : public Session_object<Gui::Session>,
_resize_requested = true;
/* notify client */
if (_mode_sigh.valid())
Signal_transmitter(_mode_sigh).submit();
if (_info_rom.constructed())
_info_rom->trigger_update();
}
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(); }
void propagate_mode_change()
{
if (_info_rom.constructed())
_info_rom->trigger_update();
}
/***************************
** GUI session interface **
@ -1048,7 +1114,7 @@ class Wm::Gui::Session_component : public Session_object<Gui::Session>,
});
if (result == View_result::OK && view_ptr) {
view_ptr->resizeable(_mode_sigh.valid());
view_ptr->resizeable(_resizeable);
_top_level_views.insert(view_ptr);
}
return result;
@ -1161,45 +1227,35 @@ class Wm::Gui::Session_component : public Session_object<Gui::Session>,
_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;
}
/*
* While resizing the window, return requested window size as
* mode
*/
if (_resize_requested)
return Framebuffer::Mode { .area = _requested_size,
.alpha = real_mode.alpha };
Ram_quota const needed_ram { 8*1024 };
if (!_ram_quota_guard().have_avail(needed_ram)) {
_starved_for_ram = true;
return Info_error::OUT_OF_RAM;
}
/*
* 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 Framebuffer::Mode { .area = v->size(),
.alpha = real_mode.alpha};
try {
Dynamic_rom_session::Content_producer &rom_producer = *this;
_info_rom.construct(*this, _env.ep(), _ram, _env.rm(), rom_producer);
_info_rom->dataspace(); /* eagerly consume RAM and caps */
}
catch (Out_of_ram) { _starved_for_ram = true; }
catch (Out_of_caps) { _starved_for_caps = true; }
/*
* If top-level view has yet been defined, return the real mode.
*/
return real_mode;
}
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);
if (_starved_for_ram || _starved_for_caps) {
if (_starved_for_ram) return Info_error::OUT_OF_RAM;
if (_starved_for_caps) return Info_error::OUT_OF_CAPS;
}
}
return _info_rom->cap();
}
Buffer_result buffer(Framebuffer::Mode mode) override
@ -1238,6 +1294,8 @@ class Wm::Gui::Root : public Rpc_object<Typed_root<Gui::Session> >,
Env &_env;
Session_component::Action &_action;
Attached_rom_dataspace _config { _env, "config" };
Sliced_heap _sliced_heap { _env.ram(), _env.rm() };
@ -1292,11 +1350,12 @@ class Wm::Gui::Root : public Rpc_object<Typed_root<Gui::Session> >,
/**
* Constructor
*/
Root(Env &env, Window_registry &window_registry,
Root(Env &env, Session_component::Action &action,
Window_registry &window_registry,
Pointer::Tracker &pointer_tracker,
Gui::Connection &focus_gui_session)
Gui::Connection &focus_gui_session)
:
_env(env),
_env(env), _action(action),
_pointer_tracker(pointer_tracker),
_window_registry(window_registry),
_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 + /* Command buffer (_command_buffer) */
1 + /* Input signal handler (_input_handler) */
1 + /* Mode signal handler (_mode_handler) */
1; /* Content-view capability */
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:
try {
Session_component &session = *new (_sliced_heap)
Session_component(_env, resources, label, diag,
Session_component(_env, _action, resources, label, diag,
_window_registry,
_pointer_tracker,
_click_handler);
@ -1586,6 +1644,12 @@ class Wm::Gui::Root : public Rpc_object<Typed_root<Gui::Session> >,
if (s->has_win_id(win_id))
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_ */

View File

@ -33,8 +33,6 @@ struct Wm::Layouter_gui_session : Session_object<Gui::Session>
*/
Gui::Connection _mode_sigh_gui;
Signal_context_capability _mode_sigh { };
Attached_ram_dataspace _command_ds;
Layouter_gui_session(Env &env,
@ -63,6 +61,11 @@ struct Wm::Layouter_gui_session : Session_object<Gui::Session>
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
{
return View_result::OK;
@ -94,19 +97,6 @@ struct Wm::Layouter_gui_session : Session_object<Gui::Session>
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; }
void focus(Capability<Gui::Session>) override { }

View File

@ -24,7 +24,7 @@
namespace Wm { class Main; }
struct Wm::Main : Pointer::Tracker
struct Wm::Main : Pointer::Tracker, Gui::Session_component::Action
{
Env &_env;
@ -46,7 +46,28 @@ struct Wm::Main : Pointer::Tracker
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)
{
@ -117,6 +138,8 @@ struct Wm::Main : Pointer::Tracker
_focus_rom.sigh(_focus_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 };
Framebuffer::Mode _nit_mode = _gui.mode();
Framebuffer::Mode _fb_mode {};
Gui::Rect _gui_window()
{
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::Signal_handler<Pdf_view> _nit_mode_handler {
_env.ep(), *this, &Pdf_view::_handle_nit_mode };
Genode::Signal_handler<Pdf_view> _gui_mode_handler {
_env.ep(), *this, &Pdf_view::_handle_gui_mode };
Genode::Signal_handler<Pdf_view> _input_handler {
_env.ep(), *this, &Pdf_view::_handle_input_events };
@ -110,10 +118,10 @@ class Pdf_view
{
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_y = Genode::max(_nit_mode.area.h, _fb_mode.area.h);
unsigned max_x = Genode::max(_win_rect.area.w, _fb_mode.area.w);
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) {
_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());
}
_pdfapp.scrw = _nit_mode.area.w;
_pdfapp.scrh = _nit_mode.area.h;
_pdfapp.scrw = _win_rect.area.w;
_pdfapp.scrh = _win_rect.area.h;
/*
* XXX replace heuristics with a meaningful computation
@ -132,17 +140,17 @@ class Pdf_view
* The magic values are hand-tweaked manually to accommodating the
* use case of showing slides.
*/
_pdfapp.resolution = Genode::min(_nit_mode.area.w/5,
_nit_mode.area.h/4);
_pdfapp.resolution = Genode::min(_win_rect.area.w/5,
_win_rect.area.h/4);
_view.area(_nit_mode.area);
_view.area(_win_rect.area);
_view.front();
}
void _handle_nit_mode()
void _handle_gui_mode()
{
_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 { };
@ -218,7 +226,7 @@ class Pdf_view
*/
Pdf_view(Genode::Env &env) : _env(env)
{
_gui.mode_sigh(_nit_mode_handler);
_gui.info_sigh(_gui_mode_handler);
_gui.input.sigh(_input_handler);
pdfapp_init(&_pdfapp);
@ -291,12 +299,12 @@ void Pdf_view::show()
int const tweaked_y_max = y_max - 2;
/* center vertically if the dst buffer is higher than the image */
if ((unsigned)_pdfapp.image->h < _nit_mode.area.h)
dst_line += dst_line_width*((_nit_mode.area.h - _pdfapp.image->h)/2);
if ((unsigned)_pdfapp.image->h < _win_rect.area.h)
dst_line += dst_line_width*((_win_rect.area.h - _pdfapp.image->h)/2);
/* center horizontally if the dst buffer is wider than the image */
if ((unsigned)_pdfapp.image->w < _nit_mode.area.w)
dst_line += (_nit_mode.area.w - _pdfapp.image->w)/2;
if ((unsigned)_pdfapp.image->w < _win_rect.area.w)
dst_line += (_win_rect.area.w - _pdfapp.image->w)/2;
for (int y = 0; y < tweaked_y_max; y++) {
copy_line_rgba(src_line, dst_line, x_max);
@ -304,7 +312,7 @@ void Pdf_view::show()
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 {
return call<Rpc_input>(); }
Info_result info() override {
return call<Rpc_info>(); }
[[nodiscard]] View_result view(View_id id, View_attr const &attr) override {
return call<Rpc_view>(id, attr); }
@ -53,12 +56,6 @@ struct Gui::Session_client : Rpc_client<Session>
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 {
return call<Rpc_buffer>(mode); }

View File

@ -17,6 +17,7 @@
#include <gui_session/client.h>
#include <framebuffer_session/client.h>
#include <input_session/client.h>
#include <rom_session/client.h>
#include <base/connection.h>
namespace Gui {
@ -52,6 +53,43 @@ class Gui::Connection : private Genode::Connection<Session>
static constexpr Ram_quota _RAM_QUOTA { 96*1024 };
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:
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
*/
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); }
};

View File

@ -19,6 +19,7 @@
#include <os/surface.h>
#include <framebuffer_session/capability.h>
#include <input_session/capability.h>
#include <rom_session/rom_session.h>
namespace Gui {
@ -44,6 +45,8 @@ namespace Gui {
using Rect = Surface_base::Rect;
using Point = Surface_base::Point;
using Area = Surface_base::Area;
struct Undefined { };
}
@ -171,6 +174,14 @@ struct Gui::Session : Genode::Session
*/
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
{
Title title;
@ -233,16 +244,6 @@ struct Gui::Session : Genode::Session
*/
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 };
/**
@ -284,6 +285,7 @@ struct Gui::Session : Genode::Session
GENODE_RPC(Rpc_framebuffer, Framebuffer::Session_capability, framebuffer);
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_child_view, Child_view_result, child_view, View_id, View_id, View_attr const &);
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_execute, void, execute);
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_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_capability, Rpc_release_view_id,
Rpc_command_dataspace, Rpc_execute, Rpc_mode,
Rpc_mode_sigh, Rpc_buffer, Rpc_focus);
Rpc_command_dataspace, Rpc_execute, Rpc_buffer, Rpc_focus);
};
#endif /* _INCLUDE__GUI_SESSION__GUI_SESSION_H_ */

View File

@ -44,14 +44,16 @@ struct Status_bar::Buffer
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.
* The status bar is as wide as nitpicker's screen and has a fixed
* height.
*/
Framebuffer::Mode const _mode { .area = { _nit_mode.area.w, HEIGHT },
Framebuffer::Mode const _mode { .area = { _scr_area.w, HEIGHT },
.alpha = false };
Dataspace_capability _init_buffer()
@ -198,7 +200,7 @@ struct Status_bar::Main
{
/* register signal handlers */
_focus_ds.sigh(_focus_handler);
_gui.mode_sigh(_mode_handler);
_gui.info_sigh(_mode_handler);
/* import initial state */
_handle_mode();

View File

@ -263,6 +263,15 @@ struct Gui_fb::Main : View_updater
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
{
long const _width { 0 };
@ -276,18 +285,18 @@ struct Gui_fb::Main : View_updater
_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)(mode.area.w + _width);
return mode.area.w;
if (_width < 0) return (unsigned)(gui_area.w + _width);
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)(mode.area.h + _height);
return mode.area.h;
if (_height < 0) return (unsigned)(gui_area.h + _height);
return gui_area.h;
}
bool valid() const { return _width != 0 && _height != 0; }
@ -296,9 +305,10 @@ struct Gui_fb::Main : View_updater
Framebuffer::Mode _initial_mode()
{
Gui::Area const gui_area = _gui_window().area;
return {
.area = { _initial_size.width (_gui.mode()),
_initial_size.height(_gui.mode()) },
.area = { _initial_size.width (gui_area),
_initial_size.height(gui_area) },
.alpha = false
};
}
@ -348,7 +358,7 @@ struct Gui_fb::Main : View_updater
/**
* 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";
@ -359,9 +369,9 @@ struct Gui_fb::Main : View_updater
Value const value = config.attribute_value(attr, Value());
if (value == "top_left") return Point(0, 0);
if (value == "top_right") return Point(mode.area.w, 0);
if (value == "bottom_left") return Point(0, mode.area.h);
if (value == "bottom_right") return Point(mode.area.w, mode.area.h);
if (value == "top_right") return Point(gui_area.w, 0);
if (value == "bottom_left") return Point(0, gui_area.h);
if (value == "bottom_right") return Point(gui_area.w, gui_area.h);
warning("unsupported ", attr, " attribute value '", value, "'");
return Point(0, 0);
@ -371,9 +381,9 @@ struct Gui_fb::Main : View_updater
{
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") ||
config.has_attribute("height");
@ -384,15 +394,12 @@ struct Gui_fb::Main : View_updater
_initial_size.set = true;
}
unsigned const gui_width = gui_mode.area.w;
unsigned const gui_height = gui_mode.area.h;
long width = config.attribute_value("width", (long)gui_mode.area.w),
height = config.attribute_value("height", (long)gui_mode.area.h);
long width = config.attribute_value("width", long(gui_area.w)),
height = config.attribute_value("height", long(gui_area.h));
if (!_initial_size.set && _initial_size.valid()) {
width = _initial_size.width (gui_mode);
height = _initial_size.height(gui_mode);
width = _initial_size.width (gui_area);
height = _initial_size.height(gui_area);
_initial_size.set = true;
} else {
@ -401,8 +408,8 @@ struct Gui_fb::Main : View_updater
* If configured width / height values are negative, the effective
* width / height is deduced from the screen size.
*/
if (width < 0) width = gui_width + width;
if (height < 0) height = gui_height + height;
if (width < 0) width = gui_area.w + width;
if (height < 0) height = gui_area.h + height;
}
_fb_session.size(Area((unsigned)width, (unsigned)height));
@ -466,7 +473,7 @@ struct Gui_fb::Main : View_updater
* Register signal handlers
*/
_config_rom.sigh(_config_update_handler);
_gui.mode_sigh(_mode_update_handler);
_gui.info_sigh(_mode_update_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:
Env &_env;
@ -185,6 +176,19 @@ class Nitpicker::Capture_session : public Session_object<Capture::Session>
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 **

View File

@ -99,7 +99,7 @@ class Nitpicker::Domain_registry
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 */
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 { .at = _offset,
.area = { .w = aligned(screen_area.w, _area.x),
.h = aligned(screen_area.h, _area.y) } };
return { .at = _offset + panorama.at,
.area = { .w = aligned(panorama.w(), _area.x),
.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)
{
/* 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();
}
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 <os/session_policy.h>
#include <os/reporter.h>
#include <os/dynamic_rom_session.h>
#include <gui_session/gui_session.h>
/* local includes */
@ -42,8 +43,19 @@ namespace Nitpicker {
class Nitpicker::Gui_session : public Session_object<Gui::Session>,
public View_owner,
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:
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 &operator = (Gui_session const &);
Env &_env;
Env &_env;
Action &_action;
Constrained_ram_allocator _ram;
@ -110,7 +123,7 @@ class Nitpicker::Gui_session : public Session_object<Gui::Session>,
Focus_updater &_focus_updater;
Hover_updater &_hover_updater;
Signal_context_capability _mode_sigh { };
Constructible<Dynamic_rom_session> _info_rom { };
View &_pointer_origin;
@ -183,9 +196,15 @@ class Nitpicker::Gui_session : public Session_object<Gui::Session>,
[&] /* ID does not exist */ { return missing_fn(); });
}
/**
* Dynamic_rom_session::Xml_producer interface
*/
void produce_xml(Xml_generator &) override;
public:
Gui_session(Env &env,
Action &action,
Resources const &resources,
Label const &label,
Diag const &diag,
@ -198,7 +217,8 @@ class Nitpicker::Gui_session : public Session_object<Gui::Session>,
Reporter &focus_reporter)
:
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()),
_session_alloc(_ram, env.rm()),
_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; }
/**
* 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; }
/**
@ -344,8 +356,8 @@ class Nitpicker::Gui_session : public Session_object<Gui::Session>,
*/
void notify_mode_change()
{
if (_mode_sigh.valid())
Signal_transmitter(_mode_sigh).submit();
if (_info_rom.constructed())
_info_rom->trigger_update();
}
/**
@ -375,6 +387,30 @@ class Nitpicker::Gui_session : public Session_object<Gui::Session>,
Input::Session_capability input() override {
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;
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;
Framebuffer::Mode mode() override;
void mode_sigh(Signal_context_capability sigh) override { _mode_sigh = sigh; }
Buffer_result buffer(Framebuffer::Mode) override;
void focus(Capability<Gui::Session>) override;

View File

@ -90,6 +90,7 @@ class Nitpicker::Gui_root : public Root_component<Gui_session>
private:
Env &_env;
Gui_session::Action &_action;
Attached_rom_dataspace const &_config;
Session_list &_session_list;
Domain_registry const &_domain_registry;
@ -118,7 +119,7 @@ class Nitpicker::Gui_root : public Root_component<Gui_session>
resources.cap_quota.value -= 2;
Gui_session *session = new (md_alloc())
Gui_session(_env,
Gui_session(_env, _action,
resources, label,
session_diag_from_args(args), _view_stack,
_focus_updater, _hover_updater, _pointer_origin,
@ -170,6 +171,7 @@ class Nitpicker::Gui_root : public Root_component<Gui_session>
* Constructor
*/
Gui_root(Env &env,
Gui_session::Action &action,
Attached_rom_dataspace const &config,
Session_list &session_list,
Domain_registry const &domain_registry,
@ -184,7 +186,7 @@ class Nitpicker::Gui_root : public Root_component<Gui_session>
Hover_updater &hover_updater)
:
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),
_view_stack(view_stack), _user_state(user_state),
_pointer_origin(pointer_origin),
@ -346,14 +348,11 @@ class Nitpicker::Capture_root : public Root_component<Capture_session>
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) {
xml.node("capture", [&] {
xml.attribute("name", capture.label());
Capture_session::gen_attr(xml, capture.bounding_box()); }); });
xml.node("capture", [&] { capture.gen_capture_attr(xml); }); });
}
};
@ -411,7 +410,8 @@ struct Nitpicker::Main : Focus_updater, Hover_updater,
Capture_session::Handler,
Event_session::Handler,
Capture_root::Action,
User_state::Action
User_state::Action,
Gui_session::Action
{
Env &_env;
@ -613,11 +613,19 @@ struct Nitpicker::Main : Focus_updater, Hover_updater,
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,
_builtin_background, _sliced_heap,
_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 };
Event_root _event_root { _env, _sliced_heap, *this };
@ -1041,7 +1049,7 @@ void Nitpicker::Main::_report_displays()
if (_fb_screen.constructed())
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()
{
Framebuffer::Mode mode = _device.resize();
Gui::Area const mode = _device.resize();
Display_info_response dir { _desc_range(1) };
memset((void*)dir.base(), 0, Display_info_response::SIZE);
dir.write<Control_header::Type>(Control_header::Type::OK_DISPLAY_INFO);
dir.write<Display_info_response::X>(0);
dir.write<Display_info_response::Y>(0);
dir.write<Display_info_response::Width>(mode.area.w);
dir.write<Display_info_response::Height>(mode.area.h);
dir.write<Display_info_response::Width>(mode.w);
dir.write<Display_info_response::Height>(mode.h);
dir.write<Display_info_response::Enabled>(1);
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 y = rf.read<Resource_flush::Y>();
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>(),
_device._fb_mode.area.h - y);
_device._gui_win.area.h - y);
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);
void * dst =
(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_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);
_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;
Cpu::Signal_handler<Virtio_gpu_device> _handler;
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 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),
_handler(cpu, env.ep(), *this, &Virtio_gpu_device::_mode_change)
{
_gui.mode_sigh(_handler);
_gui.info_sigh(_handler);
}
void buffer_notification()
@ -454,21 +462,21 @@ class Vmm::Virtio_gpu_device : public Virtio_device<Virtio_gpu_queue, 2>
_buffer_notification();
}
Framebuffer::Mode resize()
Gui::Area resize()
{
_fb_ds.destruct();
_fb_mode = _gui.mode();
_gui.buffer(_fb_mode);
_gui_win = _request_gui_window();
_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());
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.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);
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();
}
@ -340,7 +346,7 @@ void GenodeConsole::init_backends(IKeyboard * gKeyboard, IMouse * gMouse)
HRESULT rc = i_getDisplay()->QueryFramebuffer(0, &pFramebuffer);
Assert(SUCCEEDED(rc) && pFramebuffer);
_gui.mode_sigh(_mode_change_signal_dispatcher);
_gui.info_sigh(_mode_change_signal_dispatcher);
_handle_mode_change();
}

View File

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

View File

@ -33,13 +33,13 @@ class Genodefb :
Genode::Env &_env;
Gui::Connection &_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
* framebuffer mode.
*/
Fb_Genode::Mode _virtual_fb_mode;
Gui::Area _virtual_fb_mode;
void *_attach()
{
@ -62,23 +62,23 @@ class Genodefb :
{
if (!_fb_base) return;
size_t const max_h = Genode::min(_fb_mode.area.h, _virtual_fb_mode.area.h);
size_t const num_pixels = _fb_mode.area.w * max_h;
size_t const max_h = Genode::min(_gui_win.area.h, _virtual_fb_mode.h);
size_t const num_pixels = _gui_win.area.w * max_h;
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()
{
_gui.buffer(_fb_mode);
_view.area(_fb_mode.area);
_gui.buffer({ .area = _gui_win.area, .alpha = false });
_view.area(_gui_win.area);
}
Fb_Genode::Mode _initial_setup()
Gui::Area _initial_setup()
{
_adjust_buffer();
_view.front();
return _fb_mode;
return _gui_win.area;
}
public:
@ -98,14 +98,14 @@ class Genodefb :
virtual ~Genodefb() { }
int w() const { return _fb_mode.area.w; }
int h() const { return _fb_mode.area.h; }
int w() const { return _gui_win.area.w; }
int h() const { return _gui_win.area.h; }
void update_mode(Fb_Genode::Mode mode)
void update_mode(Gui::Rect gui_win)
{
Lock();
_fb_mode = mode;
_gui_win = gui_win;
if (_fb_base)
_env.rm().detach(Genode::addr_t(_fb_base));
@ -137,32 +137,32 @@ class Genodefb :
/* save the new bitmap reference */
_display->QuerySourceBitmap(screen, _display_bitmap.asOutParam());
bool const ok = (w <= (ULONG)_fb_mode.area.w) &&
(h <= (ULONG)_fb_mode.area.h);
bool const ok = (w <= (ULONG)_gui_win.area.w) &&
(h <= (ULONG)_gui_win.area.h);
bool const changed = (w != (ULONG)_virtual_fb_mode.area.w) ||
(h != (ULONG)_virtual_fb_mode.area.h);
bool const changed = (w != (ULONG)_virtual_fb_mode.w) ||
(h != (ULONG)_virtual_fb_mode.h);
if (ok && changed) {
Genode::log("fb resize : [", screen, "] ",
_virtual_fb_mode.area, " -> ",
_virtual_fb_mode, " -> ",
w, "x", h,
" (host: ", _fb_mode.area, ")");
" (host: ", _gui_win.area, ")");
if ((w < (ULONG)_fb_mode.area.w) ||
(h < (ULONG)_fb_mode.area.h)) {
if ((w < (ULONG)_gui_win.area.w) ||
(h < (ULONG)_gui_win.area.h)) {
/* clear the old content around the new, smaller area. */
_clear_screen();
}
_virtual_fb_mode = Fb_Genode::Mode { .area = { w, h } };
_virtual_fb_mode = { w, h };
result = S_OK;
} else if (changed) {
Genode::log("fb resize : [", screen, "] ",
_virtual_fb_mode.area, " -> ",
_virtual_fb_mode, " -> ",
w, "x", h, " ignored"
" (host: ", _fb_mode.area, ")");
" (host: ", _gui_win.area, ")");
}
Unlock();
@ -215,8 +215,8 @@ class Genodefb :
&ulBytesPerLine,
&bitmapFormat);
Gui::Area const area_fb = Gui::Area(_fb_mode.area.w,
_fb_mode.area.h);
Gui::Area const area_fb = Gui::Area(_gui_win.area.w,
_gui_win.area.h);
Gui::Area const area_vm = Gui::Area(ulWidth, ulHeight);
using namespace Genode;
@ -253,7 +253,7 @@ class Genodefb :
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);
using namespace Genode;
@ -292,8 +292,8 @@ class Genodefb :
if (!supported)
return E_POINTER;
*supported = ((width <= (ULONG)_fb_mode.area.w) &&
(height <= (ULONG)_fb_mode.area.h));
*supported = ((width <= (ULONG)_gui_win.area.w) &&
(height <= (ULONG)_gui_win.area.h));
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.input.sigh(_input_handler);
gui.mode_sigh(_fb_mode_handler);
gui.info_sigh(_fb_mode_handler);
Genodefb *fb = new Genodefb(_env, gui, _idisplay);
@ -438,7 +438,13 @@ void Main::_handle_fb_mode()
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)) {
/* interpret a size of 0x0 as indication to quit VirtualBox */