diff --git a/repos/os/src/server/clipboard/main.cc b/repos/os/src/server/clipboard/main.cc index 0d8b2e80b3..30b00d07d9 100644 --- a/repos/os/src/server/clipboard/main.cc +++ b/repos/os/src/server/clipboard/main.cc @@ -76,15 +76,11 @@ struct Clipboard::Main : Rom::Module::Read_policy, Rom::Module::Write_policy Genode::Attached_rom_dataspace _config { _env, "config" }; - bool _verbose_config() - { - char const *attr = "verbose"; - return _config.xml().attribute_value(attr, false); - } - - bool verbose { _verbose_config() }; + bool _verbose = false; + bool _match_labels = false; typedef Genode::String<100> Domain; + typedef Genode::String<100> Label; Genode::Attached_rom_dataspace _focus_ds { _env, "focus" }; @@ -94,6 +90,7 @@ struct Clipboard::Main : Rom::Module::Read_policy, Rom::Module::Write_policy { _env.ep(), *this, &Main::_handle_focus }; Domain _focused_domain { }; + Label _focused_label { }; /** * Handle configuration changes @@ -101,7 +98,8 @@ struct Clipboard::Main : Rom::Module::Read_policy, Rom::Module::Write_policy void _handle_config() { _config.update(); - verbose = _verbose_config(); + _verbose = _config.xml().attribute_value("verbose", false); + _match_labels = _config.xml().attribute_value("match_labels", false); } /** @@ -114,14 +112,14 @@ struct Clipboard::Main : Rom::Module::Read_policy, Rom::Module::Write_policy _focus_ds.update(); _focused_domain = Domain(); + _focused_label = Label(); - try { - Genode::Xml_node focus(_focus_ds.local_addr(), _focus_ds.size()); + Genode::Xml_node const focus = _focus_ds.xml(); - if (focus.attribute_value("active", false)) - _focused_domain = focus.attribute_value("domain", Domain()); - - } catch (...) { } + if (focus.attribute_value("active", false)) { + _focused_domain = focus.attribute_value("domain", Domain()); + _focused_label = focus.attribute_value("label", Label()); + } } Domain _domain(Genode::Session_label const &label) const @@ -135,20 +133,30 @@ struct Clipboard::Main : Rom::Module::Read_policy, Rom::Module::Write_policy return Domain(); } - Domain _domain(Rom::Reader const &reader) const + Label _label(Rom::Reader const &reader) const { Rom::Session_component const &rom_session = static_cast(reader); - return _domain(rom_session.label()); + return rom_session.label(); } - Domain _domain(Rom::Writer const &writer) const + Domain _domain(Rom::Reader const &reader) const + { + return _domain(_label(reader)); + } + + Label _label(Rom::Writer const &writer) const { Report::Session_component const &report_session = static_cast(writer); - return _domain(report_session.label()); + return report_session.label(); + } + + Domain _domain(Rom::Writer const &writer) const + { + return _domain(_label(writer)); } bool _flow_defined(Domain const &from, Domain const &to) const @@ -175,6 +183,39 @@ struct Clipboard::Main : Rom::Module::Read_policy, Rom::Module::Write_policy return result; } + bool _client_label_matches_focus(Genode::Session_label const &label) const + { + using namespace Genode; + + /* + * The client label has the suffix " -> clipboard". Strip off this + * part to make the label comparable with the label of the client's + * nitpicker session (which has of course no such suffix). + */ + char const *suffix = " -> clipboard"; + size_t const suffix_len = strlen(suffix); + + if (label.length() < suffix_len + 1) + return false; + + size_t const truncated_label_len = label.length() - suffix_len - 1; + + Session_label const + truncated_label(Cstring(label.string(), truncated_label_len)); + + /* + * We accept any subsystem of the client to have the nitpicker focus. + * E.g., a multi-window application may have multiple nitpicker + * sessions, one for each window. The labels of all of those nitpicker + * session share the first part with application's clipboard label. + */ + bool const focus_lies_in_client_subsystem = + !strcmp(_focused_label.string(), truncated_label.string(), + truncated_label_len); + + return focus_lies_in_client_subsystem; + } + /** * Rom::Module::Read_policy interface */ @@ -185,6 +226,9 @@ struct Clipboard::Main : Rom::Module::Read_policy, Rom::Module::Write_policy Domain const from_domain = _domain(writer); Domain const to_domain = _domain(reader); + if (_match_labels && !_client_label_matches_focus(_label(reader))) + return false; + if (from_domain == to_domain) return true; @@ -194,14 +238,16 @@ struct Clipboard::Main : Rom::Module::Read_policy, Rom::Module::Write_policy return false; } - /** * Rom::Module::Write_policy interface */ bool write_permitted(Rom::Module const &module, Rom::Writer const &writer) const override { - if (_focused_domain.valid() && _domain(writer) == _focused_domain) + bool const domain_matches = + _focused_domain.valid() && _domain(writer) == _focused_domain; + + if ((!_match_labels || _client_label_matches_focus(_label(writer))) && domain_matches) return true; warning("unexpected attempt by '", writer.label(), "' " @@ -212,11 +258,12 @@ struct Clipboard::Main : Rom::Module::Read_policy, Rom::Module::Write_policy Rom::Registry _rom_registry { _env.ram(), _env.rm(), *this, *this }; - Report::Root report_root = { _env, _sliced_heap, _rom_registry, verbose }; + Report::Root report_root = { _env, _sliced_heap, _rom_registry, _verbose }; Rom ::Root rom_root = { _env, _sliced_heap, _rom_registry }; Main(Genode::Env &env) : _env(env) { + _handle_config(); _focus_ds.sigh(_focus_handler); _handle_focus();