nitpicker: add version attribute in clicked report

This patch addresses a corner case where the nitpicker focus is not
solely defined by mouse clicks or (exclusively) by a window manager, but
by a policy component that takes mouse clicks and other policy (e.g.,
a lock screen) into account. It ensures that each click that follows a
focus change (however initiated) results in a new "clicked" report even
when the report looks the same. To allow the policy component to
uniquely distiguish subsequent reports, the report features a new
'version' attribute.

Fixes #3493
This commit is contained in:
Norman Feske 2019-09-12 12:37:19 +02:00
parent 972e1893c9
commit 4622ddb46f
2 changed files with 52 additions and 1 deletions

View File

@ -152,6 +152,9 @@ void User_state::_handle_input_event(Input::Event ev)
View_owner *global_receiver = nullptr;
if (_mouse_button(keycode))
_clicked_count++;
/* update focused session */
if (_mouse_button(keycode)
&& _hovered
@ -282,6 +285,7 @@ User_state::handle_input_events(Input::Event const * const ev_buf,
View_owner const * const old_focused = _focused;
View_owner const * const old_input_receiver = _input_receiver;
View_owner const * const old_last_clicked = _last_clicked;
unsigned const old_clicked_count = _clicked_count;
bool button_activity = false;
@ -333,6 +337,21 @@ User_state::handle_input_events(Input::Event const * const ev_buf,
_apply_pending_focus_change();
/*
* Determine condition for generating an updated "clicked" report
*/
bool const click_occurred = (old_clicked_count != _clicked_count);
bool const clicked_report_up_to_date =
(_last_clicked == old_last_clicked) && !_last_clicked_redeliver;
bool const last_clicked_changed = (click_occurred && !clicked_report_up_to_date);
if (last_clicked_changed) {
_last_clicked_version++;
_last_clicked_redeliver = false;
}
return {
.hover_changed = _hovered != old_hovered,
.focus_changed = (_focused != old_focused) ||
@ -341,7 +360,7 @@ User_state::handle_input_events(Input::Event const * const ev_buf,
.button_activity = button_activity,
.motion_activity = (_pointer_pos != old_pointer_pos),
.key_pressed = _key_pressed(),
.last_clicked_changed = (_last_clicked != old_last_clicked)
.last_clicked_changed = last_clicked_changed
};
}
@ -383,6 +402,8 @@ void User_state::report_last_clicked_view_owner(Xml_generator &xml) const
{
if (_last_clicked)
_last_clicked->report(xml);
xml.attribute("version", _last_clicked_version);
}

View File

@ -95,6 +95,28 @@ class Nitpicker::User_state
*/
View_owner *_last_clicked = nullptr;
/**
* Number of clicks, used to detect whether a focus-relevant click
* happened during '_handle_input_event'.
*/
unsigned _clicked_count = 0;
/**
* Version supplement for the "clicked" report
*
* The value allows the receiver of the report to detect the situation
* where two consecutive clicks refer to the same client but both
* events require a distinct focus response, i.e., if the focus (focus
* ROM) was changed in-between both clicks by other means than a click.
*/
unsigned _last_clicked_version = 0;
/*
* If set, a "clicked" report is generated even if the clicked-on view
* is the same as the previously clicked-on view.
*/
bool _last_clicked_redeliver = false;
/**
* Array for tracking the state of each key
*/
@ -148,6 +170,14 @@ class Nitpicker::User_state
if (_focused != _next_focused) {
_focused = _next_focused;
/*
* Enforce the generation of a new "clicked" report for any click
* that follows a focus change. This is needed in situations
* where the focus is defined by clicks as well as other means
* (e.g., the appearance of a lock screen).
*/
_last_clicked_redeliver = true;
/* propagate changed focus to view stack */
if (_focused)
_focus.assign(*_focused);