diff --git a/repos/os/include/nitpicker_session/client.h b/repos/os/include/nitpicker_session/client.h index f569be68a..7b4f02fb9 100644 --- a/repos/os/include/nitpicker_session/client.h +++ b/repos/os/include/nitpicker_session/client.h @@ -83,6 +83,9 @@ class Nitpicker::Session_client : public Genode::Rpc_client void focus(Nitpicker::Session_capability session) override { call(session); } + void session_control(Label selector, Session_control operation) override { + call(selector, operation); } + /** * Enqueue command to command buffer * diff --git a/repos/os/include/nitpicker_session/nitpicker_session.h b/repos/os/include/nitpicker_session/nitpicker_session.h index 23f99f9c6..1d095fc63 100644 --- a/repos/os/include/nitpicker_session/nitpicker_session.h +++ b/repos/os/include/nitpicker_session/nitpicker_session.h @@ -279,6 +279,23 @@ struct Nitpicker::Session : Genode::Session */ virtual void focus(Genode::Capability focused) = 0; + typedef Genode::String<160> Label; + + enum Session_control { SESSION_CONTROL_HIDE, SESSION_CONTROL_SHOW, + SESSION_CONTROL_TO_FRONT }; + + /** + * Perform control operation on one or multiple sessions + * + * The 'label' is used to select the sessions, on which the 'operation' is + * performed. Nitpicker creates a selector string by concatenating the + * caller's session label with the supplied 'label' argument. A session is + * selected if its label starts with the selector string. Thereby, the + * operation is limited to the caller session or any child session of the + * caller. + */ + virtual void session_control(Label label, Session_control operation) { } + /** * Return number of bytes needed for virtual framebuffer of specified size */ @@ -311,6 +328,7 @@ struct Nitpicker::Session : Genode::Session GENODE_RPC(Rpc_mode, Framebuffer::Mode, mode); GENODE_RPC(Rpc_mode_sigh, void, mode_sigh, Genode::Signal_context_capability); GENODE_RPC(Rpc_focus, void, focus, Genode::Capability); + GENODE_RPC(Rpc_session_control, void, session_control, Label, Session_control); GENODE_RPC_THROW(Rpc_buffer, void, buffer, GENODE_TYPE_LIST(Out_of_metadata), Framebuffer::Mode, bool); @@ -332,8 +350,9 @@ struct Nitpicker::Session : Genode::Session Type_tuple - > > > > > > > > > > > > Rpc_functions; + > > > > > > > > > > > > > Rpc_functions; }; #endif /* _INCLUDE__NITPICKER_SESSION__NITPICKER_SESSION_H_ */ diff --git a/repos/os/src/server/nitpicker/main.cc b/repos/os/src/server/nitpicker/main.cc index 3a9f7a32d..e50bbc5f5 100644 --- a/repos/os/src/server/nitpicker/main.cc +++ b/repos/os/src/server/nitpicker/main.cc @@ -921,6 +921,21 @@ class Nitpicker::Session_component : public Genode::Rpc_object, report_focus(_focus_reporter, session); } + void session_control(Label suffix, Session_control control) override + { + char selector[Label::size()]; + + Genode::snprintf(selector, sizeof(selector), "%s%s%s", + label().string(), + suffix.length() ? " -> " : "", suffix.string()); + + switch (control) { + case SESSION_CONTROL_HIDE: _view_stack.visible(selector, false); break; + case SESSION_CONTROL_SHOW: _view_stack.visible(selector, true); break; + case SESSION_CONTROL_TO_FRONT: _view_stack.to_front(selector); break; + } + } + /******************************* ** Buffer_provider interface ** diff --git a/repos/os/src/server/nitpicker/session.h b/repos/os/src/server/nitpicker/session.h index bc3bb037e..4a901cb75 100644 --- a/repos/os/src/server/nitpicker/session.h +++ b/repos/os/src/server/nitpicker/session.h @@ -39,6 +39,7 @@ class Session : public Session_list::Element Domain_registry::Entry const *_domain; Texture_base const *_texture = { 0 }; bool _uses_alpha = { false }; + bool _visible = true; View *_background = 0; unsigned char const *_input_mask = { 0 }; @@ -59,6 +60,21 @@ class Session : public Session_list::Element Genode::Session_label const &label() const { return _label; } + /** + * Return true if session label starts with specified 'selector' + */ + bool matches_session_label(char const *selector) const + { + /* + * Append label separator to match selectors with a trailing + * separator. + */ + char label[Genode::Session_label::MAX_LEN + 4]; + Genode::snprintf(label, sizeof(label), "%s ->", _label.string()); + return Genode::strcmp(label, selector, + Genode::strlen(selector)) == 0; + } + bool xray_opaque() const { return _domain && _domain->xray_opaque(); } bool xray_no() const { return _domain && _domain->xray_no(); } @@ -67,6 +83,10 @@ class Session : public Session_list::Element unsigned layer() const { return _domain ? _domain->layer() : ~0UL; } + bool visible() const { return _visible; } + + void visible(bool visible) { _visible = visible; } + Domain_registry::Entry::Name domain_name() const { return _domain ? _domain->name() : Domain_registry::Entry::Name(); diff --git a/repos/os/src/server/nitpicker/view_stack.cc b/repos/os/src/server/nitpicker/view_stack.cc index ecbb259fb..33f022eb8 100644 --- a/repos/os/src/server/nitpicker/view_stack.cc +++ b/repos/os/src/server/nitpicker/view_stack.cc @@ -34,6 +34,8 @@ VIEW *View_stack::_next_view(VIEW &view) const /* check if we hit the bottom of the view stack */ if (!next_view) return 0; + if (!next_view->session().visible()) continue; + if (!next_view->background()) return next_view; if (is_default_background(*next_view) || next_view == active_background) diff --git a/repos/os/src/server/nitpicker/view_stack.h b/repos/os/src/server/nitpicker/view_stack.h index 9db3ac73d..f8dde55b8 100644 --- a/repos/os/src/server/nitpicker/view_stack.h +++ b/repos/os/src/server/nitpicker/view_stack.h @@ -264,6 +264,57 @@ class View_stack } void sort_views_by_layer(); + + /** + * Set visibility of views that match the specified label selector + */ + void visible(char const *selector, bool visible) + { + for (View *v = _first_view(); v; v = v->view_stack_next()) { + + if (!v->session().matches_session_label(selector)) + continue; + + /* mark view geometry as to be redrawn */ + refresh(_outline(*v)); + + /* let the view stack omit the views of the session */ + v->session().visible(visible); + } + } + + /** + * Bring views that match the specified label selector to the front + */ + void to_front(char const *selector) + { + /* + * Move all views that match the selector to the front while + * maintaining their ordering. + */ + View *at = nullptr; + for (View *v = _first_view(); v; v = v->view_stack_next()) { + + if (!v->session().matches_session_label(selector)) + continue; + + /* + * Move view to behind the previous view that we moved to + * front. If 'v' is the first view that matches the selector, + * move it to the front ('at' argument of 'insert' is 0). + */ + _views.remove(v); + _views.insert(v, at); + + at = v; + + /* mark view geometry as to be redrawn */ + refresh(_outline(*v)); + } + + /* reestablish domain layering */ + sort_views_by_layer(); + } }; #endif