From 014e800e8ac5687b19f9061da87935c5495a7ffe Mon Sep 17 00:00:00 2001 From: Norman Feske Date: Wed, 6 Mar 2019 10:20:22 +0100 Subject: [PATCH] menu view: immediate hover update on dialog change This patch improves the hover handling in situations where the dialog changes under the pointer. Previously, hover changes were reported as response to user input only, which failed to cover this case. This became a problem with Sculpt CE's '+' menu, which changes on the fly when entering/leaving sub menus. The patch also cleanly separates the hover handling from the focus handling. Originally, the hovering was reset when the menu view got unfocused. In situations like Sculpt's '+' menu where the menu view receives a transient focus only while clicked and gets unfocused on the button-release event (aka clack), each clack would invalidate the hover information until a new input event comes in. Finally, the patch introduces the clear distinction between situations where the entire dialog is hovered or not. Previously, this state was somehow implicitly kept by issuing an invalid hover report whenever a leave event was observed. Issue #3209 --- repos/gems/src/app/menu_view/main.cc | 75 ++++++++++++++++++++-------- 1 file changed, 53 insertions(+), 22 deletions(-) diff --git a/repos/gems/src/app/menu_view/main.cc b/repos/gems/src/app/menu_view/main.cc index 9ceb4cb0ae..40c2c5604a 100644 --- a/repos/gems/src/app/menu_view/main.cc +++ b/repos/gems/src/app/menu_view/main.cc @@ -43,8 +43,19 @@ struct Menu_view::Main Nitpicker::Session::View_handle _view_handle = _nitpicker.create_view(); + /** + * Dialog position in screen coordinate space + */ Point _position { }; + /** + * Last pointer position at the time of the most recent hovering report, + * in screen coordinate space. + */ + Point _hovered_position { }; + + bool _dialog_hovered = false; + Area _configured_size { }; Area _visible_size { }; @@ -120,7 +131,7 @@ struct Menu_view::Main Attached_dataspace _input_ds { _env.rm(), _nitpicker.input()->dataspace() }; - Widget::Unique_id _hovered { }; + Widget::Unique_id _last_reported_hovered { }; void _handle_config(); @@ -154,6 +165,8 @@ struct Menu_view::Main Genode::Reporter _hover_reporter = { _env, "hover" }; + void _update_hover_report(); + bool _schedule_redraw = false; /** @@ -190,6 +203,28 @@ struct Menu_view::Main }; +void Menu_view::Main::_update_hover_report() +{ + if (!_hover_reporter.enabled()) + return; + + if (!_dialog_hovered) { + Genode::Reporter::Xml_generator xml(_hover_reporter, [&] () { }); + return; + } + + Widget::Unique_id const new_hovered = _root_widget.hovered(_hovered_position); + + if (_last_reported_hovered != new_hovered) { + + Genode::Reporter::Xml_generator xml(_hover_reporter, [&] () { + _root_widget.gen_hover_model(xml, _hovered_position); }); + + _last_reported_hovered = new_hovered; + } +} + + void Menu_view::Main::_handle_dialog_update() { try { @@ -204,12 +239,15 @@ void Menu_view::Main::_handle_dialog_update() _dialog_rom.update(); Xml_node dialog = _dialog_rom.xml(); + if (dialog.has_type("empty")) return; _root_widget.update(dialog); _root_widget.size(_root_widget_size()); + _update_hover_report(); + _schedule_redraw = true; /* @@ -247,35 +285,29 @@ void Menu_view::Main::_handle_config() void Menu_view::Main::_handle_input() { + Point const orig_hovered_position = _hovered_position; + bool const orig_dialog_hovered = _dialog_hovered; + _nitpicker.input()->for_each_event([&] (Input::Event const &ev) { ev.handle_absolute_motion([&] (int x, int y) { - - Point const at = Point(x, y) - _position; - Widget::Unique_id const new_hovered = _root_widget.hovered(at); - - if (_hovered != new_hovered) { - - if (_hover_reporter.enabled()) { - Genode::Reporter::Xml_generator xml(_hover_reporter, [&] () { - _root_widget.gen_hover_model(xml, at); - }); - } - - _hovered = new_hovered; - } + _dialog_hovered = true; + _hovered_position = Point(x, y) - _position; }); /* * Reset hover model when losing the focus */ - if (ev.focus_leave() || ev.hover_leave()) { - _hovered = Widget::Unique_id(); - - if (_hover_reporter.enabled()) { - Genode::Reporter::Xml_generator xml(_hover_reporter, [&] () { }); - } + if (ev.hover_leave()) { + _dialog_hovered = false; + _hovered_position = Point(); } }); + + bool const hover_changed = orig_dialog_hovered != _dialog_hovered + || orig_hovered_position != _hovered_position; + + if (hover_changed) + _update_hover_report(); } @@ -319,7 +351,6 @@ void Menu_view::Main::_handle_frame_timer() else _buffer->reset_surface(); - _root_widget.size(size); _root_widget.position(Point(0, 0)); // XXX restrict redraw to dirty regions