mirror of
https://github.com/genodelabs/genode.git
synced 2025-04-09 04:15:52 +00:00
sculpt: interactive deployment
This patch introduces the distinction of the manually managed config/deploy from the managed config/managed/deploy. The latter incorporates interactive changes of the system by the user. There are two user interactions supported. First, by clicking on the '+' button at the top-left of the runtime view, the user can select a component to launch. All launchers at config/launcher/ are listed in the popup menu. Each launcher can be lauched only once. While running, is not available in the popup menu. Second, when selecting a node that corresponds to a start node in config/deploy or that was interactively launched, the detailed view shows a 'remove' button, which can be used to exclude the component from the deployment. The result of the interactive manipulation is always available at config/managed/deploy. Hence, the current situation can be made persistent by using it as config/deploy. Fixes #2986
This commit is contained in:
parent
b51ee34b11
commit
f4c55aa4db
@ -96,14 +96,16 @@
|
||||
<policy label="decorator -> pointer" report="wm -> pointer"/>
|
||||
<policy label="gui -> config" report="manager -> gui_config"/>
|
||||
<policy label="gui -> menu -> dialog" report="manager -> menu_dialog"/>
|
||||
<policy label="gui -> popup -> dialog" report="manager -> popup_dialog"/>
|
||||
<policy label="manager -> menu_view_hover" report="gui -> menu -> hover"/>
|
||||
<policy label="manager -> popup_view_hover" report="gui -> popup -> hover"/>
|
||||
<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"/>
|
||||
</config>
|
||||
</start>
|
||||
|
||||
<start name="wm" caps="150">
|
||||
<start name="wm" caps="200">
|
||||
<resource name="RAM" quantum="2M"/>
|
||||
<provides> <service name="Nitpicker"/> </provides>
|
||||
<config>
|
||||
@ -118,7 +120,7 @@
|
||||
</route>
|
||||
</start>
|
||||
|
||||
<start name="decorator" caps="200">
|
||||
<start name="decorator" caps="300">
|
||||
<binary name="themed_decorator"/>
|
||||
<resource name="RAM" quantum="8M"/>
|
||||
<config>
|
||||
@ -166,6 +168,8 @@
|
||||
<route>
|
||||
<service name="Report" label="runtime_config">
|
||||
<child name="config_fs_report" label="managed -> runtime"/> </service>
|
||||
<service name="Report" label="deploy_config">
|
||||
<child name="config_fs_report" label="managed -> deploy"/> </service>
|
||||
<service name="Report" label="wifi_config">
|
||||
<child name="config_fs_report" label="managed -> wifi"/> </service>
|
||||
<service name="Report" label="fonts_config">
|
||||
@ -185,6 +189,7 @@
|
||||
<service name="ROM" label="nitpicker_hover"> <parent/> </service>
|
||||
<service name="ROM" label_prefix="report ->"> <parent/> </service>
|
||||
<service name="ROM" label="menu_view_hover"> <child name="report_rom"/> </service>
|
||||
<service name="ROM" label="popup_view_hover"> <child name="report_rom"/> </service>
|
||||
<service name="ROM" label="runtime_view_hover"> <parent/> </service>
|
||||
<service name="ROM" label="window_list"> <child name="report_rom"/> </service>
|
||||
<service name="ROM" label="decorator_margins"> <child name="report_rom"/> </service>
|
||||
@ -206,11 +211,11 @@
|
||||
|
||||
<start name="gui" caps="1400">
|
||||
<binary name="init"/>
|
||||
<resource name="RAM" quantum="14M"/>
|
||||
<resource name="RAM" quantum="20M"/>
|
||||
<route>
|
||||
<service name="ROM" label="config"> <child name="report_rom"/> </service>
|
||||
<service name="ROM" label_last="dialog"> <child name="report_rom"/> </service>
|
||||
<service name="Nitpicker"> <child name="nitpicker"/> </service>
|
||||
<service name="Nitpicker"> <child name="wm"/> </service>
|
||||
<service name="File_system" label="fonts"> <child name="fonts_fs"/> </service>
|
||||
<service name="Report" label_last="hover"> <child name="report_rom"/> </service>
|
||||
<any-service> <parent/> </any-service>
|
||||
|
@ -140,6 +140,15 @@ class Depot_deploy::Children
|
||||
result |= child.incomplete(); });
|
||||
return result;
|
||||
}
|
||||
|
||||
bool exists(Child::Name const &name) const
|
||||
{
|
||||
bool result = false;
|
||||
_children.for_each([&] (Child const &child) {
|
||||
if (child.name() == name)
|
||||
result = true; });
|
||||
return result;
|
||||
}
|
||||
};
|
||||
|
||||
#endif /* _CHILDREN_H_ */
|
||||
|
@ -81,14 +81,14 @@ void Sculpt::Deploy::gen_child_diagnostics(Xml_generator &xml) const
|
||||
|
||||
void Sculpt::Deploy::handle_deploy()
|
||||
{
|
||||
Xml_node const manual_deploy = _manual_deploy_rom.xml();
|
||||
Xml_node const managed_deploy = _managed_deploy_rom.xml();
|
||||
|
||||
/* determine CPU architecture of deployment */
|
||||
_arch = manual_deploy.attribute_value("arch", Arch());
|
||||
_arch = managed_deploy.attribute_value("arch", Arch());
|
||||
if (!_arch.valid())
|
||||
warning("manual deploy config lacks 'arch' attribute");
|
||||
warning("managed deploy config lacks 'arch' attribute");
|
||||
|
||||
try { _children.apply_config(manual_deploy); }
|
||||
try { _children.apply_config(managed_deploy); }
|
||||
catch (...) {
|
||||
error("spurious exception during deploy update (apply_config)"); }
|
||||
|
||||
@ -172,16 +172,16 @@ void Sculpt::Deploy::gen_runtime_start_nodes(Xml_generator &xml) const
|
||||
xml.node("start", [&] () {
|
||||
gen_depot_query_start_content(xml); });
|
||||
|
||||
Xml_node const manual_deploy = _manual_deploy_rom.xml();
|
||||
Xml_node const managed_deploy = _managed_deploy_rom.xml();
|
||||
|
||||
/* insert content of '<static>' node as is */
|
||||
if (manual_deploy.has_sub_node("static")) {
|
||||
Xml_node static_config = manual_deploy.sub_node("static");
|
||||
if (managed_deploy.has_sub_node("static")) {
|
||||
Xml_node static_config = managed_deploy.sub_node("static");
|
||||
xml.append(static_config.content_base(), static_config.content_size());
|
||||
}
|
||||
|
||||
/* generate start nodes for deployed packages */
|
||||
if (manual_deploy.has_sub_node("common_routes"))
|
||||
_children.gen_start_nodes(xml, manual_deploy.sub_node("common_routes"),
|
||||
if (managed_deploy.has_sub_node("common_routes"))
|
||||
_children.gen_start_nodes(xml, managed_deploy.sub_node("common_routes"),
|
||||
"depot_rom", "dynamic_depot_rom");
|
||||
}
|
||||
|
@ -22,6 +22,7 @@
|
||||
#include <children.h>
|
||||
|
||||
/* local includes */
|
||||
#include <model/launchers.h>
|
||||
#include <types.h>
|
||||
#include <runtime.h>
|
||||
#include <managed_config.h>
|
||||
@ -42,6 +43,8 @@ struct Sculpt::Deploy
|
||||
|
||||
Runtime_config_generator &_runtime_config_generator;
|
||||
|
||||
Attached_rom_dataspace const &_launcher_listing_rom;
|
||||
|
||||
typedef String<16> Arch;
|
||||
Arch _arch { };
|
||||
|
||||
@ -53,14 +56,56 @@ struct Sculpt::Deploy
|
||||
Child_state uncached_depot_rom_state {
|
||||
"dynamic_depot_rom", Ram_quota{8*1024*1024}, Cap_quota{200} };
|
||||
|
||||
Attached_rom_dataspace _manual_deploy_rom { _env, "config -> deploy" };
|
||||
|
||||
Attached_rom_dataspace _launcher_listing_rom { _env, "report -> /runtime/launcher_query/listing" };
|
||||
|
||||
Attached_rom_dataspace _blueprint_rom { _env, "report -> runtime/depot_query/blueprint" };
|
||||
|
||||
Expanding_reporter _depot_query_reporter { _env, "query", "depot_query"};
|
||||
|
||||
/*
|
||||
* Report written to '/config/managed/deploy'
|
||||
*
|
||||
* This report takes the manually maintained '/config/deploy' and the
|
||||
* interactive state as input.
|
||||
*/
|
||||
Expanding_reporter _managed_deploy_config { _env, "config", "deploy_config" };
|
||||
|
||||
/* config obtained from '/config/managed/deploy' */
|
||||
Attached_rom_dataspace _managed_deploy_rom { _env, "config -> managed/deploy" };
|
||||
|
||||
void update_managed_deploy_config(Xml_node deploy)
|
||||
{
|
||||
_managed_deploy_config.generate([&] (Xml_generator &xml) {
|
||||
|
||||
Arch const arch = deploy.attribute_value("arch", Arch());
|
||||
if (arch.valid())
|
||||
xml.attribute("arch", arch);
|
||||
|
||||
auto append_xml_node = [&] (Xml_node node) {
|
||||
xml.append("\t");
|
||||
xml.append(node.addr(), node.size());
|
||||
xml.append("\n");
|
||||
};
|
||||
|
||||
/* copy <common_routes> from manual deploy config */
|
||||
deploy.for_each_sub_node("common_routes", [&] (Xml_node node) {
|
||||
append_xml_node(node); });
|
||||
|
||||
/*
|
||||
* Copy the <start> node from manual deploy config, unless the
|
||||
* component was interactively killed by the user.
|
||||
*/
|
||||
deploy.for_each_sub_node("start", [&] (Xml_node node) {
|
||||
Start_name const name = node.attribute_value("name", Start_name());
|
||||
if (!_runtime_info.abandoned_by_user(name))
|
||||
append_xml_node(node);
|
||||
});
|
||||
|
||||
/*
|
||||
* Add start nodes for interactively launched components.
|
||||
*/
|
||||
_runtime_info.gen_launched_deploy_start_nodes(xml);
|
||||
});
|
||||
}
|
||||
|
||||
bool _manual_installation_scheduled = false;
|
||||
|
||||
Managed_config<Deploy> _installation {
|
||||
@ -81,10 +126,9 @@ struct Sculpt::Deploy
|
||||
|
||||
void handle_deploy();
|
||||
|
||||
void _handle_manual_deploy()
|
||||
void _handle_managed_deploy()
|
||||
{
|
||||
_manual_deploy_rom.update();
|
||||
_launcher_listing_rom.update();
|
||||
_managed_deploy_rom.update();
|
||||
_query_version.value++;
|
||||
handle_deploy();
|
||||
}
|
||||
@ -135,11 +179,8 @@ struct Sculpt::Deploy
|
||||
|
||||
void gen_runtime_start_nodes(Xml_generator &) const;
|
||||
|
||||
Signal_handler<Deploy> _manual_deploy_handler {
|
||||
_env.ep(), *this, &Deploy::_handle_manual_deploy };
|
||||
|
||||
Signal_handler<Deploy> _launcher_listing_handler {
|
||||
_env.ep(), *this, &Deploy::_handle_manual_deploy };
|
||||
Signal_handler<Deploy> _managed_deploy_handler {
|
||||
_env.ep(), *this, &Deploy::_handle_managed_deploy };
|
||||
|
||||
Signal_handler<Deploy> _blueprint_handler {
|
||||
_env.ep(), *this, &Deploy::_handle_blueprint };
|
||||
@ -160,14 +201,15 @@ struct Sculpt::Deploy
|
||||
|
||||
Deploy(Env &env, Allocator &alloc, Runtime_info const &runtime_info,
|
||||
Dialog::Generator &dialog_generator,
|
||||
Runtime_config_generator &runtime_config_generator)
|
||||
Runtime_config_generator &runtime_config_generator,
|
||||
Attached_rom_dataspace const &launcher_listing_rom)
|
||||
:
|
||||
_env(env), _alloc(alloc), _runtime_info(runtime_info),
|
||||
_dialog_generator(dialog_generator),
|
||||
_runtime_config_generator(runtime_config_generator)
|
||||
_runtime_config_generator(runtime_config_generator),
|
||||
_launcher_listing_rom(launcher_listing_rom)
|
||||
{
|
||||
_manual_deploy_rom.sigh(_manual_deploy_handler);
|
||||
_launcher_listing_rom.sigh(_launcher_listing_handler);
|
||||
_managed_deploy_rom.sigh(_managed_deploy_handler);
|
||||
_blueprint_rom.sigh(_blueprint_handler);
|
||||
}
|
||||
};
|
||||
|
@ -24,6 +24,7 @@
|
||||
#include <types.h>
|
||||
#include <xml.h>
|
||||
#include <model/capacity.h>
|
||||
#include <model/popup.h>
|
||||
|
||||
namespace Sculpt { struct Graph; }
|
||||
|
||||
@ -36,6 +37,10 @@ struct Sculpt::Graph
|
||||
|
||||
Storage_target const &_sculpt_partition;
|
||||
|
||||
Popup::State const &_popup_state;
|
||||
|
||||
Depot_deploy::Children const &_deploy_children;
|
||||
|
||||
Expanding_reporter _graph_dialog_reporter { _env, "dialog", "runtime_view_dialog" };
|
||||
|
||||
/*
|
||||
@ -53,7 +58,14 @@ struct Sculpt::Graph
|
||||
Signal_handler<Graph> _hover_handler {
|
||||
_env.ep(), *this, &Graph::_handle_hover };
|
||||
|
||||
Hoverable_item _node_button_item { };
|
||||
Hoverable_item _node_button_item { };
|
||||
Hoverable_item _add_button_item { };
|
||||
Activatable_item _remove_item { };
|
||||
|
||||
/*
|
||||
* Defined when '+' button is hovered
|
||||
*/
|
||||
Rect _popup_anchor { };
|
||||
|
||||
bool _hovered = false;
|
||||
|
||||
@ -93,10 +105,7 @@ struct Sculpt::Graph
|
||||
bool first_route = true;
|
||||
route.for_each_sub_node("service", [&] (Xml_node service) {
|
||||
|
||||
if (!service.has_sub_node("child"))
|
||||
return;
|
||||
|
||||
if (!first_route) {
|
||||
if (!first_route && service.has_sub_node("child")) {
|
||||
Xml_node const child = service.sub_node("child");
|
||||
fn(child.attribute_value("name", Start_name()));
|
||||
}
|
||||
@ -105,6 +114,37 @@ struct Sculpt::Graph
|
||||
});
|
||||
}
|
||||
|
||||
void _gen_selected_node_content(Xml_generator &xml, Start_name const &name,
|
||||
Runtime_state::Info const &info) const
|
||||
{
|
||||
bool const removable = _deploy_children.exists(name);
|
||||
|
||||
if (removable) {
|
||||
gen_named_node(xml, "frame", "operations", [&] () {
|
||||
xml.node("vbox", [&] () {
|
||||
gen_named_node(xml, "button", "remove", [&] () {
|
||||
_remove_item.gen_button_attr(xml, "remove");
|
||||
xml.node("label", [&] () {
|
||||
xml.attribute("text", "Remove");
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
String<100> const
|
||||
ram (Capacity{info.assigned_ram - info.avail_ram}, " / ",
|
||||
Capacity{info.assigned_ram}),
|
||||
caps(info.assigned_caps - info.avail_caps, " / ",
|
||||
info.assigned_caps, " caps");
|
||||
|
||||
gen_named_node(xml, "label", "ram", [&] () {
|
||||
xml.attribute("text", ram); });
|
||||
|
||||
gen_named_node(xml, "label", "caps", [&] () {
|
||||
xml.attribute("text", caps); });
|
||||
}
|
||||
|
||||
void _gen_graph_dialog()
|
||||
{
|
||||
Xml_node const config = _runtime_config_rom.xml();
|
||||
@ -113,6 +153,15 @@ struct Sculpt::Graph
|
||||
|
||||
xml.node("depgraph", [&] () {
|
||||
|
||||
gen_named_node(xml, "button", "global+", [&] () {
|
||||
_add_button_item.gen_button_attr(xml, "global+");
|
||||
|
||||
if (_popup_state == Popup::VISIBLE)
|
||||
xml.attribute("selected", "yes");
|
||||
|
||||
xml.node("label", [&] () {
|
||||
xml.attribute("text", "+"); }); });
|
||||
|
||||
config.for_each_sub_node("start", [&] (Xml_node start) {
|
||||
|
||||
Start_name const name = start.attribute_value("name", Start_name());
|
||||
@ -142,20 +191,8 @@ struct Sculpt::Graph
|
||||
});
|
||||
});
|
||||
|
||||
if (info.selected) {
|
||||
|
||||
String<100> const
|
||||
ram (Capacity{info.assigned_ram - info.avail_ram}, " / ",
|
||||
Capacity{info.assigned_ram}),
|
||||
caps(info.assigned_caps - info.avail_caps, " / ",
|
||||
info.assigned_caps, " caps");
|
||||
|
||||
gen_named_node(xml, "label", "ram", [&] () {
|
||||
xml.attribute("text", ram); });
|
||||
|
||||
gen_named_node(xml, "label", "caps", [&] () {
|
||||
xml.attribute("text", caps); });
|
||||
}
|
||||
if (info.selected)
|
||||
_gen_selected_node_content(xml, name, info);
|
||||
});
|
||||
});
|
||||
});
|
||||
@ -197,16 +234,54 @@ struct Sculpt::Graph
|
||||
_hovered = (hover.num_sub_nodes() != 0);
|
||||
|
||||
bool const changed =
|
||||
_node_button_item.match(hover, "dialog", "depgraph", "frame", "vbox", "button", "name");
|
||||
_node_button_item.match(hover, "dialog", "depgraph", "frame", "vbox", "button", "name") |
|
||||
_add_button_item .match(hover, "dialog", "depgraph", "button", "name") |
|
||||
_remove_item .match(hover, "dialog", "depgraph", "frame", "vbox",
|
||||
"frame", "vbox", "button", "name");
|
||||
|
||||
if (_add_button_item.hovered("global+")) {
|
||||
|
||||
/* update anchor geometry of popup menu */
|
||||
auto hovered_rect = [] (Xml_node const hover) {
|
||||
|
||||
auto point_from_xml = [] (Xml_node node) {
|
||||
return Point(node.attribute_value("xpos", 0L),
|
||||
node.attribute_value("ypos", 0L)); };
|
||||
|
||||
auto area_from_xml = [] (Xml_node node) {
|
||||
return Area(node.attribute_value("width", 0UL),
|
||||
node.attribute_value("height", 0UL)); };
|
||||
|
||||
if (!hover.has_sub_node("dialog")) return Rect();
|
||||
Xml_node const dialog = hover.sub_node("dialog");
|
||||
|
||||
if (!dialog.has_sub_node("depgraph")) return Rect();
|
||||
Xml_node const depgraph = dialog.sub_node("depgraph");
|
||||
|
||||
if (!depgraph.has_sub_node("button")) return Rect();
|
||||
Xml_node const button = depgraph.sub_node("button");
|
||||
|
||||
return Rect(point_from_xml(dialog) + point_from_xml(depgraph) +
|
||||
point_from_xml(button),
|
||||
area_from_xml(button));
|
||||
};
|
||||
|
||||
_popup_anchor = hovered_rect(hover);
|
||||
}
|
||||
|
||||
if (changed)
|
||||
_gen_graph_dialog();
|
||||
}
|
||||
|
||||
Graph(Env &env, Runtime_state &runtime_state,
|
||||
Storage_target const &sculpt_partition)
|
||||
Graph(Env &env,
|
||||
Runtime_state &runtime_state,
|
||||
Storage_target const &sculpt_partition,
|
||||
Popup::State const &popup_state,
|
||||
Depot_deploy::Children const &deploy_children)
|
||||
:
|
||||
_env(env), _runtime_state(runtime_state), _sculpt_partition(sculpt_partition)
|
||||
_env(env), _runtime_state(runtime_state),
|
||||
_sculpt_partition(sculpt_partition),
|
||||
_popup_state(popup_state), _deploy_children(deploy_children)
|
||||
{
|
||||
_runtime_config_rom.sigh(_runtime_config_handler);
|
||||
_hover_rom.sigh(_hover_handler);
|
||||
@ -214,12 +289,46 @@ struct Sculpt::Graph
|
||||
|
||||
bool hovered() const { return _hovered; }
|
||||
|
||||
void click()
|
||||
bool add_button_hovered() const { return _add_button_item._hovered.valid(); }
|
||||
|
||||
struct Action : Interface
|
||||
{
|
||||
virtual void remove_deployed_component(Start_name const &) = 0;
|
||||
virtual void toggle_launcher_selector(Rect) = 0;
|
||||
};
|
||||
|
||||
void click(Action &action)
|
||||
{
|
||||
if (_add_button_item._hovered.valid()) {
|
||||
action.toggle_launcher_selector(_popup_anchor);
|
||||
}
|
||||
|
||||
if (_node_button_item._hovered.valid()) {
|
||||
_runtime_state.toggle_selection(_node_button_item._hovered);
|
||||
_remove_item.reset();
|
||||
_gen_graph_dialog();
|
||||
}
|
||||
|
||||
if (_remove_item.hovered("remove")) {
|
||||
_remove_item.propose_activation_on_click();
|
||||
_gen_graph_dialog();
|
||||
}
|
||||
}
|
||||
|
||||
void clack(Action &action)
|
||||
{
|
||||
if (_remove_item.hovered("remove")) {
|
||||
|
||||
_remove_item.confirm_activation_on_clack();
|
||||
|
||||
if (_remove_item.activated("remove"))
|
||||
action.remove_deployed_component(_runtime_state.selected());
|
||||
|
||||
} else {
|
||||
_remove_item.reset();
|
||||
}
|
||||
|
||||
_gen_graph_dialog();
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -23,7 +23,8 @@
|
||||
|
||||
void Sculpt::Gui::_gen_menu_view_start_content(Xml_generator &xml,
|
||||
Label const &label,
|
||||
Point pos) const
|
||||
Point pos,
|
||||
unsigned width) const
|
||||
{
|
||||
xml.attribute("version", version.value);
|
||||
|
||||
@ -34,7 +35,8 @@ void Sculpt::Gui::_gen_menu_view_start_content(Xml_generator &xml,
|
||||
xml.node("config", [&] () {
|
||||
xml.attribute("xpos", pos.x());
|
||||
xml.attribute("ypos", pos.y());
|
||||
xml.attribute("width", menu_width);
|
||||
if (width)
|
||||
xml.attribute("width", width);
|
||||
xml.node("libc", [&] () { xml.attribute("stderr", "/dev/log"); });
|
||||
xml.node("report", [&] () { xml.attribute("hover", "yes"); });
|
||||
xml.node("vfs", [&] () {
|
||||
@ -104,6 +106,9 @@ void Sculpt::Gui::_generate_config(Xml_generator &xml) const
|
||||
});
|
||||
|
||||
xml.node("start", [&] () {
|
||||
_gen_menu_view_start_content(xml, "menu", Point(0, 0)); });
|
||||
_gen_menu_view_start_content(xml, "menu", Point(0, 0), menu_width); });
|
||||
|
||||
xml.node("start", [&] () {
|
||||
_gen_menu_view_start_content(xml, "popup", Point(0, 0), 0); });
|
||||
}
|
||||
|
||||
|
@ -41,7 +41,8 @@ struct Sculpt::Gui
|
||||
|
||||
unsigned menu_width = 0;
|
||||
|
||||
void _gen_menu_view_start_content(Xml_generator &, Label const &, Point) const;
|
||||
void _gen_menu_view_start_content(Xml_generator &, Label const &, Point,
|
||||
unsigned) const;
|
||||
|
||||
void _generate_config(Xml_generator &) const;
|
||||
|
||||
|
@ -25,6 +25,7 @@
|
||||
#include <model/runtime_state.h>
|
||||
#include <model/child_exit_state.h>
|
||||
#include <view/download_status.h>
|
||||
#include <view/popup_dialog.h>
|
||||
#include <gui.h>
|
||||
#include <nitpicker.h>
|
||||
#include <keyboard_focus.h>
|
||||
@ -39,7 +40,9 @@ namespace Sculpt { struct Main; }
|
||||
struct Sculpt::Main : Input_event_handler,
|
||||
Dialog::Generator,
|
||||
Runtime_config_generator,
|
||||
Storage::Target_user
|
||||
Storage::Target_user,
|
||||
Graph::Action,
|
||||
Popup_dialog::Action
|
||||
{
|
||||
Env &_env;
|
||||
|
||||
@ -175,8 +178,49 @@ struct Sculpt::Main : Input_event_handler,
|
||||
&& _network.ready()
|
||||
&& _deploy.update_needed(); };
|
||||
|
||||
Deploy _deploy { _env, _heap, _runtime_state, *this, *this };
|
||||
|
||||
/************
|
||||
** Deploy **
|
||||
************/
|
||||
|
||||
Attached_rom_dataspace _launcher_listing_rom {
|
||||
_env, "report -> /runtime/launcher_query/listing" };
|
||||
|
||||
Launchers _launchers { _heap };
|
||||
|
||||
Signal_handler<Main> _launcher_listing_handler {
|
||||
_env.ep(), *this, &Main::_handle_launcher_listing };
|
||||
|
||||
void _handle_launcher_listing()
|
||||
{
|
||||
_launcher_listing_rom.update();
|
||||
|
||||
Xml_node listing = _launcher_listing_rom.xml();
|
||||
if (listing.has_sub_node("dir")) {
|
||||
Xml_node dir = listing.sub_node("dir");
|
||||
|
||||
/* let 'update_from_xml' iterate over <file> nodes */
|
||||
_launchers.update_from_xml(dir);
|
||||
}
|
||||
|
||||
_popup_dialog.generate();
|
||||
_deploy._handle_managed_deploy();
|
||||
}
|
||||
|
||||
|
||||
Deploy _deploy { _env, _heap, _runtime_state, *this, *this, _launcher_listing_rom };
|
||||
|
||||
Attached_rom_dataspace _manual_deploy_rom { _env, "config -> deploy" };
|
||||
|
||||
void _handle_manual_deploy()
|
||||
{
|
||||
_runtime_state.reset_abandoned_and_launched_children();
|
||||
_manual_deploy_rom.update();
|
||||
_deploy.update_managed_deploy_config(_manual_deploy_rom.xml());
|
||||
}
|
||||
|
||||
Signal_handler<Main> _manual_deploy_handler {
|
||||
_env.ep(), *this, &Main::_handle_manual_deploy };
|
||||
|
||||
|
||||
/************
|
||||
@ -298,11 +342,29 @@ struct Sculpt::Main : Input_event_handler,
|
||||
if (_hovered_dialog == Hovered::NETWORK) _network.dialog.click(_network);
|
||||
if (_hovered_dialog == Hovered::RUNTIME) _network.dialog.click(_network);
|
||||
|
||||
if (_graph.hovered()) _graph.click();
|
||||
/* remove popup dialog when clicking somewhere outside */
|
||||
if (!_popup_dialog.hovered() && _popup.state == Popup::VISIBLE
|
||||
&& !_graph.add_button_hovered()) {
|
||||
|
||||
_popup.state = Popup::OFF;
|
||||
|
||||
/* de-select '+' button */
|
||||
_graph._gen_graph_dialog();
|
||||
|
||||
/* remove popup window from window layout */
|
||||
_handle_window_layout();
|
||||
}
|
||||
|
||||
if (_graph.hovered()) _graph.click(*this);
|
||||
|
||||
if (_popup_dialog.hovered()) _popup_dialog.click(*this);
|
||||
}
|
||||
|
||||
if (ev.key_release(Input::BTN_LEFT))
|
||||
_storage.dialog.clack(_storage);
|
||||
if (ev.key_release(Input::BTN_LEFT)) {
|
||||
if (_hovered_dialog == Hovered::STORAGE) _storage.dialog.clack(_storage);
|
||||
|
||||
if (_graph.hovered()) _graph.clack(*this);
|
||||
}
|
||||
|
||||
if (_keyboard_focus.target == Keyboard_focus::WPA_PASSPHRASE)
|
||||
ev.handle_press([&] (Input::Keycode, Codepoint code) {
|
||||
@ -312,6 +374,49 @@ struct Sculpt::Main : Input_event_handler,
|
||||
_keyboard_focus.update();
|
||||
}
|
||||
|
||||
/*
|
||||
* Graph::Action interface
|
||||
*/
|
||||
void remove_deployed_component(Start_name const &name) override
|
||||
{
|
||||
_runtime_state.abandon(name);
|
||||
|
||||
/* update config/managed/deploy with the component 'name' removed */
|
||||
_deploy.update_managed_deploy_config(_manual_deploy_rom.xml());
|
||||
}
|
||||
|
||||
/*
|
||||
* Graph::Action interface
|
||||
*/
|
||||
void toggle_launcher_selector(Rect anchor) override
|
||||
{
|
||||
_popup_dialog.generate();
|
||||
_popup.anchor = anchor;
|
||||
_popup.toggle();
|
||||
_graph._gen_graph_dialog();
|
||||
_handle_window_layout();
|
||||
}
|
||||
|
||||
/*
|
||||
* Popup_dialog::Action interface
|
||||
*/
|
||||
void launch_global(Path const &launcher) override
|
||||
{
|
||||
_runtime_state.launch(launcher, launcher);
|
||||
|
||||
/* close popup menu */
|
||||
_popup.state = Popup::OFF;
|
||||
_handle_window_layout();
|
||||
|
||||
/* reset state of the '+' button */
|
||||
_graph._gen_graph_dialog();
|
||||
|
||||
/* trigger change of the deployment */
|
||||
_deploy.update_managed_deploy_config(_manual_deploy_rom.xml());
|
||||
}
|
||||
|
||||
Popup_dialog _popup_dialog { _env, _launchers, _runtime_state };
|
||||
|
||||
Managed_config<Main> _fb_drv_config {
|
||||
_env, "config", "fb_drv", *this, &Main::_handle_fb_drv_config };
|
||||
|
||||
@ -360,6 +465,14 @@ struct Sculpt::Main : Input_event_handler,
|
||||
|
||||
void _handle_window_layout();
|
||||
|
||||
template <size_t N, typename FN>
|
||||
void _with_window(Xml_node window_list, String<N> const &match, FN const &fn)
|
||||
{
|
||||
window_list.for_each_sub_node("window", [&] (Xml_node win) {
|
||||
if (win.attribute_value("label", String<N>()) == match)
|
||||
fn(win); });
|
||||
}
|
||||
|
||||
Attached_rom_dataspace _window_list { _env, "window_list" };
|
||||
|
||||
Signal_handler<Main> _window_list_handler {
|
||||
@ -379,7 +492,10 @@ struct Sculpt::Main : Input_event_handler,
|
||||
** Runtime graph **
|
||||
*******************/
|
||||
|
||||
Graph _graph { _env, _runtime_state, _storage._sculpt_partition };
|
||||
Popup _popup { };
|
||||
|
||||
Graph _graph { _env, _runtime_state, _storage._sculpt_partition,
|
||||
_popup.state, _deploy._children };
|
||||
|
||||
Child_state _runtime_view_state {
|
||||
"runtime_view", Ram_quota{8*1024*1024}, Cap_quota{200} };
|
||||
@ -387,18 +503,20 @@ struct Sculpt::Main : Input_event_handler,
|
||||
|
||||
Main(Env &env) : _env(env)
|
||||
{
|
||||
_manual_deploy_rom.sigh(_manual_deploy_handler);
|
||||
_runtime_state_rom.sigh(_runtime_state_handler);
|
||||
_nitpicker_displays.sigh(_nitpicker_displays_handler);
|
||||
|
||||
/*
|
||||
* Subscribe to reports
|
||||
*/
|
||||
_update_state_rom .sigh(_update_state_handler);
|
||||
_nitpicker_hover .sigh(_nitpicker_hover_handler);
|
||||
_hover_rom .sigh(_hover_handler);
|
||||
_pci_devices .sigh(_pci_devices_handler);
|
||||
_window_list .sigh(_window_list_handler);
|
||||
_decorator_margins.sigh(_decorator_margins_handler);
|
||||
_update_state_rom .sigh(_update_state_handler);
|
||||
_nitpicker_hover .sigh(_nitpicker_hover_handler);
|
||||
_hover_rom .sigh(_hover_handler);
|
||||
_pci_devices .sigh(_pci_devices_handler);
|
||||
_window_list .sigh(_window_list_handler);
|
||||
_decorator_margins .sigh(_decorator_margins_handler);
|
||||
_launcher_listing_rom.sigh(_launcher_listing_handler);
|
||||
|
||||
/*
|
||||
* Generate initial configurations
|
||||
@ -412,6 +530,11 @@ struct Sculpt::Main : Input_event_handler,
|
||||
_deploy.handle_deploy();
|
||||
_handle_pci_devices();
|
||||
|
||||
/*
|
||||
* Generate initial config/managed/deploy configuration
|
||||
*/
|
||||
_handle_manual_deploy();
|
||||
|
||||
generate_runtime_config();
|
||||
generate_dialog();
|
||||
}
|
||||
@ -449,10 +572,10 @@ void Sculpt::Main::_handle_window_layout()
|
||||
|
||||
Framebuffer::Mode const mode = _nitpicker->mode();
|
||||
|
||||
typedef Nitpicker::Rect Rect;
|
||||
typedef Nitpicker::Area Area;
|
||||
typedef Nitpicker::Point Point;
|
||||
/* area preserved for the menu */
|
||||
Rect const menu(Point(0, 0), Area(_gui.menu_width, mode.height()));
|
||||
|
||||
/* available space on the right of the menu */
|
||||
Rect avail(Point(_gui.menu_width, 0),
|
||||
Point(mode.width() - 1, mode.height() - 1));
|
||||
|
||||
@ -490,43 +613,68 @@ void Sculpt::Main::_handle_window_layout()
|
||||
_window_list.update();
|
||||
_window_layout.generate([&] (Xml_generator &xml) {
|
||||
|
||||
_window_list.xml().for_each_sub_node("window", [&] (Xml_node win) {
|
||||
Xml_node const window_list = _window_list.xml();
|
||||
|
||||
Label const label = win.attribute_value("label", Label());
|
||||
|
||||
/**
|
||||
* Generate window with 'rect' geometry if label matches 'match'
|
||||
*/
|
||||
auto gen_matching_window = [&] (Label const &match, Rect rect) {
|
||||
if (label == match && rect.valid()) {
|
||||
xml.node("window", [&] () {
|
||||
xml.attribute("id", win.attribute_value("id", 0UL));
|
||||
xml.attribute("xpos", rect.x1());
|
||||
xml.attribute("ypos", rect.y1());
|
||||
xml.attribute("width", rect.w());
|
||||
xml.attribute("height", rect.h());
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
gen_matching_window("log", Rect(log_p1, log_p2));
|
||||
|
||||
if (label == runtime_view_label) {
|
||||
|
||||
/* center runtime view within the available main (inspect) area */
|
||||
unsigned const inspect_w = inspect_p2.x() - inspect_p1.x(),
|
||||
inspect_h = inspect_p2.y() - inspect_p1.y();
|
||||
|
||||
Area const size(min(inspect_w, win.attribute_value("width", 0UL)),
|
||||
min(inspect_h, win.attribute_value("height", 0UL)));
|
||||
|
||||
Point const pos = Rect(inspect_p1, inspect_p2).center(size);
|
||||
|
||||
gen_matching_window(runtime_view_label, Rect(pos, size));
|
||||
auto gen_window = [&] (Xml_node win, Rect rect) {
|
||||
if (rect.valid()) {
|
||||
xml.node("window", [&] () {
|
||||
xml.attribute("id", win.attribute_value("id", 0UL));
|
||||
xml.attribute("xpos", rect.x1());
|
||||
xml.attribute("ypos", rect.y1());
|
||||
xml.attribute("width", rect.w());
|
||||
xml.attribute("height", rect.h());
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
if (_last_clicked == Hovered::STORAGE)
|
||||
gen_matching_window(inspect_label, Rect(inspect_p1, inspect_p2));
|
||||
auto win_size = [&] (Xml_node win) {
|
||||
|
||||
unsigned const inspect_w = inspect_p2.x() - inspect_p1.x(),
|
||||
inspect_h = inspect_p2.y() - inspect_p1.y();
|
||||
|
||||
return Area(min(inspect_w, win.attribute_value("width", 0UL)),
|
||||
min(inspect_h, win.attribute_value("height", 0UL)));
|
||||
};
|
||||
|
||||
_with_window(window_list, Label("gui -> menu -> "), [&] (Xml_node win) {
|
||||
gen_window(win, menu); });
|
||||
|
||||
/* calculate centered runtime view within the available main (inspect) area */
|
||||
Rect runtime_view;
|
||||
_with_window(window_list, runtime_view_label, [&] (Xml_node win) {
|
||||
Area const size = win_size(win);
|
||||
Point const pos = Rect(inspect_p1, inspect_p2).center(size);
|
||||
runtime_view = Rect(pos, size);
|
||||
});
|
||||
|
||||
if (_popup.state == Popup::VISIBLE) {
|
||||
_with_window(window_list, Label("gui -> popup -> "), [&] (Xml_node win) {
|
||||
Area const size = win_size(win);
|
||||
|
||||
int const anchor_y_center = (_popup.anchor.y1() + _popup.anchor.y2())/2;
|
||||
|
||||
int const x = runtime_view.x1() + _popup.anchor.x2();
|
||||
int const y = max(0, runtime_view.y1() + anchor_y_center - (int)size.h()/2);
|
||||
|
||||
gen_window(win, Rect(Point(x, y), size));
|
||||
});
|
||||
}
|
||||
|
||||
_with_window(window_list, Label("log"), [&] (Xml_node win) {
|
||||
gen_window(win, Rect(log_p1, log_p2)); });
|
||||
|
||||
if (_last_clicked == Hovered::STORAGE) {
|
||||
_with_window(window_list, inspect_label, [&] (Xml_node win) {
|
||||
gen_window(win, Rect(inspect_p1, inspect_p2)); });
|
||||
}
|
||||
|
||||
_with_window(window_list, runtime_view_label, [&] (Xml_node win) {
|
||||
|
||||
/* center runtime view within the available main (inspect) area */
|
||||
Area const size = win_size(win);
|
||||
Point const pos = Rect(inspect_p1, inspect_p2).center(size);
|
||||
|
||||
gen_window(win, Rect(pos, size));
|
||||
});
|
||||
});
|
||||
|
||||
|
102
repos/gems/src/app/sculpt_manager/model/launchers.h
Normal file
102
repos/gems/src/app/sculpt_manager/model/launchers.h
Normal file
@ -0,0 +1,102 @@
|
||||
/*
|
||||
* \brief Cached information about available launchers
|
||||
* \author Norman Feske
|
||||
* \date 2018-09-13
|
||||
*/
|
||||
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef _MODEL__LAUNCHERS_H_
|
||||
#define _MODEL__LAUNCHERS_H_
|
||||
|
||||
/* Genode includes */
|
||||
#include <util/list_model.h>
|
||||
#include <util/avl_tree.h>
|
||||
|
||||
/* local includes */
|
||||
#include <types.h>
|
||||
#include <runtime.h>
|
||||
|
||||
namespace Sculpt { class Launchers; }
|
||||
|
||||
|
||||
class Sculpt::Launchers : public Noncopyable
|
||||
{
|
||||
public:
|
||||
|
||||
struct Info : Noncopyable
|
||||
{
|
||||
Path const path;
|
||||
Info(Path const &path) : path(path) { }
|
||||
};
|
||||
|
||||
private:
|
||||
|
||||
Allocator &_alloc;
|
||||
|
||||
struct Launcher : Info, Avl_node<Launcher>, List_model<Launcher>::Element
|
||||
{
|
||||
Avl_tree<Launcher> &_avl_tree;
|
||||
|
||||
Launcher(Avl_tree<Launcher> &avl_tree, Path const &path)
|
||||
: Info(path), _avl_tree(avl_tree)
|
||||
{ _avl_tree.insert(this); }
|
||||
|
||||
~Launcher() { _avl_tree.remove(this); }
|
||||
|
||||
/**
|
||||
* Avl_node interface
|
||||
*/
|
||||
bool higher(Launcher *l) {
|
||||
return strcmp(l->path.string(), path.string()) > 0; }
|
||||
};
|
||||
|
||||
Avl_tree<Launcher> _sorted { };
|
||||
|
||||
List_model<Launcher> _launchers { };
|
||||
|
||||
struct Update_policy : List_model<Launcher>::Update_policy
|
||||
{
|
||||
Allocator &_alloc;
|
||||
|
||||
Avl_tree<Launcher> &_sorted;
|
||||
|
||||
Update_policy(Allocator &alloc, Avl_tree<Launcher> &sorted)
|
||||
: _alloc(alloc), _sorted(sorted) { }
|
||||
|
||||
void destroy_element(Launcher &elem) { destroy(_alloc, &elem); }
|
||||
|
||||
Launcher &create_element(Xml_node node)
|
||||
{
|
||||
return *new (_alloc)
|
||||
Launcher(_sorted, node.attribute_value("name", Path()));
|
||||
}
|
||||
|
||||
void update_element(Launcher &, Xml_node) { }
|
||||
|
||||
static bool element_matches_xml_node(Launcher const &elem, Xml_node node)
|
||||
{
|
||||
return node.attribute_value("name", Path()) == elem.path;
|
||||
}
|
||||
};
|
||||
|
||||
public:
|
||||
|
||||
Launchers(Allocator &alloc) : _alloc(alloc) { }
|
||||
|
||||
void update_from_xml(Xml_node node)
|
||||
{
|
||||
Update_policy policy(_alloc, _sorted);
|
||||
_launchers.update_from_xml(policy, node);
|
||||
}
|
||||
|
||||
template <typename FN>
|
||||
void for_each(FN const &fn) const { _sorted.for_each(fn); }
|
||||
};
|
||||
|
||||
#endif /* _MODEL__LAUNCHERS_H_ */
|
31
repos/gems/src/app/sculpt_manager/model/popup.h
Normal file
31
repos/gems/src/app/sculpt_manager/model/popup.h
Normal file
@ -0,0 +1,31 @@
|
||||
/*
|
||||
* \brief State of popup menu
|
||||
* \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.
|
||||
*/
|
||||
|
||||
#ifndef _MODEL__POPUP_H_
|
||||
#define _MODEL__POPUP_H_
|
||||
|
||||
#include "types.h"
|
||||
|
||||
namespace Sculpt { struct Popup; }
|
||||
|
||||
|
||||
struct Sculpt::Popup : Noncopyable
|
||||
{
|
||||
enum State { OFF, VISIBLE } state { OFF };
|
||||
|
||||
Rect anchor { };
|
||||
|
||||
void toggle() { state = (state == OFF) ? VISIBLE : OFF; }
|
||||
};
|
||||
|
||||
#endif /* _MODEL__POPUP_H_ */
|
@ -49,18 +49,47 @@ class Sculpt::Runtime_state : public Runtime_info
|
||||
|
||||
Info info { false, 0, 0, 0, 0 };
|
||||
|
||||
bool abandoned_by_user = false;
|
||||
|
||||
Child(Start_name const &name) : name(name) { }
|
||||
};
|
||||
|
||||
List_model<Child> _children { };
|
||||
|
||||
/**
|
||||
* Child present in initial deploy config but interactively removed
|
||||
*/
|
||||
struct Abandoned_child : Interface
|
||||
{
|
||||
Start_name const name;
|
||||
Abandoned_child(Start_name const &name) : name(name) { };
|
||||
};
|
||||
|
||||
Registry<Registered<Abandoned_child> > _abandoned_children { };
|
||||
|
||||
/**
|
||||
* Child that was interactively launched
|
||||
*/
|
||||
struct Launched_child : Interface
|
||||
{
|
||||
Start_name const name;
|
||||
Path const launcher;
|
||||
Launched_child(Start_name const &name, Path const &launcher)
|
||||
: name(name), launcher(launcher) { };
|
||||
};
|
||||
|
||||
Registry<Registered<Launched_child> > _launched_children { };
|
||||
|
||||
struct Update_policy : List_model<Child>::Update_policy
|
||||
{
|
||||
Allocator &_alloc;
|
||||
|
||||
Update_policy(Allocator &alloc) : _alloc(alloc) { }
|
||||
|
||||
void destroy_element(Child &elem) { destroy(_alloc, &elem); }
|
||||
void destroy_element(Child &elem)
|
||||
{
|
||||
destroy(_alloc, &elem);
|
||||
}
|
||||
|
||||
Child &create_element(Xml_node node)
|
||||
{
|
||||
@ -95,6 +124,8 @@ class Sculpt::Runtime_state : public Runtime_info
|
||||
|
||||
Runtime_state(Allocator &alloc) : _alloc(alloc) { }
|
||||
|
||||
~Runtime_state() { reset_abandoned_and_launched_children(); }
|
||||
|
||||
void update_from_state_report(Xml_node state)
|
||||
{
|
||||
Update_policy policy(_alloc);
|
||||
@ -113,6 +144,29 @@ class Sculpt::Runtime_state : public Runtime_info
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Runtime_info interface
|
||||
*/
|
||||
bool abandoned_by_user(Start_name const &name) const override
|
||||
{
|
||||
bool result = false;
|
||||
_abandoned_children.for_each([&] (Abandoned_child const &child) {
|
||||
if (!result && child.name == name)
|
||||
result = true; });
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Runtime_info interface
|
||||
*/
|
||||
void gen_launched_deploy_start_nodes(Xml_generator &xml) const override
|
||||
{
|
||||
_launched_children.for_each([&] (Launched_child const &child) {
|
||||
gen_named_node(xml, "start", child.name, [&] () {
|
||||
if (child.name != child.launcher)
|
||||
xml.attribute("launcher", child.launcher); }); });
|
||||
}
|
||||
|
||||
Info info(Start_name const &name) const
|
||||
{
|
||||
Info result { .selected = false, 0, 0, 0, 0 };
|
||||
@ -122,11 +176,57 @@ class Sculpt::Runtime_state : public Runtime_info
|
||||
return result;
|
||||
}
|
||||
|
||||
Start_name selected() const
|
||||
{
|
||||
Start_name result;
|
||||
_children.for_each([&] (Child const &child) {
|
||||
if (child.info.selected)
|
||||
result = child.name; });
|
||||
return result;
|
||||
}
|
||||
|
||||
void toggle_selection(Start_name const &name)
|
||||
{
|
||||
_children.for_each([&] (Child &child) {
|
||||
child.info.selected = (child.name == name) && !child.info.selected; });
|
||||
}
|
||||
|
||||
void abandon(Start_name const &name)
|
||||
{
|
||||
/*
|
||||
* If child was launched interactively, remove corresponding
|
||||
* entry from '_launched_children'.
|
||||
*/
|
||||
bool was_interactively_launched = false;
|
||||
_launched_children.for_each([&] (Launched_child &child) {
|
||||
if (child.name == name) {
|
||||
was_interactively_launched = true;
|
||||
destroy(_alloc, &child);
|
||||
}
|
||||
});
|
||||
|
||||
if (was_interactively_launched)
|
||||
return;
|
||||
|
||||
/*
|
||||
* Child was present at initial deploy config, mark as abandoned
|
||||
*/
|
||||
new (_alloc) Registered<Abandoned_child>(_abandoned_children, name);
|
||||
}
|
||||
|
||||
void launch(Start_name const &name, Path const &launcher)
|
||||
{
|
||||
new (_alloc) Registered<Launched_child>(_launched_children, name, launcher);
|
||||
}
|
||||
|
||||
void reset_abandoned_and_launched_children()
|
||||
{
|
||||
_abandoned_children.for_each([&] (Abandoned_child &child) {
|
||||
destroy(_alloc, &child); });
|
||||
|
||||
_launched_children.for_each([&] (Launched_child &child) {
|
||||
destroy(_alloc, &child); });
|
||||
}
|
||||
};
|
||||
|
||||
#endif /* _MODEL__RUNTIME_STATE_H_ */
|
||||
|
@ -224,5 +224,6 @@ void Sculpt::Network::gen_runtime_start_nodes(Xml_generator &xml) const
|
||||
|
||||
if (_nic_target.type() != Nic_target::OFF)
|
||||
xml.node("start", [&] () {
|
||||
gen_nic_router_start_content(xml, _nic_target); });
|
||||
gen_nic_router_start_content(xml, _nic_target,
|
||||
_use_nic_drv, _use_wifi_drv); });
|
||||
}
|
||||
|
@ -33,6 +33,10 @@ namespace Sculpt {
|
||||
* Return true if specified child is present in the runtime subsystem
|
||||
*/
|
||||
virtual bool present_in_runtime(Start_name const &) const = 0;
|
||||
|
||||
virtual bool abandoned_by_user(Start_name const &) const = 0;
|
||||
|
||||
virtual void gen_launched_deploy_start_nodes(Xml_generator &) const = 0;
|
||||
};
|
||||
|
||||
void gen_chroot_start_content(Xml_generator &, Start_name const &,
|
||||
@ -63,7 +67,7 @@ namespace Sculpt {
|
||||
void gen_nic_drv_start_content(Xml_generator &);
|
||||
void gen_wifi_drv_start_content(Xml_generator &);
|
||||
|
||||
void gen_nic_router_start_content(Xml_generator &, Nic_target const &);
|
||||
void gen_nic_router_start_content(Xml_generator &, Nic_target const &, bool, bool);
|
||||
void gen_nic_router_uplink(Xml_generator &, char const *);
|
||||
|
||||
struct Prepare_version { unsigned value; };
|
||||
|
@ -15,7 +15,9 @@
|
||||
|
||||
|
||||
void Sculpt::gen_nic_router_start_content(Xml_generator &xml,
|
||||
Nic_target const &nic_target)
|
||||
Nic_target const &nic_target,
|
||||
bool nic_drv_present,
|
||||
bool wifi_drv_present)
|
||||
{
|
||||
gen_common_start_content(xml, "nic_router",
|
||||
Cap_quota{300}, Ram_quota{10*1024*1024});
|
||||
@ -36,11 +38,13 @@ void Sculpt::gen_nic_router_start_content(Xml_generator &xml,
|
||||
* the NIC target.
|
||||
*/
|
||||
if (nic_target.wifi()) {
|
||||
gen_nic_route("wifi", "wifi_drv");
|
||||
gen_nic_route("wired", "nic_drv");
|
||||
} else {
|
||||
gen_nic_route("wired", "nic_drv");
|
||||
gen_nic_route("wifi", "wifi_drv");
|
||||
if (wifi_drv_present) gen_nic_route("wifi", "wifi_drv");
|
||||
if (nic_drv_present) gen_nic_route("wired", "nic_drv");
|
||||
}
|
||||
|
||||
if (nic_target.wired()) {
|
||||
if (nic_drv_present) gen_nic_route("wired", "nic_drv");
|
||||
if (wifi_drv_present) gen_nic_route("wifi", "wifi_drv");
|
||||
}
|
||||
|
||||
gen_parent_rom_route(xml, "nic_router");
|
||||
@ -52,5 +56,15 @@ void Sculpt::gen_nic_router_start_content(Xml_generator &xml,
|
||||
gen_parent_route<Log_session> (xml);
|
||||
gen_parent_route<Timer::Session> (xml);
|
||||
gen_parent_route<Report::Session> (xml);
|
||||
|
||||
/*
|
||||
* If the NIC target is set to local, we define the route to the
|
||||
* drivers down here be avoid presenting it as primary route in the
|
||||
* deploy graph.
|
||||
*/
|
||||
if (nic_target.local()) {
|
||||
if (nic_drv_present) gen_nic_route("wired", "nic_drv");
|
||||
if (wifi_drv_present) gen_nic_route("wifi", "wifi_drv");
|
||||
}
|
||||
});
|
||||
}
|
||||
|
@ -43,6 +43,8 @@ namespace Sculpt {
|
||||
typedef String<64> Label;
|
||||
|
||||
typedef Nitpicker::Point Point;
|
||||
typedef Nitpicker::Rect Rect;
|
||||
typedef Nitpicker::Area Area;
|
||||
|
||||
enum Writeable { WRITEABLE, READ_ONLY };
|
||||
}
|
||||
|
116
repos/gems/src/app/sculpt_manager/view/popup_dialog.h
Normal file
116
repos/gems/src/app/sculpt_manager/view/popup_dialog.h
Normal file
@ -0,0 +1,116 @@
|
||||
/*
|
||||
* \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.
|
||||
*/
|
||||
|
||||
#ifndef _VIEW__POPUP_DIALOG_H_
|
||||
#define _VIEW__POPUP_DIALOG_H_
|
||||
|
||||
#include <types.h>
|
||||
#include <model/launchers.h>
|
||||
#include <view/dialog.h>
|
||||
#include <view/selectable_item.h>
|
||||
|
||||
namespace Sculpt { struct Popup_dialog; }
|
||||
|
||||
|
||||
struct Sculpt::Popup_dialog
|
||||
{
|
||||
Env &_env;
|
||||
|
||||
Launchers const &_launchers;
|
||||
|
||||
Runtime_info const &_runtime_info;
|
||||
|
||||
Expanding_reporter _dialog_reporter { _env, "dialog", "popup_dialog" };
|
||||
|
||||
Attached_rom_dataspace _hover_rom { _env, "popup_view_hover" };
|
||||
|
||||
Signal_handler<Popup_dialog> _hover_handler {
|
||||
_env.ep(), *this, &Popup_dialog::_handle_hover };
|
||||
|
||||
Hoverable_item _item { };
|
||||
|
||||
bool _hovered = false;
|
||||
|
||||
void _handle_hover()
|
||||
{
|
||||
_hover_rom.update();
|
||||
|
||||
Xml_node const hover = _hover_rom.xml();
|
||||
|
||||
_hovered = hover.has_sub_node("dialog");
|
||||
|
||||
bool const changed = _item.match(hover, "dialog", "frame", "vbox", "hbox", "name");
|
||||
|
||||
if (changed)
|
||||
generate();
|
||||
}
|
||||
|
||||
bool hovered() const { return _hovered; };
|
||||
|
||||
void generate()
|
||||
{
|
||||
_dialog_reporter.generate([&] (Xml_generator &xml) {
|
||||
xml.node("frame", [&] () {
|
||||
xml.node("vbox", [&] () {
|
||||
|
||||
_launchers.for_each([&] (Launchers::Info const &info) {
|
||||
|
||||
/* allow each launcher to be used only once */
|
||||
if (_runtime_info.present_in_runtime(info.path))
|
||||
return;
|
||||
|
||||
gen_named_node(xml, "hbox", info.path, [&] () {
|
||||
|
||||
gen_named_node(xml, "float", "left", [&] () {
|
||||
xml.attribute("west", "yes");
|
||||
|
||||
xml.node("hbox", [&] () {
|
||||
gen_named_node(xml, "button", "button", [&] () {
|
||||
_item.gen_button_attr(xml, info.path);
|
||||
xml.node("label", [&] () {
|
||||
xml.attribute("text", " "); }); });
|
||||
gen_named_node(xml, "label", "name", [&] () {
|
||||
xml.attribute("text", Path(" ", info.path)); });
|
||||
});
|
||||
});
|
||||
|
||||
gen_named_node(xml, "hbox", "right", [&] () { });
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
struct Action : Interface
|
||||
{
|
||||
virtual void launch_global(Path const &launcher) = 0;
|
||||
};
|
||||
|
||||
void click(Action &action)
|
||||
{
|
||||
action.launch_global(_item._hovered);
|
||||
}
|
||||
|
||||
Popup_dialog(Env &env, Launchers const &launchers,
|
||||
Runtime_info const &runtime_info)
|
||||
:
|
||||
_env(env), _launchers(launchers), _runtime_info(runtime_info)
|
||||
{
|
||||
_hover_rom.sigh(_hover_handler);
|
||||
|
||||
generate();
|
||||
}
|
||||
};
|
||||
|
||||
#endif /* _VIEW__POPUP_DIALOG_H_ */
|
Loading…
x
Reference in New Issue
Block a user