diff --git a/repos/gems/src/app/phone_manager/main.cc b/repos/gems/src/app/phone_manager/main.cc index 29f3434164..8725fa6846 100644 --- a/repos/gems/src/app/phone_manager/main.cc +++ b/repos/gems/src/app/phone_manager/main.cc @@ -915,9 +915,14 @@ struct Sculpt::Main : Input_event_handler, && _software_tabs_widget.hosted.options_selected() && _storage._selected_target.valid()); - s.widget(_software_add_widget, _software_title_bar.selected() - && _software_tabs_widget.hosted.add_selected() - && _storage._selected_target.valid()); + { + using Attr = Software_add_widget::Attr; + s.widget(_software_add_widget, _software_title_bar.selected() + && _software_tabs_widget.hosted.add_selected() + && _storage._selected_target.valid(), + Attr { .visible_frames = true, + .left_aligned_items = false }); + } _image_index_rom.with_xml([&] (Xml_node const &image_index) { s.widget(_software_update_widget, _software_title_bar.selected() diff --git a/repos/gems/src/app/sculpt_manager/keyboard_focus.h b/repos/gems/src/app/sculpt_manager/keyboard_focus.h index dbfdb52755..65e2de3552 100644 --- a/repos/gems/src/app/sculpt_manager/keyboard_focus.h +++ b/repos/gems/src/app/sculpt_manager/keyboard_focus.h @@ -18,17 +18,19 @@ #include /* local includes */ -#include #include +#include +#include #include #include #include +#include namespace Sculpt { struct Keyboard_focus; } struct Sculpt::Keyboard_focus { - enum Target { INITIAL, WPA_PASSPHRASE, SYSTEM_DIALOG, WM } target { INITIAL }; + enum Target { UNDEFINED, WPA_PASSPHRASE, SYSTEM_DIALOG, POPUP, WM } target { UNDEFINED }; Expanding_reporter _focus_reporter; @@ -36,13 +38,21 @@ struct Sculpt::Keyboard_focus Wpa_passphrase &_wpa_passphrase; Panel_dialog::State const &_panel; System_dialog const &_system_dialog; + Popup_dialog const &_popup_dialog; bool const &_system_visible; + Popup const &_popup; void update() { Target const orig_target = target; - target = WM; + target = UNDEFINED; + + if (_panel.inspect_tab_visible()) + target = WM; + + if ((_popup.state == Popup::VISIBLE) && _popup_dialog.keyboard_needed()) + target = POPUP; if (_panel.network_visible() && _network_widget.need_keyboard_focus_for_passphrase()) target = WPA_PASSPHRASE; @@ -61,10 +71,13 @@ struct Sculpt::Keyboard_focus case WPA_PASSPHRASE: case SYSTEM_DIALOG: + case POPUP: xml.attribute("label", "manager -> input"); break; - case INITIAL: + case UNDEFINED: + break; + case WM: xml.attribute("label", "wm -> "); break; @@ -77,14 +90,18 @@ struct Sculpt::Keyboard_focus Wpa_passphrase &wpa_passphrase, Panel_dialog::State const &panel, System_dialog const &system_dialog, - bool const &system_visible) + bool const &system_visible, + Popup_dialog const &popup_dialog, + Popup const &popup) : _focus_reporter(env, "focus", "focus"), _network_widget(network_widget), _wpa_passphrase(wpa_passphrase), _panel(panel), _system_dialog(system_dialog), - _system_visible(system_visible) + _popup_dialog(popup_dialog), + _system_visible(system_visible), + _popup(popup) { update(); } diff --git a/repos/gems/src/app/sculpt_manager/main.cc b/repos/gems/src/app/sculpt_manager/main.cc index b19e6f59d8..23be556d94 100644 --- a/repos/gems/src/app/sculpt_manager/main.cc +++ b/repos/gems/src/app/sculpt_manager/main.cc @@ -64,16 +64,15 @@ struct Sculpt::Main : Input_event_handler, Network::Info, Graph::Action, Panel_dialog::Action, - Popup_dialog::Action, Network_widget::Action, Settings_widget::Action, Software_presets_widget::Action, Software_update_widget::Action, File_browser_dialog::Action, - Popup_dialog::Construction_info, + Popup_dialog::Action, + Component::Construction_info, Depot_query, Panel_dialog::State, - Popup_dialog::Refresh, Screensaver::Action, Drivers::Info, Drivers::Action @@ -414,6 +413,8 @@ struct Sculpt::Main : Input_event_handler, Depot::Archive::User _image_index_user = _build_info.depot_user; + Depot::Archive::User _index_user = _build_info.depot_user; + Expanding_reporter _depot_query_reporter { _env, "query", "depot_query"}; /** @@ -442,13 +443,19 @@ struct Sculpt::Main : Input_event_handler, xml.attribute("arch", _deploy._arch); xml.attribute("version", _query_version.value); - if (_popup_dialog.depot_query_needs_users()) + bool const query_users = _popup_dialog.watches_depot() + || _system_dialog_watches_depot() + || !_scan_rom.valid(); + if (query_users) xml.node("scan", [&] { xml.attribute("users", "yes"); }); - if (_system_dialog_watches_depot() || !_scan_rom.valid()) - xml.node("scan", [&] { - xml.attribute("users", "yes"); }); + if (_popup_dialog.watches_depot() || !_image_index_rom.valid()) + xml.node("index", [&] { + xml.attribute("user", _index_user); + xml.attribute("version", _sculpt_version); + xml.attribute("content", "yes"); + }); if (_system_dialog_watches_depot() || !_image_index_rom.valid()) xml.node("image_index", [&] { @@ -457,8 +464,9 @@ struct Sculpt::Main : Input_event_handler, xml.attribute("user", _image_index_user); }); - _scan_rom.with_xml([&] (Xml_node const &scan) { - _popup_dialog.gen_depot_query(xml, scan); }); + _runtime_state.with_construction([&] (Component const &component) { + xml.node("blueprint", [&] { + xml.attribute("pkg", component.path); }); }); /* update query for blueprints of all unconfigured start nodes */ _deploy.gen_depot_query(xml); @@ -482,6 +490,29 @@ struct Sculpt::Main : Input_event_handler, } + /****************** + ** Browse index ** + ******************/ + + Rom_handler
_index_rom { + _env, "report -> runtime/depot_query/index", *this, &Main::_handle_index }; + + void _handle_index(Xml_node const &) + { + if (_popup_dialog.watches_depot()) + _popup_dialog.refresh(); + } + + /** + * Software_add_widget::Action interface + */ + void query_index(Depot::Archive::User const &user) override + { + _index_user = user; + trigger_depot_query(); + } + + /********************* ** Blueprint query ** *********************/ @@ -502,9 +533,10 @@ struct Sculpt::Main : Input_event_handler, return; _runtime_state.apply_to_construction([&] (Component &component) { - _popup_dialog.apply_blueprint(component, blueprint); }); + component.try_apply_blueprint(blueprint); }); _deploy.handle_deploy(); + _popup_dialog.refresh(); } @@ -519,8 +551,9 @@ struct Sculpt::Main : Input_event_handler, void _handle_scan(Xml_node const &) { - _popup_dialog.depot_users_scan_updated(); _system_dialog.sanitize_user_selection(); + _popup_dialog.sanitize_user_selection(); + _popup_dialog.refresh(); } Rom_handler
_image_index_rom { @@ -734,7 +767,8 @@ struct Sculpt::Main : Input_event_handler, ****************************/ Keyboard_focus _keyboard_focus { _env, _network.dialog, _network.wpa_passphrase, - *this, _system_dialog, _system_visible }; + *this, _system_dialog, _system_visible, + _popup_dialog, _popup }; struct Keyboard_focus_guard { @@ -786,14 +820,18 @@ struct Sculpt::Main : Input_event_handler, ev.handle_press([&] (Input::Keycode, Codepoint code) { if (_keyboard_focus.target == Keyboard_focus::WPA_PASSPHRASE) _network.handle_key_press(code); + if (_keyboard_focus.target == Keyboard_focus::POPUP) + _popup_dialog.handle_key(code, *this); else if (_system_visible && _system_dialog.keyboard_needed()) _system_dialog.handle_key(code, *this); need_generate_dialog = true; }); - if (need_generate_dialog) + if (need_generate_dialog) { _generate_dialog(); + _popup_dialog.refresh(); + } } /* @@ -996,6 +1034,41 @@ struct Sculpt::Main : Input_event_handler, generate_runtime_config(); } + /** + * Software_add_dialog::Action interface + */ + void update_sculpt_index(Depot::Archive::User const &user, Verify verify) override + { + _download_queue.remove_inactive_downloads(); + _index_update_queue.remove_inactive_updates(); + _index_update_queue.add(Path(user, "/index/", _sculpt_version), verify); + generate_runtime_config(); + } + + /** + * Popup_options_widget::Action interface + */ + void enable_optional_component(Path const &launcher) override + { + _runtime_state.launch(launcher, launcher); + + /* trigger change of the deployment */ + _deploy.update_managed_deploy_config(); + _download_queue.remove_inactive_downloads(); + } + + /** + * Popup_options_widget::Action interface + */ + void disable_optional_component(Path const &launcher) override + { + _runtime_state.abandon(launcher); + + /* update config/managed/deploy with the component 'name' removed */ + _deploy.update_managed_deploy_config(); + _download_queue.remove_inactive_downloads(); + } + /* * Panel::Action interface */ @@ -1254,7 +1327,6 @@ struct Sculpt::Main : Input_event_handler, { /* close popup menu */ _popup.state = Popup::OFF; - _popup_dialog.reset(); _popup_dialog.refresh(); /* remove popup window from window layout */ @@ -1264,31 +1336,32 @@ struct Sculpt::Main : Input_event_handler, _graph_view.refresh(); } - /* - * Popup_dialog::Action interface - */ - void launch_global(Path const &launcher) override + void new_construction(Component::Path const &pkg, Verify verify, + Component::Info const &info) override { - _runtime_state.launch(launcher, launcher); - - _close_popup_dialog(); - - /* trigger change of the deployment */ - _download_queue.remove_inactive_downloads(); - _deploy.update_managed_deploy_config(); + _runtime_state.new_construction(pkg, verify, info, _affinity_space); + trigger_depot_query(); } - Start_name new_construction(Component::Path const &pkg, Verify verify, - Component::Info const &info) override - { - return _runtime_state.new_construction(pkg, verify, info, _affinity_space); - } - - void _apply_to_construction(Popup_dialog::Action::Apply_to &fn) override + void _apply_to_construction(Component::Construction_action::Apply_to &fn) override { _runtime_state.apply_to_construction([&] (Component &c) { fn.apply_to(c); }); } + /** + * Component::Construction_action interface + */ + void trigger_pkg_download() override + { + _runtime_state.apply_to_construction([&] (Component &c) { + _download_queue.add(c.path, c.verify); }); + + /* incorporate new download-queue content into update */ + _deploy.update_installation(); + + generate_runtime_config(); + } + void discard_construction() override { _runtime_state.discard_construction(); } void launch_construction() override @@ -1301,37 +1374,10 @@ struct Sculpt::Main : Input_event_handler, _deploy.update_managed_deploy_config(); } - void trigger_download(Path const &path, Verify verify) override - { - _download_queue.remove_inactive_downloads(); - _download_queue.add(path, verify); - - /* incorporate new download-queue content into update */ - _deploy.update_installation(); - - generate_runtime_config(); - _generate_dialog(); - } - - void remove_index(Depot::Archive::User const &user) override - { - auto remove = [&] (Path const &path) { - _file_operation_queue.remove_file(path); }; - - remove(Path("/rw/depot/", user, "/index/", _sculpt_version)); - remove(Path("/rw/public/", user, "/index/", _sculpt_version, ".xz")); - remove(Path("/rw/public/", user, "/index/", _sculpt_version, ".xz.sig")); - - if (!_file_operation_queue.any_operation_in_progress()) - _file_operation_queue.schedule_next_operations(); - - generate_runtime_config(); - } - /** - * Popup_dialog::Construction_info interface + * Component::Construction_info interface */ - void _with_construction(Popup_dialog::Construction_info::With const &fn) const override + void _with_construction(Component::Construction_info::With const &fn) const override { _runtime_state.with_construction([&] (Component const &c) { fn.with(c); }); } @@ -1346,21 +1392,18 @@ struct Sculpt::Main : Input_event_handler, Dialog_view _diag_dialog { _dialog_runtime, *this, _heap }; - Dialog_view _popup_dialog { _dialog_runtime, _env, *this, *this, + Dialog_view _popup_dialog { _dialog_runtime, *this, + _build_info, _sculpt_version, _launchers, _network._nic_state, - _network._nic_target, _runtime_state, - _cached_runtime_config, _download_queue, - _scan_rom, *this, *this }; + _index_update_queue, _index_rom, + _download_queue, _runtime_state, + _cached_runtime_config, _scan_rom, + *this }; Dialog_view _file_browser_dialog { _dialog_runtime, _cached_runtime_config, _file_browser_state, *this }; - /** - * Popup_dialog::Refresh interface - */ - void refresh_popup_dialog() override { _popup_dialog.refresh(); } - Managed_config
_fb_drv_config { _env, "config", "fb_drv", *this, &Main::_handle_fb_drv_config }; @@ -1958,14 +2001,7 @@ void Sculpt::Main::_handle_runtime_state(Xml_node const &state) _deploy.update_installation(); /* update depot-user selection after adding new depot URL */ - if (_system_visible) - trigger_depot_query(); - - /* - * The removal of an index file may have completed, re-query index - * files to reflect this change at the depot selection menu. - */ - if (_popup_dialog.interested_in_file_operations()) + if (_system_visible || (_popup.state == Popup::VISIBLE)) trigger_depot_query(); } } diff --git a/repos/gems/src/app/sculpt_manager/types.h b/repos/gems/src/app/sculpt_manager/types.h index 56d0baa3d9..26ed2c424d 100644 --- a/repos/gems/src/app/sculpt_manager/types.h +++ b/repos/gems/src/app/sculpt_manager/types.h @@ -15,6 +15,7 @@ #define _TYPES_H_ #include +#include #include #include #include diff --git a/repos/gems/src/app/phone_manager/view/component_add_widget.h b/repos/gems/src/app/sculpt_manager/view/component_add_widget.h similarity index 97% rename from repos/gems/src/app/phone_manager/view/component_add_widget.h rename to repos/gems/src/app/sculpt_manager/view/component_add_widget.h index aa1eedae0e..4cec660998 100644 --- a/repos/gems/src/app/phone_manager/view/component_add_widget.h +++ b/repos/gems/src/app/sculpt_manager/view/component_add_widget.h @@ -14,6 +14,7 @@ #ifndef _VIEW__COMPONENT_ADD_WIDGET_H_ #define _VIEW__COMPONENT_ADD_WIDGET_H_ +#include #include #include #include @@ -167,6 +168,10 @@ struct Sculpt::Component_add_widget : Widget _launch.propagate(at); + if (at.matching_id() == Id { "debug" }) + action.apply_to_construction([&] (Component &component) { + _debug.propagate(at, component); }); + Id const route_id = at.matching_id(); /* select route to present routing options */ diff --git a/repos/gems/src/app/phone_manager/view/component_info_widget.h b/repos/gems/src/app/sculpt_manager/view/component_info_widget.h similarity index 100% rename from repos/gems/src/app/phone_manager/view/component_info_widget.h rename to repos/gems/src/app/sculpt_manager/view/component_info_widget.h diff --git a/repos/gems/src/app/sculpt_manager/view/depot_users_widget.h b/repos/gems/src/app/sculpt_manager/view/depot_users_widget.h index 654e73ebaf..46849eae91 100644 --- a/repos/gems/src/app/sculpt_manager/view/depot_users_widget.h +++ b/repos/gems/src/app/sculpt_manager/view/depot_users_widget.h @@ -17,6 +17,7 @@ #include #include #include +#include namespace Sculpt { struct Depot_users_widget; } diff --git a/repos/gems/src/app/phone_manager/view/index_menu_widget.h b/repos/gems/src/app/sculpt_manager/view/index_menu_widget.h similarity index 100% rename from repos/gems/src/app/phone_manager/view/index_menu_widget.h rename to repos/gems/src/app/sculpt_manager/view/index_menu_widget.h diff --git a/repos/gems/src/app/phone_manager/view/index_pkg_widget.h b/repos/gems/src/app/sculpt_manager/view/index_pkg_widget.h similarity index 100% rename from repos/gems/src/app/phone_manager/view/index_pkg_widget.h rename to repos/gems/src/app/sculpt_manager/view/index_pkg_widget.h diff --git a/repos/gems/src/app/sculpt_manager/view/popup_dialog.cc b/repos/gems/src/app/sculpt_manager/view/popup_dialog.cc deleted file mode 100644 index b39607eb05..0000000000 --- a/repos/gems/src/app/sculpt_manager/view/popup_dialog.cc +++ /dev/null @@ -1,532 +0,0 @@ -/* - * \brief Popup dialog - * \author Norman Feske - * \date 2018-09-12 - */ - -/* - * Copyright (C) 2018 Genode Labs GmbH - * - * This file is part of the Genode OS framework, which is distributed - * under the terms of the GNU Affero General Public License version 3. - */ - -#include -#include - -using namespace Sculpt; - - -static Dialog::Id launcher_id(unsigned n) { return { Dialog::Id::Value("launcher ", n) }; } -static Dialog::Id user_id (unsigned n) { return { Dialog::Id::Value("user ", n) }; } - - -static void view_component_info(auto &s, Component const &component) -{ - if (component.info.length() > 1) { - s.named_sub_node("label", "info", [&] { - s.attribute("text", Component::Info(" ", component.info, " ")); }); - - s.template sub_scope(""); - } - s.template sub_scope(component.path); -} - - -void Popup_dialog::_view_pkg_elements(Scope &s, - Component const &component) const -{ - using Info = Component::Info; - - s.widget(_back, Index_menu::Name("Add ", Pretty(_construction_name))); - - view_component_info(s, component); - - s.sub_scope(Info(Capacity{component.ram}, " ", - component.caps, " caps")); - s.sub_scope(); - - unsigned count = 0; - component.routes.for_each([&] (Route const &route) { - - Id const id { Id::Value { count++ } }; - - s.sub_scope([&] (Scope &s) { - s.sub_scope([&] (Scope &s) { - - bool const selected = _route_selected(id.value); - bool const defined = route.selected_service.constructed(); - - if (!selected) { - Route_entry entry { id }; - s.widget(entry, defined, - defined ? Info(route.selected_service->info) - : Info(route)); - } - - /* - * List of routing options - */ - if (selected) { - Route_entry back { Id { "back" } }; - s.widget(back, true, Info(route), "back"); - - unsigned count = 0; - _runtime_config.for_each_service([&] (Service const &service) { - - Id const service_id { Id::Value("service.", count++) }; - - bool const service_selected = - route.selected_service.constructed() && - service_id.value == route.selected_service_id; - - if (service.type == route.required) { - Service_entry entry { service_id }; - s.widget(entry, service_selected, service.info); - } - }); - } - }); - }); - }); - - /* don't show the PD menu if only the system PD service is available */ - if (_runtime_config.num_service_options(Service::Type::PD) > 1) - s.sub_scope([&] (Scope &s) { - s.widget(_pd_route, _selected_route, component); }); - - s.sub_scope(Id { "resources" }, [&] (Scope &s) { - s.sub_scope([&] (Scope &s) { - - bool const selected = _route_selected("resources"); - - if (!selected) { - Route_entry entry { Id { "resources" } }; - s.widget(entry, false, "Resource assignment ...", "enter"); - } - - if (selected) { - Route_entry entry { Id { "back" } }; - s.widget(entry, true, "Resource assignment ...", "back"); - - s.widget(_resources, component); - } - }); - }); - - s.sub_scope([&] (Scope &s) { - s.widget(_debug, component); }); - - /* - * Display "Add component" button once all routes are defined - */ - if (component.all_routes_defined()) - s.widget(_launch); -} - - -void Popup_dialog::_view_menu_elements(Scope &s, Xml_node const &depot_users) const -{ - /* - * Lauchers - */ - if (_state == TOP_LEVEL || _state < DEPOT_SHOWN) { - unsigned count = 0; - for_each_viewed_launcher([&] (Launchers::Info const &info) { - Hosted menu_entry { launcher_id(count++) }; - s.widget(menu_entry, false, String<100>(Pretty(info.path))); - }); - - Hosted depot_menu_entry { Id { "depot" } }; - s.widget(depot_menu_entry, false, "Depot ..."); - } - - /* - * Depot users with an available index - */ - if (_state == DEPOT_SHOWN || _state == INDEX_REQUESTED) { - s.widget(_back, "Depot"); - - unsigned count = 0; - depot_users.for_each_sub_node("user", [&] (Xml_node user) { - - User const name = user.attribute_value("name", User()); - bool const selected = (_selected_user == name); - Id const id = user_id(count++); - - if (_index_avail(name)) { - Hosted menu_entry { id }; - s.widget(menu_entry, selected, User(name, " ...")); - } - }); - - /* - * Depot selection menu item - */ - if (_nic_ready()) { - Hosted menu_entry { Id { "selection" } }; - s.widget(menu_entry, false, "Selection ..."); - } - } - - /* - * List of depot users for removing/adding indices - */ - if (_state == DEPOT_SELECTION) { - s.widget(_back, "Selection"); - - unsigned count = 0; - depot_users.for_each_sub_node("user", [&] (Xml_node user) { - - User const name = user.attribute_value("name", User()); - bool const selected = _index_avail(name); - Id const id = user_id(count++); - - String<32> const suffix = _download_queue.in_progress(_index_path(name)) - ? " fetch... " : " "; - - Hosted user_entry { id }; - s.widget(user_entry, selected, User(name, suffix), "checkbox"); - }); - } - - /* - * Title of index - */ - if (_state >= INDEX_SHOWN && _state < PKG_SHOWN) { - Index_menu::Name title("Depot ", _selected_user); - if (_menu._level) - title = Index_menu::Name(title, " ", _menu, " "); - - s.widget(_back, title); - } - - /* - * Index menu - */ - if (_state >= INDEX_SHOWN && _state < PKG_SHOWN) { - - unsigned count = 0; - _for_each_menu_item([&] (Xml_node item) { - - Id const id { Id::Value(count) }; - - if (item.has_type("index")) { - auto const name = item.attribute_value("name", Index_menu::Name()); - Hosted entry { id }; - s.widget(entry, false, Index_menu::Name(name, " ...")); - } - - if (item.has_type("pkg")) { - auto const path = item.attribute_value("path", Depot::Archive::Path()); - auto const name = Depot::Archive::name(path); - auto const version = Depot::Archive::version(path); - - bool selected = false; - - bool const installing = _download_queue.in_progress(path); - - _construction_info.with_construction([&] (Component const &component) { - - if (component.path == path) - selected = true; - }); - - String<100> const text(Pretty(name), " " "(", version, ")", - installing ? " installing... " : "... "); - - Hosted entry { id }; - s.widget(entry, selected, text); - - if (selected && !installing) { - - _construction_info.with_construction([&] (Component const &component) { - - s.sub_scope(Id { "install" }, [&] (Scope &s) { - s.sub_scope([&] (Scope &s) { - - /* - * Package is installed but content is missing - * - * This can happen when the pkg's runtime is - * inconsistent with the content contained in - * the pkg's archives. - */ - if (_blueprint_info.incomplete()) { - s.sub_scope(); - s.sub_scope(component.path); - s.sub_scope(); - s.sub_scope