diff --git a/repos/gems/src/app/window_layouter/action.h b/repos/gems/src/app/window_layouter/action.h deleted file mode 100644 index 995274b6ac..0000000000 --- a/repos/gems/src/app/window_layouter/action.h +++ /dev/null @@ -1,86 +0,0 @@ -/* - * \brief Action triggered by the user - * \author Norman Feske - * \date 2016-02-01 - */ - -/* - * Copyright (C) 2016-2017 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 _ACTION_H_ -#define _ACTION_H_ - -#include - -namespace Window_layouter { class Action; } - - -/** - * Result of the application of a key event to the key-sequence tracker - */ -class Window_layouter::Action -{ - public: - - enum Type { - NONE, - NEXT_WINDOW, - PREV_WINDOW, - RAISE_WINDOW, - TOGGLE_FULLSCREEN, - CLOSE, - NEXT_WORKSPACE, - PREV_WORKSPACE, - MARK, - DETACH, - ATTACH, - COLUMN, - ROW, - REMOVE, - NEXT_COLUMN, - PREV_COLUMN, - NEXT_ROW, - PREV_ROW, - NEXT_TAB, - PREV_TAB, - TOOGLE_OVERLAY, - SCREEN, - RELEASE_GRAB, - }; - - private: - - Type _type; - Target::Name _target; - - template - static Type _type_by_string(String const &string) - { - if (string == "next_window") return NEXT_WINDOW; - if (string == "prev_window") return PREV_WINDOW; - if (string == "raise_window") return RAISE_WINDOW; - if (string == "toggle_fullscreen") return TOGGLE_FULLSCREEN; - if (string == "screen") return SCREEN; - if (string == "release_grab") return RELEASE_GRAB; - - Genode::warning("cannot convert \"", string, "\" to action type"); - return NONE; - } - - public: - - Action(Type type) : _type(type), _target() { } - - template - Action(String const &string, Target::Name const &arg) - : _type(_type_by_string(string)), _target(arg) { } - - Type type() const { return _type; } - Target::Name target_name() const { return _target; } -}; - -#endif /* _ACTION_H_ */ diff --git a/repos/gems/src/app/window_layouter/assign.h b/repos/gems/src/app/window_layouter/assign.h index afcdb9edeb..eeb8950976 100644 --- a/repos/gems/src/app/window_layouter/assign.h +++ b/repos/gems/src/app/window_layouter/assign.h @@ -42,17 +42,63 @@ class Window_layouter::Assign : public List_model::Element : Registry::Element(registry, *this), window(window) { } }; - using Label = String<80>; - Target::Name target_name { }; private: Registry _members { }; + struct Label + { + using Value = String<80>; + + Value exact, prefix, suffix; + + static Label from_xml(Xml_node const &node) + { + return { .exact = node.attribute_value("label", Value()), + .prefix = node.attribute_value("label_prefix", Value()), + .suffix = node.attribute_value("label_suffix", Value()) }; + } + + bool operator == (Label const &other) const + { + return exact == other.exact + && prefix == other.prefix + && suffix == other.suffix; + } + + bool matches(Value const &label) const + { + if (exact.valid() && label == exact) + return true; + + if (exact.valid()) + return false; + + bool const prefix_matches = + prefix.valid() && + !strcmp(label.string(), prefix.string(), prefix.length() - 1); + + bool suffix_matches = false; + if (label.length() >= suffix.length()) { + size_t const offset = label.length() - suffix.length(); + suffix_matches = !strcmp(label.string() + offset, suffix.string()); + } + + return (!prefix.valid() || prefix_matches) + && (!suffix.valid() || suffix_matches); + } + + void gen_attr(Xml_generator &xml) const + { + if (exact .valid()) xml.attribute("label", exact); + if (prefix.valid()) xml.attribute("label_prefix", prefix); + if (suffix.valid()) xml.attribute("label_suffix", suffix); + } + }; + Label const _label; - Label const _label_prefix; - Label const _label_suffix; bool _pos_defined = false; bool _xpos_any = false; @@ -66,12 +112,7 @@ class Window_layouter::Assign : public List_model::Element 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())) - { } + Assign(Xml_node assign) : _label(Label::from_xml(assign)) { } void update(Xml_node assign) { @@ -89,19 +130,12 @@ class Window_layouter::Assign : public List_model::Element /** * List_model::Element */ - 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; - } + bool matches(Xml_node node) const { return Label::from_xml(node) == _label; } /** * List_model::Element */ - static bool type_matches(Xml_node const &node) - { - return node.has_type("assign"); + static bool type_matches(Xml_node const &node) { return node.has_type("assign"); } /** @@ -136,38 +170,19 @@ class Window_layouter::Assign : public List_model::Element * * This method is used for associating assignments to windows. */ - template - void with_matching_members_registry(Label const &label, FN const &fn) + void with_matching_members_registry(Label::Value const &label, auto 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 = (unsigned)(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) + if (_label.matches(label)) fn(_members); } /** * Used to generate nodes of windows captured via wildcard */ - template - void for_each_wildcard_member(FN const &fn) const + void for_each_wildcard_member(auto const &fn) const { /* skip non-wildcards */ - if (_label.valid()) + if (_label.exact.valid()) return; _members.for_each([&] (Assign::Member const &member) { fn(member); }); @@ -176,10 +191,9 @@ class Window_layouter::Assign : public List_model::Element /** * Used to bring wildcard-matching windows to front */ - template - void for_each_wildcard_member(FN const &fn) + void for_each_wildcard_member(auto const &fn) { - if (_label.valid()) + if (_label.exact.valid()) return; _members.for_each([&] (Assign::Member &member) { fn(member); }); @@ -187,17 +201,14 @@ class Window_layouter::Assign : public List_model::Element bool floating() const { return _pos_defined; } - bool wildcard() const { return !_label.valid(); } + bool wildcard() const { return !_label.exact.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); - + _label.gen_attr(xml); xml.attribute("target", target_name); } @@ -247,11 +258,8 @@ class Window_layouter::Assign : public List_model::Element xml.attribute("visible", "no"); } - 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); } + void for_each_member(auto const &fn) { _members.for_each(fn); } + void for_each_member(auto const &fn) const { _members.for_each(fn); } }; #endif /* _ASSIGN_H_ */ diff --git a/repos/gems/src/app/window_layouter/assign_list.h b/repos/gems/src/app/window_layouter/assign_list.h index 22aa53dc8b..77c0929779 100644 --- a/repos/gems/src/app/window_layouter/assign_list.h +++ b/repos/gems/src/app/window_layouter/assign_list.h @@ -55,21 +55,19 @@ class Window_layouter::Assign_list : Noncopyable auto fn = [&] (Registry ®istry) { window.assignment(registry); }; - assign.with_matching_members_registry(window.label(), fn); + assign.with_matching_members_registry(window.label, fn); }); }); } - template - void for_each_wildcard_member(FN const &fn) const + void for_each_wildcard_member(auto const &fn) const { _assignments.for_each([&] (Assign const &assign) { assign.for_each_wildcard_member([&] (Assign::Member const &member) { fn(assign, member); }); }); } - template - void for_each_wildcard_assigned_window(FN const &fn) + void for_each_wildcard_assigned_window(auto const &fn) { _assignments.for_each([&] (Assign &assign) { assign.for_each_wildcard_member([&] (Assign::Member &member) { diff --git a/repos/gems/src/app/window_layouter/command.h b/repos/gems/src/app/window_layouter/command.h new file mode 100644 index 0000000000..2461286175 --- /dev/null +++ b/repos/gems/src/app/window_layouter/command.h @@ -0,0 +1,52 @@ +/* + * \brief Command triggered via the keyboard + * \author Norman Feske + * \date 2016-02-01 + */ + +/* + * Copyright (C) 2016-2017 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 _COMMAND_H_ +#define _COMMAND_H_ + +#include + +namespace Window_layouter { class Command; } + + +struct Window_layouter::Command +{ + enum Type { NONE, NEXT_WINDOW, PREV_WINDOW, RAISE_WINDOW, TOGGLE_FULLSCREEN, + NEXT_TAB, PREV_TAB, SCREEN, RELEASE_GRAB, }; + + Type type; + Target::Name target; + + static Command from_xml(Xml_node const &node) + { + auto from_string = [] (auto const &string) -> Type + { + if (string == "next_window") return NEXT_WINDOW; + if (string == "prev_window") return PREV_WINDOW; + if (string == "raise_window") return RAISE_WINDOW; + if (string == "toggle_fullscreen") return TOGGLE_FULLSCREEN; + if (string == "screen") return SCREEN; + if (string == "release_grab") return RELEASE_GRAB; + + warning("cannot convert \"", string, "\" to action type"); + return NONE; + }; + + return { + .type = from_string(node.attribute_value("action", String<32>())), + .target = node.attribute_value("target", Name()) + }; + } +}; + +#endif /* _COMMAND_H_ */ diff --git a/repos/gems/src/app/window_layouter/decorator_margins.h b/repos/gems/src/app/window_layouter/decorator_margins.h index a4b2ea9156..7560765d7f 100644 --- a/repos/gems/src/app/window_layouter/decorator_margins.h +++ b/repos/gems/src/app/window_layouter/decorator_margins.h @@ -24,13 +24,13 @@ struct Window_layouter::Decorator_margins { unsigned top, bottom, left, right; - Decorator_margins(Xml_node node) - : - top (node.attribute_value("top", 0U)), - bottom(node.attribute_value("bottom", 0U)), - left (node.attribute_value("left", 0U)), - right (node.attribute_value("right", 0U)) - { } + static Decorator_margins from_xml(Xml_node const &node) + { + return { .top = node.attribute_value("top", 0U), + .bottom = node.attribute_value("bottom", 0U), + .left = node.attribute_value("left", 0U), + .right = node.attribute_value("right", 0U) }; + } /** * Convert outer geometry to inner geometry diff --git a/repos/gems/src/app/window_layouter/key_sequence_tracker.h b/repos/gems/src/app/window_layouter/key_sequence_tracker.h index 27619ad8ae..f1b8be3a15 100644 --- a/repos/gems/src/app/window_layouter/key_sequence_tracker.h +++ b/repos/gems/src/app/window_layouter/key_sequence_tracker.h @@ -15,7 +15,7 @@ #define _KEY_SEQUENCE_TRACKER_H_ /* local includes */ -#include "action.h" +#include namespace Window_layouter { class Key_sequence_tracker; } @@ -28,20 +28,18 @@ class Window_layouter::Key_sequence_tracker { struct Entry { - enum Type { PRESS, RELEASE }; + bool press; - Type type = PRESS; - - Input::Keycode keycode = Input::KEY_UNKNOWN; - - Entry() { } - - Entry(Type type, Input::Keycode keycode) - : type(type), keycode(keycode) { } + Input::Keycode key; bool operator == (Entry const &other) const { - return other.type == type && other.keycode == keycode; + return other.press == press && other.key == key; + } + + void print(Output &out) const + { + Genode::print(out, press ? "press " : "release ", Input::key_name(key)); } }; @@ -50,7 +48,7 @@ class Window_layouter::Key_sequence_tracker * sequence. */ enum { MAX_ENTRIES = 64 }; - Entry entries[MAX_ENTRIES]; + Entry entries[MAX_ENTRIES] { }; unsigned pos = 0; @@ -91,82 +89,69 @@ class Window_layouter::Key_sequence_tracker } void reset() { pos = 0; } + + void print(Output &out) const + { + Genode::print(out, "[", pos, "]: "); + for (unsigned i = 0; i < pos; i++) + Genode::print(out, " ", entries[i]); + } }; Stack _stack { }; - Xml_node _matching_sub_node(Xml_node curr, Stack::Entry entry) + void _with_matching_sub_node(Xml_node const &curr, Stack::Entry entry, + auto const &fn, auto const &no_match_fn) const { - char const *node_type = entry.type == Stack::Entry::PRESS - ? "press" : "release"; + auto const node_type = entry.press ? "press" : "release"; using Key_name = String<32>; - Key_name const key(Input::key_name(entry.keycode)); - - Xml_node result(""); + Key_name const key(Input::key_name(entry.key)); + bool done = false; /* process the first match only */ curr.for_each_sub_node(node_type, [&] (Xml_node const &node) { + if (!done && node.attribute_value("key", Key_name()) == key) { + fn(node); + done = true; } }); - if (node.attribute_value("key", Key_name()) != key) - return; - - /* set 'result' only once, so we return the first match */ - if (result.has_type("none")) - result = node; - }); - - return result; + if (!done) + no_match_fn(); } + void _with_match_rec(unsigned const pos, Xml_node const &node, auto const &fn) const + { + if (pos == _stack.pos) { + fn(node); + return; + } + + /* recursion is bounded by Stack::MAX_ENTRIES */ + _with_matching_sub_node(node, _stack.entries[pos], + [&] (Xml_node const &sub_node) { + if (pos < _stack.pos) + _with_match_rec(pos + 1, sub_node, fn); }, + [&] { }); + }; + /** - * Lookup XML node that matches the state of the key sequence + * Call 'fn' with XML node that matches the state of the key sequence * * Traverse the nested '' and '' nodes of the * configuration according to the history of events of the current * sequence. - * - * \return XML node of the type '' or ''. - * If the configuration does not contain a matching node, the - * method returns a dummy node ''. */ - Xml_node _xml_by_path(Xml_node config) + void _with_xml_by_path(Xml_node const &config, auto const &fn) const { - Xml_node curr = config; - - /* - * Each iteration corresponds to a nesting level - */ - for (unsigned i = 0; i < _stack.pos; i++) { - - Stack::Entry const entry = _stack.entries[i]; - - Xml_node const match = _matching_sub_node(curr, entry); - - if (match.has_type("none")) - return match; - - curr = match; - } - - return curr; + _with_match_rec(0, config, fn); } /** - * Execute action denoted in the specific XML node + * Execute command denoted in the specific XML node */ - template - void _execute_action(Xml_node node, FUNC const &func) + void _execute_command(Xml_node node, auto const &fn) { - if (!node.has_attribute("action")) - return; - - using Action = String<32>; - Action action = node.attribute_value("action", Action()); - - using Name = Window_layouter::Target::Name; - Name const target = node.attribute_value("target", Name()); - - func(Window_layouter::Action(action, target)); + if (node.has_attribute("action")) + fn(Command::from_xml(node)); } public: @@ -179,13 +164,12 @@ class Window_layouter::Key_sequence_tracker /** * Apply event to key sequence * - * \param func functor to be called if the event leads to a node in - * the key-sequence configuration and the node is - * equipped with an 'action' attribute. The functor is - * called with an 'Action' as argument. + * \param fn functor to be called if the event leads to a node in + * the key-sequence configuration and the node is + * equipped with an 'action' attribute. The functor is + * called with an 'Action' as argument. */ - template - void apply(Input::Event const &ev, Xml_node config, FUNC const &func) + void apply(Input::Event const &ev, Xml_node const &config, auto const &fn) { /* * If the sequence contains a press-release combination for @@ -194,44 +178,44 @@ class Window_layouter::Key_sequence_tracker * once. */ ev.handle_press([&] (Input::Keycode key, Codepoint) { - _stack.flush(Stack::Entry(Stack::Entry::PRESS, key)); - _stack.flush(Stack::Entry(Stack::Entry::RELEASE, key)); + _stack.flush(Stack::Entry { .press = true, .key = key }); + _stack.flush(Stack::Entry { .press = false, .key = key }); }); - Xml_node curr_node = _xml_by_path(config); + _with_xml_by_path(config, [&] (Xml_node const &curr_node) { - ev.handle_press([&] (Input::Keycode key, Codepoint) { + ev.handle_press([&] (Input::Keycode key, Codepoint) { - Stack::Entry const entry(Stack::Entry::PRESS, key); + Stack::Entry const press { .press = true, .key = key }; - _execute_action(_matching_sub_node(curr_node, entry), func); - _stack.push(entry); - }); + _with_matching_sub_node(curr_node, press, + [&] (Xml_node const &node) { _execute_command(node, fn); }, + [&] { }); - ev.handle_release([&] (Input::Keycode key) { + _stack.push(press); + }); - Stack::Entry const entry(Stack::Entry::RELEASE, key); + ev.handle_release([&] (Input::Keycode key) { - Xml_node const next_node = _matching_sub_node(curr_node, entry); + Stack::Entry const release { .press = false, .key = key }; - /* - * If there exists a specific path for the release event, - * follow the path. Otherwise, we remove the released key from - * the sequence. - */ - if (!next_node.has_type("none")) { - - _execute_action(next_node, func); - _stack.push(entry); - - } else { - - Stack::Entry entry(Stack::Entry::PRESS, key); - _stack.flush(entry); - } + /* + * If there exists a specific path for the release event, + * follow the path. Otherwise, we remove the released key + * from the sequence. + */ + _with_matching_sub_node(curr_node, release, + [&] (Xml_node const &next_node) { + _execute_command(next_node, fn); + _stack.push(release); + }, + [&] /* no match */ { + Stack::Entry const press { .press = true, .key = key }; + _stack.flush(press); + }); + }); }); } }; - #endif /* _KEY_SEQUENCE_TRACKER_H_ */ diff --git a/repos/gems/src/app/window_layouter/layout_rules.h b/repos/gems/src/app/window_layouter/layout_rules.h index 230458d4d1..77baecfdb2 100644 --- a/repos/gems/src/app/window_layouter/layout_rules.h +++ b/repos/gems/src/app/window_layouter/layout_rules.h @@ -28,7 +28,7 @@ class Window_layouter::Layout_rules : Noncopyable { public: - struct Change_handler : Interface + struct Action : Interface { virtual void layout_rules_changed() = 0; }; @@ -39,7 +39,7 @@ class Window_layouter::Layout_rules : Noncopyable Allocator &_alloc; - Change_handler &_change_handler; + Action &_action; Constructible _config_rules { }; @@ -49,19 +49,19 @@ class Window_layouter::Layout_rules : Noncopyable Attached_rom_dataspace rom; - Change_handler &_change_handler; + Action &_action; void _handle() { rom.update(); - _change_handler.layout_rules_changed(); + _action.layout_rules_changed(); } Signal_handler _handler; - Rom_rules(Env &env, Change_handler &change_handler) + Rom_rules(Env &env, Action &action) : - rom(env, node_type()), _change_handler(change_handler), + rom(env, node_type()), _action(action), _handler(env.ep(), *this, &Rom_rules::_handle) { rom.sigh(_handler); @@ -73,9 +73,9 @@ class Window_layouter::Layout_rules : Noncopyable public: - Layout_rules(Env &env, Allocator &alloc, Change_handler &change_handler) + Layout_rules(Env &env, Allocator &alloc, Action &action) : - _env(env), _alloc(alloc), _change_handler(change_handler) + _env(env), _alloc(alloc), _action(action) { } void update_config(Xml_node config) @@ -83,14 +83,14 @@ class Window_layouter::Layout_rules : Noncopyable bool const use_rules_from_rom = (config.attribute_value(Rom_rules::node_type(), String<10>()) == "rom"); - _rom_rules.conditional(use_rules_from_rom, _env, _change_handler); + _rom_rules.conditional(use_rules_from_rom, _env, _action); _config_rules.destruct(); if (config.has_sub_node(Rom_rules::node_type())) _config_rules.construct(_alloc, config.sub_node(Rom_rules::node_type())); - _change_handler.layout_rules_changed(); + _action.layout_rules_changed(); } /** @@ -102,8 +102,7 @@ class Window_layouter::Layout_rules : Noncopyable * definitions are present, the rules ROM - if valid - takes * precedence over the configuration's '' node. */ - template - void with_rules(FN const &fn) const + void with_rules(auto const &fn) const { if (_rom_rules.constructed()) { Xml_node const rules = _rom_rules->rom.xml(); diff --git a/repos/gems/src/app/window_layouter/main.cc b/repos/gems/src/app/window_layouter/main.cc index 167b66f854..4ee0c0f5a6 100644 --- a/repos/gems/src/app/window_layouter/main.cc +++ b/repos/gems/src/app/window_layouter/main.cc @@ -30,14 +30,13 @@ #include #include #include -#include namespace Window_layouter { struct Main; } -struct Window_layouter::Main : Operations, - Layout_rules::Change_handler, - Window_list::Change_handler +struct Window_layouter::Main : User_state::Action, + Layout_rules::Action, + Window_list::Action { Env &_env; @@ -63,7 +62,7 @@ struct Window_layouter::Main : Operations, Layout_rules _layout_rules { _env, _heap, *this }; - Decorator_margins _decorator_margins { Xml_node("") }; + Decorator_margins _decorator_margins { }; Window_list _window_list { _env, _heap, *this, _focus_history, _decorator_margins }; @@ -104,17 +103,17 @@ struct Window_layouter::Main : Operations, _assign_list.for_each([&] (Assign &assign) { _target_list.for_each([&] (Target const &target) { - if (target.name() != assign.target_name) + if (target.name != assign.target_name) return; assign.for_each_member([&] (Assign::Member &member) { member.window.floating(assign.floating()); - member.window.target_area(target.geometry().area); + member.window.target_area(target.rect.area); - Rect const rect = assign.window_geometry(member.window.id().value, + Rect const rect = assign.window_geometry(member.window.id.value, member.window.client_size(), - target.geometry().area, + target.rect.area, _decorator_margins); member.window.outer_geometry(rect); member.window.maximized(assign.maximized()); @@ -135,7 +134,7 @@ struct Window_layouter::Main : Operations, } /** - * Layout_rules::Change_handler interface + * Layout_rules::Action interface */ void layout_rules_changed() override { @@ -145,7 +144,7 @@ struct Window_layouter::Main : Operations, } /** - * Window_list::Change_handler interface + * Window_list::Action interface */ void window_list_changed() override { _update_window_layout(); } @@ -165,9 +164,9 @@ struct Window_layouter::Main : Operations, User_state _user_state { *this, _focus_history }; - /************************** - ** Operations interface ** - **************************/ + /********************************** + ** User_state::Action interface ** + **********************************/ void close(Window_id id) override { @@ -226,11 +225,11 @@ struct Window_layouter::Main : Operations, _assign_list.for_each([&] (Assign &assign) { Window *window_ptr = nullptr; assign.for_each_member([&] (Assign::Member &member) { - if (member.window.id() == id) + if (member.window.id == id) window_ptr = &member.window; }); if (window_ptr) { - assign.target_name = to.name(); - window_ptr->warp(from.geometry().at - to.geometry().at); + assign.target_name = to.name; + window_ptr->warp(from.rect.at - to.rect.at); } }); } @@ -240,7 +239,7 @@ struct Window_layouter::Main : Operations, /* change of screen under the dragged window */ if (_drag.dragging()) _with_target_change(_drag.window_id, name, [&] (Target const &from, Target const &to) { - if (from.geometry() == to.geometry()) + if (from.rect == to.rect) _retarget_window(_drag.window_id, from, to); }); _gen_rules_with_frontmost_screen(name); @@ -253,7 +252,7 @@ struct Window_layouter::Main : Operations, bool const moving = _moving(id, element); _target_list.with_target_at(curr, [&] (Target const &pointed) { - _drag = { Drag::State::DRAGGING, moving, id, curr, pointed.geometry() }; }); + _drag = { Drag::State::DRAGGING, moving, id, curr, pointed.rect }; }); to_front(id); @@ -319,8 +318,8 @@ struct Window_layouter::Main : Operations, bool const moving = _moving(id, element); if (moving) { _target_list.with_target_at(curr, [&] (Target const &pointed) { - _drag = { Drag::State::SETTLING, moving, id, curr, pointed.geometry() }; - _with_target_change(id, pointed.name(), [&] (Target const &from, Target const &to) { + _drag = { Drag::State::SETTLING, moving, id, curr, pointed.rect }; + _with_target_change(id, pointed.name, [&] (Target const &from, Target const &to) { _retarget_window(id, from, to); }); }); } @@ -359,8 +358,8 @@ struct Window_layouter::Main : Operations, _decorator_margins_rom.update(); Xml_node const margins = _decorator_margins_rom.xml(); - if (margins.has_sub_node("floating")) - _decorator_margins = Decorator_margins(margins.sub_node("floating")); + margins.with_optional_sub_node("floating", [&] (Xml_node const floating) { + _decorator_margins = Decorator_margins::from_xml(floating); }); /* respond to change by adapting the maximized window geometry */ _handle_mode_change(); @@ -424,8 +423,7 @@ struct Window_layouter::Main : Operations, _gen_rules_with_frontmost_screen(Target::Name()); } - template - void _gen_rules_assignments(Xml_generator &, FN const &); + void _gen_rules_assignments(Xml_generator &, auto const &); /** * Constructor @@ -461,11 +459,11 @@ void Window_layouter::Main::_gen_window_layout() /* update hover and focus state of each window */ _window_list.for_each_window([&] (Window &window) { - window.focused(window.has_id(_user_state.focused_window_id())); + window.focused(window.id == _user_state.focused_window_id()); - bool const hovered = window.has_id(_user_state.hover_state().window_id); + bool const hovered = (window.id == _user_state.hover_state().window_id); window.hovered(hovered ? _user_state.hover_state().element - : Window::Element::UNDEFINED); + : Window::Element { }); }); _window_layout_reporter.generate([&] (Xml_generator &xml) { @@ -502,8 +500,7 @@ void Window_layouter::Main::_gen_focus() } -template -void Window_layouter::Main::_gen_rules_assignments(Xml_generator &xml, FN const &filter) +void Window_layouter::Main::_gen_rules_assignments(Xml_generator &xml, auto const &filter_fn) { auto gen_window_geometry = [] (Xml_generator &xml, Assign const &assign, Window const &window) { @@ -517,11 +514,11 @@ void Window_layouter::Main::_gen_rules_assignments(Xml_generator &xml, FN const /* turn wildcard assignments into exact assignments */ auto fn = [&] (Assign const &assign, Assign::Member const &member) { - if (!filter(member.window)) + if (!filter_fn(member.window)) return; xml.node("assign", [&] () { - xml.attribute("label", member.window.label()); + xml.attribute("label", member.window.label); xml.attribute("target", assign.target_name); gen_window_geometry(xml, assign, member.window); }); @@ -546,7 +543,7 @@ void Window_layouter::Main::_gen_rules_assignments(Xml_generator &xml, FN const assign.for_each_member([&] (Assign::Member const &member) { - if (geometry_generated || !filter(member.window)) + if (geometry_generated || !filter_fn(member.window)) return; xml.node("assign", [&] () { @@ -618,69 +615,20 @@ void Window_layouter::Main::_gen_rules_with_frontmost_screen(Target::Name const } -/** - * Determine window element that corresponds to hover model - */ -static Window_layouter::Window::Element -_element_from_hover_model(Genode::Xml_node hover_window_xml) -{ - using Type = Window_layouter::Window::Element::Type; - - bool const left_sizer = hover_window_xml.has_sub_node("left_sizer"), - right_sizer = hover_window_xml.has_sub_node("right_sizer"), - top_sizer = hover_window_xml.has_sub_node("top_sizer"), - bottom_sizer = hover_window_xml.has_sub_node("bottom_sizer"); - - if (left_sizer && top_sizer) return Type::TOP_LEFT; - if (left_sizer && bottom_sizer) return Type::BOTTOM_LEFT; - if (left_sizer) return Type::LEFT; - - if (right_sizer && top_sizer) return Type::TOP_RIGHT; - if (right_sizer && bottom_sizer) return Type::BOTTOM_RIGHT; - if (right_sizer) return Type::RIGHT; - - if (top_sizer) return Type::TOP; - if (bottom_sizer) return Type::BOTTOM; - - if (hover_window_xml.has_sub_node("title")) return Type::TITLE; - if (hover_window_xml.has_sub_node("closer")) return Type::CLOSER; - if (hover_window_xml.has_sub_node("maximizer")) return Type::MAXIMIZER; - if (hover_window_xml.has_sub_node("minimizer")) return Type::MINIMIZER; - - return Type::UNDEFINED; -} - - void Window_layouter::Main::_handle_hover() { _hover.update(); User_state::Hover_state const orig_hover_state = _user_state.hover_state(); - try { - Xml_node const hover_window_xml = _hover.xml().sub_node("window"); - - _user_state.hover({ hover_window_xml.attribute_value("id", 0U) }, - _element_from_hover_model(hover_window_xml)); - } - - /* - * An exception may occur during the 'Xml_node' construction if the hover - * model lacks a window. Under this condition, we invalidate the hover - * state. - */ - catch (...) { - - _user_state.reset_hover(); - - /* - * Don't generate a focus-model update here. In a situation where the - * pointer has moved over a native GUI view (outside the realm of - * the window manager), the hover model as generated by the decorator - * naturally becomes empty. If we posted a focus update, this would - * steal the focus away from the native GUI view. - */ - } + _hover.xml().with_sub_node("window", + [&] (Xml_node const &hover) { + _user_state.hover({ hover.attribute_value("id", 0U) }, + Window::Element::from_xml(hover)); + }, + [&] /* the hover model lacks a window */ { + _user_state.reset_hover(); + }); /* * Propagate changed hovering to the decorator @@ -698,7 +646,7 @@ void Window_layouter::Main::_handle_focus_request() { _focus_request.update(); - int const id = (int)_focus_request.xml().attribute_value("id", 0L); + int const id = _focus_request.xml().attribute_value("id", 0); /* don't apply the same focus request twice */ if (id == _handled_focus_request_id) @@ -718,9 +666,9 @@ void Window_layouter::Main::_handle_focus_request() _window_list.for_each_window([&] (Window &window) { - if (label_matches(prefix, window.label())) { + if (label_matches(prefix, window.label)) { window.to_front_cnt(next_to_front_cnt); - _user_state.focused_window_id(window.id()); + _user_state.focused_window_id(window.id); stacking_order_changed = true; } }); diff --git a/repos/gems/src/app/window_layouter/operations.h b/repos/gems/src/app/window_layouter/operations.h deleted file mode 100644 index 5cf7da46cc..0000000000 --- a/repos/gems/src/app/window_layouter/operations.h +++ /dev/null @@ -1,38 +0,0 @@ -/* - * \brief Window layouter - * \author Norman Feske - * \date 2015-12-31 - */ - -/* - * Copyright (C) 2015-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 _OPERATIONS_H_ -#define _OPERATIONS_H_ - -/* Genode includes */ -#include - -/* local includes */ -#include "window.h" - -namespace Window_layouter { struct Operations; } - - -struct Window_layouter::Operations : Interface -{ - virtual void close(Window_id) = 0; - virtual void toggle_fullscreen(Window_id) = 0; - virtual void focus(Window_id) = 0; - virtual void release_grab() = 0; - virtual void to_front(Window_id) = 0; - virtual void drag(Window_id, Window::Element, Point clicked, Point curr) = 0; - virtual void finalize_drag(Window_id, Window::Element, Point clicked, Point final) = 0; - virtual void screen(Target::Name const &) = 0; -}; - -#endif /* _OPERATIONS_H_ */ diff --git a/repos/gems/src/app/window_layouter/target.h b/repos/gems/src/app/window_layouter/target.h index 3c2c65fb27..e1c2601a55 100644 --- a/repos/gems/src/app/window_layouter/target.h +++ b/repos/gems/src/app/window_layouter/target.h @@ -20,38 +20,27 @@ namespace Window_layouter { class Target; } -class Window_layouter::Target : Noncopyable +struct Window_layouter::Target : Noncopyable { - public: + using Name = String<64>; - using Name = String<64>; + struct Visible { bool value; }; - struct Visible { bool value; }; + Name const name; + unsigned const layer; + Rect const rect; + bool const visible; - private: + Target(Xml_node target, Rect rect, Visible visible) + : + name (target.attribute_value("name", Name())), + layer(target.attribute_value("layer", 9999U)), + rect (rect), + visible(visible.value) + { } - Name const _name; - unsigned const _layer; - Rect const _geometry; - bool const _visible; - - public: - - Target(Xml_node target, Rect geometry, Visible visible) - : - _name (target.attribute_value("name", Name())), - _layer(target.attribute_value("layer", 9999U)), - _geometry(geometry), - _visible(visible.value) - { } - - /* needed to use class as 'Registered' */ - virtual ~Target() { } - - Name name() const { return _name; } - unsigned layer() const { return _layer; } - Rect geometry() const { return _geometry; } - bool visible() const { return _visible; } + /* needed to use class as 'Registered' */ + virtual ~Target() { } }; #endif /* _TARGET_H_ */ diff --git a/repos/gems/src/app/window_layouter/target_list.h b/repos/gems/src/app/window_layouter/target_list.h index 9ec68f180f..d663e9d6ec 100644 --- a/repos/gems/src/app/window_layouter/target_list.h +++ b/repos/gems/src/app/window_layouter/target_list.h @@ -144,8 +144,8 @@ class Window_layouter::Target_list /* search targets for next matching layer */ unsigned layer = MAX_LAYER; _targets.for_each([&] (Target const &target) { - if (target.layer() >= min_layer && target.layer() <= layer) - layer = target.layer(); }); + if (target.layer >= min_layer && target.layer <= layer) + layer = target.layer; }); Rect const drag_origin_boundary = drag.dragging() && drag.moving ? target_boundary(assignments, drag.window_id) @@ -153,31 +153,31 @@ class Window_layouter::Target_list /* search target by name */ _targets.for_each([&] (Target const &target) { - if (target.layer() != layer) + if (target.layer != layer) return; - if (!target.visible()) + if (!target.visible) return; - if (assignments.target_empty(target.name()) && !drag.moving_at_target_rect(target.geometry())) + if (assignments.target_empty(target.name) && !drag.moving_at_target_rect(target.rect)) return; - Rect const boundary = target.geometry(); + Rect const boundary = target.rect; xml.node("boundary", [&] { - xml.attribute("name", target.name()); + xml.attribute("name", target.name); generate(xml, boundary); /* in-flux window node for the currently dragged window */ - if (drag.moving_at_target_rect(target.geometry())) + if (drag.moving_at_target_rect(target.rect)) assignments.for_each([&] (Assign const &assign) { assign.for_each_member([&] (Assign::Member const &member) { - if (drag.moving_window(member.window.id())) + if (drag.moving_window(member.window.id)) member.window.generate(xml, drag_origin_boundary); }); }); /* visit all windows on the layer, except for the dragged one */ - assignments.for_each_visible(target.name(), [&] (Assign const &assign) { + assignments.for_each_visible(target.name, [&] (Assign const &assign) { assign.for_each_member([&] (Assign::Member const &member) { - if (!drag.moving_window(member.window.id())) + if (!drag.moving_window(member.window.id)) member.window.generate(xml, boundary); }); }); }); }); @@ -291,7 +291,7 @@ class Window_layouter::Target_list { Target const *ptr = nullptr; for_each([&] (Target const &target) { - if (target.name() == name) + if (target.name == name) ptr = ⌖ }); if (ptr) fn(*ptr); @@ -301,7 +301,7 @@ class Window_layouter::Target_list { Target const *ptr = nullptr; for_each([&] (Target const &target) { - if (target.visible() && target.geometry().contains(at)) + if (target.visible && target.rect.contains(at)) ptr = ⌖ }); if (ptr) fn(*ptr); @@ -311,9 +311,9 @@ class Window_layouter::Target_list { Target const *ptr = nullptr; _targets.for_each([&] (Target const &target) { - assignments.for_each_visible(target.name(), [&] (Assign const &assign) { + assignments.for_each_visible(target.name, [&] (Assign const &assign) { assign.for_each_member([&] (Assign::Member const &member) { - if (member.window.id() == id) + if (member.window.id == id) ptr = ⌖ }); }); }); if (ptr) fn(*ptr); @@ -326,10 +326,9 @@ class Window_layouter::Target_list { Rect result { }; with_target(assignments, id, [&] (Target const &target) { - result = target.geometry(); }); + result = target.rect; }); return result; } - }; #endif /* _TARGET_LIST_H_ */ diff --git a/repos/gems/src/app/window_layouter/user_state.h b/repos/gems/src/app/window_layouter/user_state.h index 95f03995bc..82d8bbc625 100644 --- a/repos/gems/src/app/window_layouter/user_state.h +++ b/repos/gems/src/app/window_layouter/user_state.h @@ -15,8 +15,7 @@ #define _USER_STATE_H_ /* local includes */ -#include "operations.h" -#include "key_sequence_tracker.h" +#include namespace Window_layouter { class User_state; } @@ -25,15 +24,22 @@ class Window_layouter::User_state { public: + struct Action : Interface + { + virtual void close(Window_id) = 0; + virtual void toggle_fullscreen(Window_id) = 0; + virtual void focus(Window_id) = 0; + virtual void release_grab() = 0; + virtual void to_front(Window_id) = 0; + virtual void drag(Window_id, Window::Element, Point clicked, Point curr) = 0; + virtual void finalize_drag(Window_id, Window::Element, Point clicked, Point final) = 0; + virtual void screen(Target::Name const &) = 0; + }; + struct Hover_state { Window_id window_id; - Window::Element element { Window::Element::UNDEFINED }; - - Hover_state(Window_id id, Window::Element element) - : - window_id(id), element(element) - { } + Window::Element element; bool operator != (Hover_state const &other) const { @@ -44,16 +50,18 @@ class Window_layouter::User_state private: + Action &_action; + Window_id _hovered_window_id { }; Window_id _focused_window_id { }; Window_id _dragged_window_id { }; - unsigned _key_cnt = 0; + unsigned _key_cnt = 0; Key_sequence_tracker _key_sequence_tracker { }; - Window::Element _hovered_element = Window::Element::UNDEFINED; - Window::Element _dragged_element = Window::Element::UNDEFINED; + Window::Element _hovered_element { }; + Window::Element _dragged_element { }; /* * True while drag operation in progress @@ -77,8 +85,6 @@ class Window_layouter::User_state */ Point _pointer_curr { }; - Operations &_operations; - Focus_history &_focus_history; /* @@ -107,16 +113,16 @@ class Window_layouter::User_state /* * Toggle maximized (fullscreen) state */ - if (_hovered_element == Window::Element::MAXIMIZER) { + if (_hovered_element.maximizer()) { _dragged_window_id = _hovered_window_id; _focused_window_id = _hovered_window_id; _focus_history.focus(_focused_window_id); - _operations.toggle_fullscreen(_hovered_window_id); + _action.toggle_fullscreen(_hovered_window_id); - _hovered_element = Window::Element::UNDEFINED; - _hovered_window_id = Window_id(); + _hovered_element = { }; + _hovered_window_id = { }; return; } @@ -128,19 +134,19 @@ class Window_layouter::User_state _focused_window_id = _hovered_window_id; _focus_history.focus(_focused_window_id); - _operations.to_front(_hovered_window_id); - _operations.focus(_hovered_window_id); + _action.to_front(_hovered_window_id); + _action.focus(_hovered_window_id); } - _operations.drag(_dragged_window_id, _dragged_element, - _pointer_clicked, _pointer_curr); + _action.drag(_dragged_window_id, _dragged_element, + _pointer_clicked, _pointer_curr); } public: - User_state(Operations &operations, Focus_history &focus_history) + User_state(Action &action, Focus_history &focus_history) : - _operations(operations), _focus_history(focus_history) + _action(action), _focus_history(focus_history) { } void handle_input(Input::Event const events[], unsigned num_events, @@ -155,8 +161,8 @@ class Window_layouter::User_state * Issue drag operation when in dragged state */ if (_drag_state && _drag_init_done && (_pointer_curr != pointer_last)) - _operations.drag(_dragged_window_id, _dragged_element, - _pointer_clicked, _pointer_curr); + _action.drag(_dragged_window_id, _dragged_element, + _pointer_clicked, _pointer_curr); } void hover(Window_id window_id, Window::Element element) @@ -186,15 +192,13 @@ class Window_layouter::User_state /* * Let focus follows the pointer - * - * XXX obtain policy from config */ if (!_drag_state && _hovered_window_id.valid() && _hovered_window_id != last_hovered_window_id) { _focused_window_id = _hovered_window_id; _focus_history.focus(_focused_window_id); - _operations.focus(_focused_window_id); + _action.focus(_focused_window_id); } } @@ -204,8 +208,8 @@ class Window_layouter::User_state if (_drag_state) return; - _hovered_element = Window::Element::UNDEFINED; - _hovered_window_id = Window_id(); + _hovered_element = { }; + _hovered_window_id = { }; } Window_id focused_window_id() const { return _focused_window_id; } @@ -225,8 +229,8 @@ void Window_layouter::User_state::_handle_event(Input::Event const &e, if (e.absolute_motion() || e.focus_enter()) { if (_drag_state && _drag_init_done) - _operations.drag(_dragged_window_id, _dragged_element, - _pointer_clicked, _pointer_curr); + _action.drag(_dragged_window_id, _dragged_element, + _pointer_clicked, _pointer_curr); } /* track number of pressed buttons/keys */ @@ -277,12 +281,12 @@ void Window_layouter::User_state::_handle_event(Input::Event const &e, /* * Issue resize to 0x0 when releasing the the window closer */ - if (_dragged_element == Window::Element::CLOSER) + if (_dragged_element.closer()) if (_dragged_element == _hovered_element) - _operations.close(_dragged_window_id); + _action.close(_dragged_window_id); - _operations.finalize_drag(_dragged_window_id, _dragged_element, - _pointer_clicked, _pointer_curr); + _action.finalize_drag(_dragged_window_id, _dragged_element, + _pointer_clicked, _pointer_curr); } } @@ -292,38 +296,38 @@ void Window_layouter::User_state::_handle_event(Input::Event const &e, if (e.press() && _key_cnt == 1) _key_sequence_tracker.reset(); - _key_sequence_tracker.apply(e, config, [&] (Action action) { + _key_sequence_tracker.apply(e, config, [&] (Command const &command) { - switch (action.type()) { + switch (command.type) { - case Action::TOGGLE_FULLSCREEN: - _operations.toggle_fullscreen(_focused_window_id); + case Command::TOGGLE_FULLSCREEN: + _action.toggle_fullscreen(_focused_window_id); return; - case Action::RAISE_WINDOW: - _operations.to_front(_focused_window_id); + case Command::RAISE_WINDOW: + _action.to_front(_focused_window_id); return; - case Action::NEXT_WINDOW: + case Command::NEXT_WINDOW: _focused_window_id = _focus_history.next(_focused_window_id); - _operations.focus(_focused_window_id); + _action.focus(_focused_window_id); return; - case Action::PREV_WINDOW: + case Command::PREV_WINDOW: _focused_window_id = _focus_history.prev(_focused_window_id); - _operations.focus(_focused_window_id); + _action.focus(_focused_window_id); return; - case Action::SCREEN: - _operations.screen(action.target_name()); + case Command::SCREEN: + _action.screen(command.target); return; - case Action::RELEASE_GRAB: - _operations.release_grab(); + case Command::RELEASE_GRAB: + _action.release_grab(); return; default: - warning("action ", (int)action.type(), " unhanded"); + warning("command ", (int)command.type, " unhanded"); } }); } diff --git a/repos/gems/src/app/window_layouter/window.h b/repos/gems/src/app/window_layouter/window.h index 27622b93f6..7c55a9ecc0 100644 --- a/repos/gems/src/app/window_layouter/window.h +++ b/repos/gems/src/app/window_layouter/window.h @@ -58,7 +58,29 @@ class Window_layouter::Window : public List_model::Element return ""; } - Element(Type type) : type(type) { } + static Element from_xml(Xml_node const &hover) + { + bool const left = hover.has_sub_node("left_sizer"), + right = hover.has_sub_node("right_sizer"), + top = hover.has_sub_node("top_sizer"), + bottom = hover.has_sub_node("bottom_sizer"); + + if (top && left) return { TOP_LEFT }; + if (bottom && left) return { BOTTOM_LEFT }; + if (left) return { LEFT }; + if (top && right) return { TOP_RIGHT }; + if (bottom && right) return { BOTTOM_RIGHT }; + if (right) return { RIGHT }; + if (top) return { TOP }; + if (bottom) return { BOTTOM }; + + if (hover.has_sub_node("title")) return { TITLE }; + if (hover.has_sub_node("closer")) return { CLOSER }; + if (hover.has_sub_node("maximizer")) return { MAXIMIZER }; + if (hover.has_sub_node("minimizer")) return { MINIMIZER }; + + return { UNDEFINED }; + } bool operator != (Element const &other) const { return other.type != type; } bool operator == (Element const &other) const { return other.type == type; } @@ -71,16 +93,29 @@ class Window_layouter::Window : public List_model::Element || type == BOTTOM_LEFT || type == BOTTOM_RIGHT || type == MAXIMIZER; } + + bool _any_of(Type t1, Type t2, Type t3) const + { + return type == t1 || type == t2 || type == t3; + } + + bool left() const { return _any_of(LEFT, TOP_LEFT, BOTTOM_LEFT); } + bool right() const { return _any_of(RIGHT, TOP_RIGHT, BOTTOM_RIGHT); } + bool top() const { return _any_of(TOP, TOP_LEFT, TOP_RIGHT); } + bool bottom() const { return _any_of(BOTTOM, BOTTOM_LEFT, BOTTOM_RIGHT); } + + bool maximizer() const { return type == MAXIMIZER; } + bool closer() const { return type == CLOSER; } }; + Window_id const id; + + Label const label; + private: - Window_id const _id; - Title _title { }; - Label const _label; - Decorator_margins const &_decorator_margins; Rect _geometry { }; @@ -172,10 +207,13 @@ class Window_layouter::Window : public List_model::Element Focus_history::Entry _focus_history_entry; - bool _drag_left_border = false; - bool _drag_right_border = false; - bool _drag_top_border = false; - bool _drag_bottom_border = false; + struct Dragged_border + { + bool left, right, top, bottom; + + bool any() const { return left || right || top || bottom; }; + + } _dragged_border { }; /** * Called when the user starts dragging a window element @@ -185,22 +223,10 @@ class Window_layouter::Window : public List_model::Element _dragged_element = element; if (_resizeable) { - - _drag_left_border = (element.type == Window::Element::LEFT) - || (element.type == Window::Element::TOP_LEFT) - || (element.type == Window::Element::BOTTOM_LEFT); - - _drag_right_border = (element.type == Window::Element::RIGHT) - || (element.type == Window::Element::TOP_RIGHT) - || (element.type == Window::Element::BOTTOM_RIGHT); - - _drag_top_border = (element.type == Window::Element::TOP) - || (element.type == Window::Element::TOP_LEFT) - || (element.type == Window::Element::TOP_RIGHT); - - _drag_bottom_border = (element.type == Window::Element::BOTTOM) - || (element.type == Window::Element::BOTTOM_LEFT) - || (element.type == Window::Element::BOTTOM_RIGHT); + _dragged_border.left = element.left(); + _dragged_border.right = element.right(); + _dragged_border.top = element.top(); + _dragged_border.bottom = element.bottom(); } _orig_geometry = _geometry; @@ -217,7 +243,7 @@ class Window_layouter::Window : public List_model::Element void _apply_drag_operation(Point offset) { /* move window */ - if (!_drag_border()) { + if (!_dragged_border.any()) { _drag_geometry = Rect(_orig_geometry.p1() + offset, _orig_geometry.area); return; @@ -233,25 +259,16 @@ class Window_layouter::Window : public List_model::Element auto clamped = [] (int v, int lowest, int highest) { return min(max(v, lowest), highest); }; - if (_drag_left_border) x1 = clamped(min(x1 + offset.x, x2), inner.x1(), outer.x2()); - if (_drag_right_border) x2 = clamped(max(x2 + offset.x, x1), outer.x1(), inner.x2()); - if (_drag_top_border) y1 = clamped(min(y1 + offset.y, y2), inner.y1(), outer.y2()); - if (_drag_bottom_border) y2 = clamped(max(y2 + offset.y, y1), outer.y1(), inner.y2()); + if (_dragged_border.left) x1 = clamped(min(x1 + offset.x, x2), inner.x1(), outer.x2()); + if (_dragged_border.right) x2 = clamped(max(x2 + offset.x, x1), outer.x1(), inner.x2()); + if (_dragged_border.top) y1 = clamped(min(y1 + offset.y, y2), inner.y1(), outer.y2()); + if (_dragged_border.bottom) y2 = clamped(max(y2 + offset.y, y1), outer.y1(), inner.y2()); _drag_geometry = Rect::compound(Point { x1, y1 }, Point { x2, y2 }); _dragged_size = _drag_geometry.area; } - /** - * Return true if user drags a window border - */ - bool _drag_border() const - { - return _drag_left_border || _drag_right_border - || _drag_top_border || _drag_bottom_border; - } - Constructible _assign_member { }; public: @@ -260,21 +277,15 @@ class Window_layouter::Window : public List_model::Element Focus_history &focus_history, Decorator_margins const &decorator_margins) : - _id(id), _label(label), + id(id), label(label), _decorator_margins(decorator_margins), _client_size(initial_size), _dragged_size(initial_size), - _focus_history_entry(focus_history, _id) + _focus_history_entry(focus_history, id) { } - bool has_id(Window_id id) const { return id == _id; } - - Window_id id() const { return _id; } - void title(Title const &title) { _title = title; } - Label label() const { return _label; } - bool dragged() const { return _dragged; } Rect effective_inner_geometry() const @@ -286,14 +297,14 @@ class Window_layouter::Window : public List_model::Element x2 = _orig_geometry.x2(), y2 = _orig_geometry.y2(); /* move window */ - if (!_drag_border()) + if (!_dragged_border.any()) return _drag_geometry; /* resize window */ - if (_drag_left_border) x1 = x2 - _client_size.w + 1; - if (_drag_right_border) x2 = x1 + _client_size.w - 1; - if (_drag_top_border) y1 = y2 - _client_size.h + 1; - if (_drag_bottom_border) y2 = y1 + _client_size.h - 1; + if (_dragged_border.left) x1 = x2 - _client_size.w + 1; + if (_dragged_border.right) x2 = x1 + _client_size.w - 1; + if (_dragged_border.top) y1 = y2 - _client_size.h + 1; + if (_dragged_border.bottom) y2 = y1 + _client_size.h - 1; return Rect::compound(Point(x1, y1), Point(x2, y2)); } @@ -335,8 +346,6 @@ class Window_layouter::Window : public List_model::Element bool resizeable() const { return _resizeable; } - bool label_matches(Label const &label) const { return label == _label; } - /** * Define window size * @@ -370,7 +379,7 @@ class Window_layouter::Window : public List_model::Element return; xml.node("window", [&] () { - xml.attribute("id", _id.value); + xml.attribute("id", id.value); xml.attribute("width", size.w); xml.attribute("height", size.h); }); @@ -384,14 +393,14 @@ class Window_layouter::Window : public List_model::Element xml.node("window", [&]() { - xml.attribute("id", _id.value); + xml.attribute("id", id.value); /* present concatenation of label and title in the window's title bar */ { bool const has_title = strlen(_title.string()) > 0; String const - title(_label, (has_title ? " " : ""), _title); + title(label, (has_title ? " " : ""), _title); xml.attribute("title", title); } @@ -471,13 +480,10 @@ class Window_layouter::Window : public List_model::Element void finalize_drag_operation() { - _drag_left_border = false; - _drag_right_border = false; - _drag_top_border = false; - _drag_bottom_border = false; - _geometry = effective_inner_geometry(); - _dragged_size = _geometry.area; - _dragged = false; + _dragged_border = { }; + _geometry = effective_inner_geometry(); + _dragged_size = _geometry.area; + _dragged = false; } void to_front_cnt(unsigned to_front_cnt) { _to_front_cnt = to_front_cnt; } @@ -520,7 +526,7 @@ class Window_layouter::Window : public List_model::Element */ bool matches(Xml_node const &node) const { - return node.attribute_value("id", 0U) == _id.value; + return node.attribute_value("id", 0U) == id.value; } /** diff --git a/repos/gems/src/app/window_layouter/window_list.h b/repos/gems/src/app/window_layouter/window_list.h index 3f5a310921..4b1c43f51c 100644 --- a/repos/gems/src/app/window_layouter/window_list.h +++ b/repos/gems/src/app/window_layouter/window_list.h @@ -25,7 +25,7 @@ class Window_layouter::Window_list { public: - struct Change_handler : Interface + struct Action : Interface { virtual void window_list_changed() = 0; }; @@ -34,7 +34,7 @@ class Window_layouter::Window_list Env &_env; Allocator &_alloc; - Change_handler &_change_handler; + Action &_action; Focus_history &_focus_history; Decorator_margins const &_decorator_margins; @@ -79,20 +79,20 @@ class Window_layouter::Window_list ); /* notify main program */ - _change_handler.window_list_changed(); + _action.window_list_changed(); } public: Window_list(Env &env, Allocator &alloc, - Change_handler &change_handler, + Action &action, Focus_history &focus_history, Decorator_margins const &decorator_margins) : _env(env), _alloc(alloc), - _change_handler(change_handler), + _action(action), _focus_history(focus_history), _decorator_margins(decorator_margins) { @@ -107,27 +107,22 @@ class Window_layouter::Window_list win.dissolve_from_assignment(); }); } - template - void with_window(Window_id id, FN const &fn) + void with_window(Window_id id, auto const &fn) { _list.for_each([&] (Window &win) { - if (win.has_id(id)) + if (win.id == id) fn(win); }); } - template - void with_window(Window_id id, FN const &fn) const + void with_window(Window_id id, auto const &fn) const { _list.for_each([&] (Window const &win) { - if (win.has_id(id)) + if (win.id == id) fn(win); }); } - template - void for_each_window(FN const &fn) { _list.for_each(fn); } - - template - void for_each_window(FN const &fn) const { _list.for_each(fn); } + void for_each_window(auto const &fn) { _list.for_each(fn); } + void for_each_window(auto const &fn) const { _list.for_each(fn); } }; #endif /* _WINDOW_LIST_H_ */