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) {