nitpicker: improve activity reporting

Nitpicker's hover and focus reports contain an 'active' attribute, which
can be inspected for the detection of user activity, e.g., as trigger
for a screensaver or for dynamic clipboard policies.

When using the 'Event' session, the reporting code updated the reports
only on incoming events. This patch adds the periodic reporting as used
when using the old 'Input' session.

Issue #4950
This commit is contained in:
Norman Feske 2023-06-29 16:23:57 +02:00
parent ba67b535f8
commit 8463f4910a
2 changed files with 47 additions and 21 deletions

View File

@ -576,6 +576,17 @@ struct Nitpicker::Main : Focus_updater, Hover_updater,
*/
void handle_input_events(User_state::Input_batch) override;
bool _reported_button_activity = false;
bool _reported_motion_activity = false;
unsigned _reported_focus_count = 0;
unsigned _reported_hover_count = 0;
unsigned _focus_count = 0;
unsigned _hover_count = 0;
void _update_motion_and_focus_activity_reports();
/**
* Signal handler periodically invoked for the reception of user input and redraw
*/
@ -598,7 +609,7 @@ struct Nitpicker::Main : Focus_updater, Hover_updater,
* Number of periods after the last user activity when we regard the user
* as becoming inactive
*/
unsigned _activity_threshold = 50;
unsigned const _activity_threshold = 50;
/**
* True if the user has recently interacted with buttons or keys
@ -654,9 +665,6 @@ struct Nitpicker::Main : Focus_updater, Hover_updater,
void Nitpicker::Main::handle_input_events(User_state::Input_batch batch)
{
bool const old_button_activity = _button_activity;
bool const old_motion_activity = _motion_activity;
User_state::Handle_input_result const result =
_user_state.handle_input_events(batch);
@ -688,15 +696,13 @@ void Nitpicker::Main::handle_input_events(User_state::Input_batch batch)
_user_state.report_last_clicked_view_owner(xml); });
}
if (result.focus_changed)
if (result.focus_changed) {
_focus_count++;
_view_stack.update_all_views();
}
/* flag user as inactive after activity threshold is reached */
if (_period_cnt == _last_button_activity_period + _activity_threshold)
_button_activity = false;
if (_period_cnt == _last_motion_activity_period + _activity_threshold)
_motion_activity = false;
if (result.hover_changed)
_hover_count++;
/* report mouse-position updates */
if (_pointer_reporter.enabled() && result.motion_activity) {
@ -704,22 +710,37 @@ void Nitpicker::Main::handle_input_events(User_state::Input_batch batch)
_user_state.report_pointer_position(xml); });
}
/* report hover changes */
if (_hover_reporter.enabled()
&& (result.hover_changed || (old_motion_activity != _motion_activity))) {
/* update pointer position */
if (result.motion_activity)
_update_pointer_position();
}
void Nitpicker::Main::_update_motion_and_focus_activity_reports()
{
/* flag user as inactive after activity threshold is reached */
if (_period_cnt == _last_button_activity_period + _activity_threshold)
_button_activity = false;
if (_period_cnt == _last_motion_activity_period + _activity_threshold)
_motion_activity = false;
bool const hover_changed = (_reported_hover_count != _hover_count);
if (hover_changed || (_reported_motion_activity != _motion_activity)) {
Reporter::Xml_generator xml(_hover_reporter, [&] () {
_user_state.report_hovered_view_owner(xml, _motion_activity); });
}
/* report focus changes */
if (result.focus_changed || (old_button_activity != _button_activity)) {
bool const focus_changed = (_reported_focus_count != _focus_count);
if (focus_changed || (_reported_button_activity != _button_activity)) {
Reporter::Xml_generator xml(_focus_reporter, [&] () {
_user_state.report_focused_view_owner(xml, _button_activity); });
}
/* update pointer position */
if (result.motion_activity)
_update_pointer_position();
_reported_motion_activity = _motion_activity;
_reported_button_activity = _button_activity;
_reported_hover_count = _hover_count;
_reported_focus_count = _focus_count;
}
@ -739,6 +760,8 @@ void Nitpicker::Main::_handle_period()
handle_input_events(batch);
}
_update_motion_and_focus_activity_reports();
/* perform redraw */
if (_framebuffer.constructed() && _fb_screen.constructed()) {
/* call 'Dirty_rect::flush' on a copy to preserve the state */

View File

@ -365,9 +365,12 @@ User_state::handle_input_events(Input_batch batch)
*/
button_activity |= _key_pressed();
bool touch_occurred = false;
bool key_state_affected = false;
for (unsigned i = 0; i < batch.count; i++)
for (unsigned i = 0; i < batch.count; i++) {
key_state_affected |= (batch.events[i].press() || batch.events[i].release());
touch_occurred |= batch.events[i].touch();
}
_apply_pending_focus_change();
@ -392,7 +395,7 @@ User_state::handle_input_events(Input_batch batch)
(_input_receiver != old_input_receiver),
.key_state_affected = key_state_affected,
.button_activity = button_activity,
.motion_activity = (_pointer_pos != old_pointer_pos),
.motion_activity = (_pointer_pos != old_pointer_pos) || touch_occurred,
.key_pressed = _key_pressed(),
.last_clicked_changed = last_clicked_changed
};