/* * \brief Assignment of window-manager clients to target area * \author Norman Feske * \date 2018-09-27 */ /* * Copyright (C) 2018 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 _ASSIGN_H_ #define _ASSIGN_H_ /* Genode includes */ #include #include #include /* local includes */ #include #include #include namespace Window_layouter { class Assign; } class Window_layouter::Assign : public List_model::Element { public: /* * Used for associating windows with assignments. Hosted in 'Window' * objects. */ struct Member : Registry::Element { Window &window; Member(Registry ®istry, Window &window) : Registry::Element(registry, *this), window(window) { } }; typedef String<80> Label; private: Registry _members { }; Label const _label; Label const _label_prefix; Label const _label_suffix; Target::Name _target_name { }; bool _pos_defined = false; bool _xpos_any = false; bool _ypos_any = false; bool _size_defined = false; bool _maximized = false; Point _pos { }; Area _size { }; public: Assign(Xml_node assign) : _label (assign.attribute_value("label", Label())), _label_prefix(assign.attribute_value("label_prefix", Label())), _label_suffix(assign.attribute_value("label_suffix", Label())) { } void update(Xml_node assign) { _target_name = assign.attribute_value("target", Target::Name()); _pos_defined = assign.has_attribute("xpos") && assign.has_attribute("ypos"); _size_defined = assign.has_attribute("width") && assign.has_attribute("height"); _maximized = assign.attribute_value("maximized", false); _xpos_any = assign.attribute_value("xpos", String<20>()) == "any"; _ypos_any = assign.attribute_value("ypos", String<20>()) == "any"; _pos = point_attribute(assign); _size = area_attribute(assign); } /* * Used by 'Assign_list::update_from_xml' */ bool matches(Xml_node node) const { return node.attribute_value("label", Label()) == _label && node.attribute_value("label_prefix", Label()) == _label_prefix && node.attribute_value("label_suffix", Label()) == _label_suffix; } /** * Calculate window geometry */ Rect window_geometry(unsigned win_id, Area client_size, Rect target_geometry, Decorator_margins const &decorator_margins) const { if (_maximized || !_pos_defined) return target_geometry; Point const any_pos(150*win_id % 800, 30 + (100*win_id % 500)); Point const pos(_xpos_any ? any_pos.x() : _pos.x(), _ypos_any ? any_pos.y() : _pos.y()); /* floating non-maximized window */ Rect const inner(pos, _size_defined ? _size : client_size); Rect const outer = decorator_margins.outer_geometry(inner); return Rect(outer.p1() + target_geometry.p1(), outer.area()); } /** * Call 'fn' with 'Registry' if label matches assignment * * This method is used for associating assignments to windows. */ template void with_matching_members_registry(Label const &label, FN const &fn) { bool const label_matches = (_label.valid() && label == _label); bool const prefix_matches = _label_prefix.valid() && !strcmp(label.string(), _label_prefix.string(), _label_prefix.length() - 1); bool suffix_matches = false; if (label.length() >= _label_suffix.length()) { unsigned const offset = label.length() - _label_suffix.length(); suffix_matches = !strcmp(_label.string() + offset, _label_suffix.string()); } bool const wildcard_matches = !_label.valid() && (!_label_prefix.valid() || prefix_matches) && (!_label_suffix.valid() || suffix_matches); if (label_matches || wildcard_matches) fn(_members); } Target::Name target_name() const { return _target_name; } /** * Used to generate nodes of windows captured via wildcard */ template void for_each_wildcard_member(FN const &fn) const { /* skip non-wildcards */ if (_label.valid()) return; _members.for_each([&] (Assign::Member const &member) { fn(member); }); } /** * Used to bring wildcard-matching windows to front */ template void for_each_wildcard_member(FN const &fn) { if (_label.valid()) return; _members.for_each([&] (Assign::Member &member) { fn(member); }); } bool floating() const { return _pos_defined; } bool wildcard() const { return !_label.valid(); } /** * Generate node */ void gen_assign_attr(Xml_generator &xml) const { if (_label.valid()) xml.attribute("label", _label); if (_label_prefix.valid()) xml.attribute("label_prefix", _label_prefix); if (_label_suffix.valid()) xml.attribute("label_suffix", _label_suffix); xml.attribute("target", _target_name); } void gen_geometry_attr(Xml_generator &xml) const { if (_pos_defined) { if (_xpos_any) xml.attribute("xpos", "any"); else xml.attribute("xpos", _pos.x()); if (_ypos_any) xml.attribute("ypos", "any"); else xml.attribute("ypos", _pos.y()); } if (_size_defined) { xml.attribute("width", _size.w()); xml.attribute("height", _size.h()); } if (_maximized) xml.attribute("maximized", true); } template void for_each_member(FN const &fn) { _members.for_each(fn); } template void for_each_member(FN const &fn) const { _members.for_each(fn); } }; #endif /* _ASSIGN_H_ */