sculpt: use one menu_view for all dialogs

This patch replaces the former use of one menu-view component per dialog
by a single menu view presenting all dialogs. This change reduces the
runtime config by about 20%, improves the boot time, and lowers RAM and
CPU usage at runtime.

Issue #5170
This commit is contained in:
Norman Feske 2024-04-03 19:10:26 +02:00 committed by Christian Helmuth
parent 9ce7c72c7c
commit ac2d708205
6 changed files with 230 additions and 232 deletions

View File

@ -119,38 +119,25 @@
<policy label="manager -> window_list" report="wm -> window_list"/>
<policy label="manager -> decorator_margins" report="decorator -> decorator_margins"/>
<policy label="nitpicker -> focus" report="manager -> focus"/>
<policy label="runtime -> leitzentrale -> diag_view -> dialog"
<policy label="runtime -> leitzentrale -> diag_dialog"
report="manager -> diag_dialog"/>
<policy label="runtime -> leitzentrale -> network_view -> dialog"
<policy label="runtime -> leitzentrale -> network_dialog"
report="manager -> network_dialog"/>
<policy label="runtime -> leitzentrale -> settings_view -> dialog"
<policy label="runtime -> leitzentrale -> settings_dialog"
report="manager -> settings_dialog"/>
<policy label="runtime -> leitzentrale -> system_view -> dialog"
<policy label="runtime -> leitzentrale -> system_dialog"
report="manager -> system_dialog"/>
<policy label="runtime -> leitzentrale -> file_browser_view -> dialog"
<policy label="runtime -> leitzentrale -> file_browser_dialog"
report="manager -> file_browser_dialog"/>
<policy label="runtime -> leitzentrale -> popup_view -> dialog"
<policy label="runtime -> leitzentrale -> popup_dialog"
report="manager -> popup_dialog"/>
<policy label="runtime -> leitzentrale -> panel_view -> dialog"
<policy label="runtime -> leitzentrale -> panel_dialog"
report="manager -> panel_dialog"/>
<policy label="runtime -> leitzentrale -> runtime_view -> dialog"
<policy label="runtime -> leitzentrale -> runtime_dialog"
report="manager -> runtime_dialog"/>
<policy label="manager -> diag_view_hover"
report="runtime -> leitzentrale -> diag_view -> hover"/>
<policy label="manager -> network_view_hover"
report="runtime -> leitzentrale -> network_view -> hover"/>
<policy label="manager -> settings_view_hover"
report="runtime -> leitzentrale -> settings_view -> hover"/>
<policy label="manager -> system_view_hover"
report="runtime -> leitzentrale -> system_view -> hover"/>
<policy label="manager -> file_browser_view_hover"
report="runtime -> leitzentrale -> file_browser_view -> hover"/>
<policy label="manager -> runtime_view_hover"
<policy label="manager -> hover"
report="runtime -> leitzentrale -> runtime_view -> hover"/>
<policy label="manager -> panel_view_hover"
report="runtime -> leitzentrale -> panel_view -> hover"/>
<policy label="manager -> popup_view_hover"
report="runtime -> leitzentrale -> popup_view -> hover"/>
</config>
</start>
@ -191,14 +178,14 @@
<dir name="dev"> <log/> </dir>
</vfs>
<policy label="log" decoration="yes" motion="20"/>
<policy label="runtime -> leitzentrale -> settings_view" decoration="no" motion="20"/>
<policy label="runtime -> leitzentrale -> system_view" decoration="no" motion="20"/>
<policy label="runtime -> leitzentrale -> file_browser_view" decoration="no" motion="30"/>
<policy label="runtime -> leitzentrale -> network_view" decoration="no" motion="20"/>
<policy label="runtime -> leitzentrale -> runtime_view" decoration="no" motion="30"/>
<policy label="runtime -> leitzentrale -> diag_view" decoration="no" motion="30"/>
<policy label="runtime -> leitzentrale -> popup_view" decoration="no" motion="20"/>
<policy label="runtime -> leitzentrale -> panel_view" decoration="no" motion="20"/>
<policy label="runtime -> leitzentrale -> settings_dialog" decoration="no" motion="20"/>
<policy label="runtime -> leitzentrale -> system_dialog" decoration="no" motion="20"/>
<policy label="runtime -> leitzentrale -> file_browser_dialog" decoration="no" motion="30"/>
<policy label="runtime -> leitzentrale -> network_dialog" decoration="no" motion="20"/>
<policy label="runtime -> leitzentrale -> runtime_dialog" decoration="no" motion="30"/>
<policy label="runtime -> leitzentrale -> diag_dialog" decoration="no" motion="30"/>
<policy label="runtime -> leitzentrale -> popup_dialog" decoration="no" motion="20"/>
<policy label="runtime -> leitzentrale -> panel_dialog" decoration="no" motion="20"/>
<policy label_prefix="logo" decoration="no"/>
<default-policy/>
</config>
@ -257,7 +244,7 @@
<service name="ROM" label_prefix="report ->"> <parent/> </service>
<service name="ROM" label="nitpicker_focus"> <parent/> </service>
<service name="ROM" label="nitpicker_hover"> <parent/> </service>
<service name="ROM" label_suffix="_hover"> <child name="report_rom"/> </service>
<service name="ROM" label="hover"> <child name="report_rom"/> </service>
<service name="ROM" label="window_list"> <child name="report_rom"/> </service>
<service name="ROM" label="decorator_margins"> <child name="report_rom"/> </service>
<service name="Gui"> <parent/> </service>

View File

@ -45,10 +45,10 @@
<policy label="decorator -> pointer" report="wm -> pointer"/>
<policy label="manager -> window_list" report="wm -> window_list"/>
<policy label="manager -> decorator_margins" report="decorator -> decorator_margins"/>
<policy label="runtime -> leitzentrale -> main_view -> dialog"
<policy label="runtime -> leitzentrale -> main_dialog"
report="manager -> main_dialog"/>
<policy label="manager -> main_view_hover"
report="runtime -> leitzentrale -> main_view -> hover"/>
<policy label="manager -> hover"
report="runtime -> leitzentrale -> runtime_view -> hover"/>
</config>
</start>
@ -147,7 +147,7 @@
<service name="ROM" label_prefix="report ->"> <parent/> </service>
<service name="ROM" label="nitpicker_focus"> <parent/> </service>
<service name="ROM" label="nitpicker_hover"> <parent/> </service>
<service name="ROM" label_suffix="_hover"> <child name="report_rom"/> </service>
<service name="ROM" label="hover"> <child name="report_rom"/> </service>
<service name="ROM" label="window_list"> <child name="report_rom"/> </service>
<service name="ROM" label="decorator_margins"> <child name="report_rom"/> </service>
<service name="ROM" label="clicked"> <child name="report_rom"/> </service>

View File

@ -1173,8 +1173,7 @@ struct Sculpt::Main : Input_event_handler,
Dialog::Distant_runtime::View
_main_view { _dialog_runtime, _main_dialog,
{ .opaque = true,
.background = _background_color,
.initial_ram = { 12*1024*1024 } } };
.background = _background_color } };
void _click(Clicked_at const &at)
{
@ -2049,7 +2048,7 @@ void Sculpt::Main::_update_window_layout(Xml_node const &decorator_margins,
Decorator_margins const margins { decorator_margins };
using Label = String<128>;
Label const main_view_label ("runtime -> leitzentrale -> main_view");
Label const main_view_label ("runtime -> leitzentrale -> main_dialog");
Label const touch_keyboard_label("runtime -> leitzentrale -> touch_keyboard");
/*

View File

@ -50,42 +50,16 @@ static bool clack(Input::Event const &event)
bool Distant_runtime::apply_runtime_state(Xml_node const &state)
{
using Name = Top_level_dialog::Name;
/* the dialog name is the start name with the "_view" suffix removed */
auto with_dialog_name = [] (Start_name const &name, auto const &fn)
{
if (name.length() > 6) {
size_t const dialog_name_len = name.length() - 6;
char const * const view_suffix_ptr = name.string() + dialog_name_len;
if (strcmp(view_suffix_ptr, "_view") == 0)
fn(Name(Cstring(name.string(), dialog_name_len)));
}
};
bool reconfiguration_needed = false;
state.for_each_sub_node("child", [&] (Xml_node const &child) {
Start_name const start_name = child.attribute_value("name", Start_name());
with_dialog_name(start_name, [&] (Name const &name) {
_views.with_element(name,
[&] (View &view) {
if (view._apply_child_state_report(child))
reconfiguration_needed = true; },
[&] /* no view named after this child */ { });
});
});
if (_apply_child_state_report(child))
reconfiguration_needed = true;
});
return reconfiguration_needed;
}
void Distant_runtime::gen_start_nodes(Xml_generator &xml) const
{
_views.for_each([&] (View const &view) {
view._gen_start_node(xml); });
}
void Distant_runtime::route_input_event(Event::Seq_number seq_number, Input::Event const &event)
{
_global_seq_number = seq_number;
@ -109,19 +83,36 @@ void Distant_runtime::route_input_event(Event::Seq_number seq_number, Input::Eve
}
void Distant_runtime::_handle_hover(Xml_node const &hover)
{
using Name = Top_level_dialog::Name;
Name const orig_hovered_dialog = _hovered_dialog;
_hover_seq_number = { hover.attribute_value("seq_number", 0U) };
hover.with_sub_node("dialog",
[&] (Xml_node const &dialog) {
_hovered_dialog = dialog.attribute_value("name", Name()); },
[&] { _hovered_dialog = { }; });
if (orig_hovered_dialog.valid() && orig_hovered_dialog != _hovered_dialog)
_views.with_element(orig_hovered_dialog,
[&] (View &view) { view._leave(); },
[&] { });
if (_hovered_dialog.valid())
_views.with_element(_hovered_dialog,
[&] (View &view) { view._handle_hover(); },
[&] { });
}
void Distant_runtime::_try_handle_click_and_clack()
{
auto with_hovered_view = [&] (Event::Seq_number seq_number, auto const &fn)
{
/* find name of dialog hovered with matching 'seq_number' */
Top_level_dialog::Name name { };
_views.for_each([&] (View const &view) {
if (seq_number == view._hover_seq_number)
name = view._dialog.name; });
/* apply 'fn' with (non-const) view as argument */
if (name.valid())
_views.with_element(name,
if (_hover_seq_number == seq_number)
_views.with_element(_hovered_dialog,
[&] (View &view) { fn(view); },
[&] { });
};
@ -167,7 +158,7 @@ void Distant_runtime::_try_handle_click_and_clack()
}
void Distant_runtime::View::_gen_start_node(Xml_generator &xml) const
void Distant_runtime::gen_start_nodes(Xml_generator &xml) const
{
xml.node("start", [&] {
@ -187,12 +178,6 @@ void Distant_runtime::View::_gen_start_node(Xml_generator &xml) const
xml.node("config", [&] {
if (min_width) xml.attribute("width", min_width);
if (min_height) xml.attribute("height", min_height);
if (_opaque) xml.attribute("opaque", "yes");
xml.attribute("background", String<20>(_background));
xml.node("report", [&] {
xml.attribute("hover", "yes"); });
@ -213,9 +198,10 @@ void Distant_runtime::View::_gen_start_node(Xml_generator &xml) const
});
});
});
});
using Label = Session_label::String;
_views.for_each([&] (View const &view) {
view._gen_menu_view_dialog(xml); });
});
xml.node("route", [&] {
gen_parent_rom_route(xml, "menu_view");
@ -231,21 +217,13 @@ void Distant_runtime::View::_gen_start_node(Xml_generator &xml) const
gen_parent_route<Log_session> (xml);
gen_parent_route<Timer::Session> (xml);
gen_service_node<Gui::Session>(xml, [&] {
xml.node("parent", [&] {
xml.attribute("label", Label("leitzentrale -> ", _start_name)); }); });
gen_service_node<Rom_session>(xml, [&] {
xml.attribute("label", "dialog");
xml.node("parent", [&] {
xml.attribute("label", Label("leitzentrale -> ", _start_name, " -> dialog"));
});
});
_views.for_each([&] (View const &view) {
view._gen_menu_view_routes(xml); });
gen_service_node<Report::Session>(xml, [&] {
xml.attribute("label", "hover");
xml.node("parent", [&] {
xml.attribute("label", Label("leitzentrale -> ", _start_name, " -> hover"));
xml.attribute("label", "leitzentrale -> runtime_view -> hover");
});
});
@ -256,3 +234,33 @@ void Distant_runtime::View::_gen_start_node(Xml_generator &xml) const
});
});
}
void Distant_runtime::View::_gen_menu_view_dialog(Xml_generator &xml) const
{
xml.node("dialog", [&] {
xml.attribute("name", name);
if (min_width) xml.attribute("width", min_width);
if (min_height) xml.attribute("height", min_height);
if (_opaque) xml.attribute("opaque", "yes");
xml.attribute("background", String<20>(_background));
});
}
void Distant_runtime::View::_gen_menu_view_routes(Xml_generator &xml) const
{
Session_label::String const label { "leitzentrale -> ", name, "_dialog" };
gen_service_node<Rom_session>(xml, [&] {
xml.attribute("label", name);
xml.node("parent", [&] {
xml.attribute("label", label); }); });
gen_service_node<Gui::Session>(xml, [&] {
xml.attribute("label", name);
xml.node("parent", [&] {
xml.attribute("label", label); }); });
}

View File

@ -41,13 +41,33 @@ class Dialog::Distant_runtime : Noncopyable
private:
using Start_name = Session_label::String;
Env &_env;
using Views = Dictionary<View, Top_level_dialog::Name>;
Views _views { };
Event::Seq_number _global_seq_number { 1 };
Views _views { };
Start_name const _start_name { "runtime_view" };
Ram_quota const _initial_ram { 4*1024*1024 };
Cap_quota const _initial_caps { 200 };
Ram_quota _ram = _initial_ram;
Cap_quota _caps = _initial_caps;
unsigned _version = 0;
Top_level_dialog::Name _hovered_dialog { };
Sculpt::Rom_handler<Distant_runtime> _hover_rom {
_env, "hover", *this, &Distant_runtime::_handle_hover };
void _handle_hover(Xml_node const &);
Event::Seq_number _hover_seq_number { };
/* sequence numbers to correlate hover info with click/clack events */
Constructible<Event::Seq_number> _click_seq_number { };
@ -67,122 +87,6 @@ class Dialog::Distant_runtime : Noncopyable
void _try_handle_click_and_clack();
public:
Distant_runtime(Env &env) : _env(env) { }
/**
* Route input event to the 'Top_level_dialog' click/clack interfaces
*/
void route_input_event(Event::Seq_number, Input::Event const &);
/**
* Respond to runtime-init state changes
*
* \return true if the runtime-init configuration needs to be updated
*/
bool apply_runtime_state(Xml_node const &);
void gen_start_nodes(Xml_generator &) const;
};
class Dialog::Distant_runtime::View : private Views::Element
{
private:
/* needed for privately inheriting 'Views::Element' */
friend class Dictionary<View, Top_level_dialog::Name>;
friend class Avl_node<View>;
friend class Avl_tree<View>;
friend class Distant_runtime;
using Start_name = Session_label::String;
Env &_env;
Distant_runtime &_runtime;
Top_level_dialog &_dialog;
Start_name const _start_name { _dialog.name, "_view" };
Ram_quota const _initial_ram { 4*1024*1024 };
Cap_quota const _initial_caps { 200 };
bool const _opaque;
Color const _background;
Ram_quota _ram = _initial_ram;
Cap_quota _caps = _initial_caps;
unsigned _version = 0;
Expanding_reporter _dialog_reporter {
_env, "dialog", { _dialog.name, "_dialog" } };
Sculpt::Rom_handler<View> _hover_rom {
_env, Session_label::String(_dialog.name, "_view_hover").string(),
*this, &View::_handle_hover };
bool _dialog_hovered = false; /* used to cut hover feedback loop */
Event::Seq_number _hover_seq_number { };
void _with_dialog_hover(auto const &fn) const
{
bool done = false;
_hover_rom.with_xml([&] (Xml_node const &hover) {
hover.with_optional_sub_node("dialog", [&] (Xml_node const &dialog) {
fn(dialog);
done = true; }); });
if (!done)
fn(Xml_node("<empty/>"));
}
void _handle_hover(Xml_node const &hover)
{
bool const orig_dialog_hovered = _dialog_hovered;
_hover_seq_number = { hover.attribute_value("seq_number", 0U) };
_dialog_hovered = (hover.num_sub_nodes() > 0);
if (_runtime._dragged()) {
_with_dialog_hover([&] (Xml_node const &hover) {
Dragged_at at(*_runtime._click_seq_number, hover);
_dialog.drag(at);
});
}
_runtime._try_handle_click_and_clack();
if (orig_dialog_hovered != _dialog_hovered || _dialog_hovered)
_generate_dialog();
}
Signal_handler<View> _refresh_handler { _env.ep(), *this, &View::_generate_dialog };
void _generate_dialog()
{
_dialog_reporter.generate([&] (Xml_generator &xml) {
_with_dialog_hover([&] (Xml_node const &hover) {
Event::Dragged const dragged { _runtime._dragged() };
bool const supply_hover = _runtime._hover_observable_without_click
|| dragged.value;
static Xml_node omitted_hover("<hover/>");
At const at { _runtime._global_seq_number,
supply_hover ? hover : omitted_hover };
Scope<> top_level_scope(xml, at, dragged, { _dialog.name });
_dialog.view(top_level_scope);
});
});
}
/**
* Adapt runtime state information to the child
*
@ -220,7 +124,111 @@ class Dialog::Distant_runtime::View : private Views::Element
return result;
}
void _gen_start_node(Xml_generator &) const;
public:
Distant_runtime(Env &env) : _env(env) { }
/**
* Route input event to the 'Top_level_dialog' click/clack interfaces
*/
void route_input_event(Event::Seq_number, Input::Event const &);
/**
* Respond to runtime-init state changes
*
* \return true if the runtime-init configuration needs to be updated
*/
bool apply_runtime_state(Xml_node const &);
void gen_start_nodes(Xml_generator &) const;
};
class Dialog::Distant_runtime::View : private Views::Element
{
private:
/* needed for privately inheriting 'Views::Element' */
friend class Dictionary<View, Top_level_dialog::Name>;
friend class Avl_node<View>;
friend class Avl_tree<View>;
friend class Distant_runtime;
Env &_env;
Distant_runtime &_runtime;
Top_level_dialog &_dialog;
Expanding_reporter _dialog_reporter {
_env, "dialog", { _dialog.name, "_dialog" } };
bool _dialog_hovered = false; /* used to cut hover feedback loop */
Signal_handler<View> _refresh_handler { _env.ep(), *this, &View::_generate_dialog };
void _generate_dialog()
{
_dialog_reporter.generate([&] (Xml_generator &xml) {
_with_dialog_hover([&] (Xml_node const &hover) {
Event::Dragged const dragged { _runtime._dragged() };
bool const supply_hover = _runtime._hover_observable_without_click
|| dragged.value;
static Xml_node omitted_hover("<hover/>");
At const at { _runtime._global_seq_number,
supply_hover ? hover : omitted_hover };
Scope<> top_level_scope(xml, at, dragged, { _dialog.name });
_dialog.view(top_level_scope);
});
});
}
void _with_dialog_hover(auto const &fn) const
{
bool done = false;
_runtime._hover_rom.with_xml([&] (Xml_node const &hover) {
hover.with_optional_sub_node("dialog", [&] (Xml_node const &dialog) {
if (dialog.attribute_value("name", Top_level_dialog::Name()) == name) {
fn(dialog);
done = true;
}
});
});
if (!done)
fn(Xml_node("<empty/>"));
}
void _handle_hover()
{
_dialog_hovered = true;
if (_runtime._dragged()) {
_with_dialog_hover([&] (Xml_node const &hover) {
Dragged_at at(*_runtime._click_seq_number, hover);
_dialog.drag(at);
});
}
_runtime._try_handle_click_and_clack();
_generate_dialog();
}
void _leave()
{
_dialog_hovered = false;
}
bool const _opaque;
Color const _background;
void _gen_menu_view_dialog(Xml_generator &) const;
void _gen_menu_view_routes(Xml_generator &) const;
public:
@ -228,17 +236,15 @@ class Dialog::Distant_runtime::View : private Views::Element
struct Attr
{
bool opaque;
Color background;
Ram_quota initial_ram;
bool opaque;
Color background;
};
View(Distant_runtime &runtime, Top_level_dialog &dialog, Attr attr)
:
Views::Element(runtime._views, dialog.name),
_env(runtime._env), _runtime(runtime), _dialog(dialog),
_initial_ram(attr.initial_ram), _opaque(attr.opaque),
_background(attr.background)
_opaque(attr.opaque), _background(attr.background)
{
_refresh_handler.local_submit();
}
@ -246,8 +252,7 @@ class Dialog::Distant_runtime::View : private Views::Element
View(Distant_runtime &runtime, Top_level_dialog &dialog)
:
View(runtime, dialog, Attr { .opaque = false,
.background = { },
.initial_ram = { 4*1024*1024 } })
.background = { } })
{ }
void refresh() { _refresh_handler.local_submit(); }

View File

@ -1475,8 +1475,7 @@ struct Sculpt::Main : Input_event_handler,
Dialog::Distant_runtime::View
_graph_view { _dialog_runtime, _graph_dialog,
{ .opaque = false,
.background = { },
.initial_ram = { 8*1024*1024 } } };
.background = { } } };
Main(Env &env) : _env(env)
{
@ -1538,14 +1537,14 @@ void Sculpt::Main::_update_window_layout(Xml_node const &decorator_margins,
typedef String<128> Label;
Label const
inspect_label ("runtime -> leitzentrale -> inspect"),
runtime_view_label ("runtime -> leitzentrale -> runtime_view"),
panel_view_label ("runtime -> leitzentrale -> panel_view"),
diag_view_label ("runtime -> leitzentrale -> diag_view"),
popup_view_label ("runtime -> leitzentrale -> popup_view"),
system_view_label ("runtime -> leitzentrale -> system_view"),
settings_view_label ("runtime -> leitzentrale -> settings_view"),
network_view_label ("runtime -> leitzentrale -> network_view"),
file_browser_view_label("runtime -> leitzentrale -> file_browser_view"),
runtime_view_label ("runtime -> leitzentrale -> runtime_dialog"),
panel_view_label ("runtime -> leitzentrale -> panel_dialog"),
diag_view_label ("runtime -> leitzentrale -> diag_dialog"),
popup_view_label ("runtime -> leitzentrale -> popup_dialog"),
system_view_label ("runtime -> leitzentrale -> system_dialog"),
settings_view_label ("runtime -> leitzentrale -> settings_dialog"),
network_view_label ("runtime -> leitzentrale -> network_dialog"),
file_browser_view_label("runtime -> leitzentrale -> file_browser_dialog"),
editor_view_label ("runtime -> leitzentrale -> editor"),
logo_label ("logo");