nitpicker: add 'session_control' RPC function

The new 'session_control' function can be used to perform operations on
the global view stack that span one or multiple sessions, e.g., bringing
all views of specific sessions to the front, or hiding them.
This commit is contained in:
Norman Feske 2014-10-04 18:50:06 +02:00
parent 5af830c0de
commit 08d28e9b94
6 changed files with 111 additions and 1 deletions

View File

@ -83,6 +83,9 @@ class Nitpicker::Session_client : public Genode::Rpc_client<Session>
void focus(Nitpicker::Session_capability session) override {
call<Rpc_focus>(session); }
void session_control(Label selector, Session_control operation) override {
call<Rpc_session_control>(selector, operation); }
/**
* Enqueue command to command buffer
*

View File

@ -279,6 +279,23 @@ struct Nitpicker::Session : Genode::Session
*/
virtual void focus(Genode::Capability<Session> 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<Session>);
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_mode_sigh,
Type_tuple<Rpc_buffer,
Type_tuple<Rpc_focus,
Type_tuple<Rpc_session_control,
Genode::Meta::Empty>
> > > > > > > > > > > > Rpc_functions;
> > > > > > > > > > > > > Rpc_functions;
};
#endif /* _INCLUDE__NITPICKER_SESSION__NITPICKER_SESSION_H_ */

View File

@ -921,6 +921,21 @@ class Nitpicker::Session_component : public Genode::Rpc_object<Session>,
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 **

View File

@ -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();

View File

@ -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)

View File

@ -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