From ee463b21ae03fb96659efc836d42c8edad361586 Mon Sep 17 00:00:00 2001 From: Norman Feske Date: Tue, 12 Oct 2021 16:00:48 +0200 Subject: [PATCH] nitpicker: fix interplay of hover with dragging This patch extends the notion of having only one uniquely hovered client in the presence of held keys. If motion occurs once a key is pressed (e.g., while dragging), the receiver of the key sequence observes the motion events. In this case, we have to submit an artificial leave event to the originally hovered client so that no more than one client observes itself as being hovered at the same time. Once the key sequence is finished, the hovering is updated again, eventually presenting a motion event to the originally hovered client and a leave event to the receiver of the key sequence. Issue #4176 --- repos/os/src/server/nitpicker/user_state.cc | 42 ++++++++++++++++----- repos/os/src/server/nitpicker/user_state.h | 5 +++ 2 files changed, 38 insertions(+), 9 deletions(-) diff --git a/repos/os/src/server/nitpicker/user_state.cc b/repos/os/src/server/nitpicker/user_state.cc index 1607d17a90..73f2a5d2a2 100644 --- a/repos/os/src/server/nitpicker/user_state.cc +++ b/repos/os/src/server/nitpicker/user_state.cc @@ -105,11 +105,9 @@ void User_state::_handle_input_event(Input::Event ev) ev.handle_absolute_motion([&] (int x, int y) { _pointer_pos = Point(x, y); }); - bool const drag = _key_cnt > 0; - /* count keys */ - if (ev.press()) _key_cnt++; - if (ev.release() && drag) _key_cnt--; + if (ev.press()) _key_cnt++; + if (ev.release() && (_key_cnt > 0)) _key_cnt--; /* track key states */ ev.handle_press([&] (Keycode key, Codepoint) { @@ -124,9 +122,25 @@ void User_state::_handle_input_event(Input::Event ev) _key_array.pressed(key, false); }); - if (ev.absolute_motion() || ev.relative_motion()) + if (ev.absolute_motion() || ev.relative_motion()) { update_hover(); + if (_key_cnt > 0) { + _drag = true; + + /* + * Submit leave event to the originally hovered client if motion + * occurs while a key is held. Otherwise, both the hovered client + * and the receiver of the key sequence would observe a motion + * event last, each appearing as being hovered at the same time. + */ + if (_hovered && (_input_receiver != _hovered)) { + _hovered->submit_input_event(Hover_leave()); + _hovered = nullptr; /* updated when _key_cnt reaches 0 */ + } + } + } + /* * Handle start of a key sequence */ @@ -252,11 +266,21 @@ void User_state::_handle_input_event(Input::Event ev) _input_receiver->submit_input_event(ev); /* - * Detect end of global key sequence + * Detect end of key sequence */ - if (ev.release() && (_key_cnt == 0) && _global_key_sequence) { - _input_receiver = _focused; - _global_key_sequence = false; + if (ev.release() && (_key_cnt == 0)) { + + update_hover(); + + if (_drag && _input_receiver && (_input_receiver != _hovered)) + _input_receiver->submit_input_event(Hover_leave()); + + _drag = false; + + if (_global_key_sequence) { + _input_receiver = _focused; + _global_key_sequence = false; + } } } diff --git a/repos/os/src/server/nitpicker/user_state.h b/repos/os/src/server/nitpicker/user_state.h index 7f5195b736..4880f6cc26 100644 --- a/repos/os/src/server/nitpicker/user_state.h +++ b/repos/os/src/server/nitpicker/user_state.h @@ -52,6 +52,11 @@ class Nitpicker::User_state */ bool _global_key_sequence = false; + /* + * True if motion events occur while a key is presse + */ + bool _drag = false; + /* * True if the input focus should change directly whenever the user * clicks on an unfocused client. This is the traditional behaviour