diff --git a/repos/gems/run/wm.run b/repos/gems/run/wm.run index afcb094b0..bb3dc4787 100644 --- a/repos/gems/run/wm.run +++ b/repos/gems/run/wm.run @@ -134,6 +134,7 @@ append config { + diff --git a/repos/gems/src/app/floating_window_layouter/main.cc b/repos/gems/src/app/floating_window_layouter/main.cc index 2146ac426..d3a457a1b 100644 --- a/repos/gems/src/app/floating_window_layouter/main.cc +++ b/repos/gems/src/app/floating_window_layouter/main.cc @@ -16,6 +16,7 @@ #include #include #include +#include #include #include #include @@ -69,6 +70,7 @@ class Floating_window_layouter::Window : public List::Element public: typedef String<256> Title; + typedef String<256> Label; struct Element { @@ -105,6 +107,8 @@ class Floating_window_layouter::Window : public List::Element Title _title; + Label _label; + Rect _geometry; /** @@ -151,6 +155,8 @@ class Floating_window_layouter::Window : public List::Element void title(Title const &title) { _title = title; } + void label(Label const &label) { _label = label; } + void geometry(Rect geometry) { _geometry = geometry; } Point position() const { return _geometry.p1(); } @@ -161,6 +167,8 @@ class Floating_window_layouter::Window : public List::Element void is_hidden(bool is_hidden) { _is_hidden = is_hidden; } + bool label_matches(Label const &label) const { return label == _label; } + /** * Return true if user drags a window border */ @@ -210,8 +218,22 @@ class Floating_window_layouter::Window : public List::Element return; xml.node("window", [&]() { - xml.attribute("id", _id); - xml.attribute("title", _title.string()); + + xml.attribute("id", _id); + + /* present concatenation of label and title in the window's title bar */ + { + bool const has_title = Genode::strlen(_title.string()) > 0; + + char buf[Label::capacity()]; + Genode::snprintf(buf, sizeof(buf), "%s%s%s", + _label.string(), + has_title ? " " : "", + _title.string()); + + xml.attribute("title", buf); + } + xml.attribute("xpos", _geometry.x1()); xml.attribute("ypos", _geometry.y1()); xml.attribute("width", _geometry.w()); @@ -319,6 +341,21 @@ struct Floating_window_layouter::Main Attached_rom_dataspace window_list { "window_list" }; + /** + * Install handler for responding to focus requests + */ + void handle_focus_request_update(unsigned); + + void _apply_focus_request(); + + int handled_focus_request_id = 0; + + Signal_dispatcher
focus_request_dispatcher = { + sig_rec, *this, &Main::handle_focus_request_update }; + + Attached_rom_dataspace focus_request { "focus_request" }; + + /** * Install handler for responding to hover changes */ @@ -366,6 +403,8 @@ struct Floating_window_layouter::Main { window_list.sigh(window_list_dispatcher); + focus_request.sigh(focus_request_dispatcher); + hover.sigh(hover_dispatcher); input.sigh(input_dispatcher); @@ -413,7 +452,8 @@ void Floating_window_layouter::Main::import_window_list(Xml_node window_list_xml } win->size(area_attribute(node)); - win->title(string_attribute(node, "title", Window::Title("untitled"))); + win->label(string_attribute(node, "label", Window::Label(""))); + win->title(string_attribute(node, "title", Window::Title(""))); win->has_alpha(node.has_attribute("has_alpha") && node.attribute("has_alpha").has_value("yes")); win->is_hidden(node.has_attribute("hidden") @@ -531,6 +571,74 @@ void Floating_window_layouter::Main::handle_window_list_update(unsigned) } +void Floating_window_layouter::Main::_apply_focus_request() +{ + try { + Xml_node node(focus_request.local_addr()); + + Window::Label const label = node.attribute_value("label", Window::Label("")); + + int const id = node.attribute_value("id", 0L); + + /* don't apply the same focus request twice */ + if (id == handled_focus_request_id) + return; + + bool focus_redefined = false; + + /* + * Move all windows that match the requested label to the front while + * maintaining their ordering. + */ + Window *at = nullptr; + for (Window *w = windows.first(); w; w = w->next()) { + + if (!w->label_matches(label)) + continue; + + focus_redefined = true; + + /* + * Move window to behind the previous window that we moved to + * front. If 'w' is the first window that matches the selector, + * move it to the front ('at' argument of 'insert' is 0). + */ + windows.remove(w); + windows.insert(w, at); + + /* + * Bring top-most window to the front of nitpicker's global view + * stack and set the focus to the top-most window. + */ + if (at == nullptr) { + w->topped(); + + focused_window_id = w->id(); + generate_focus_model(); + } + + at = w; + } + + if (focus_redefined) + handled_focus_request_id = id; + + } + catch (...) { + PERR("Error while handling focus request"); } +} + + +void Floating_window_layouter::Main::handle_focus_request_update(unsigned) +{ + focus_request.update(); + + _apply_focus_request(); + + generate_window_layout_model(); +} + + void Floating_window_layouter::Main::handle_hover_update(unsigned) { hover.update(); diff --git a/repos/gems/src/server/wm/main.cc b/repos/gems/src/server/wm/main.cc index e4e9c331b..780367716 100644 --- a/repos/gems/src/server/wm/main.cc +++ b/repos/gems/src/server/wm/main.cc @@ -54,11 +54,14 @@ struct Wm::Main /* list of present windows, to be consumed by the layouter */ Reporter window_list_reporter = { "window_list" }; + /* request to the layouter to set the focus */ + Reporter focus_request_reporter = { "focus_request" }; + Window_registry window_registry { *env()->heap(), window_list_reporter }; Nitpicker::Root nitpicker_root { ep, window_registry, *env()->heap(), env()->ram_session_cap(), - pointer_reporter }; + pointer_reporter, focus_request_reporter }; Nitpicker::Connection focus_nitpicker_session; @@ -125,6 +128,8 @@ struct Wm::Main window_list_reporter.enabled(true); Genode::Reporter::Xml_generator xml(window_list_reporter, [&] () { }); + focus_request_reporter.enabled(true); + focus_rom.sigh(focus_dispatcher); resize_request_rom.sigh(resize_request_dispatcher); } diff --git a/repos/gems/src/server/wm/nitpicker.h b/repos/gems/src/server/wm/nitpicker.h index ecb97650e..b13afa092 100644 --- a/repos/gems/src/server/wm/nitpicker.h +++ b/repos/gems/src/server/wm/nitpicker.h @@ -228,23 +228,8 @@ class Wm::Nitpicker::Top_level_view : public View, */ Rect _content_geometry; - /* - * The window title is the concatenation of the session label with - * view title. - */ - struct Window_title : Title - { - Window_title(Session_label const session_label, Title const &title) - { - bool const has_title = Genode::strlen(title.string()) > 0; - char buf[256]; - Genode::snprintf(buf, sizeof(buf), "%s%s%s", - session_label.string(), - has_title ? " " : "", title.string()); - - *static_cast(this) = Title(buf); - } - } _window_title; + Title _window_title; + Session_label _session_label; typedef Nitpicker::Session::Command Command; @@ -257,7 +242,7 @@ class Wm::Nitpicker::Top_level_view : public View, : View(real_nitpicker, session_label, has_alpha), _window_registry(window_registry), - _window_title(session_label, "") + _session_label(session_label) { } ~Top_level_view() @@ -280,6 +265,7 @@ class Wm::Nitpicker::Top_level_view : public View, if (!_win_id.valid()) { _win_id = _window_registry.create(); _window_registry.title(_win_id, _window_title.string()); + _window_registry.label(_win_id, _session_label); _window_registry.has_alpha(_win_id, View::has_alpha()); } @@ -294,7 +280,7 @@ class Wm::Nitpicker::Top_level_view : public View, { View::title(title); - _window_title = Window_title(_session_label, title); + _window_title = Title(title); if (_win_id.valid()) _window_registry.title(_win_id, _window_title.string()); @@ -773,6 +759,8 @@ class Wm::Nitpicker::Session_component : public Rpc_object<Nitpicker::Session>, return false; } + Session_label session_label() const { return _session_label; } + bool matches_session_label(char const *selector) const { /* @@ -961,6 +949,10 @@ class Wm::Nitpicker::Root : public Genode::Rpc_object<Genode::Typed_root<Session Reporter &_pointer_reporter; + Reporter &_focus_request_reporter; + + unsigned _focus_request_cnt = 0; + Last_motion _last_motion = LAST_MOTION_DECORATOR; Window_registry &_window_registry; @@ -1043,10 +1035,11 @@ class Wm::Nitpicker::Root : public Genode::Rpc_object<Genode::Typed_root<Session Root(Entrypoint &ep, Window_registry &window_registry, Allocator &md_alloc, Ram_session_capability ram, - Reporter &pointer_reporter) + Reporter &pointer_reporter, Reporter &focus_request_reporter) : _ep(ep), _md_alloc(md_alloc), _ram(ram), _pointer_reporter(pointer_reporter), + _focus_request_reporter(focus_request_reporter), _window_registry(window_registry) { _window_layouter_input.event_queue().enabled(true); @@ -1208,7 +1201,14 @@ class Wm::Nitpicker::Root : public Genode::Rpc_object<Genode::Typed_root<Session break; case Session::SESSION_CONTROL_TO_FRONT: - PWRN("SESSION_CONTROL_TO_FRONT not implemented"); + + /* post focus request to the layouter */ + Genode::Reporter::Xml_generator + xml(_focus_request_reporter, [&] () { + xml.attribute("label", s->session_label().string()); + xml.attribute("id", ++_focus_request_cnt); + }); + break; } } diff --git a/repos/gems/src/server/wm/window_registry.h b/repos/gems/src/server/wm/window_registry.h index ea3687d23..fbc04a15a 100644 --- a/repos/gems/src/server/wm/window_registry.h +++ b/repos/gems/src/server/wm/window_registry.h @@ -20,6 +20,7 @@ #include <base/allocator.h> #include <os/surface.h> #include <os/reporter.h> +#include <os/session_policy.h> /* gems includes */ #include <gems/local_reporter.h> @@ -60,7 +61,8 @@ class Wm::Window_registry { public: - typedef Genode::String<200> Title; + typedef Genode::String<200> Title; + typedef Genode::Session_label Session_label; enum Has_alpha { HAS_ALPHA, HAS_NO_ALPHA }; @@ -72,6 +74,8 @@ class Wm::Window_registry Title _title; + Session_label _label; + Area _size; Has_alpha _has_alpha = HAS_NO_ALPHA; @@ -89,15 +93,17 @@ class Wm::Window_registry /* * Accessors for setting attributes */ - void attr(Title const &title) { _title = title; } - void attr(Area size) { _size = size; } - void attr(Has_alpha has_alpha) { _has_alpha = has_alpha; } - void attr(Is_hidden is_hidden) { _is_hidden = is_hidden; } + void attr(Title const &title) { _title = title; } + void attr(Session_label const &label) { _label = label; } + void attr(Area size) { _size = size; } + void attr(Has_alpha has_alpha) { _has_alpha = has_alpha; } + void attr(Is_hidden is_hidden) { _is_hidden = is_hidden; } void generate_window_list_entry_xml(Xml_generator &xml) const { xml.node("window", [&] () { xml.attribute("id", _id.value); + xml.attribute("label", _label.string()); xml.attribute("title", _title.string()); xml.attribute("width", _size.w()); xml.attribute("height", _size.h()); @@ -200,6 +206,8 @@ class Wm::Window_registry void title(Id id, Window::Title title) { _set_attr(id, title); } + void label(Id id, Window::Session_label label) { _set_attr(id, label); } + void has_alpha(Id id, bool has_alpha) { _set_attr(id, has_alpha ? Window::HAS_ALPHA : Window::HAS_NO_ALPHA); diff --git a/repos/libports/run/qt5_common.inc b/repos/libports/run/qt5_common.inc index 53b53fe8d..9335f98f5 100644 --- a/repos/libports/run/qt5_common.inc +++ b/repos/libports/run/qt5_common.inc @@ -103,6 +103,7 @@ proc qt5_start_nodes { feature_arg } { <config> <rom> <policy label="layouter -> window_list" report="wm -> window_list"/> + <policy label="layouter -> focus_request" report="wm -> focus_request"/> <policy label="decorator -> window_layout" report="layouter -> window_layout"/> <policy label="wm -> resize_request" report="layouter -> resize_request"/> <policy label="decorator -> pointer" report="wm -> pointer"/>