nitpicker: handle Input::Session::exclusive

While the focused client has enabled exclusive input, nitpicker does
not translate relative motion to absolute motion but routes relative
motion directly to the client. Additionally, the pointer origin is
forcibly moved to a position outside the screen boundaries, making the
pointer invisible.

Issue #5355
This commit is contained in:
Norman Feske 2024-10-06 14:00:48 +02:00 committed by Christian Helmuth
parent 996d9b300c
commit 92227df624
6 changed files with 92 additions and 28 deletions

View File

@ -44,7 +44,8 @@ class Nitpicker::Gui_session : public Session_object<Gui::Session>,
public View_owner,
public Buffer_provider,
private Session_list::Element,
private Dynamic_rom_session::Xml_producer
private Dynamic_rom_session::Xml_producer,
private Input::Session_component::Action
{
public:
@ -54,6 +55,8 @@ class Nitpicker::Gui_session : public Session_object<Gui::Session>,
* \param rect domain-specific panorama rectangle
*/
virtual void gen_capture_info(Xml_generator &xml, Rect rect) const = 0;
virtual void exclusive_input_changed() = 0;
};
private:
@ -116,7 +119,7 @@ class Nitpicker::Gui_session : public Session_object<Gui::Session>,
bool const _input_session_accounted = (
withdraw(Ram_quota{Input::Session_component::ev_ds_size()}), true );
Input::Session_component _input_session_component { _env };
Input::Session_component _input_session_component { _env, *this };
View_stack &_view_stack;
@ -201,6 +204,19 @@ class Nitpicker::Gui_session : public Session_object<Gui::Session>,
*/
void produce_xml(Xml_generator &) override;
bool _exclusive_input_requested = false;
/**
* Input::Session_component::Action interface
*/
void exclusive_input_requested(bool const requested) override
{
bool const orig = _exclusive_input_requested;
_exclusive_input_requested = requested;
if (orig != requested)
_action.exclusive_input_changed();
}
public:
Gui_session(Env &env,
@ -318,6 +334,11 @@ class Nitpicker::Gui_session : public Session_object<Gui::Session>,
void submit_input_event(Input::Event e) override;
bool exclusive_input_requested() const override
{
return _exclusive_input_requested;
}
void report(Xml_generator &xml) const override
{
xml.attribute("label", _label);

View File

@ -32,6 +32,11 @@ class Input::Session_component : public Rpc_object<Session>
{
public:
struct Action : Interface
{
virtual void exclusive_input_requested(bool) = 0;
};
enum { MAX_EVENTS = 200 };
static size_t ev_ds_size() {
@ -40,6 +45,7 @@ class Input::Session_component : public Rpc_object<Session>
private:
Entrypoint &_ep;
Action &_action;
/*
* Exported event buffer dataspace
@ -58,9 +64,10 @@ class Input::Session_component : public Rpc_object<Session>
public:
Session_component(Env &env)
Session_component(Env &env, Action &action)
:
_ep(env.ep()), _ev_ram_ds(env.ram(), env.rm(), ev_ds_size())
_ep(env.ep()), _action(action),
_ev_ram_ds(env.ram(), env.rm(), ev_ds_size())
{
_ep.manage(*this);
}
@ -114,7 +121,10 @@ class Input::Session_component : public Rpc_object<Session>
void sigh(Signal_context_capability sigh) override { _sigh = sigh; }
void exclusive(bool) override { }
void exclusive(bool requested) override
{
_action.exclusive_input_requested(requested);
}
};
#endif /* _INPUT_SESSION_COMPONENT_H_ */

View File

@ -760,6 +760,22 @@ struct Nitpicker::Main : Focus_updater, Hover_updater,
capture_buffer_size_changed();
}
bool _exclusive_input = false;
/**
* Input::Session_component::Action interface
*/
void exclusive_input_changed() override
{
if (_user_state.exclusive_input() != _exclusive_input) {
_exclusive_input = _user_state.exclusive_input();
/* toggle pointer visibility */
_update_pointer_position();
_view_stack.update_all_views();
}
}
/**
* Signal handler for externally triggered focus changes
*/
@ -797,6 +813,11 @@ struct Nitpicker::Main : Focus_updater, Hover_updater,
void _update_pointer_position()
{
/* move pointer out of the way while a client receives exclusive input */
if (_user_state.exclusive_input()) {
_view_stack.geometry(_pointer_origin, Rect { { -1000*1000, 0 }, { } });
return;
}
_user_state.pointer().with_result(
[&] (Point p) {
_view_stack.geometry(_pointer_origin, Rect(p, Area{})); },

View File

@ -93,13 +93,13 @@ void User_state::_handle_input_event(Input::Event ev)
_last_seq_number.construct(seq); });
/* transparently convert relative into absolute motion event */
ev.handle_relative_motion([&] (int x, int y) {
_pointer.with_result(
[&] (Point orig_pos) {
Point const p = orig_pos + Point { x, y };
ev = Absolute_motion { p.x, p.y }; },
[&] (Nowhere) { });
});
if (!exclusive_input())
ev.handle_relative_motion([&] (int x, int y) {
_pointer.with_result(
[&] (Point orig_pos) {
Point const p = orig_pos + Point { x, y };
ev = Absolute_motion { p.x, p.y }; },
[&] (Nowhere) { }); });
/* respond to motion events by updating the pointer position */
ev.handle_absolute_motion([&] (int x, int y) {
@ -249,27 +249,31 @@ void User_state::_handle_input_event(Input::Event ev)
/*
* Deliver event to session
*/
bool const forward_to_session = (ev.absolute_motion() || ev.wheel() ||
ev.touch() || ev.touch_release() ||
ev.seq_number());
bool const forward_to_session = ev.absolute_motion() || ev.relative_motion()
|| ev.touch() || ev.touch_release()
|| ev.wheel() || ev.seq_number();
if (forward_to_session) {
if (_key_cnt == 0) {
View_owner *receiver = _input_receiver;
if (_hovered) {
if (_key_cnt == 0 && _hovered) {
/*
* Unless the domain of the pointed session is configured to
* always receive hover events, we deliver motion events only
* to the focused domain.
*/
if (_hovered->hover_always() || _hovered->has_same_domain(_focused))
receiver = _hovered;
}
/*
* Unless the domain of the pointed session is configured to
* always receive hover events, we deliver motion events only
* to the focused domain.
*/
if (_hovered->hover_always()
|| _hovered->has_same_domain(_focused))
_hovered->submit_input_event(ev);
}
/*
* Route relative motion (exclusive input) to the focused client
*/
if (ev.relative_motion() && _focused)
receiver = _focused;
} else if (_input_receiver)
_input_receiver->submit_input_event(ev);
if (receiver)
receiver->submit_input_event(ev);
}
/*

View File

@ -252,6 +252,12 @@ class Nitpicker::User_state
Handle_input_result handle_input_events(Input_batch);
bool exclusive_input() const
{
return (_focused && _focused->exclusive_input_requested())
|| (_input_receiver && _input_receiver->exclusive_input_requested());
}
/**
* Discard all references to specified view owner
*/

View File

@ -86,6 +86,8 @@ struct Nitpicker::View_owner : Interface
virtual void submit_input_event(Input::Event) { }
virtual bool exclusive_input_requested() const { return false; }
/**
* Produce report with the owner's information
*/