From 328a4fa6448f1ec5887fda483c0e6ceec4c818ad Mon Sep 17 00:00:00 2001 From: Norman Feske Date: Fri, 4 Sep 2020 13:46:52 +0200 Subject: [PATCH] nitpicker: update hovering on view-stack changes With the change of nitpicker to the event session interface, the formerly periodic hovering updates moved to the - now sporadic - input processing. This has the unfortunate side effect that hovering changes caused by non-user-input, in particular view-stack changes issued by the GUI clients that change the view under the current pointer position, would no longer be reported immediately but only after receiving the next incoming input event. This patch reworks the hover handling such that potential hovering changes due to view-stack operations are evaluated immediately by those operations, covering the update of the hover report and the generation of artificial enter/motion events. Issue #3812 --- repos/os/src/server/nitpicker/focus.h | 1 + repos/os/src/server/nitpicker/gui_session.cc | 5 ++ repos/os/src/server/nitpicker/gui_session.h | 5 +- repos/os/src/server/nitpicker/main.cc | 41 +++++++++++----- repos/os/src/server/nitpicker/user_state.cc | 51 +++++++++++--------- repos/os/src/server/nitpicker/user_state.h | 5 ++ 6 files changed, 73 insertions(+), 35 deletions(-) diff --git a/repos/os/src/server/nitpicker/focus.h b/repos/os/src/server/nitpicker/focus.h index 22eff0842e..6aad016bb9 100644 --- a/repos/os/src/server/nitpicker/focus.h +++ b/repos/os/src/server/nitpicker/focus.h @@ -20,6 +20,7 @@ namespace Nitpicker { struct Focus; struct Focus_updater : Interface { virtual void update_focus() = 0; }; + struct Hover_updater : Interface { virtual void update_hover() = 0; }; } diff --git a/repos/os/src/server/nitpicker/gui_session.cc b/repos/os/src/server/nitpicker/gui_session.cc index 85217edae5..5d51bfd21e 100644 --- a/repos/os/src/server/nitpicker/gui_session.cc +++ b/repos/os/src/server/nitpicker/gui_session.cc @@ -337,6 +337,8 @@ void Gui_session::destroy_view(View_handle handle) break; } } + + _hover_updater.update_hover(); } @@ -386,6 +388,7 @@ void Gui_session::execute() catch (View_handle_registry::Lookup_failed) { warning("view lookup failed during command execution"); } } + _hover_updater.update_hover(); } @@ -446,6 +449,8 @@ void Gui_session::session_control(Label suffix, Session_control control) _view_stack.to_front(Label(label(), suffix).string()); break; } + + _hover_updater.update_hover(); } diff --git a/repos/os/src/server/nitpicker/gui_session.h b/repos/os/src/server/nitpicker/gui_session.h index bac1fdb037..25c4cd3bae 100644 --- a/repos/os/src/server/nitpicker/gui_session.h +++ b/repos/os/src/server/nitpicker/gui_session.h @@ -104,6 +104,7 @@ class Nitpicker::Gui_session : public Session_object, View_stack &_view_stack; Focus_updater &_focus_updater; + Hover_updater &_hover_updater; Signal_context_capability _mode_sigh { }; @@ -174,6 +175,7 @@ class Nitpicker::Gui_session : public Session_object, Diag const &diag, View_stack &view_stack, Focus_updater &focus_updater, + Hover_updater &hover_updater, View &pointer_origin, View &builtin_background, bool provides_default_bg, @@ -185,7 +187,8 @@ class Nitpicker::Gui_session : public Session_object, _ram(env.ram(), _ram_quota_guard(), _cap_quota_guard()), _session_alloc(_ram, env.rm()), _framebuffer_session_component(view_stack, *this, *this), - _view_stack(view_stack), _focus_updater(focus_updater), + _view_stack(view_stack), + _focus_updater(focus_updater), _hover_updater(hover_updater), _pointer_origin(pointer_origin), _builtin_background(builtin_background), _framebuffer_session_cap(_env.ep().manage(_framebuffer_session_component)), diff --git a/repos/os/src/server/nitpicker/main.cc b/repos/os/src/server/nitpicker/main.cc index 558f99884b..3402b48705 100644 --- a/repos/os/src/server/nitpicker/main.cc +++ b/repos/os/src/server/nitpicker/main.cc @@ -83,6 +83,7 @@ class Nitpicker::Gui_root : public Root_component, Reporter &_focus_reporter; Reporter &_hover_reporter; Focus_updater &_focus_updater; + Hover_updater &_hover_updater; protected: @@ -95,8 +96,8 @@ class Nitpicker::Gui_root : public Root_component, Gui_session *session = new (md_alloc()) Gui_session(_env, session_resources_from_args(args), label, - session_diag_from_args(args), - _view_stack, _focus_updater, _pointer_origin, + session_diag_from_args(args), _view_stack, + _focus_updater, _hover_updater, _pointer_origin, _builtin_background, provides_default_bg, _focus_reporter, *this); @@ -104,6 +105,7 @@ class Nitpicker::Gui_root : public Root_component, _session_list.insert(session); _global_keys.apply_config(_config.xml(), _session_list); _focus_updater.update_focus(); + _hover_updater.update_hover(); return session; } @@ -128,11 +130,8 @@ class Nitpicker::Gui_root : public Root_component, Genode::destroy(md_alloc(), session); - /* report hover changes */ - if (_hover_reporter.enabled() && result.hover_changed) { - Reporter::Xml_generator xml(_hover_reporter, [&] () { - _user_state.report_hovered_view_owner(xml, false); }); - } + if (result.hover_changed) + _hover_updater.update_hover(); /* report focus changes */ if (_focus_reporter.enabled() && result.focus_changed) { @@ -158,7 +157,8 @@ class Nitpicker::Gui_root : public Root_component, Allocator &md_alloc, Reporter &focus_reporter, Reporter &hover_reporter, - Focus_updater &focus_updater) + Focus_updater &focus_updater, + Hover_updater &hover_updater) : Root_component(&env.ep().rpc_ep(), &md_alloc), _env(env), _config(config), _session_list(session_list), @@ -167,7 +167,7 @@ class Nitpicker::Gui_root : public Root_component, _pointer_origin(pointer_origin), _builtin_background(builtin_background), _focus_reporter(focus_reporter), _hover_reporter(hover_reporter), - _focus_updater(focus_updater) + _focus_updater(focus_updater), _hover_updater(hover_updater) { } @@ -343,7 +343,7 @@ class Nitpicker::Event_root : public Root_component }; -struct Nitpicker::Main : Focus_updater, +struct Nitpicker::Main : Focus_updater, Hover_updater, View_stack::Damage, Capture_session::Handler, Event_session::Handler @@ -467,12 +467,20 @@ struct Nitpicker::Main : Focus_updater, Gui_root _gui_root { _env, _config_rom, _session_list, *_domain_registry, _global_keys, _view_stack, _user_state, _pointer_origin, _builtin_background, _sliced_heap, - _focus_reporter, _hover_reporter, *this }; + _focus_reporter, _hover_reporter, *this, *this }; Capture_root _capture_root { _env, _sliced_heap, _view_stack, *this }; Event_root _event_root { _env, _sliced_heap, *this }; + void _generate_hover_report() + { + if (_hover_reporter.enabled()) { + Reporter::Xml_generator xml(_hover_reporter, [&] () { + _user_state.report_hovered_view_owner(xml, false); }); + } + } + /** * View_stack::Damage interface */ @@ -536,6 +544,17 @@ struct Nitpicker::Main : Focus_updater, */ void update_focus() override { _handle_focus(); } + /** + * Hover_updater interface + * + * Called whenever the view composition changes. + */ + void update_hover() override + { + if (_user_state.update_hover().hover_changed) + _generate_hover_report(); + } + /* * Configuration-update handler, executed in the context of the RPC * entrypoint. diff --git a/repos/os/src/server/nitpicker/user_state.cc b/repos/os/src/server/nitpicker/user_state.cc index 41741b1c3c..f681036887 100644 --- a/repos/os/src/server/nitpicker/user_state.cc +++ b/repos/os/src/server/nitpicker/user_state.cc @@ -124,23 +124,8 @@ void User_state::_handle_input_event(Input::Event ev) _key_array.pressed(key, false); }); - View const * const pointed_view = _view_stack.find_view(_pointer_pos); - - View_owner * const hovered = pointed_view ? &pointed_view->owner() : 0; - - /* - * Deliver a leave event if pointed-to session changed, notify newly - * hovered session about the current pointer position. - */ - if (hovered != _hovered) { - if (_hovered) - _hovered->submit_input_event(Hover_leave()); - - if (hovered && _key_cnt == 0) - hovered->submit_input_event(Absolute_motion{_pointer_pos.x(), - _pointer_pos.y()}); - _hovered = hovered; - } + if (ev.absolute_motion() || ev.relative_motion()) + update_hover(); /* * Handle start of a key sequence @@ -411,17 +396,13 @@ User_state::Handle_forget_result User_state::forget(View_owner const &owner) _focus.forget(owner); bool const need_to_update_all_views = (&owner == _focused); - bool const hover_changed = &owner == _hovered; bool const focus_changed = &owner == _focused; if (&owner == _focused) _focused = nullptr; if (&owner == _next_focused) _next_focused = nullptr; if (&owner == _last_clicked) _last_clicked = nullptr; - if (_hovered == &owner) { - View * const pointed_view = _view_stack.find_view(_pointer_pos); - _hovered = pointed_view ? &pointed_view->owner() : nullptr; - } + Update_hover_result const update_hover_result = update_hover(); if (_input_receiver == &owner) _input_receiver = nullptr; @@ -430,12 +411,36 @@ User_state::Handle_forget_result User_state::forget(View_owner const &owner) _view_stack.update_all_views(); return { - .hover_changed = hover_changed, + .hover_changed = update_hover_result.hover_changed, .focus_changed = focus_changed, }; } +User_state::Update_hover_result User_state::update_hover() +{ + View_owner * const old_hovered = _hovered; + View const * const pointed_view = _view_stack.find_view(_pointer_pos); + + _hovered = pointed_view ? &pointed_view->owner() : nullptr; + + /* + * Deliver a leave event if pointed-to session changed, notify newly + * hovered session about the current pointer position. + */ + if (old_hovered != _hovered) { + if (old_hovered) + old_hovered->submit_input_event(Hover_leave()); + + if (_hovered && _key_cnt == 0) + _hovered->submit_input_event(Absolute_motion{_pointer_pos.x(), + _pointer_pos.y()}); + } + + return { .hover_changed = (_hovered != old_hovered) }; +} + + void User_state::_focus_view_owner_via_click(View_owner &owner) { _next_focused = &owner; diff --git a/repos/os/src/server/nitpicker/user_state.h b/repos/os/src/server/nitpicker/user_state.h index e0873c09b2..a462cf4b69 100644 --- a/repos/os/src/server/nitpicker/user_state.h +++ b/repos/os/src/server/nitpicker/user_state.h @@ -252,8 +252,13 @@ class Nitpicker::User_state bool const hover_changed; bool const focus_changed; }; + Handle_forget_result forget(View_owner const &); + struct Update_hover_result { bool const hover_changed; }; + + Update_hover_result update_hover(); + void report_keystate(Xml_generator &) const; void report_pointer_position(Xml_generator &) const; void report_hovered_view_owner(Xml_generator &, bool motion_active) const;