nitpicker: add event service

Issue #3812
This commit is contained in:
Norman Feske 2020-07-14 17:38:40 +02:00
parent 66c520cdae
commit 7932c76d85
5 changed files with 182 additions and 25 deletions

View File

@ -7,4 +7,5 @@ timer_session
framebuffer_session
gui_session
capture_session
event_session
report_session

View File

@ -0,0 +1,82 @@
/*
* \brief Event session component
* \author Norman Feske
* \date 2020-07-14
*/
/*
* Copyright (C) 2020 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU Affero General Public License version 3.
*/
#ifndef _EVENT_SESSION_H_
#define _EVENT_SESSION_H_
/* Genode includes */
#include <base/session_object.h>
#include <event_session/event_session.h>
/* local includes */
#include "user_state.h"
namespace Nitpicker { class Event_session; }
class Nitpicker::Event_session : public Session_object<Event::Session, Event_session>
{
public:
struct Handler : Interface
{
virtual void handle_input_events(User_state::Input_batch) = 0;
};
private:
Handler &_handler;
Constrained_ram_allocator _ram;
Attached_ram_dataspace _ds;
public:
Event_session(Env &env,
Resources const &resources,
Label const &label,
Diag const &diag,
Handler &handler)
:
Session_object(env.ep(), resources, label, diag),
_handler(handler),
_ram(env.ram(), _ram_quota_guard(), _cap_quota_guard()),
_ds(_ram, env.rm(), 4096)
{ }
~Event_session() { }
/*****************************
** Event session interface **
*****************************/
Dataspace_capability dataspace() { return _ds.cap(); }
void submit_batch(unsigned const count)
{
size_t const max_events = _ds.size() / sizeof(Input::Event);
if (count > max_events)
warning("number of events exceeds dataspace capacity");
User_state::Input_batch const batch {
.events = _ds.local_addr<Input::Event>(),
.count = min(count, max_events) };
_handler.handle_input_events(batch);
}
};
#endif /* _EVENT_SESSION_H_ */

View File

@ -33,10 +33,12 @@
#include "pointer_origin.h"
#include "domain_registry.h"
#include "capture_session.h"
#include "event_session.h"
namespace Nitpicker {
class Gui_root;
class Capture_root;
class Event_root;
struct Main;
}
@ -293,15 +295,64 @@ class Nitpicker::Capture_root : public Root_component<Capture_session>
};
/*****************************************
** Implementation of the event service **
*****************************************/
class Nitpicker::Event_root : public Root_component<Event_session>
{
private:
Env &_env;
Event_session::Handler &_handler;
protected:
Event_session *_create_session(const char *args) override
{
return new (md_alloc())
Event_session(_env,
session_resources_from_args(args),
session_label_from_args(args),
session_diag_from_args(args),
_handler);
}
void _upgrade_session(Event_session *s, const char *args) override
{
s->upgrade(ram_quota_from_args(args));
s->upgrade(cap_quota_from_args(args));
}
void _destroy_session(Event_session *session) override
{
Genode::destroy(md_alloc(), session);
}
public:
/**
* Constructor
*/
Event_root(Env &env, Allocator &md_alloc, Event_session::Handler &handler)
:
Root_component<Event_session>(&env.ep().rpc_ep(), &md_alloc),
_env(env), _handler(handler)
{ }
};
struct Nitpicker::Main : Focus_updater,
View_stack::Damage,
Capture_session::Handler
Capture_session::Handler,
Event_session::Handler
{
Env &_env;
Timer::Connection _timer { _env };
Signal_handler<Main> _timer_handler = { _env.ep(), *this, &Main::_handle_input };
Signal_handler<Main> _timer_handler = { _env.ep(), *this, &Main::_handle_period };
unsigned long _timer_period_ms = 10;
@ -420,6 +471,8 @@ struct Nitpicker::Main : Focus_updater,
Capture_root _capture_root { _env, _sliced_heap, _view_stack, *this };
Event_root _event_root { _env, _sliced_heap, *this };
/**
* View_stack::Damage interface
*/
@ -502,11 +555,16 @@ struct Nitpicker::Main : Focus_updater,
Signal_handler<Main> _focus_handler = { _env.ep(), *this, &Main::_handle_focus };
/**
* Signal handler invoked on the reception of user input
* Event_session::Handler interface
*/
void _handle_input();
void handle_input_events(User_state::Input_batch) override;
Signal_handler<Main> _input_handler = { _env.ep(), *this, &Main::_handle_input };
/**
* Signal handler periodically invoked for the reception of user input and redraw
*/
void _handle_period();
Signal_handler<Main> _input_period = { _env.ep(), *this, &Main::_handle_period };
/**
* Counter that is incremented periodically
@ -562,30 +620,28 @@ struct Nitpicker::Main : Focus_updater,
if (_config_rom.xml().has_sub_node("capture"))
_env.parent().announce(_env.ep().manage(_capture_root));
if (_config_rom.xml().has_sub_node("event"))
_env.parent().announce(_env.ep().manage(_event_root));
/*
* Detect initial motion activity such that the first hover report
* contains the boot-time activity of the user in the very first
* report.
*/
_handle_input();
_handle_period();
_report_displays();
}
};
void Nitpicker::Main::_handle_input()
void Nitpicker::Main::handle_input_events(User_state::Input_batch batch)
{
_period_cnt++;
bool const old_button_activity = _button_activity;
bool const old_motion_activity = _motion_activity;
/* handle batch of pending events */
User_state::Handle_input_result const result = _input.constructed()
? _user_state.handle_input_events(_input->ev_ds.local_addr<Input::Event>(),
_input->connection.flush())
: User_state::Handle_input_result { };
User_state::Handle_input_result const result =
_user_state.handle_input_events(batch);
if (result.button_activity) {
_last_button_activity_period = _period_cnt;
@ -647,6 +703,24 @@ void Nitpicker::Main::_handle_input()
/* update pointer position */
if (result.motion_activity)
_update_pointer_position();
}
void Nitpicker::Main::_handle_period()
{
_period_cnt++;
/* handle batch of pending events */
if (_input.constructed()) {
size_t const max_events = _input->ev_ds.size() / sizeof(Input::Event);
User_state::Input_batch const batch {
.events = _input->ev_ds.local_addr<Input::Event>(),
.count = min(max_events, (size_t)_input->connection.flush()) };
handle_input_events(batch);
}
/* perform redraw */
if (_framebuffer.constructed() && _fb_screen.constructed()) {
@ -812,7 +886,7 @@ void Nitpicker::Main::_handle_fb_mode()
if (_request_framebuffer && !_framebuffer.constructed()) {
_framebuffer.construct(_env, Framebuffer::Mode{});
_framebuffer->mode_sigh(_fb_mode_handler);
_framebuffer->sync_sigh(_input_handler);
_framebuffer->sync_sigh(_timer_handler);
_timer.trigger_periodic(0);
}

View File

@ -277,8 +277,7 @@ void User_state::_handle_input_event(Input::Event ev)
User_state::Handle_input_result
User_state::handle_input_events(Input::Event const * const ev_buf,
unsigned const num_ev)
User_state::handle_input_events(Input_batch batch)
{
Point const old_pointer_pos = _pointer_pos;
View_owner * const old_hovered = _hovered;
@ -289,18 +288,18 @@ User_state::handle_input_events(Input::Event const * const ev_buf,
bool button_activity = false;
if (num_ev > 0) {
if (batch.count > 0) {
/*
* Take events from input event buffer, merge consecutive motion
* events, and pass result to the user state.
*/
for (unsigned src_ev_cnt = 0; src_ev_cnt < num_ev; src_ev_cnt++) {
for (unsigned src_ev_cnt = 0; src_ev_cnt < batch.count; src_ev_cnt++) {
Input::Event const *e = &ev_buf[src_ev_cnt];
Input::Event const *e = &batch.events[src_ev_cnt];
Input::Event curr = *e;
if (e->absolute_motion() || e->relative_motion()) {
unsigned const n = num_consecutive_events(e, num_ev - src_ev_cnt);
unsigned const n = num_consecutive_events(e, batch.count - src_ev_cnt);
curr = merge_motion_events(e, n);
/* skip merged events */
@ -332,8 +331,8 @@ User_state::handle_input_events(Input::Event const * const ev_buf,
button_activity |= _key_pressed();
bool key_state_affected = false;
for (unsigned i = 0; i < num_ev; i++)
key_state_affected |= (ev_buf[i].press() || ev_buf[i].release());
for (unsigned i = 0; i < batch.count; i++)
key_state_affected |= (batch.events[i].press() || batch.events[i].release());
_apply_pending_focus_change();

View File

@ -229,6 +229,8 @@ class Nitpicker::User_state
** Interface used by the main program **
****************************************/
struct Input_batch { Input::Event *events; size_t count; };
struct Handle_input_result
{
bool const hover_changed;
@ -240,8 +242,7 @@ class Nitpicker::User_state
bool const last_clicked_changed;
};
Handle_input_result handle_input_events(Input::Event const *ev_buf,
unsigned num_ev);
Handle_input_result handle_input_events(Input_batch);
/**
* Discard all references to specified view owner