diff --git a/repos/gems/run/sculpt.run b/repos/gems/run/sculpt.run index ed66ee7dd6..850a193866 100644 --- a/repos/gems/run/sculpt.run +++ b/repos/gems/run/sculpt.run @@ -483,7 +483,7 @@ install_config { - + @@ -848,7 +848,7 @@ set fd [open [managed_config_path depot_query] w] puts $fd "" close $fd -foreach config { fonts wifi runtime event_filter system } { +foreach config { fonts wifi runtime event_filter system nitpicker } { set ingredient [single_ingredient $config "default"] if {$ingredient != ""} { set from [ingredient_path $config $ingredient] diff --git a/repos/gems/sculpt/leitzentrale/default b/repos/gems/sculpt/leitzentrale/default index 9d5a5f7011..c371aeeee0 100644 --- a/repos/gems/sculpt/leitzentrale/default +++ b/repos/gems/sculpt/leitzentrale/default @@ -231,6 +231,8 @@ + + diff --git a/repos/gems/src/app/sculpt_manager/main.cc b/repos/gems/src/app/sculpt_manager/main.cc index 35d453d990..bb77a85b1b 100644 --- a/repos/gems/src/app/sculpt_manager/main.cc +++ b/repos/gems/src/app/sculpt_manager/main.cc @@ -41,6 +41,7 @@ #include #include #include +#include #include #include #include @@ -1609,6 +1610,32 @@ struct Sculpt::Main : Input_event_handler, ** Display driver configuration ** **********************************/ + Managed_config
_nitpicker_config { + _env, "config", "nitpicker", *this, &Main::_handle_nitpicker_config }; + + void _handle_nitpicker_config(Xml_node const &node) + { + _nitpicker_config.generate([&] (Xml_generator &xml) { + copy_attributes(xml, node); + node.for_each_sub_node([&] (Xml_node const &sub_node) { + if (sub_node.has_type("capture") && sub_node.num_sub_nodes() == 0) { + xml.node("capture", [&] { + + /* generate panorama of fb-driver sessions */ + Panorama_config(_fb_config).gen_policy_entries(xml); + + /* default policy for capture applications like screenshot */ + xml.node("default-policy", [&] { }); + }); + } else { + copy_node(xml, sub_node, { 5 }); + } + }); + }); + } + + Panorama_config _panorama_config { }; + Fb_connectors _fb_connectors { }; Rom_handler
_manual_fb_handler { _env, "config -> fb", *this, &Main::_handle_manual_fb }; @@ -1621,12 +1648,16 @@ struct Sculpt::Main : Input_event_handler, { _managed_fb_reporter.generate([&] (Xml_generator &xml) { _fb_config.generate_managed_fb(xml); }); + + /* update nitpicker config if the new fb config affects the panorama */ + Panorama_config const orig = _panorama_config; + _panorama_config = Panorama_config(_fb_config); + if (orig != Panorama_config(_fb_config)) + _nitpicker_config.trigger_update(); } void _handle_manual_fb(Xml_node const &node) { - log("_handle_manual_fb: ", node); - _fb_config = { }; _fb_config.import_manual_config(node); _fb_config.apply_connectors(_fb_connectors); @@ -1734,6 +1765,7 @@ struct Sculpt::Main : Input_event_handler, _gui.input.sigh(_input_handler); _gui.info_sigh(_gui_mode_handler); _handle_gui_mode(); + _nitpicker_config.trigger_update(); /* * Generate initial configurations diff --git a/repos/gems/src/app/sculpt_manager/model/fb_config.h b/repos/gems/src/app/sculpt_manager/model/fb_config.h index ce8f249b95..da00f925a9 100644 --- a/repos/gems/src/app/sculpt_manager/model/fb_config.h +++ b/repos/gems/src/app/sculpt_manager/model/fb_config.h @@ -326,7 +326,7 @@ struct Sculpt::Fb_config struct Merge_info { Entry::Name name; Area px; }; - void _with_merge_info(auto const &fn) const + void with_merge_info(auto const &fn) const { Merge_info info { }; @@ -354,7 +354,7 @@ struct Sculpt::Fb_config void _gen_merge_node(Xml_generator &xml) const { - _with_merge_info([&] (Merge_info const &info) { + with_merge_info([&] (Merge_info const &info) { xml.node("merge", [&] { xml.attribute("width", info.px.w); xml.attribute("height", info.px.h); @@ -388,6 +388,15 @@ struct Sculpt::Fb_config connectors.with_connector(entry.name, fn); } + void for_each_discrete_entry(auto const &fn) const + { + for (unsigned i = _num_merged; i < MAX_ENTRIES; i++) { + Entry const &entry = _entries[i]; + if (entry.defined && entry.present) + fn(entry); + } + } + unsigned num_present_merged() const { unsigned count = 0; diff --git a/repos/gems/src/app/sculpt_manager/model/panorama_config.h b/repos/gems/src/app/sculpt_manager/model/panorama_config.h new file mode 100644 index 0000000000..36aa10ed47 --- /dev/null +++ b/repos/gems/src/app/sculpt_manager/model/panorama_config.h @@ -0,0 +1,100 @@ +/* + * \brief Representation of nitpicker's configuration + * \author Norman Feske + * \date 2024-10-25 + */ + +/* + * Copyright (C) 2024 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 _MODEL__PANORAMA_CONFIG_H_ +#define _MODEL__PANORAMA_CONFIG_H_ + +#include +#include + +namespace Sculpt { struct Panorama_config; }; + + +struct Sculpt::Panorama_config +{ + struct Entry + { + using Name = Fb_config::Entry::Name; + + Name name; + Rect rect; + + bool operator != (Entry const &other) const + { + return (name != other.name) || (rect != other.rect); + } + + void gen_policy(Xml_generator &xml) const + { + xml.node("policy", [&] { + xml.attribute("label_suffix", name); + xml.attribute("xpos", rect.x1()); + xml.attribute("ypos", rect.y1()); + xml.attribute("width", rect.w()); + xml.attribute("height", rect.h()); + }); + } + }; + + static constexpr unsigned MAX_ENTRIES = 16; + + Entry _entries[MAX_ENTRIES] { }; + + unsigned _num_entries = 0; + + Panorama_config() { }; + + Panorama_config(Fb_config const &fb_config) + { + int xpos = 0; + + auto append = [&] (auto const &name, auto const area) + { + if (_num_entries == MAX_ENTRIES) + return; + + _entries[_num_entries] = Entry { + .name = name, + .rect = { .at = { .x = xpos, .y = 0 }, .area = area } }; + + _num_entries++; + xpos += area.w; + }; + + fb_config.with_merge_info([&] (Fb_config::Merge_info const &info) { + append(info.name, info.px); }); + + fb_config.for_each_discrete_entry([&] (Fb_config::Entry const &entry) { + append(entry.name, entry.mode_attr.px); }); + } + + void gen_policy_entries(Xml_generator &xml) const + { + for (unsigned i = 0; i < _num_entries; i++) + _entries[i].gen_policy(xml); + } + + bool operator != (Panorama_config const &other) const + { + if (other._num_entries != _num_entries) + return true; + + for (unsigned i = 0; i < _num_entries; i++) + if (other._entries[i] != _entries[i]) + return true; + + return false; + } +}; + +#endif /* _MODEL__PANORAMA_CONFIG_H_ */