nitpicker: Domain configuration

This patch introduces the notion of a "domain" to the nitpicker
configuration concept. Session policies always refer to a domain where
multiple session policies can refer to the same domain. Thereby a domain
provides a way to express the grouping of sessions. This is useful for
applications that open multiple nitpicker sessions (such as Qt5 apps that
use one nitpicker session per window, menu, etc.). We want to assign all
those sessions to a single domain.

The configuration looks as follows:

<config>
  ...
  <domain name="default" color="#ffffff"/>
  <policy label="" domain="default"/>
  ...
</config>
This commit is contained in:
Norman Feske 2014-06-13 11:37:34 +02:00
parent 91e01411a4
commit dbebfd624e
6 changed files with 207 additions and 40 deletions

View File

@ -119,6 +119,9 @@ append config {
<resource name="RAM" quantum="1M"/>
<provides><service name="Nitpicker"/></provides>
<config>
<domain name="default" color="#ffffff"/>
<policy label="" domain="default"/>
<global-keys>
<key name="KEY_SCROLLLOCK" operation="xray" />
<key name="KEY_SYSRQ" operation="kill" />

View File

@ -0,0 +1,119 @@
/*
* \brief Domain registry
* \author Norman Feske
* \date 2014-06-12
*/
/*
* Copyright (C) 2014 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU General Public License version 2.
*/
#ifndef _DOMAIN_REGISTRY_
#define _DOMAIN_REGISTRY_
#include <util/xml_node.h>
#include <util/color.h>
class Domain_registry
{
public:
class Entry : public Genode::List<Entry>::Element
{
public:
typedef Genode::String<64> Name;
typedef Genode::Color Color;
private:
Name _name;
Color _color;
friend class Domain_registry;
Entry(Name const &name, Color color)
:
_name(name), _color(color)
{ }
public:
bool has_name(Name const &name) const { return name == _name; }
Color color() const { return _color; }
};
void _insert(Genode::Xml_node domain)
{
char buf[sizeof(Entry::Name)];
buf[0] = 0;
bool name_defined = false;
try {
domain.attribute("name").value(buf, sizeof(buf));
name_defined = true;
} catch (...) { }
if (!name_defined) {
PERR("no valid domain name specified");
return;
}
Entry::Name const name(buf);
if (lookup(name)) {
PERR("domain name \"%s\" is not unique", name.string());
return;
}
Entry::Color const color = domain.attribute_value("color", Entry::Color());
_entries.insert(new (_alloc) Entry(name, color));
}
private:
Genode::List<Entry> _entries;
Genode::Allocator &_alloc;
public:
Domain_registry(Genode::Allocator &alloc, Genode::Xml_node config)
:
_alloc(alloc)
{
char const *type = "domain";
if (!config.has_sub_node(type))
return;
Genode::Xml_node domain = config.sub_node(type);
for (;; domain = domain.next(type)) {
_insert(domain);
if (domain.is_last(type))
break;
}
}
~Domain_registry()
{
while (Entry *e = _entries.first())
Genode::destroy(_alloc, e);
}
Entry const *lookup(Entry::Name const &name) const
{
for (Entry const *e = _entries.first(); e; e = e->next())
if (e->has_name(name))
return e;
return 0;
}
};
#endif /* _DOMAIN_REGISTRY_ */

View File

@ -39,6 +39,7 @@
#include "clip_guard.h"
#include "mouse_cursor.h"
#include "chunky_menubar.h"
#include "domain_registry.h"
namespace Input { class Session_component; }
namespace Framebuffer { class Session_component; }
@ -895,13 +896,14 @@ class Nitpicker::Root : public Genode::Root_component<Session_component>
{
private:
Session_list &_session_list;
Global_keys &_global_keys;
Framebuffer::Mode _scr_mode;
View_stack &_view_stack;
Mode &_mode;
Framebuffer::Session &_framebuffer;
int _default_v_offset;
Session_list &_session_list;
Domain_registry const &_domain_registry;
Global_keys &_global_keys;
Framebuffer::Mode _scr_mode;
View_stack &_view_stack;
Mode &_mode;
Framebuffer::Session &_framebuffer;
int _default_v_offset;
protected:
@ -933,7 +935,7 @@ class Nitpicker::Root : public Genode::Root_component<Session_component>
_framebuffer, v_offset, provides_default_bg,
stay_top, *md_alloc(), unused_quota);
session->apply_session_color();
session->apply_session_policy(_domain_registry);
_session_list.insert(session);
_global_keys.apply_config(_session_list);
@ -962,17 +964,16 @@ class Nitpicker::Root : public Genode::Root_component<Session_component>
/**
* Constructor
*/
Root(Session_list &session_list, Global_keys &global_keys,
Rpc_entrypoint &session_ep, View_stack &view_stack,
Mode &mode, Allocator &md_alloc,
Framebuffer::Session &framebuffer,
Root(Session_list &session_list,
Domain_registry const &domain_registry, Global_keys &global_keys,
Rpc_entrypoint &session_ep, View_stack &view_stack, Mode &mode,
Allocator &md_alloc, Framebuffer::Session &framebuffer,
int default_v_offset)
:
Root_component<Session_component>(&session_ep, &md_alloc),
_session_list(session_list), _global_keys(global_keys),
_view_stack(view_stack), _mode(mode),
_framebuffer(framebuffer),
_default_v_offset(default_v_offset)
_session_list(session_list), _domain_registry(domain_registry),
_global_keys(global_keys), _view_stack(view_stack), _mode(mode),
_framebuffer(framebuffer), _default_v_offset(default_v_offset)
{ }
};
@ -1046,6 +1047,13 @@ struct Nitpicker::Main
Session_list session_list;
/*
* Construct empty domain registry. The initial version will be replaced
* on the first call of 'handle_config'.
*/
Genode::Volatile_object<Domain_registry> domain_registry {
*env()->heap(), Genode::Xml_node("<config/>") };
User_state user_state = { global_keys, fb_screen->screen.size(), fb_screen->menubar };
/*
@ -1062,9 +1070,9 @@ struct Nitpicker::Main
*/
Genode::Sliced_heap sliced_heap = { env()->ram_session(), env()->rm_session() };
Root<PT> np_root = { session_list, global_keys, ep.rpc_ep(), user_state,
user_state, sliced_heap, framebuffer,
Framebuffer_screen::MENUBAR_HEIGHT };
Root<PT> np_root = { session_list, *domain_registry, global_keys,
ep.rpc_ep(), user_state, user_state, sliced_heap,
framebuffer, Framebuffer_screen::MENUBAR_HEIGHT };
Genode::Reporter pointer_reporter = { "pointer" };
@ -1196,9 +1204,16 @@ void Nitpicker::Main::handle_config(unsigned)
.has_value("yes"));
} catch (...) { }
/* update session policies */
/* update domain registry and session policies */
for (::Session *s = session_list.first(); s; s = s->next())
s->apply_session_color();
s->reset_domain();
try {
domain_registry.construct(*env()->heap(), config()->xml_node()); }
catch (...) { }
for (::Session *s = session_list.first(); s; s = s->next())
s->apply_session_policy(*domain_registry);
/* redraw */
user_state.update_all_views();

View File

@ -53,7 +53,8 @@ class Mode
bool has_key_cnt(unsigned cnt) const { return cnt == _key_cnt; }
Session *focused_session() { return _focused_session; }
Session *focused_session() { return _focused_session; }
Session const *focused_session() const { return _focused_session; }
virtual void focused_session(Session *session) { _focused_session = session; }

View File

@ -22,6 +22,7 @@
/* local includes */
#include "color.h"
#include "canvas.h"
#include "domain_registry.h"
class View;
class Session;
@ -34,14 +35,14 @@ class Session : public Session_list::Element
{
private:
Genode::Session_label const _label;
Color _color;
Texture_base const *_texture = { 0 };
bool _uses_alpha = { false };
View *_background = 0;
int _v_offset;
unsigned char const *_input_mask = { 0 };
bool const _stay_top;
Genode::Session_label const _label;
Domain_registry::Entry const *_domain;
Texture_base const *_texture = { 0 };
bool _uses_alpha = { false };
View *_background = 0;
int _v_offset;
unsigned char const *_input_mask = { 0 };
bool const _stay_top;
public:
@ -87,7 +88,7 @@ class Session : public Session_list::Element
*/
void input_mask(unsigned char const *mask) { _input_mask = mask; }
Color color() const { return _color; }
Color color() const { return _domain ? _domain->color() : WHITE; }
View *background() const { return _background; }
@ -120,22 +121,51 @@ class Session : public Session_list::Element
return _input_mask[p.y()*_texture->size().w() + p.x()];
}
bool has_same_domain(Session const *s) const
{
return s && (s->_domain == _domain);
}
bool has_valid_domain() const
{
return _domain;
}
void reset_domain()
{
_domain = nullptr;
}
/**
* Set session color according to the list of configured policies
* Set session domain according to the list of configured policies
*
* Select the policy that matches the label. If multiple policies
* match, select the one with the largest number of characters.
*/
void apply_session_color()
void apply_session_policy(Domain_registry const &domain_registry)
{
/* use white by default */
_color = WHITE;
reset_domain();
try {
Genode::Session_policy policy(_label);
/* read color attribute */
policy.attribute("color").value(&_color);
/* read domain attribute */
if (!policy.has_attribute("domain")) {
PERR("policy for label \"%s\" lacks domain declaration",
_label.string());
return;
}
typedef Domain_registry::Entry::Name Domain_name;
char buf[sizeof(Domain_name)];
buf[0] = 0;
try {
policy.attribute("domain").value(buf, sizeof(buf)); }
catch (...) { }
Domain_name name(buf);
_domain = domain_registry.lookup(name);
} catch (...) { }
}
};

View File

@ -79,8 +79,7 @@ void View::frame(Canvas_base &canvas, Mode const &mode) const
void View::draw(Canvas_base &canvas, Mode const &mode) const
{
/* is this the currently focused view? */
bool const session_is_focused = mode.is_focused(_session);
bool const is_focused = _session.has_same_domain(mode.focused_session());
Color const frame_color = _session.color();
@ -88,7 +87,7 @@ void View::draw(Canvas_base &canvas, Mode const &mode) const
* Use dimming in x-ray and kill mode, but do not dim the focused view in
* x-ray mode.
*/
Texture_painter::Mode const op = mode.flat() || (mode.xray() && session_is_focused)
Texture_painter::Mode const op = mode.flat() || (mode.xray() && is_focused)
? Texture_painter::SOLID : Texture_painter::MIXED;
Rect const view_rect = abs_geometry();