mirror of
https://github.com/genodelabs/genode.git
synced 2024-12-19 05:37:54 +00:00
nitpicker: respond to external focus policy
This patch enables nitpicker to use an external focus policy instead of the traditional builtin click-to-focus policy. The external focus policy is obtained from a 'focus' ROM. The focus ROM is expected to have a 'label' attribute with the value set to the label of the to-be focused client.
This commit is contained in:
parent
7ca56a62fd
commit
544274feb9
@ -122,6 +122,20 @@ If not specified, the focus attribute defaults to 'none'.
|
||||
Note that the input focus may also be manipulated via nitpicker's session
|
||||
interface, which allows a client to yield the focus to other clients.
|
||||
|
||||
By default, nitpicker has a builtin click-to-focus policy where focus changes
|
||||
are initiated exclusively by the user by clicking on a view of an unfocused
|
||||
client. However, the builtin policy is not always desired. For example, in
|
||||
console-like scenarios, the focus should always correspond to the visible
|
||||
console regardless of any mouse clicks. Nitpicker supports such scenarios by
|
||||
the use of an external focus-policy component (e.g., nit_focus). By setting
|
||||
the '<config>' attribute 'focus' to "rom", the focus is obtained from an
|
||||
external ROM module named "focus". The focus ROM is expected to have a 'label'
|
||||
attribute with the value set to the label of the to-be focused client. When
|
||||
using an external focus policy, domains configured as "click" are internally
|
||||
handled like "transient" focusable domains. It is up to the external focus
|
||||
policy component to make a new focus permanent by providing an updated "focus"
|
||||
ROM.
|
||||
|
||||
|
||||
Hovering policy
|
||||
---------------
|
||||
|
@ -65,6 +65,8 @@ class Nitpicker::Focus : Noncopyable
|
||||
*/
|
||||
void assign(View_owner const &focused) { _focused = &focused; }
|
||||
|
||||
void reset() { _focused = nullptr; }
|
||||
|
||||
void forget(View_owner const &owner)
|
||||
{
|
||||
if (_focused == &owner)
|
||||
|
@ -32,6 +32,9 @@
|
||||
#include "domain_registry.h"
|
||||
|
||||
namespace Nitpicker {
|
||||
|
||||
struct Focus_updater { virtual void update_focus() = 0; };
|
||||
|
||||
template <typename> class Root;
|
||||
struct Main;
|
||||
}
|
||||
@ -83,6 +86,7 @@ class Nitpicker::Root : public Root_component<Session_component>,
|
||||
View_component &_builtin_background;
|
||||
Framebuffer::Session &_framebuffer;
|
||||
Reporter &_focus_reporter;
|
||||
Focus_updater &_focus_updater;
|
||||
|
||||
protected:
|
||||
|
||||
@ -113,6 +117,7 @@ class Nitpicker::Root : public Root_component<Session_component>,
|
||||
session->apply_session_policy(_config.xml(), _domain_registry);
|
||||
_session_list.insert(session);
|
||||
_global_keys.apply_config(_config.xml(), _session_list);
|
||||
_focus_updater.update_focus();
|
||||
|
||||
return session;
|
||||
}
|
||||
@ -144,7 +149,8 @@ class Nitpicker::Root : public Root_component<Session_component>,
|
||||
Global_keys &global_keys, View_stack &view_stack,
|
||||
User_state &user_state, View_component &pointer_origin,
|
||||
View_component &builtin_background, Allocator &md_alloc,
|
||||
Framebuffer::Session &framebuffer, Reporter &focus_reporter)
|
||||
Framebuffer::Session &framebuffer, Reporter &focus_reporter,
|
||||
Focus_updater &focus_updater)
|
||||
:
|
||||
Root_component<Session_component>(&env.ep().rpc_ep(), &md_alloc),
|
||||
_env(env), _config(config), _session_list(session_list),
|
||||
@ -153,7 +159,7 @@ class Nitpicker::Root : public Root_component<Session_component>,
|
||||
_pointer_origin(pointer_origin),
|
||||
_builtin_background(builtin_background),
|
||||
_framebuffer(framebuffer),
|
||||
_focus_reporter(focus_reporter)
|
||||
_focus_reporter(focus_reporter), _focus_updater(focus_updater)
|
||||
{ }
|
||||
|
||||
|
||||
@ -185,7 +191,7 @@ class Nitpicker::Root : public Root_component<Session_component>,
|
||||
};
|
||||
|
||||
|
||||
struct Nitpicker::Main
|
||||
struct Nitpicker::Main : Focus_updater
|
||||
{
|
||||
Env &_env;
|
||||
|
||||
@ -268,12 +274,21 @@ struct Nitpicker::Main
|
||||
Reporter _keystate_reporter = { _env, "keystate" };
|
||||
Reporter _clicked_reporter = { _env, "clicked" };
|
||||
|
||||
Attached_rom_dataspace _config { _env, "config" };
|
||||
Attached_rom_dataspace _config_rom { _env, "config" };
|
||||
|
||||
Root<PT> _root = { _env, _config, _session_list, *_domain_registry,
|
||||
Constructible<Attached_rom_dataspace> _focus_rom;
|
||||
|
||||
Root<PT> _root = { _env, _config_rom, _session_list, *_domain_registry,
|
||||
_global_keys, _view_stack, _user_state, _pointer_origin,
|
||||
_builtin_background, _sliced_heap, _framebuffer,
|
||||
_focus_reporter };
|
||||
_focus_reporter, *this };
|
||||
|
||||
/**
|
||||
* Focus_updater interface
|
||||
*
|
||||
* Called whenever a new session appears.
|
||||
*/
|
||||
void update_focus() override { _handle_focus(); }
|
||||
|
||||
/*
|
||||
* Configuration-update handler, executed in the context of the RPC
|
||||
@ -284,7 +299,14 @@ struct Nitpicker::Main
|
||||
*/
|
||||
void _handle_config();
|
||||
|
||||
Signal_handler<Main> _config_handler = { _env.ep(), *this, &Main::_handle_config};
|
||||
Signal_handler<Main> _config_handler = { _env.ep(), *this, &Main::_handle_config };
|
||||
|
||||
/**
|
||||
* Signal handler for externally triggered focus changes
|
||||
*/
|
||||
void _handle_focus();
|
||||
|
||||
Signal_handler<Main> _focus_handler = { _env.ep(), *this, &Main::_handle_focus };
|
||||
|
||||
/**
|
||||
* Signal handler invoked on the reception of user input
|
||||
@ -333,7 +355,7 @@ struct Nitpicker::Main
|
||||
_view_stack.stack(_pointer_origin);
|
||||
_view_stack.stack(_builtin_background);
|
||||
|
||||
_config.sigh(_config_handler);
|
||||
_config_rom.sigh(_config_handler);
|
||||
_handle_config();
|
||||
|
||||
_framebuffer.sync_sigh(_input_handler);
|
||||
@ -433,11 +455,34 @@ static void configure_reporter(Genode::Xml_node config, Genode::Reporter &report
|
||||
}
|
||||
|
||||
|
||||
void Nitpicker::Main::_handle_focus()
|
||||
{
|
||||
if (!_focus_rom.constructed())
|
||||
return;
|
||||
|
||||
_focus_rom->update();
|
||||
|
||||
typedef Session::Label Label;
|
||||
Label const label = _focus_rom->xml().attribute_value("label", Label());
|
||||
|
||||
/* determine session that matches the label found in the focus ROM */
|
||||
View_owner *next_focus = nullptr;
|
||||
for (Session_component *s = _session_list.first(); s; s = s->next())
|
||||
if (s->label() == label)
|
||||
next_focus = s;
|
||||
|
||||
if (next_focus)
|
||||
_user_state.focus(*next_focus);
|
||||
else
|
||||
_user_state.reset_focus();
|
||||
}
|
||||
|
||||
|
||||
void Nitpicker::Main::_handle_config()
|
||||
{
|
||||
_config.update();
|
||||
_config_rom.update();
|
||||
|
||||
Xml_node const config = _config.xml();
|
||||
Xml_node const config = _config_rom.xml();
|
||||
|
||||
/* update global keys policy */
|
||||
_global_keys.apply_config(config, _session_list);
|
||||
@ -473,6 +518,22 @@ void Nitpicker::Main::_handle_config()
|
||||
*/
|
||||
_view_stack.sort_views_by_layer();
|
||||
|
||||
/*
|
||||
* Respond to a configuration change of the input-focus mechanism
|
||||
*/
|
||||
bool const focus_rom = (config.attribute_value("focus", String<16>()) == "rom");
|
||||
if (_focus_rom.constructed() && !focus_rom)
|
||||
_focus_rom.destruct();
|
||||
|
||||
if (!_focus_rom.constructed() && focus_rom) {
|
||||
_focus_rom.construct(_env, "focus");
|
||||
_focus_rom->sigh(_focus_handler);
|
||||
_handle_focus();
|
||||
}
|
||||
|
||||
/* disable builtin focus handling when using an external focus policy */
|
||||
_user_state.focus_via_click(!_focus_rom.constructed());
|
||||
|
||||
/* redraw */
|
||||
_view_stack.update_all_views();
|
||||
|
||||
|
@ -176,7 +176,21 @@ void User_state::_handle_input_event(Input::Event ev)
|
||||
if (_hovered->has_transient_focusable_domain()) {
|
||||
global_receiver = _hovered;
|
||||
} else {
|
||||
_focus_view_owner_via_click(*_hovered);
|
||||
/*
|
||||
* Distinguish the use of the builtin focus switching and the
|
||||
* alternative use of an external focus policy. In the latter
|
||||
* case, focusable domains are handled like transiently
|
||||
* focusable domains. The permanent focus change is triggered
|
||||
* by an external focus-policy component by posting and updated
|
||||
* focus ROM, which is then propagated into the user state via
|
||||
* the 'User_state::focus' and 'User_state::reset_focus'
|
||||
* methods.
|
||||
*/
|
||||
if (_focus_via_click)
|
||||
_focus_view_owner_via_click(*_hovered);
|
||||
else
|
||||
global_receiver = _hovered;
|
||||
|
||||
_last_clicked = _hovered;
|
||||
}
|
||||
}
|
||||
@ -434,9 +448,6 @@ bool User_state::_focus_change_permitted(View_owner const &caller) const
|
||||
|
||||
void User_state::_focus_view_owner_via_click(View_owner &owner)
|
||||
{
|
||||
_focus.assign(owner);
|
||||
|
||||
_focused = &owner;
|
||||
_next_focused = &owner;
|
||||
_focused = &owner;
|
||||
|
||||
|
@ -46,6 +46,14 @@ class Nitpicker::User_state : public Focus_controller
|
||||
*/
|
||||
bool _global_key_sequence = false;
|
||||
|
||||
/*
|
||||
* True if the input focus should change directly whenever the user
|
||||
* clicks on an unfocused client. This is the traditional behaviour
|
||||
* of nitpicker. This builtin policy is now superseded by the use of an
|
||||
* external focus-management component (e.g., nit_focus).
|
||||
*/
|
||||
bool _focus_via_click = true;
|
||||
|
||||
/**
|
||||
* Input-focus information propagated to the view stack
|
||||
*/
|
||||
@ -133,8 +141,15 @@ class Nitpicker::User_state : public Focus_controller
|
||||
if (_key_pressed() && !_global_key_sequence)
|
||||
return;
|
||||
|
||||
if (_focused != _next_focused)
|
||||
if (_focused != _next_focused) {
|
||||
_focused = _next_focused;
|
||||
|
||||
/* propagate changed focus to view stack */
|
||||
if (_focused)
|
||||
_focus.assign(*_focused);
|
||||
else
|
||||
_focus.reset();
|
||||
}
|
||||
}
|
||||
|
||||
public:
|
||||
@ -205,6 +220,32 @@ class Nitpicker::User_state : public Focus_controller
|
||||
void report_last_clicked_view_owner(Xml_generator &) const;
|
||||
|
||||
Point pointer_pos() { return _pointer_pos; }
|
||||
|
||||
/**
|
||||
* Enable/disable direct focus changes by clicking on a client
|
||||
*/
|
||||
void focus_via_click(bool enabled) { _focus_via_click = enabled; }
|
||||
|
||||
/**
|
||||
* Set input focus to specified view owner
|
||||
*
|
||||
* This method is used when nitpicker's focus is managed by an
|
||||
* external focus-policy component like 'nit_focus'.
|
||||
*
|
||||
* The focus change is not applied immediately but deferred to the
|
||||
* next call of 'handle_input_events' (which happens periodically).
|
||||
*/
|
||||
void focus(View_owner &owner)
|
||||
{
|
||||
/*
|
||||
* The focus change is not applied immediately but deferred to the
|
||||
* next call of '_apply_pending_focus_change' via the periodic
|
||||
* call of 'handle_input_events'.
|
||||
*/
|
||||
_next_focused = &owner;
|
||||
}
|
||||
|
||||
void reset_focus() { _next_focused = nullptr; }
|
||||
};
|
||||
|
||||
#endif /* _USER_STATE_H_ */
|
||||
|
Loading…
Reference in New Issue
Block a user