From ac2d70820539045000cf4454d684fab2a9faf5bd Mon Sep 17 00:00:00 2001 From: Norman Feske Date: Wed, 3 Apr 2024 19:10:26 +0200 Subject: [PATCH] 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 --- repos/gems/sculpt/leitzentrale/default | 51 ++-- repos/gems/sculpt/leitzentrale/phone | 8 +- repos/gems/src/app/phone_manager/main.cc | 5 +- .../sculpt_manager/dialog/distant_runtime.cc | 124 +++++---- .../sculpt_manager/dialog/distant_runtime.h | 255 +++++++++--------- repos/gems/src/app/sculpt_manager/main.cc | 19 +- 6 files changed, 230 insertions(+), 232 deletions(-) diff --git a/repos/gems/sculpt/leitzentrale/default b/repos/gems/sculpt/leitzentrale/default index efeecf3142..7cb08bb673 100644 --- a/repos/gems/sculpt/leitzentrale/default +++ b/repos/gems/sculpt/leitzentrale/default @@ -119,38 +119,25 @@ - - - - - - - - - - - - - - - - @@ -191,14 +178,14 @@ - - - - - - - - + + + + + + + + @@ -257,7 +244,7 @@ - + diff --git a/repos/gems/sculpt/leitzentrale/phone b/repos/gems/sculpt/leitzentrale/phone index 04759365e9..fb0f25eb2f 100644 --- a/repos/gems/sculpt/leitzentrale/phone +++ b/repos/gems/sculpt/leitzentrale/phone @@ -45,10 +45,10 @@ - - + @@ -147,7 +147,7 @@ - + diff --git a/repos/gems/src/app/phone_manager/main.cc b/repos/gems/src/app/phone_manager/main.cc index 8725fa6846..c8cfc7242c 100644 --- a/repos/gems/src/app/phone_manager/main.cc +++ b/repos/gems/src/app/phone_manager/main.cc @@ -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"); /* diff --git a/repos/gems/src/app/sculpt_manager/dialog/distant_runtime.cc b/repos/gems/src/app/sculpt_manager/dialog/distant_runtime.cc index a5d5f74256..375eae9d07 100644 --- a/repos/gems/src/app/sculpt_manager/dialog/distant_runtime.cc +++ b/repos/gems/src/app/sculpt_manager/dialog/distant_runtime.cc @@ -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 (xml); gen_parent_route (xml); - gen_service_node(xml, [&] { - xml.node("parent", [&] { - xml.attribute("label", Label("leitzentrale -> ", _start_name)); }); }); - - gen_service_node(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(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(xml, [&] { + xml.attribute("label", name); + xml.node("parent", [&] { + xml.attribute("label", label); }); }); + + gen_service_node(xml, [&] { + xml.attribute("label", name); + xml.node("parent", [&] { + xml.attribute("label", label); }); }); +} diff --git a/repos/gems/src/app/sculpt_manager/dialog/distant_runtime.h b/repos/gems/src/app/sculpt_manager/dialog/distant_runtime.h index dc7e0181e9..2d9b0ab562 100644 --- a/repos/gems/src/app/sculpt_manager/dialog/distant_runtime.h +++ b/repos/gems/src/app/sculpt_manager/dialog/distant_runtime.h @@ -41,13 +41,33 @@ class Dialog::Distant_runtime : Noncopyable private: + using Start_name = Session_label::String; + Env &_env; using Views = Dictionary; + 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 _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 _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; - friend class Avl_node; - friend class Avl_tree; - - 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 _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("")); - } - - 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 _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(""); - - 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; + friend class Avl_node; + friend class Avl_tree; + + 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 _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(""); + + 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("")); + } + + 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(); } diff --git a/repos/gems/src/app/sculpt_manager/main.cc b/repos/gems/src/app/sculpt_manager/main.cc index 23be556d94..b7766ecf24 100644 --- a/repos/gems/src/app/sculpt_manager/main.cc +++ b/repos/gems/src/app/sculpt_manager/main.cc @@ -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");