diff --git a/repos/gems/sculpt/leitzentrale/default b/repos/gems/sculpt/leitzentrale/default
index 1b49dbb316..673f342fbb 100644
--- a/repos/gems/sculpt/leitzentrale/default
+++ b/repos/gems/sculpt/leitzentrale/default
@@ -91,6 +91,7 @@
+
@@ -114,6 +115,7 @@
+
@@ -240,9 +242,10 @@
-
-
+
+
+
diff --git a/repos/gems/src/app/sculpt_manager/gui.cc b/repos/gems/src/app/sculpt_manager/gui.cc
index 6be2d8df44..dbf75b5bb3 100644
--- a/repos/gems/src/app/sculpt_manager/gui.cc
+++ b/repos/gems/src/app/sculpt_manager/gui.cc
@@ -24,6 +24,8 @@ struct Gui::Session_component : Rpc_object
Input_event_handler &_event_handler;
+ Input::Seq_number &_global_input_seq_number;
+
Gui::Connection _connection;
Input::Session_component _input_component { _env, _env.ram() };
@@ -35,16 +37,28 @@ struct Gui::Session_component : Rpc_object
{
_connection.input()->for_each_event([&] (Input::Event ev) {
- /* handle event locally within the sculpt manager */
+ /*
+ * Augment input stream with sequence numbers to correlate
+ * clicks with hover reports.
+ */
+ if (ev.key_press(Input::BTN_LEFT) || ev.key_release(Input::BTN_LEFT)) {
+ _global_input_seq_number.value++;
+ _input_component.submit(_global_input_seq_number);
+ }
+
+ /* handle event locally within the sculpt manager */
_event_handler.handle_input_event(ev);
_input_component.submit(ev);
});
}
- Session_component(Env &env, char const *args, Input_event_handler &event_handler)
+ Session_component(Env &env, char const *args,
+ Input_event_handler &event_handler,
+ Input::Seq_number &global_input_seq_number)
:
_env(env), _event_handler(event_handler),
+ _global_input_seq_number(global_input_seq_number),
_connection(env, session_label_from_args(args).string())
{
_connection.input()->sigh(_input_handler);
@@ -108,7 +122,8 @@ struct Gui::Session_component : Rpc_object
Gui::Session_component *Gui::Root::_create_session(const char *args)
{
- return new (md_alloc()) Session_component(_env, args, _event_handler);
+ return new (md_alloc()) Session_component(_env, args, _event_handler,
+ _global_input_seq_number);
}
@@ -124,10 +139,13 @@ void Gui::Root::_destroy_session(Session_component *session)
}
-Gui::Root::Root(Env &env, Allocator &md_alloc, Input_event_handler &event_handler)
+Gui::Root::Root(Env &env, Allocator &md_alloc,
+ Input_event_handler &event_handler,
+ Input::Seq_number &global_input_seq_number)
:
Root_component(env.ep(), md_alloc),
- _env(env), _event_handler(event_handler)
+ _env(env), _event_handler(event_handler),
+ _global_input_seq_number(global_input_seq_number)
{
env.parent().announce(env.ep().manage(*this));
}
diff --git a/repos/gems/src/app/sculpt_manager/gui.h b/repos/gems/src/app/sculpt_manager/gui.h
index 5d13b1ec2a..c38ebefb2a 100644
--- a/repos/gems/src/app/sculpt_manager/gui.h
+++ b/repos/gems/src/app/sculpt_manager/gui.h
@@ -36,12 +36,13 @@ struct Gui::Root : Genode::Root_component
{
Env &_env;
Input_event_handler &_event_handler;
+ Input::Seq_number &_global_input_seq_number;
Session_component *_create_session(const char *) override;
void _upgrade_session(Session_component *, const char *) override;
void _destroy_session(Session_component *) override;
- Root(Env &, Allocator &, Input_event_handler &);
+ Root(Env &, Allocator &, Input_event_handler &, Input::Seq_number &);
~Root();
};
diff --git a/repos/gems/src/app/sculpt_manager/main.cc b/repos/gems/src/app/sculpt_manager/main.cc
index 03f6047afd..c2bae02eaa 100644
--- a/repos/gems/src/app/sculpt_manager/main.cc
+++ b/repos/gems/src/app/sculpt_manager/main.cc
@@ -62,7 +62,8 @@ struct Sculpt::Main : Input_event_handler,
Depot_query,
Panel_dialog::State,
Dialog,
- Popup_dialog::Refresh
+ Popup_dialog::Refresh,
+ Menu_view::Hover_update_handler
{
Env &_env;
@@ -72,11 +73,13 @@ struct Sculpt::Main : Input_event_handler,
Registry _child_states { };
+ Input::Seq_number _global_input_seq_number { };
+
Gui::Connection _gui { _env, "input" };
bool _gui_mode_ready = false; /* becomes true once the graphics driver is up */
- Gui::Root _gui_root { _env, _heap, *this };
+ Gui::Root _gui_root { _env, _heap, *this, _global_input_seq_number };
Signal_handler _input_handler {
_env.ep(), *this, &Main::_handle_input };
@@ -209,7 +212,7 @@ struct Sculpt::Main : Input_event_handler,
}
- Network _network { _env, _heap, _child_states, *this, _runtime_state, _pci_info };
+ Network _network { _env, _heap, _child_states, *this, *this, _runtime_state, _pci_info };
/************
@@ -546,8 +549,137 @@ struct Sculpt::Main : Input_event_handler,
** Interactive operations **
****************************/
+ /*
+ * Track nitpicker's "clicked" report to reliably detect clicks outside
+ * any menu view (closing the popup window).
+ */
+
+ Attached_rom_dataspace _clicked_rom { _env, "clicked" };
+
+ Signal_handler _clicked_handler {
+ _env.ep(), *this, &Main::_handle_clicked };
+
+ void _handle_clicked()
+ {
+ _clicked_rom.update();
+ _try_handle_click();
+ }
+
Keyboard_focus _keyboard_focus { _env, _network.dialog, _network.wpa_passphrase, *this };
+ Constructible _clicked_seq_number { };
+ Constructible _clacked_seq_number { };
+
+ void _try_handle_click()
+ {
+ if (!_clicked_seq_number.constructed())
+ return;
+
+ Input::Seq_number const seq = *_clicked_seq_number;
+
+ auto click_outside_popup = [&] ()
+ {
+ Xml_node const clicked = _clicked_rom.xml();
+
+ if (!clicked.has_attribute("seq"))
+ return false;
+
+ if (clicked.attribute_value("seq", 0u) != seq.value)
+ return false;
+
+ Label const popup_label { "wm -> runtime -> leitzentrale -> popup_view" };
+
+ if (clicked.attribute_value("label", Label()) == popup_label)
+ return false;
+
+ return true;
+ };
+
+ /* remove popup dialog when clicking somewhere outside */
+ if (click_outside_popup() && _popup.state == Popup::VISIBLE
+ && !_graph.add_button_hovered()) {
+
+ _popup.state = Popup::OFF;
+ _popup_dialog.reset();
+ discard_construction();
+
+ /* de-select '+' button */
+ _graph_menu_view.generate();
+
+ /* remove popup window from window layout */
+ _handle_window_layout();
+ }
+
+ if (_main_menu_view.hovered(seq)) {
+ _main_menu_view.generate();
+ _clicked_seq_number.destruct();
+ }
+ else if (_graph_menu_view.hovered(seq)) {
+ _graph.click(*this);
+ _graph_menu_view.generate();
+ _clicked_seq_number.destruct();
+ }
+ else if (_popup_menu_view.hovered(seq)) {
+ _popup_dialog.click(*this);
+ _popup_menu_view.generate();
+ _clicked_seq_number.destruct();
+ }
+ else if (_panel_menu_view.hovered(seq)) {
+ _panel_dialog.click(*this);
+ _clicked_seq_number.destruct();
+ }
+ else if (_settings_menu_view.hovered(seq)) {
+ _settings_dialog.click(*this);
+ _settings_menu_view.generate();
+ _clicked_seq_number.destruct();
+ }
+ else if (_network.dialog_hovered(seq)) {
+ _network.dialog.click(_network);
+ _network.update_view();
+ _clicked_seq_number.destruct();
+ }
+ else if (_file_browser_menu_view.hovered(seq)) {
+ _file_browser_dialog.click(*this);
+ _file_browser_menu_view.generate();
+ _clicked_seq_number.destruct();
+ }
+ }
+
+ void _try_handle_clack()
+ {
+ if (!_clacked_seq_number.constructed())
+ return;
+
+ Input::Seq_number const seq = *_clacked_seq_number;
+
+ if (_main_menu_view.hovered(seq)) {
+ _storage.dialog.clack(_storage);
+ _main_menu_view.generate();
+ _clacked_seq_number.destruct();
+ }
+ else if (_graph_menu_view.hovered(seq)) {
+ _graph.clack(*this, _storage);
+ _graph_menu_view.generate();
+ _clacked_seq_number.destruct();
+ }
+ else if (_popup_menu_view.hovered(seq)) {
+ _popup_dialog.clack(*this);
+ _clacked_seq_number.destruct();
+ }
+ }
+
+ /**
+ * Menu_view::Hover_update_handler interface
+ */
+ void menu_view_hover_updated() override
+ {
+ if (_clicked_seq_number.constructed())
+ _try_handle_click();
+
+ if (_clacked_seq_number.constructed())
+ _try_handle_clack();
+ }
+
/**
* Input_event_handler interface
*/
@@ -556,60 +688,13 @@ struct Sculpt::Main : Input_event_handler,
bool need_generate_dialog = false;
if (ev.key_press(Input::BTN_LEFT)) {
-
- /* remove popup dialog when clicking somewhere outside */
- if (!_popup_menu_view.hovered() && _popup.state == Popup::VISIBLE
- && !_graph.add_button_hovered()) {
-
- _popup.state = Popup::OFF;
- _popup_dialog.reset();
- discard_construction();
-
- /* de-select '+' button */
- _graph_menu_view.generate();
-
- /* remove popup window from window layout */
- _handle_window_layout();
- }
-
- if (_main_menu_view.hovered()) {
- _main_menu_view.generate();
- }
- else if (_graph_menu_view.hovered()) {
- _graph.click(*this);
- _graph_menu_view.generate();
- }
- else if (_popup_menu_view.hovered()) {
- _popup_dialog.click(*this);
- _popup_menu_view.generate();
- }
- else if (_panel_menu_view.hovered()) {
- _panel_dialog.click(*this);
- }
- else if (_settings_menu_view.hovered()) {
- _settings_dialog.click(*this);
- _settings_menu_view.generate();
- }
- else if (_network.dialog_hovered()) {
- _network.dialog.click(_network);
- _network.update_view();
- }
- else if (_file_browser_menu_view.hovered()) {
- _file_browser_dialog.click(*this);
- _file_browser_menu_view.generate();
- }
+ _clicked_seq_number.construct(_global_input_seq_number);
+ _try_handle_click();
}
if (ev.key_release(Input::BTN_LEFT)) {
- if (_main_menu_view.hovered()) {
- _storage.dialog.clack(_storage);
- _main_menu_view.generate();
- }
- else if (_graph_menu_view.hovered()) {
- _graph.clack(*this, _storage);
- _graph_menu_view.generate();
- }
- else if (_popup_menu_view.hovered()) _popup_dialog.clack(*this);
+ _clacked_seq_number.construct(_global_input_seq_number);
+ _try_handle_clack();
}
if (_keyboard_focus.target == Keyboard_focus::WPA_PASSPHRASE)
@@ -1021,17 +1106,17 @@ struct Sculpt::Main : Input_event_handler,
Menu_view _panel_menu_view { _env, _child_states, _panel_dialog, "panel_view",
Ram_quota{4*1024*1024}, Cap_quota{150},
- "panel_dialog", "panel_view_hover" };
+ "panel_dialog", "panel_view_hover", *this };
Settings_dialog _settings_dialog { _settings };
Menu_view _settings_menu_view { _env, _child_states, _settings_dialog, "settings_view",
Ram_quota{4*1024*1024}, Cap_quota{150},
- "settings_dialog", "settings_view_hover" };
+ "settings_dialog", "settings_view_hover", *this };
Menu_view _main_menu_view { _env, _child_states, *this, "menu_view",
Ram_quota{4*1024*1024}, Cap_quota{150},
- "menu_dialog", "menu_view_hover" };
+ "menu_dialog", "menu_view_hover", *this };
Popup_dialog _popup_dialog { _env, *this, _launchers,
_network._nic_state, _network._nic_target,
@@ -1040,13 +1125,13 @@ struct Sculpt::Main : Input_event_handler,
Menu_view _popup_menu_view { _env, _child_states, _popup_dialog, "popup_view",
Ram_quota{4*1024*1024}, Cap_quota{150},
- "popup_dialog", "popup_view_hover" };
+ "popup_dialog", "popup_view_hover", *this };
File_browser_dialog _file_browser_dialog { _cached_runtime_config, _file_browser_state };
Menu_view _file_browser_menu_view { _env, _child_states, _file_browser_dialog, "file_browser_view",
Ram_quota{8*1024*1024}, Cap_quota{150},
- "file_browser_dialog", "file_browser_view_hover" };
+ "file_browser_dialog", "file_browser_view_hover", *this };
/**
* Popup_dialog::Refresh interface
@@ -1098,7 +1183,7 @@ struct Sculpt::Main : Input_event_handler,
Menu_view _graph_menu_view { _env, _child_states, _graph, "runtime_view",
Ram_quota{8*1024*1024}, Cap_quota{200},
- "runtime_dialog", "runtime_view_hover" };
+ "runtime_dialog", "runtime_view_hover", *this };
Main(Env &env) : _env(env)
{
_manual_deploy_rom.sigh(_manual_deploy_handler);
@@ -1117,6 +1202,7 @@ struct Sculpt::Main : Input_event_handler,
_launcher_listing_rom.sigh(_launcher_listing_handler);
_blueprint_rom .sigh(_blueprint_handler);
_editor_saved_rom .sigh(_editor_saved_handler);
+ _clicked_rom .sigh(_clicked_handler);
/*
* Generate initial configurations
@@ -1132,6 +1218,7 @@ struct Sculpt::Main : Input_event_handler,
_deploy.handle_deploy();
_handle_pci_devices();
_handle_runtime_config();
+ _handle_clicked();
/*
* Read static platform information
@@ -1849,6 +1936,9 @@ void Sculpt::Main::_generate_event_filter_config(Xml_generator &xml)
});
});
+ xml.node("touch-click", [&] () {
+ gen_input("touch"); });
+
gen_input("usb");
gen_input("touch");
gen_input("sdl");
diff --git a/repos/gems/src/app/sculpt_manager/menu_view.cc b/repos/gems/src/app/sculpt_manager/menu_view.cc
index d774a19dad..8bf0df6ab5 100644
--- a/repos/gems/src/app/sculpt_manager/menu_view.cc
+++ b/repos/gems/src/app/sculpt_manager/menu_view.cc
@@ -28,7 +28,14 @@ void Menu_view::_handle_hover()
Hover_result hover_result = Hover_result::UNMODIFIED;
- _hover_rom.xml().with_sub_node("dialog", [&] (Xml_node hover) {
+ Xml_node hover = _hover_rom.xml();
+
+ if (hover.has_attribute("seq_number")) {
+ Input::Seq_number const seq { hover.attribute_value("seq_number", 0U) };
+ _seq_number.construct(seq);
+ }
+
+ hover.with_sub_node("dialog", [&] (Xml_node hover) {
_hovered = true;
hover_result = _dialog.hover(hover);
});
@@ -41,6 +48,9 @@ void Menu_view::_handle_hover()
if (dialog_hover_changed || widget_hover_changed)
generate();
+
+ /* trigger handling of pending click/clack actions */
+ _hover_update_handler.menu_view_hover_updated();
}
@@ -48,9 +58,11 @@ Menu_view::Menu_view(Env &env, Registry ®istry,
Dialog &dialog, Start_name const &name,
Ram_quota ram_quota, Cap_quota cap_quota,
Session_label const &dialog_report_name,
- Session_label const &hover_rom_name)
+ Session_label const &hover_rom_name,
+ Hover_update_handler &hover_update_handler)
:
_dialog(dialog),
+ _hover_update_handler(hover_update_handler),
_child_state(registry, name, Priority::LEITZENTRALE, ram_quota, cap_quota),
_dialog_reporter(env, "dialog", dialog_report_name.string()),
_hover_rom(env, hover_rom_name.string()),
diff --git a/repos/gems/src/app/sculpt_manager/menu_view.h b/repos/gems/src/app/sculpt_manager/menu_view.h
index b743835125..6e9b8f8ea0 100644
--- a/repos/gems/src/app/sculpt_manager/menu_view.h
+++ b/repos/gems/src/app/sculpt_manager/menu_view.h
@@ -29,8 +29,15 @@ namespace Sculpt { struct Menu_view; }
struct Sculpt::Menu_view : Noncopyable
{
+ struct Hover_update_handler : Interface, Noncopyable
+ {
+ virtual void menu_view_hover_updated() = 0;
+ };
+
Dialog &_dialog;
+ Hover_update_handler &_hover_update_handler;
+
Child_state _child_state;
Expanding_reporter _dialog_reporter;
@@ -41,6 +48,8 @@ struct Sculpt::Menu_view : Noncopyable
bool _hovered = false;
+ Constructible _seq_number { };
+
unsigned min_width = 0;
unsigned min_height = 0;
@@ -51,11 +60,18 @@ struct Sculpt::Menu_view : Noncopyable
Menu_view(Env &, Registry ®istry,
Dialog &, Start_name const &, Ram_quota, Cap_quota,
Session_label const &dialog_report_name,
- Session_label const &hover_rom_name);
+ Session_label const &hover_rom_name,
+ Hover_update_handler &);
void generate();
- bool hovered() const { return _hovered; }
+ bool hovered(Input::Seq_number const &seq_number) const
+ {
+ if (!_seq_number.constructed() || !_hovered)
+ return false;
+
+ return (_seq_number->value >= seq_number.value);
+ }
void reset();
diff --git a/repos/gems/src/app/sculpt_manager/network.h b/repos/gems/src/app/sculpt_manager/network.h
index 0f2585a4a8..1eb41732e3 100644
--- a/repos/gems/src/app/sculpt_manager/network.h
+++ b/repos/gems/src/app/sculpt_manager/network.h
@@ -37,6 +37,8 @@ struct Sculpt::Network : Network_dialog::Action
Registry &_child_states;
+ Menu_view::Hover_update_handler &_hover_update_handler;
+
Runtime_config_generator &_runtime_config_generator;
Runtime_info const &_runtime_info;
@@ -103,11 +105,12 @@ struct Sculpt::Network : Network_dialog::Action
Menu_view _menu_view { _env, _child_states, dialog, "network_view",
Ram_quota{4*1024*1024}, Cap_quota{150},
- "network_dialog", "network_view_hover" };
+ "network_dialog", "network_view_hover",
+ _hover_update_handler };
void min_dialog_width(unsigned value) { _menu_view.min_width = value; }
- bool dialog_hovered() const { return _menu_view.hovered(); }
+ bool dialog_hovered(Input::Seq_number seq) const { return _menu_view.hovered(seq); }
void update_view() { _menu_view.generate(); }
@@ -223,10 +226,12 @@ struct Sculpt::Network : Network_dialog::Action
}
Network(Env &env, Allocator &alloc, Registry &child_states,
+ Menu_view::Hover_update_handler &hover_update_handler,
Runtime_config_generator &runtime_config_generator,
Runtime_info const &runtime_info, Pci_info const &pci_info)
:
_env(env), _alloc(alloc), _child_states(child_states),
+ _hover_update_handler(hover_update_handler),
_runtime_config_generator(runtime_config_generator),
_runtime_info(runtime_info), _pci_info(pci_info)
{