diff --git a/repos/ports/run/vbox_pointer.run b/repos/ports/run/vbox_pointer.run
index a33d9c0dec..dc14cd8af8 100644
--- a/repos/ports/run/vbox_pointer.run
+++ b/repos/ports/run/vbox_pointer.run
@@ -85,9 +85,9 @@ set config {
 		<provides><service name="Nitpicker"/></provides>
 		<config>
 			<report focus="yes" hover="yes" xray="yes"/>
-			<domain name="pointer"    layer="1" content="client" label="no" origin="pointer"/>
-			<domain name="smiley"     layer="3" content="client" label="no"/>
-			<domain name="default"    layer="3" content="client" label="no"/>
+			<domain name="pointer" layer="1" content="client" label="no"  origin="pointer"/>
+			<domain name="smiley"  layer="3" content="client" label="no"  hover="always" focus="click"/>
+			<domain name="default" layer="3" content="client" label="yes" hover="always" focus="click"/>
 
 			<policy label_prefix="pointer"            domain="pointer"/>
 			<policy label_prefix="test-domain-smiley" domain="smiley"/>
diff --git a/repos/ports/src/app/vbox_pointer/main.cc b/repos/ports/src/app/vbox_pointer/main.cc
index 8e56a70d17..e739f3092d 100644
--- a/repos/ports/src/app/vbox_pointer/main.cc
+++ b/repos/ports/src/app/vbox_pointer/main.cc
@@ -14,8 +14,9 @@
  */
 
 /* Genode includes */
-#include <os/attached_rom_dataspace.h>
-#include <os/config.h>
+#include <base/component.h>
+#include <base/heap.h>
+#include <base/attached_rom_dataspace.h>
 #include <os/pixel_rgb565.h>
 #include <nitpicker_session/connection.h>
 
@@ -24,6 +25,8 @@
 #include "policy.h"
 #include "big_mouse.h"
 
+namespace Vbox_pointer { class Main; }
+
 
 template <typename PT>
 void convert_default_pointer_data_to_pixels(PT *pixel, Nitpicker::Area size)
@@ -45,29 +48,32 @@ void convert_default_pointer_data_to_pixels(PT *pixel, Nitpicker::Area size)
 }
 
 
-class Main : public Vbox_pointer::Pointer_updater
+class Vbox_pointer::Main : public Vbox_pointer::Pointer_updater
 {
 	private:
 
+		Genode::Env &_env;
+
 		typedef Vbox_pointer::String          String;
 		typedef Vbox_pointer::Policy          Policy;
 		typedef Vbox_pointer::Policy_registry Policy_registry;
 
-		Genode::Attached_rom_dataspace _hover_ds { "hover" };
-		Genode::Attached_rom_dataspace _xray_ds  { "xray" };
+		Genode::Attached_rom_dataspace _hover_ds { _env, "hover"  };
+		Genode::Attached_rom_dataspace _xray_ds  { _env, "xray"   };
+		Genode::Attached_rom_dataspace _config   { _env, "config" };
 
-		Genode::Signal_receiver _sig_rec;
+		Genode::Signal_handler<Main> _hover_signal_handler {
+			_env.ep(), *this, &Main::_handle_hover };
+		Genode::Signal_handler<Main> _xray_signal_handler {
+			_env.ep(), *this, &Main::_handle_xray };
 
-		Genode::Signal_dispatcher<Main> _hover_signal_dispatcher {
-			_sig_rec, *this, &Main::_handle_hover };
-		Genode::Signal_dispatcher<Main> _xray_signal_dispatcher {
-			_sig_rec, *this, &Main::_handle_xray };
-
-		Nitpicker::Connection _nitpicker;
+		Nitpicker::Connection _nitpicker { _env };
 
 		Nitpicker::Session::View_handle _view = _nitpicker.create_view();
 
-		Policy_registry _policy_registry { *this };
+		Genode::Heap _heap { _env.ram(), _env.rm() };
+
+		Policy_registry _policy_registry { *this, _env, _heap };
 
 		String _hovered_label;
 		String _hovered_domain;
@@ -82,24 +88,22 @@ class Main : public Vbox_pointer::Pointer_updater
 		void _show_default_pointer();
 		void _show_shape_pointer(Policy *p);
 		void _update_pointer();
-		void _handle_hover(unsigned num = 0);
-		void _handle_xray(unsigned num = 0);
+		void _handle_hover();
+		void _handle_xray();
 
 	public:
 
-		Main();
+		Main(Genode::Env &);
 
 		/*******************************
 		 ** Pointer_updater interface **
 		 *******************************/
 
-		void update_pointer(Policy *policy) override;
-
-		Genode::Signal_receiver & signal_receiver() override { return _sig_rec; }
+		void update_pointer(Policy &policy) override;
 };
 
 
-void Main::_resize_nitpicker_buffer_if_needed(Nitpicker::Area pointer_size)
+void Vbox_pointer::Main::_resize_nitpicker_buffer_if_needed(Nitpicker::Area pointer_size)
 {
 	if (pointer_size == _current_pointer_size)
 		return;
@@ -116,7 +120,7 @@ void Main::_resize_nitpicker_buffer_if_needed(Nitpicker::Area pointer_size)
 }
 
 
-void Main::_show_default_pointer()
+void Vbox_pointer::Main::_show_default_pointer()
 {
 	/* only draw default pointer if not already drawn */
 	if (_default_pointer_visible)
@@ -146,7 +150,7 @@ void Main::_show_default_pointer()
 }
 
 
-void Main::_show_shape_pointer(Policy *p)
+void Vbox_pointer::Main::_show_shape_pointer(Policy *p)
 {
 	try {
 		_resize_nitpicker_buffer_if_needed(p->shape_size());
@@ -156,7 +160,7 @@ void Main::_show_shape_pointer(Policy *p)
 		throw;
 	}
 
-	Genode::Attached_dataspace ds { _pointer_ds };
+	Genode::Attached_dataspace ds { _env.rm(), _pointer_ds };
 
 	p->draw_shape(ds.local_addr<Genode::Pixel_rgb565>());
 
@@ -170,7 +174,7 @@ void Main::_show_shape_pointer(Policy *p)
 }
 
 
-void Main::_update_pointer()
+void Vbox_pointer::Main::_update_pointer()
 {
 	Policy *policy = nullptr;
 
@@ -185,7 +189,7 @@ void Main::_update_pointer()
 }
 
 
-void Main::_handle_hover(unsigned)
+void Vbox_pointer::Main::_handle_hover()
 {
 	using Vbox_pointer::read_string_attribute;
 
@@ -213,7 +217,7 @@ void Main::_handle_hover(unsigned)
 }
 
 
-void Main::_handle_xray(unsigned)
+void Vbox_pointer::Main::_handle_xray()
 {
 	_xray_ds.update();
 	if (!_xray_ds.valid())
@@ -236,15 +240,15 @@ void Main::_handle_xray(unsigned)
 }
 
 
-void Main::update_pointer(Policy *policy)
+void Vbox_pointer::Main::update_pointer(Policy &policy)
 {
 	/* update pointer if shape-changing policy is hovered */
-	if (policy == _policy_registry.lookup(_hovered_label, _hovered_domain))
+	if (&policy == _policy_registry.lookup(_hovered_label, _hovered_domain))
 		_update_pointer();
 }
 
 
-Main::Main()
+Vbox_pointer::Main::Main(Genode::Env &env) : _env(env)
 {
 	/*
 	 * Try to allocate the Nitpicker buffer for the maximum supported
@@ -256,11 +260,11 @@ Main::Main()
 
 	_nitpicker.buffer(mode, true /* use alpha */);
 
-	_policy_registry.update(Genode::config()->xml_node());
+	_policy_registry.update(_config.xml());
 
 	/* register signal handlers */
-	_hover_ds.sigh(_hover_signal_dispatcher);
-	_xray_ds.sigh(_xray_signal_dispatcher);
+	_hover_ds.sigh(_hover_signal_handler);
+	_xray_ds.sigh(_xray_signal_handler);
 
 	_nitpicker.enqueue<Nitpicker::Session::Command::To_front>(_view);
 	_nitpicker.execute();
@@ -272,18 +276,4 @@ Main::Main()
 }
 
 
-int main()
-{
-	static Main main;
-
-	/* dispatch signals */
-	for (;;) {
-
-		Genode::Signal sig = main.signal_receiver().wait_for_signal();
-		Genode::Signal_dispatcher_base *dispatcher =
-			dynamic_cast<Genode::Signal_dispatcher_base *>(sig.context());
-
-		if (dispatcher)
-			dispatcher->dispatch(sig.num());
-	}
-}
+void Component::construct(Genode::Env &env) { static Vbox_pointer::Main main(env); }
diff --git a/repos/ports/src/app/vbox_pointer/policy.cc b/repos/ports/src/app/vbox_pointer/policy.cc
index eb6925925d..c9781c0f30 100644
--- a/repos/ports/src/app/vbox_pointer/policy.cc
+++ b/repos/ports/src/app/vbox_pointer/policy.cc
@@ -34,28 +34,30 @@ class Vbox_pointer::Policy_entry : public Vbox_pointer::Policy,
 {
 	private:
 
+		Genode::Env &_env;
+
 		String _label;
 		String _domain;
 
 		Pointer_updater &_updater;
 
-		Genode::Attached_ram_dataspace _texture_pixel_ds { Genode::env()->ram_session(),
+		Genode::Attached_ram_dataspace _texture_pixel_ds { _env.ram(), _env.rm(),
 		                                                   Vbox_pointer::MAX_WIDTH  *
 		                                                   Vbox_pointer::MAX_HEIGHT *
 		                                                   sizeof(Genode::Pixel_rgb888) };
 
-		Genode::Attached_ram_dataspace _texture_alpha_ds { Genode::env()->ram_session(),
+		Genode::Attached_ram_dataspace _texture_alpha_ds { _env.ram(), _env.rm(),
 		                                                   Vbox_pointer::MAX_WIDTH  *
 		                                                   Vbox_pointer::MAX_HEIGHT };
 		Genode::Attached_rom_dataspace _shape_ds;
 
-		Genode::Signal_dispatcher<Policy_entry> shape_signal_dispatcher {
-			_updater.signal_receiver(), *this, &Policy_entry::_import_shape };
+		Genode::Signal_handler<Policy_entry> _shape_signal_handler {
+			_env.ep(), *this, &Policy_entry::_import_shape };
 
 		Nitpicker::Area  _shape_size;
 		Nitpicker::Point _shape_hot;
 
-		void _import_shape(unsigned = 0)
+		void _import_shape()
 		{
 			using namespace Genode;
 
@@ -76,7 +78,7 @@ class Vbox_pointer::Policy_entry : public Vbox_pointer::Policy,
 			 || shape_report->height > Vbox_pointer::MAX_HEIGHT) {
 				_shape_size = Nitpicker::Area();
 				_shape_hot  = Nitpicker::Point();
-				_updater.update_pointer(this);
+				_updater.update_pointer(*this);
 			}
 
 			_shape_size = Nitpicker::Area(shape_report->width, shape_report->height);
@@ -104,20 +106,21 @@ class Vbox_pointer::Policy_entry : public Vbox_pointer::Policy,
 				texture.rgba(rgba_line, _shape_size.w(), y);
 			}
 
-			_updater.update_pointer(this);
+			_updater.update_pointer(*this);
 		}
 
 	public:
 
-		Policy_entry(String const &label, String const &domain, String const &rom,
+		Policy_entry(Genode::Env &env, String const &label,
+		             String const &domain, String const &rom,
 		             Pointer_updater &updater)
 		:
-			_label(label), _domain(domain), _updater(updater),
-			_shape_ds(rom.string())
+			_env(env), _label(label), _domain(domain), _updater(updater),
+			_shape_ds(_env, rom.string())
 		{
 			_import_shape();
 
-			_shape_ds.sigh(shape_signal_dispatcher);
+			_shape_ds.sigh(_shape_signal_handler);
 		}
 
 		/**
@@ -185,23 +188,19 @@ void Vbox_pointer::Policy_registry::update(Genode::Xml_node config)
 {
 	/* TODO real update should flush at least */
 
-	try {
-		for (Genode::Xml_node policy = config.sub_node("policy");
-		     true; policy = policy.next("policy")) {
+	config.for_each_sub_node("policy", [&] (Genode::Xml_node policy) {
 
-			String label  = read_string_attribute(policy, "label",  String());
-			String domain = read_string_attribute(policy, "domain", String());
-			String rom    = read_string_attribute(policy, "rom",    String());
+		String const label  = read_string_attribute(policy, "label",  String());
+		String const domain = read_string_attribute(policy, "domain", String());
+		String const rom    = read_string_attribute(policy, "rom",    String());
 
-			if (!label.valid() && !domain.valid())
-				Genode::warning("policy does not declare label/domain attribute");
-			else if (!rom.valid())
-				Genode::warning("policy does not declare shape rom");
-			else
-				insert(new (Genode::env()->heap())
-				       Policy_entry(label, domain, rom, _updater));
-		}
-	} catch (...) { }
+		if (!label.valid() && !domain.valid())
+			Genode::warning("policy does not declare label/domain attribute");
+		else if (!rom.valid())
+			Genode::warning("policy does not declare shape rom");
+		else
+			insert(new (_alloc) Policy_entry(_env, label, domain, rom, _updater));
+	});
 }
 
 
diff --git a/repos/ports/src/app/vbox_pointer/policy.h b/repos/ports/src/app/vbox_pointer/policy.h
index 64cccbea3e..f44b44f52c 100644
--- a/repos/ports/src/app/vbox_pointer/policy.h
+++ b/repos/ports/src/app/vbox_pointer/policy.h
@@ -34,8 +34,7 @@ namespace Vbox_pointer {
 
 struct Vbox_pointer::Pointer_updater
 {
-	virtual void update_pointer(Policy *initiator)      = 0;
-	virtual Genode::Signal_receiver & signal_receiver() = 0;
+	virtual void update_pointer(Policy &initiator) = 0;
 };
 
 
@@ -53,12 +52,15 @@ class Vbox_pointer::Policy_registry : private Genode::List<Policy_entry>
 {
 	private:
 
-		Pointer_updater &_updater;
+		Pointer_updater   &_updater;
+		Genode::Env       &_env;
+		Genode::Allocator &_alloc;
 
 	public:
 
-		Policy_registry(Pointer_updater &updater)
-		: _updater(updater) { }
+		Policy_registry(Pointer_updater &updater, Genode::Env &env,
+		                Genode::Allocator &alloc)
+		: _updater(updater), _env(env), _alloc(alloc) { }
 
 		void update(Genode::Xml_node config);
 
diff --git a/repos/ports/src/test/vbox_pointer/main.cc b/repos/ports/src/test/vbox_pointer/main.cc
index 5840f4030f..58a4f04fe7 100644
--- a/repos/ports/src/test/vbox_pointer/main.cc
+++ b/repos/ports/src/test/vbox_pointer/main.cc
@@ -11,84 +11,30 @@
  * under the terms of the GNU General Public License version 2.
  */
 
-#include <base/printf.h>
+#include <base/component.h>
+#include <base/attached_rom_dataspace.h>
 #include <util/string.h>
 #include <os/reporter.h>
-#include <os/config.h>
 #include <vbox_pointer/shape_report.h>
 
-
-static bool const verbose = false;
-
-
-typedef Genode::String<16> String;
-
-static String read_string_attribute(Genode::Xml_node const &node,
-                                    char             const *attr,
-                                    String           const &default_value)
-{
-	try {
-		char buf[String::capacity()];
-		node.attribute(attr).value(buf, sizeof(buf));
-		return String(Genode::Cstring(buf));
-	}
-	catch (...) {
-		return default_value; }
-}
-
-
 struct Shape
 {
 	enum { WIDTH = 16, HEIGHT = 16 };
 
-	String        const id;
+	typedef Genode::String<16> Id;
+
+	Id            const id;
 	unsigned      const x_hot;
 	unsigned      const y_hot;
 	unsigned char const map[WIDTH*HEIGHT];
-};
 
-
-struct Shape_report : Vbox_pointer::Shape_report
-{
-	Genode::Reporter reporter { "shape", "shape", sizeof(Vbox_pointer::Shape_report) };
-
-	Shape_report()
-	:
-		Vbox_pointer::Shape_report{true, 0, 0, Shape::WIDTH, Shape::HEIGHT, { 0 }}
+	void print(Genode::Output &output) const
 	{
-		reporter.enabled(true);
-	}
-
-	void report(Shape const &s)
-	{
-		x_hot = s.x_hot;
-		y_hot = s.y_hot;
-
-		unsigned const w = Shape::WIDTH;
-		unsigned const h = Shape::HEIGHT;
-
-		for (unsigned y = 0; y < h; ++y) {
-			for (unsigned x = 0; x < w; ++x) {
-				shape[(y*w + x)*4 + 0] = 0xff;
-				shape[(y*w + x)*4 + 1] = 0xff;
-				shape[(y*w + x)*4 + 2] = 0xff;
-				shape[(y*w + x)*4 + 3] = s.map[y*w +x] ? 0xe0 : 0;
-
-				if (verbose)
-					Genode::printf("%c", s.map[y*w +x] ? 'X' : ' ');
-			}
-			if (verbose)
-				Genode::printf("\n");
-		}
-
-		if (verbose)
-			Genode::printf(".%s.%u.%u.\n", s.id.string(), s.x_hot, s.y_hot);
-
-		reporter.report(static_cast<Vbox_pointer::Shape_report *>(this),
-		                sizeof(Vbox_pointer::Shape_report));
+		Genode::print(output, ".", id, ".", x_hot, ".", y_hot, ".");
 	}
 };
 
+
 static Shape const shape[] = {
 	{ "arrow", 0, 0, {
 		1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
@@ -178,10 +124,9 @@ static Shape const shape[] = {
 };
 
 
-static Shape const & select_shape()
+static Shape const &select_shape(Genode::Xml_node config)
 {
-	String const id = read_string_attribute(Genode::config()->xml_node(),
-	                                        "shape", String("arrow"));
+	Shape::Id const id = config.attribute_value("shape", Shape::Id("arrow"));
 
 	for (Shape const &s : shape)
 		if (s.id == id)
@@ -192,19 +137,52 @@ static Shape const & select_shape()
 }
 
 
-int main()
+struct Main
 {
-	static Shape_report r;
+	Genode::Env &_env;
 
-	/* register signal handler for config changes */
-	Genode::Signal_receiver sig_rec;
-	Genode::Signal_context  sig_ctx;
+	Vbox_pointer::Shape_report _shape_report {
+		true, 0, 0, Shape::WIDTH, Shape::HEIGHT, { 0 } };
 
-	Genode::config()->sigh(sig_rec.manage(&sig_ctx));
+	Genode::Reporter _reporter {
+		"shape", "shape", sizeof(Vbox_pointer::Shape_report) };
 
-	while (true) {
-		r.report(select_shape());
-		sig_rec.wait_for_signal();
-		Genode::config()->reload();
+	Genode::Signal_handler<Main> _config_handler {
+		_env.ep(), *this, &Main::_handle_config };
+
+	Genode::Attached_rom_dataspace _config { _env, "config" };
+
+	void _handle_config()
+	{
+		_config.update();
+
+		Shape const &shape = select_shape(_config.xml());
+
+		_shape_report.x_hot = shape.x_hot;
+		_shape_report.y_hot = shape.y_hot;
+
+		unsigned const w = Shape::WIDTH;
+		unsigned const h = Shape::HEIGHT;
+
+		for (unsigned y = 0; y < h; ++y) {
+			for (unsigned x = 0; x < w; ++x) {
+				_shape_report.shape[(y*w + x)*4 + 0] = 0xff;
+				_shape_report.shape[(y*w + x)*4 + 1] = 0xff;
+				_shape_report.shape[(y*w + x)*4 + 2] = 0xff;
+				_shape_report.shape[(y*w + x)*4 + 3] = shape.map[y*w +x] ? 0xe0 : 0;
+			}
+		}
+
+		_reporter.report(&_shape_report, sizeof(Vbox_pointer::Shape_report));
 	}
-}
+
+	Main(Genode::Env &env) : _env(env)
+	{
+		_reporter.enabled(true);
+		_config.sigh(_config_handler);
+		_handle_config();
+	}
+};
+
+
+void Component::construct(Genode::Env &env) { static Main main(env); }