diff --git a/repos/gems/run/launcher.run b/repos/gems/run/launcher.run
new file mode 100644
index 0000000000..a643cae848
--- /dev/null
+++ b/repos/gems/run/launcher.run
@@ -0,0 +1,177 @@
+#
+# Build
+#
+
+set build_components {
+ core init drivers/timer drivers/framebuffer drivers/input drivers/pci
+ server/dynamic_rom server/nitpicker server/report_rom
+ app/pointer app/menu_view
+ app/scout app/launchpad app/launcher test/nitpicker
+ server/nit_fader
+}
+
+build $build_components
+
+create_boot_directory
+
+#
+# Generate config
+#
+
+append config {
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ }
+
+append_if [have_spec sdl] config {
+
+
+
+
+
+
+ }
+
+append_if [have_spec pci] config {
+
+
+
+ }
+
+append_if [have_spec framebuffer] config {
+
+
+
+
+ }
+
+append_if [have_spec ps2] config {
+
+
+
+ }
+
+append config {
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+}
+
+install_config $config
+
+#
+# Boot modules
+#
+
+# generic modules
+set boot_modules {
+ core init timer dynamic_rom nitpicker pointer menu_view
+ ld.lib.so libpng.lib.so libc.lib.so libm.lib.so zlib.lib.so
+ menu_view_styles.tar
+ scout launchpad testnit
+ nit_fader report_rom launcher
+}
+
+# platform-specific modules
+lappend_if [have_spec linux] boot_modules fb_sdl
+lappend_if [have_spec pci] boot_modules pci_drv
+lappend_if [have_spec ps2] boot_modules ps2_drv
+lappend_if [have_spec framebuffer] boot_modules fb_drv
+
+build_boot_image $boot_modules
+
+run_genode_until forever
diff --git a/repos/gems/src/app/launcher/context_dialog.h b/repos/gems/src/app/launcher/context_dialog.h
new file mode 100644
index 0000000000..d9c0f03ba7
--- /dev/null
+++ b/repos/gems/src/app/launcher/context_dialog.h
@@ -0,0 +1,230 @@
+/*
+ * \brief Context dialog
+ * \author Norman Feske
+ * \date 2014-10-04
+ */
+
+/*
+ * 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 _CONTEXT_DIALOG_H_
+#define _CONTEXT_DIALOG_H_
+
+/* local includes */
+#include
+
+namespace Launcher { struct Context_dialog; }
+
+
+class Launcher::Context_dialog : Input_event_handler, Dialog_generator,
+ Hover_handler, Dialog_model
+{
+ public:
+
+ struct Response_handler
+ {
+ virtual void handle_context_kill() = 0;
+ virtual void handle_context_hide() = 0;
+ };
+
+ private:
+
+ struct Element : List::Element
+ {
+ Label label;
+
+ bool hovered = false;
+ bool touched = false;
+ bool selected = false;
+
+ Element(char const *label) : label(label) { }
+ };
+
+ Label _hovered() const
+ {
+ for (Element const *e = _elements.first(); e; e = e->next())
+ if (e->hovered)
+ return e->label;
+
+ return Label("");
+ }
+
+ List _elements;
+
+ void _generate_dialog_elements(Xml_generator &xml)
+ {
+ for (Element const *e = _elements.first(); e; e = e->next()) {
+
+ xml.node("button", [&] () {
+ xml.attribute("name", e->label.string());
+
+ if ((e->hovered && !_click_in_progress)
+ || (e->hovered && e->touched))
+ xml.attribute("hovered", "yes");
+
+ if (e->selected || e->touched)
+ xml.attribute("selected", "yes");
+
+ xml.node("label", [&] () {
+ xml.attribute("text", e->label.string());
+ });
+ });
+ }
+ }
+
+ void _touch(Label const &label)
+ {
+ for (Element *e = _elements.first(); e; e = e->next())
+ e->touched = (e->label == label);
+ }
+
+ void _reset_hover()
+ {
+ for (Element *e = _elements.first(); e; e = e->next())
+ e->hovered = false;
+ }
+
+ Element _hide_button { "Hide" };
+ Element _kill_button { "Kill" };
+
+ Fading_dialog _dialog;
+
+ unsigned _key_cnt = 0;
+ Label _clicked;
+ bool _click_in_progress = false;
+
+ Label _subsystem;
+
+ Response_handler &_response_handler;
+
+ public:
+
+ Context_dialog(Server::Entrypoint &ep, Cap_session &cap, Ram_session &ram,
+ Report_rom_slave &report_rom_slave,
+ Response_handler &response_handler)
+ :
+ _dialog(ep, cap, ram, report_rom_slave, "context_dialog", "context_hover",
+ *this, *this, *this, *this,
+ Fading_dialog::Position(364, 64)),
+ _response_handler(response_handler)
+ {
+ _elements.insert(&_hide_button);
+ _elements.insert(&_kill_button);
+
+ _dialog.update();
+ }
+
+ /**
+ * Dialog_generator interface
+ */
+ void generate_dialog(Xml_generator &xml) override
+ {
+ xml.node("frame", [&] () {
+ xml.node("vbox", [&] () {
+ _generate_dialog_elements(xml);
+ });
+ });
+ }
+
+ /**
+ * Hover_handler interface
+ */
+ void hover_changed(Xml_node hover) override
+ {
+ Label const old_hovered = _hovered();
+
+ _reset_hover();
+
+ try {
+ Xml_node button = hover.sub_node("dialog")
+ .sub_node("frame")
+ .sub_node("vbox")
+ .sub_node("button");
+
+ for (Element *e = _elements.first(); e; e = e->next()) {
+
+ Label const label =
+ Decorator::string_attribute(button, "name", Label(""));
+
+ if (e->label == label)
+ e->hovered = true;
+ }
+ } catch (Xml_node::Nonexistent_sub_node) { }
+
+ Label const new_hovered = _hovered();
+
+ if (old_hovered != new_hovered)
+ dialog_changed();
+ }
+
+ /**
+ * Input_event_handler interface
+ */
+ bool handle_input_event(Input::Event const &ev) override
+ {
+ if (ev.type() == Input::Event::MOTION)
+ return true;
+
+ if (ev.type() == Input::Event::PRESS) _key_cnt++;
+ if (ev.type() == Input::Event::RELEASE) _key_cnt--;
+
+ if (ev.type() == Input::Event::PRESS
+ && ev.keycode() == Input::BTN_LEFT
+ && _key_cnt == 1) {
+
+ Label const hovered = _hovered();
+
+ _click_in_progress = true;
+ _clicked = hovered;
+ _touch(hovered);
+ dialog_changed();
+ }
+
+ if (ev.type() == Input::Event::RELEASE
+ && _click_in_progress && _key_cnt == 0) {
+
+ Label const hovered = _hovered();
+
+ if (_clicked == hovered) {
+
+ if (_kill_button.hovered)
+ _response_handler.handle_context_kill();
+
+ if (_hide_button.hovered)
+ _response_handler.handle_context_hide();
+ } else {
+ _touch("");
+ }
+
+ _clicked = Label("");
+ _click_in_progress = false;
+ dialog_changed();
+ }
+
+ return false;
+ }
+
+ void visible(bool visible)
+ {
+ /* reset touch state when (re-)opening the context dialog */
+ if (visible) {
+ _touch("");
+ _reset_hover();
+ dialog_changed();
+ _dialog.update();
+ }
+
+ _dialog.visible(visible);
+ }
+
+ void position(Fading_dialog::Position position)
+ {
+ _dialog.position(position);
+ }
+};
+
+#endif /* _CONTEXT_DIALOG_H_ */
diff --git a/repos/gems/src/app/launcher/dialog_nitpicker.h b/repos/gems/src/app/launcher/dialog_nitpicker.h
new file mode 100644
index 0000000000..f6f51842f7
--- /dev/null
+++ b/repos/gems/src/app/launcher/dialog_nitpicker.h
@@ -0,0 +1,123 @@
+/*
+ * \brief Local nitpicker service provided to dialog slaves
+ * \author Norman Feske
+ * \date 2014-10-01
+ *
+ * This implementation of the nitpicker interface intercepts the input events
+ * of a dialog slave to let the launcher respond to events (like mouse clicks)
+ * directly.
+ */
+
+/*
+ * 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 _DIALOG_NITPICKER_H_
+#define _DIALOG_NITPICKER_H_
+
+/* Genode includes */
+#include
+#include
+#include
+#include
+#include
+#include
+
+/* gems includes */
+#include
+
+/* local includes */
+#include
+
+namespace Launcher {
+
+ struct Dialog_nitpicker_session;
+ struct Dialog_nitpicker_service;
+}
+
+
+struct Launcher::Dialog_nitpicker_session : Wrapped_nitpicker_session
+{
+ struct Input_event_handler
+ {
+ /**
+ * Handle input event
+ *
+ * \return true if the event should be propagated to the wrapped
+ * nitpicker session
+ */
+ virtual bool handle_input_event(Input::Event const &ev) = 0;
+ };
+
+ Input_event_handler &_input_event_handler;
+
+ Server::Entrypoint &_ep;
+
+ Nitpicker::Session &_nitpicker_session;
+
+ Input::Session_client _nitpicker_input { _nitpicker_session.input_session() };
+
+ Attached_dataspace _nitpicker_input_ds { _nitpicker_input.dataspace() };
+
+ Signal_rpc_member
+ _input_dispatcher { _ep, *this, &Dialog_nitpicker_session::_input_handler };
+
+ Input::Session_component _input_session;
+
+ Capability _input_session_cap { _ep.manage(_input_session) };
+
+ /**
+ * Constructor
+ */
+ Dialog_nitpicker_session(Nitpicker::Session &nitpicker_session,
+ Server::Entrypoint &ep,
+ Input_event_handler &input_event_handler)
+ :
+ Wrapped_nitpicker_session(nitpicker_session),
+ _input_event_handler(input_event_handler),
+ _ep(ep),
+ _nitpicker_session(nitpicker_session)
+ {
+ _nitpicker_input.sigh(_input_dispatcher);
+
+ _input_session.event_queue().enabled(true);
+ }
+
+ ~Dialog_nitpicker_session()
+ {
+ _ep.dissolve(_input_session);
+ }
+
+ void _input_handler(unsigned)
+ {
+ Input::Event const * const events =
+ _nitpicker_input_ds.local_addr();
+
+ while (_nitpicker_input.is_pending()) {
+
+ size_t const num_events = _nitpicker_input.flush();
+ for (size_t i = 0; i < num_events; i++) {
+
+ Input::Event const &ev = events[i];
+
+ if (_input_event_handler.handle_input_event(ev))
+ _input_session.submit(ev);
+ }
+ }
+ }
+
+
+ /*********************************
+ ** Nitpicker session interface **
+ *********************************/
+
+ Input::Session_capability input_session() override
+ {
+ return _input_session_cap;
+ }
+};
+
+#endif /* _DIALOG_NITPICKER_H_ */
diff --git a/repos/gems/src/app/launcher/fading_dialog.h b/repos/gems/src/app/launcher/fading_dialog.h
new file mode 100644
index 0000000000..09e2e9489b
--- /dev/null
+++ b/repos/gems/src/app/launcher/fading_dialog.h
@@ -0,0 +1,254 @@
+/*
+ * \brief Dialog
+ * \author Norman Feske
+ * \date 2014-10-02
+ */
+
+/*
+ * 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 _FADING_DIALOG_H_
+#define _FADING_DIALOG_H_
+
+/* gems includes */
+#include
+#include
+
+/* local includes */
+#include
+#include
+#include
+#include
+
+namespace Launcher
+{
+ struct Dialog_generator { virtual void generate_dialog(Xml_generator &) = 0; };
+
+ struct Hover_handler { virtual void hover_changed(Xml_node hover) = 0; };
+
+ typedef Dialog_nitpicker_session::Input_event_handler Input_event_handler;
+
+ class Fading_dialog;
+
+ class Dialog_model
+ {
+ private:
+
+ bool _up_to_date = true;
+
+ friend class Fading_dialog;
+
+ public:
+
+ void dialog_changed() { _up_to_date = false; }
+ };
+}
+
+
+
+class Launcher::Fading_dialog : private Input_event_handler
+{
+ private:
+
+ Rom_session_capability _dialog_rom;
+
+ /* dialog reported locally */
+ Capability _dialog_report;
+
+ Rom_session_client _hover_rom;
+
+ Lazy_volatile_object _hover_ds;
+
+ /* hovered element reported by menu view */
+ Capability _hover_report;
+
+ Local_reporter _dialog_reporter { "dialog", _dialog_report };
+
+ Input_event_handler &_dialog_input_event_handler;
+
+ Hover_handler &_hover_handler;
+
+ Dialog_generator &_dialog_generator;
+
+ Dialog_model &_dialog_model;
+
+ void _update_dialog()
+ {
+ bool const dialog_needs_update = !_dialog_model._up_to_date;
+
+ _dialog_model._up_to_date = false;
+
+ if (dialog_needs_update) {
+ Local_reporter::Xml_generator xml(_dialog_reporter, [&] ()
+ {
+ _dialog_generator.generate_dialog(xml);
+ });
+ }
+ }
+
+ /**
+ * Input_event_handler interface
+ */
+ bool handle_input_event(Input::Event const &ev) override
+ {
+ bool const forward_event = _dialog_input_event_handler.handle_input_event(ev);
+ _update_dialog();
+ return forward_event;
+ }
+
+ void _handle_hover_update(unsigned)
+ {
+ try {
+ if (!_hover_ds.is_constructed() || _hover_rom.update() == false) {
+ if (_hover_ds.is_constructed())
+ _hover_ds->invalidate();
+ _hover_ds.construct(_hover_rom.dataspace());
+ }
+
+ Xml_node hover(_hover_ds->local_addr());
+
+ _hover_handler.hover_changed(hover);
+
+ bool const dialog_needs_update = !_dialog_model._up_to_date;
+
+ _dialog_model._up_to_date = true;
+
+ if (dialog_needs_update) {
+ Local_reporter::Xml_generator xml(_dialog_reporter, [&] ()
+ {
+ _dialog_generator.generate_dialog(xml);
+ });
+ }
+
+ } catch (...) {
+ PWRN("no menu hover model available");
+ }
+ }
+
+ Signal_rpc_member _hover_update_dispatcher;
+
+ private:
+
+ /**
+ * Local nitpicker service to be handed out to the menu view slave
+ */
+ struct Nitpicker_service : Genode::Service
+ {
+ Server::Entrypoint &ep;
+ Rpc_entrypoint &child_ep;
+
+ /* connection to real nitpicker */
+ Nitpicker::Connection connection { "menu" };
+
+ Dialog_nitpicker_session wrapper_session;
+
+ Capability session_cap { child_ep.manage(&wrapper_session) };
+
+ Nitpicker_service(Server::Entrypoint &ep,
+ Rpc_entrypoint &child_ep,
+ Dialog_nitpicker_session::Input_event_handler &ev_handler)
+ :
+ Genode::Service(Nitpicker::Session::service_name()),
+ ep(ep), child_ep(child_ep),
+ wrapper_session(connection, ep, ev_handler)
+ { }
+
+ /*******************************
+ ** Genode::Service interface **
+ *******************************/
+
+ Genode::Session_capability
+ session(const char *, Genode::Affinity const &) override
+ {
+ return session_cap;
+ }
+
+ void upgrade(Genode::Session_capability, const char *args) override
+ {
+ PDBG("upgrade called args: '%s'", args);
+ }
+
+ void close(Genode::Session_capability) override { }
+ };
+
+ /*
+ * Entrypoint for the fader slave
+ *
+ * This entrypoint is used for handling the parent interface for the
+ * fader slave and for providing the wrapped nitpicker service to the
+ * slave. The latter cannot be provided by the main entrypoint because
+ * during the construction of the 'nit_fader_slave' (executed in the
+ * context of the main entrypoint), the slave tries to create a
+ * nitpicker session (to be answered with the wrapped session).
+ */
+ size_t const _fader_slave_ep_stack_size = 4*1024*sizeof(addr_t);
+ Rpc_entrypoint _fader_slave_ep;
+
+ Nitpicker_service _nitpicker_service;
+ Nit_fader_slave _nit_fader_slave;
+ Menu_view_slave _menu_view_slave;
+
+
+ public:
+
+ typedef Menu_view_slave::Position Position;
+
+ /**
+ * Constructor
+ *
+ * \param ep main entrypoint, used for managing the local input
+ * session provided (indirectly through the wrapped
+ * nitpicker session) to the menu view
+ * \param cap capability session to be used for creating the
+ * slave entrypoints
+ * \param ram RAM session where to draw the memory for providing
+ * configuration data to the slave processes
+ */
+ Fading_dialog(Server::Entrypoint &ep,
+ Cap_session &cap,
+ Ram_session &ram,
+ Report_rom_slave &report_rom_slave,
+ char const *dialog_name,
+ char const *hover_name,
+ Input_event_handler &input_event_handler,
+ Hover_handler &hover_handler,
+ Dialog_generator &dialog_generator,
+ Dialog_model &dialog_model,
+ Position initial_position)
+ :
+ _dialog_rom(report_rom_slave.rom_session(dialog_name)),
+ _dialog_report(report_rom_slave.report_session(dialog_name)),
+ _hover_rom(report_rom_slave.rom_session(hover_name)),
+ _hover_report(report_rom_slave.report_session(hover_name)),
+ _dialog_input_event_handler(input_event_handler),
+ _hover_handler(hover_handler),
+ _dialog_generator(dialog_generator),
+ _dialog_model(dialog_model),
+ _hover_update_dispatcher(ep, *this, &Fading_dialog::_handle_hover_update),
+ _fader_slave_ep(&cap, _fader_slave_ep_stack_size, "nit_fader"),
+ _nitpicker_service(ep, _fader_slave_ep, *this),
+ _nit_fader_slave(_fader_slave_ep, ram, _nitpicker_service),
+ _menu_view_slave(cap, ram, _nit_fader_slave.nitpicker_session("menu"),
+ _dialog_rom, _hover_report, initial_position)
+ {
+ Rom_session_client(_hover_rom).sigh(_hover_update_dispatcher);
+ }
+
+ void update()
+ {
+ Local_reporter::Xml_generator xml(_dialog_reporter, [&] ()
+ {
+ _dialog_generator.generate_dialog(xml);
+ });
+ }
+
+ void visible(bool visible) { _nit_fader_slave.visible(visible); }
+
+ void position(Position position) { _menu_view_slave.position(position); }
+};
+
+#endif /* _FADING_DIALOG_H_ */
diff --git a/repos/gems/src/app/launcher/main.cc b/repos/gems/src/app/launcher/main.cc
new file mode 100644
index 0000000000..d7ef593628
--- /dev/null
+++ b/repos/gems/src/app/launcher/main.cc
@@ -0,0 +1,147 @@
+/*
+ * \brief Launcher
+ * \author Norman Feske
+ * \date 2014-09-30
+ */
+
+/*
+ * 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.
+ */
+
+/* Genode includes */
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+/* local includes */
+#include
+
+
+namespace Launcher { struct Main; }
+
+struct Launcher::Main
+{
+ Server::Entrypoint ep;
+
+ Genode::Cap_connection cap;
+
+ char const *report_rom_config =
+ " "
+ " "
+ " "
+ " "
+ " "
+ " ";
+
+ Report_rom_slave report_rom_slave = { cap, *env()->ram_session(), report_rom_config };
+
+
+ /**
+ * Nitpicker session used to perform session-control operations on the
+ * subsystem's nitpicker sessions.
+ */
+ Nitpicker::Connection nitpicker;
+
+ Subsystem_manager subsystem_manager { ep, cap };
+
+ Menu_dialog menu_dialog { ep, cap, *env()->ram_session(), report_rom_slave,
+ subsystem_manager, nitpicker };
+
+
+ Lazy_volatile_object xray_rom_ds;
+
+ enum Visibility { VISIBILITY_ALWAYS, VISIBILITY_XRAY };
+
+ Visibility visibility = VISIBILITY_ALWAYS;
+
+ void handle_config(unsigned);
+
+ Genode::Signal_rpc_member xray_update_dispatcher =
+ { ep, *this, &Main::handle_xray_update };
+
+ void handle_xray_update(unsigned);
+
+
+ /**
+ * Constructor
+ */
+ Main(Server::Entrypoint &ep) : ep(ep)
+ {
+ handle_config(0);
+
+ if (visibility == VISIBILITY_ALWAYS)
+ menu_dialog.visible(true);
+ }
+};
+
+
+void Launcher::Main::handle_config(unsigned)
+{
+ config()->reload();
+
+ /* set default visibility */
+ visibility = VISIBILITY_ALWAYS;
+
+ /* obtain model about nitpicker's xray mode */
+ if (config()->xml_node().has_attribute("visibility")) {
+ if (config()->xml_node().attribute("visibility").has_value("xray")) {
+ xray_rom_ds.construct("xray");
+ xray_rom_ds->sigh(xray_update_dispatcher);
+
+ visibility = VISIBILITY_XRAY;
+
+ /* manually import the initial xray state */
+ handle_xray_update(0);
+ }
+ }
+
+ menu_dialog.update();
+}
+
+
+void Launcher::Main::handle_xray_update(unsigned)
+{
+ xray_rom_ds->update();
+ if (!xray_rom_ds->is_valid()) {
+ PWRN("could not access xray info");
+ menu_dialog.visible(false);
+ return;
+ }
+
+ Xml_node xray(xray_rom_ds->local_addr());
+
+ bool const visible = xray.has_attribute("enabled")
+ && xray.attribute("enabled").has_value("yes");
+
+ menu_dialog.visible(visible);
+}
+
+
+/************
+ ** Server **
+ ************/
+
+namespace Server {
+
+ char const *name() { return "desktop_ep"; }
+
+ size_t stack_size() { return 4*1024*sizeof(long); }
+
+ void construct(Entrypoint &ep)
+ {
+ /* look for dynamic linker */
+ try {
+ static Rom_connection rom("ld.lib.so");
+ Process::dynamic_linker(rom.dataspace());
+ } catch (...) { }
+
+ static Launcher::Main desktop(ep);
+ }
+}
diff --git a/repos/gems/src/app/launcher/menu_dialog.h b/repos/gems/src/app/launcher/menu_dialog.h
new file mode 100644
index 0000000000..0ff7e137e2
--- /dev/null
+++ b/repos/gems/src/app/launcher/menu_dialog.h
@@ -0,0 +1,387 @@
+/*
+ * \brief Menu dialog
+ * \author Norman Feske
+ * \date 2014-10-04
+ */
+
+/*
+ * 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 _MENU_DIALOG_H_
+#define _MENU_DIALOG_H_
+
+/* Genode includes */
+#include
+
+/* local includes */
+#include
+#include
+#include
+
+namespace Launcher { struct Menu_dialog; }
+
+
+class Launcher::Menu_dialog : Input_event_handler, Dialog_generator,
+ Hover_handler, Dialog_model,
+ Context_dialog::Response_handler
+{
+ private:
+
+ typedef String<128> Title;
+
+ struct Element : List::Element
+ {
+ Label label;
+ Title title;
+
+ bool hovered = false;
+ bool touched = false;
+ bool running = false;
+
+ Element(Xml_node node)
+ :
+ label(Decorator::string_attribute(node, "name", Label(""))),
+ title(Decorator::string_attribute(node, "title", Title(label.string())))
+ { }
+ };
+
+ List _elements;
+
+ void _generate_dialog_elements(Xml_generator &xml)
+ {
+ for (Element const *e = _elements.first(); e; e = e->next()) {
+
+ xml.node("button", [&] () {
+ xml.attribute("name", e->label.string());
+
+ if ((e->hovered && !_click_in_progress)
+ || (e->hovered && e->touched))
+ xml.attribute("hovered", "yes");
+
+ if (e->running || e->touched)
+ xml.attribute("selected", "yes");
+
+ xml.node("label", [&] () {
+ xml.attribute("text", e->title.string());
+ });
+ });
+ }
+ }
+
+ class Lookup_failed { };
+
+ Element const &_lookup_const(Label const &label) const
+ {
+ for (Element const *e = _elements.first(); e; e = e->next())
+ if (e->label == label)
+ return *e;
+
+ throw Lookup_failed();
+ }
+
+ Element &_lookup(Label const &label)
+ {
+ for (Element *e = _elements.first(); e; e = e->next())
+ if (e->label == label)
+ return *e;
+
+ throw Lookup_failed();
+ }
+
+ Fading_dialog::Position _position { 32, 32 };
+
+ Timer::Connection _timer;
+ Subsystem_manager &_subsystem_manager;
+ Nitpicker::Session &_nitpicker;
+ Fading_dialog _dialog;
+
+ Rect _hovered_rect;
+
+ unsigned _key_cnt = 0;
+ Label _clicked;
+ bool _click_in_progress = false;
+
+ Signal_rpc_member _timer_dispatcher;
+
+ Label _context_subsystem;
+ Context_dialog _context_dialog;
+
+ Label _hovered() const
+ {
+ for (Element const *e = _elements.first(); e; e = e->next())
+ if (e->hovered)
+ return e->label;
+
+ return Label("");
+ }
+
+ bool _running(Label const &label) const
+ {
+ try { return _lookup_const(label).running; }
+ catch (Lookup_failed) { return false; }
+ }
+
+ void _running(Label const &label, bool running)
+ {
+ try { _lookup(label).running = running; }
+ catch (Lookup_failed) { }
+ }
+
+ void _touch(Label const &label)
+ {
+ for (Element *e = _elements.first(); e; e = e->next())
+ e->touched = (e->label == label);
+ }
+
+ /**
+ * Lookup subsystem in config
+ */
+ static Xml_node _subsystem(Xml_node config, char const *name)
+ {
+ Xml_node node = config.sub_node("subsystem");
+ for (;; node = node.next("subsystem")) {
+ if (node.attribute("name").has_value(name))
+ return node;
+ }
+ }
+
+ void _start(Label const &label)
+ {
+ try {
+ _subsystem_manager.start(_subsystem(config()->xml_node(),
+ label.string()));
+ _running(label, true);
+
+ dialog_changed();
+
+ } catch (Xml_node::Nonexistent_sub_node) {
+ PERR("no subsystem config found for \"%s\"", label.string());
+ } catch (Subsystem_manager::Invalid_config) {
+ PERR("invalid subsystem configuration for \"%s\"", label.string());
+ }
+ }
+
+ void _kill(Label const &label)
+ {
+ _subsystem_manager.kill(label.string());
+ _running(label, false);
+ dialog_changed();
+ _dialog.update();
+
+ _context_dialog.visible(false);
+ }
+
+ void _hide(Label const &label)
+ {
+ _nitpicker.session_control(selector(label.string()),
+ Nitpicker::Session::SESSION_CONTROL_HIDE);
+
+ _context_dialog.visible(false);
+ }
+
+ void _handle_timer(unsigned)
+ {
+ if (_click_in_progress && _hovered() == _clicked) {
+
+ _touch("");
+
+ Fading_dialog::Position position(_hovered_rect.p2().x(),
+ _hovered_rect.p1().y() - 44);
+ _context_subsystem = _clicked;
+ _context_dialog.position(_position + position);
+ _context_dialog.visible(true);
+ }
+
+ _click_in_progress = false;
+ }
+
+ public:
+
+ Menu_dialog(Server::Entrypoint &ep, Cap_session &cap, Ram_session &ram,
+ Report_rom_slave &report_rom_slave,
+ Subsystem_manager &subsystem_manager,
+ Nitpicker::Session &nitpicker)
+ :
+ _subsystem_manager(subsystem_manager),
+ _nitpicker(nitpicker),
+ _dialog(ep, cap, ram, report_rom_slave, "menu_dialog", "menu_hover",
+ *this, *this, *this, *this,
+ _position),
+ _timer_dispatcher(ep, *this, &Menu_dialog::_handle_timer),
+ _context_dialog(ep, cap, ram, report_rom_slave, *this)
+ {
+ _timer.sigh(_timer_dispatcher);
+ }
+
+ /**
+ * Dialog_generator interface
+ */
+ void generate_dialog(Xml_generator &xml) override
+ {
+ xml.node("frame", [&] () {
+ xml.node("vbox", [&] () {
+ _generate_dialog_elements(xml);
+ });
+ });
+ }
+
+ Rect _hovered_button_rect(Xml_node hover) const
+ {
+ Point p(0, 0);
+
+ for (;; hover = hover.sub_node()) {
+
+ p = p + Point(point_attribute(hover));
+
+ if (hover.has_type("button"))
+ return Rect(p, area_attribute(hover));
+
+ if (!hover.num_sub_nodes())
+ break;
+ }
+
+ return Rect();
+ }
+
+ /**
+ * Hover_handler interface
+ */
+ void hover_changed(Xml_node hover) override
+ {
+ Label const old_hovered = _hovered();
+
+ for (Element *e = _elements.first(); e; e = e->next())
+ e->hovered = false;
+
+ try {
+ Xml_node button = hover.sub_node("dialog")
+ .sub_node("frame")
+ .sub_node("vbox")
+ .sub_node("button");
+
+ for (Element *e = _elements.first(); e; e = e->next()) {
+
+ Label const label =
+ Decorator::string_attribute(button, "name", Label(""));
+
+ if (e->label == label) {
+ e->hovered = true;
+
+ _hovered_rect = _hovered_button_rect(hover);
+ }
+ }
+ } catch (Xml_node::Nonexistent_sub_node) { }
+
+ Label const new_hovered = _hovered();
+
+ if (old_hovered != new_hovered)
+ dialog_changed();
+ }
+
+ /**
+ * Input_event_handler interface
+ */
+ bool handle_input_event(Input::Event const &ev) override
+ {
+ if (ev.type() == Input::Event::MOTION)
+ return true;
+
+ if (ev.type() == Input::Event::PRESS) _key_cnt++;
+ if (ev.type() == Input::Event::RELEASE) _key_cnt--;
+
+ if (ev.type() == Input::Event::PRESS
+ && ev.keycode() == Input::BTN_LEFT
+ && _key_cnt == 1) {
+
+ _context_dialog.visible(false);
+
+ Label const hovered = _hovered();
+
+ _click_in_progress = true;
+ _clicked = hovered;
+ _touch(hovered);
+
+ enum { CONTEXT_DELAY = 500 };
+
+ if (_running(hovered)) {
+ _nitpicker.session_control(selector(hovered.string()),
+ Nitpicker::Session::SESSION_CONTROL_TO_FRONT);
+ _nitpicker.session_control(selector(hovered.string()),
+ Nitpicker::Session::SESSION_CONTROL_SHOW);
+ _timer.trigger_once(CONTEXT_DELAY*1000);
+ }
+ }
+
+ if (ev.type() == Input::Event::RELEASE
+ && _click_in_progress && _key_cnt == 0) {
+
+ Label const hovered = _hovered();
+
+ if (_clicked == hovered) {
+
+ if (!_running(hovered))
+ _start(hovered);
+ } else {
+ _touch("");
+ }
+
+ _clicked = Label("");
+ _click_in_progress = false;
+ }
+
+ return false;
+ }
+
+ /**
+ * Context_dialog::Response_handler interface
+ */
+ void handle_context_kill() override
+ {
+ _kill(_context_subsystem);
+ }
+
+ /**
+ * Context_dialog::Response_handler interface
+ */
+ void handle_context_hide() override
+ {
+ _hide(_context_subsystem);
+ }
+
+ void visible(bool visible)
+ {
+ _dialog.visible(visible);
+
+ if (!visible)
+ _context_dialog.visible(false);
+ }
+
+ void update()
+ {
+ if (_elements.first()) {
+ PERR("subsequent updates are not supported");
+ return;
+ }
+
+ Element *last = nullptr;
+
+ Xml_node subsystems = config()->xml_node();
+
+ subsystems.for_each_sub_node("subsystem",
+ [&] (Xml_node subsystem)
+ {
+ Element * const e = new (env()->heap()) Element(subsystem);
+
+ _elements.insert(e, last);
+ last = e;
+ });
+
+ _dialog.update();
+ }
+};
+
+#endif /* _MENU_DIALOG_H_ */
diff --git a/repos/gems/src/app/launcher/menu_view_slave.h b/repos/gems/src/app/launcher/menu_view_slave.h
new file mode 100644
index 0000000000..06b92db91d
--- /dev/null
+++ b/repos/gems/src/app/launcher/menu_view_slave.h
@@ -0,0 +1,161 @@
+/*
+ * \brief Slave used for presenting the menu
+ * \author Norman Feske
+ * \date 2014-09-30
+ */
+
+/*
+ * 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 _MENU_VIEW_SLAVE_H_
+#define _MENU_VIEW_SLAVE_H_
+
+/* Genode includes */
+#include
+#include
+
+/* gems includes */
+#include
+
+/* local includes */
+#include
+
+namespace Launcher { class Menu_view_slave; }
+
+
+class Launcher::Menu_view_slave
+{
+ public:
+
+ typedef Surface_base::Point Position;
+
+ private:
+
+ class Policy : public Genode::Slave_policy
+ {
+ private:
+
+ Lock mutable _nitpicker_root_lock { Lock::LOCKED };
+ Capability _nitpicker_root_cap;
+
+ Single_session_service _nitpicker_service;
+ Single_session_service _dialog_rom_service;
+ Single_session_service _hover_report_service;
+
+ Position _position;
+
+ protected:
+
+ char const **_permitted_services() const
+ {
+ static char const *permitted_services[] = {
+ "ROM", "CAP", "LOG", "SIGNAL", "RM", "Timer", 0 };
+
+ return permitted_services;
+ };
+
+ private:
+
+ void _configure(Position pos)
+ {
+ char config[1024];
+
+ snprintf(config, sizeof(config),
+ "\n"
+ " \n"
+ " \n"
+ " \n"
+ " \n"
+ " \n"
+ " \n"
+ "",
+ pos.x(), pos.y());
+
+ configure(config);
+ }
+
+ public:
+
+ Policy(Genode::Rpc_entrypoint &entrypoint,
+ Genode::Ram_session &ram,
+ Capability nitpicker_session,
+ Capability dialog_rom_session,
+ Capability hover_report_session,
+ Position position)
+ :
+ Slave_policy("menu_view", entrypoint, &ram),
+ _nitpicker_service(Nitpicker::Session::service_name(), nitpicker_session),
+ _dialog_rom_service(Rom_session::service_name(), dialog_rom_session),
+ _hover_report_service(Report::Session::service_name(), hover_report_session),
+ _position(position)
+ {
+ _configure(position);
+ }
+
+ void position(Position pos)
+ {
+ _configure(pos);
+ }
+
+ Genode::Service *resolve_session_request(const char *service_name,
+ const char *args) override
+ {
+ using Genode::strcmp;
+
+ if (strcmp(service_name, "Nitpicker") == 0)
+ return &_nitpicker_service;
+
+ char label[128];
+ Arg_string::find_arg(args, "label").string(label, sizeof(label), "");
+
+ if (strcmp(service_name, "ROM") == 0) {
+
+ if (strcmp(label, "menu_view -> dialog") == 0)
+ return &_dialog_rom_service;
+ }
+
+ if (strcmp(service_name, "Report") == 0) {
+
+ if (strcmp(label, "menu_view -> hover") == 0)
+ return &_hover_report_service;
+ }
+
+ return Genode::Slave_policy::resolve_session_request(service_name, args);
+ }
+ };
+
+ Genode::size_t const _ep_stack_size = 4*1024*sizeof(Genode::addr_t);
+ Genode::Rpc_entrypoint _ep;
+ Policy _policy;
+ Genode::size_t const _quota = 4*1024*1024;
+ Genode::Slave _slave;
+
+ public:
+
+ /**
+ * Constructor
+ *
+ * \param ep entrypoint used for child thread
+ * \param ram RAM session used to allocate the configuration
+ * dataspace
+ */
+ Menu_view_slave(Genode::Cap_session &cap, Genode::Ram_session &ram,
+ Capability nitpicker_session,
+ Capability dialog_rom_session,
+ Capability hover_report_session,
+ Position initial_position)
+ :
+ _ep(&cap, _ep_stack_size, "nit_fader"),
+ _policy(_ep, ram, nitpicker_session, dialog_rom_session,
+ hover_report_session, initial_position),
+ _slave(_ep, _policy, _quota)
+ { }
+
+ void position(Position position) { _policy.position(position); }
+};
+
+#endif /* _NIT_FADER_SLAVE_H_ */
diff --git a/repos/gems/src/app/launcher/nit_fader_slave.h b/repos/gems/src/app/launcher/nit_fader_slave.h
new file mode 100644
index 0000000000..7c55dd16be
--- /dev/null
+++ b/repos/gems/src/app/launcher/nit_fader_slave.h
@@ -0,0 +1,153 @@
+/*
+ * \brief Slave used for toggling the visibility of a nitpicker session
+ * \author Norman Feske
+ * \date 2014-09-30
+ */
+
+/*
+ * 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 _NIT_FADER_SLAVE_H_
+#define _NIT_FADER_SLAVE_H_
+
+/* Genode includes */
+#include
+#include
+
+/* local includes */
+#include
+
+namespace Launcher { class Nit_fader_slave; }
+
+
+class Launcher::Nit_fader_slave
+{
+ private:
+
+ class Policy : public Slave_policy
+ {
+ private:
+
+ Genode::Service &_nitpicker_service;
+ Lock mutable _nitpicker_root_lock { Lock::LOCKED };
+ Capability _nitpicker_root_cap;
+
+ protected:
+
+ char const **_permitted_services() const
+ {
+ static char const *permitted_services[] = {
+ "CAP", "LOG", "SIGNAL", "RM", "Timer", 0 };
+
+ return permitted_services;
+ };
+
+ public:
+
+ Policy(Rpc_entrypoint &entrypoint,
+ Ram_session &ram,
+ Genode::Service &nitpicker_service)
+ :
+ Slave_policy("nit_fader", entrypoint, &ram),
+ _nitpicker_service(nitpicker_service)
+ {
+ visible(false);
+ }
+
+ void visible(bool visible)
+ {
+ char config[256];
+ snprintf(config, sizeof(config),
+ "", visible ? 255 : 0);
+ configure(config, strlen(config) + 1);
+ }
+
+ bool announce_service(const char *service_name,
+ Root_capability root,
+ Allocator *,
+ Genode::Server *)
+ {
+ if (strcmp(service_name, "Nitpicker") == 0)
+ _nitpicker_root_cap = root;
+ else
+ return false;
+
+ if (_nitpicker_root_cap.valid())
+ _nitpicker_root_lock.unlock();
+
+ return true;
+ }
+
+ Genode::Service *resolve_session_request(const char *service_name,
+ const char *args) override
+ {
+ if (Genode::strcmp(service_name, "Nitpicker") == 0)
+ return &_nitpicker_service;
+
+ return Genode::Slave_policy::resolve_session_request(service_name, args);
+ }
+
+ Root_capability nitpicker_root() const
+ {
+ Lock::Guard guard(_nitpicker_root_lock);
+ return _nitpicker_root_cap;
+ }
+ };
+
+ Policy _policy;
+ size_t const _quota = 2*1024*1024;
+ Slave _slave;
+ Root_client _nitpicker_root;
+
+ public:
+
+ /**
+ * Constructor
+ *
+ * \param ep entrypoint used for nitpicker child thread
+ * \param ram RAM session used to allocate the configuration
+ * dataspace
+ */
+ Nit_fader_slave(Rpc_entrypoint &ep, Ram_session &ram,
+ Genode::Service &nitpicker_service)
+ :
+ _policy(ep, ram, nitpicker_service),
+ _slave(ep, _policy, _quota),
+ _nitpicker_root(_policy.nitpicker_root())
+ {
+ visible(false);
+ }
+
+ Capability nitpicker_session(char const *label)
+ {
+ enum { ARGBUF_SIZE = 128 };
+ char argbuf[ARGBUF_SIZE];
+ argbuf[0] = 0;
+
+ /*
+ * Declare ram-quota donation
+ */
+ enum { SESSION_METADATA = 8*1024 };
+ Arg_string::set_arg(argbuf, sizeof(argbuf), "ram_quota", SESSION_METADATA);
+
+ /*
+ * Set session label
+ */
+ Arg_string::set_arg(argbuf, sizeof(argbuf), "label", label);
+
+ Session_capability session_cap = _nitpicker_root.session(argbuf, Affinity());
+
+ return static_cap_cast(session_cap);
+ }
+
+ void visible(bool visible)
+ {
+ _policy.visible(visible);
+ }
+};
+
+#endif /* _NIT_FADER_SLAVE_H_ */
diff --git a/repos/gems/src/app/launcher/subsystem_manager.h b/repos/gems/src/app/launcher/subsystem_manager.h
new file mode 100644
index 0000000000..3f90f4fb90
--- /dev/null
+++ b/repos/gems/src/app/launcher/subsystem_manager.h
@@ -0,0 +1,237 @@
+/*
+ * \brief Management of subsystems
+ * \author Norman Feske
+ * \date 2014-10-02
+ */
+
+/*
+ * 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 _SUBSYSTEM_MANAGER_H_
+#define _SUBSYSTEM_MANAGER_H_
+
+/* Genode includes */
+#include
+#include
+
+/* CLI-monitor includes */
+#include
+
+namespace Launcher {
+
+ class Subsystem_manager;
+ using Decorator::string_attribute;
+}
+
+/***************
+ ** Utilities **
+ ***************/
+
+/*
+ * XXX copied from 'cli_monitor/main.cc'
+ */
+static Genode::size_t ram_preservation_from_config()
+{
+ Genode::Number_of_bytes ram_preservation = 0;
+ try {
+ Genode::Xml_node node =
+ Genode::config()->xml_node().sub_node("preservation");
+
+ if (node.attribute("name").has_value("RAM"))
+ node.attribute("quantum").value(&ram_preservation);
+ } catch (...) { }
+
+ return ram_preservation;
+}
+
+
+class Launcher::Subsystem_manager
+{
+ public:
+
+ /**
+ * Exception types
+ */
+ class Invalid_config { };
+
+ private:
+
+ Server::Entrypoint &_ep;
+ Cap_session &_cap;
+
+ struct Child : Child_base, List::Element
+ {
+ typedef String<128> Binary_name;
+
+ Child(Ram &ram,
+ Label const &label,
+ Binary_name const &binary,
+ Cap_session &cap_session,
+ size_t ram_quota,
+ size_t ram_limit,
+ Signal_context_capability yield_response_sig_cap)
+ :
+ Child_base(ram,
+ label.string(),
+ binary.string(),
+ cap_session,
+ ram_quota,
+ ram_limit,
+ yield_response_sig_cap)
+ { }
+ };
+
+ List _children;
+
+ void _try_response_to_resource_request()
+ {
+ for (Child *child = _children.first(); child; child = child->next())
+ child->try_response_to_resource_request();
+ }
+
+ Genode::Signal_rpc_member _yield_broadcast_dispatcher =
+ { _ep, *this, &Subsystem_manager::_handle_yield_broadcast };
+
+ void _handle_yield_broadcast(unsigned)
+ {
+ _try_response_to_resource_request();
+
+ /*
+ * XXX copied from 'cli_monitor/main.cc'
+ */
+
+ /*
+ * Compute argument of yield request to be broadcasted to all
+ * processes.
+ */
+ size_t amount = 0;
+
+ /* amount needed to reach preservation limit */
+ Ram::Status ram_status = _ram.status();
+ if (ram_status.avail < ram_status.preserve)
+ amount += ram_status.preserve - ram_status.avail;
+
+ /* sum of pending resource requests */
+ for (Child *child = _children.first(); child; child = child->next())
+ amount += child->requested_ram_quota();
+
+ for (Child *child = _children.first(); child; child = child->next())
+ child->yield(amount, true);
+ }
+
+ Genode::Signal_rpc_member _resource_avail_dispatcher =
+ { _ep, *this, &Subsystem_manager::_handle_resource_avail };
+
+ void _handle_resource_avail(unsigned)
+ {
+ _try_response_to_resource_request();
+ }
+
+ Genode::Signal_rpc_member _yield_response_dispatcher =
+ { _ep, *this, &Subsystem_manager::_handle_yield_response };
+
+ void _handle_yield_response(unsigned)
+ {
+ _try_response_to_resource_request();
+ }
+
+ Ram _ram { ram_preservation_from_config(),
+ _yield_broadcast_dispatcher,
+ _resource_avail_dispatcher };
+
+ static Child::Binary_name _binary_name(Xml_node subsystem)
+ {
+ try {
+ return string_attribute(subsystem.sub_node("binary"),
+ "name", Child::Binary_name(""));
+ } catch (Xml_node::Nonexistent_sub_node) {
+ PERR("missing definition");
+ throw Invalid_config();
+ }
+ }
+
+ struct Ram_config { Number_of_bytes quantum, limit; };
+
+ static Ram_config _ram_config(Xml_node subsystem)
+ {
+ Number_of_bytes quantum = 0, limit = 0;
+ try {
+ subsystem.for_each_sub_node("resource", [&] (Xml_node rsc) {
+ if (rsc.attribute("name").has_value("RAM")) {
+
+ rsc.attribute("quantum").value(&quantum);
+
+ if (rsc.has_attribute("limit"))
+ rsc.attribute("limit").value(&limit);
+ }
+ });
+ } catch (...) {
+ PERR("invalid RAM resource declaration");
+ throw Invalid_config();
+ }
+
+ return Ram_config { quantum, limit };
+ }
+
+ public:
+
+ Subsystem_manager(Server::Entrypoint &ep, Cap_session &cap)
+ :
+ _ep(ep), _cap(cap)
+ { }
+
+ /**
+ * Start subsystem
+ *
+ * \throw Invalid_config
+ */
+ void start(Xml_node subsystem)
+ {
+ Child::Binary_name const binary_name = _binary_name(subsystem);
+
+ Child::Label const label = string_attribute(subsystem, "name",
+ Child::Label(""));
+
+ Ram_config const ram_config = _ram_config(subsystem);
+
+ PINF("starting child '%s'", label.string());
+
+ try {
+ Child *child = new (env()->heap())
+ Child(_ram, label, binary_name.string(), _cap,
+ ram_config.quantum, ram_config.limit,
+ _yield_broadcast_dispatcher);
+
+ /* configure child */
+ try {
+ Xml_node config_node = subsystem.sub_node("config");
+ child->configure(config_node.addr(), config_node.size());
+ } catch (...) { }
+
+ _children.insert(child);
+
+ child->start();
+
+ } catch (Rom_connection::Rom_connection_failed) {
+ PERR("binary \"%s\" is missing", binary_name.string());
+ throw Invalid_config();
+ }
+ }
+
+ void kill(char const *label)
+ {
+ for (Child *c = _children.first(); c; c = c->next()) {
+ if (c->label() == Child::Label(label)) {
+ _children.remove(c);
+ destroy(env()->heap(), c);
+ return;
+ }
+ }
+ }
+};
+
+#endif /* _SUBSYSTEM_MANAGER_H_ */
diff --git a/repos/gems/src/app/launcher/target.mk b/repos/gems/src/app/launcher/target.mk
new file mode 100644
index 0000000000..a1a5d82d98
--- /dev/null
+++ b/repos/gems/src/app/launcher/target.mk
@@ -0,0 +1,4 @@
+TARGET = launcher
+SRC_CC = main.cc
+LIBS = base server config
+INC_DIR += $(PRG_DIR)
diff --git a/repos/gems/src/app/launcher/types.h b/repos/gems/src/app/launcher/types.h
new file mode 100644
index 0000000000..a22f7c4083
--- /dev/null
+++ b/repos/gems/src/app/launcher/types.h
@@ -0,0 +1,45 @@
+/*
+ * \brief Common types for launcher
+ * \author Norman Feske
+ * \date 2014-09-30
+ */
+
+/*
+ * 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 _TYPES_H_
+#define _TYPES_H_
+
+/* Genode includes */
+#include
+#include
+
+namespace Launcher {
+ using namespace Genode;
+
+ typedef String<128> Label;
+
+ static Nitpicker::Session::Label selector(Label label)
+ {
+ /*
+ * Append label separator to uniquely identify the subsystem.
+ * Otherwise, the selector may be ambiguous if the label of one
+ * subsystem starts with the label of another subsystem.
+ */
+ char selector[Nitpicker::Session::Label::size()];
+ snprintf(selector, sizeof(selector), "%s ->", label.string());
+ return Nitpicker::Session::Label(selector);
+ }
+
+ using Decorator::area_attribute;
+ using Decorator::point_attribute;
+
+ typedef Nitpicker::Point Point;
+ typedef Nitpicker::Rect Rect;
+}
+
+#endif /* _TYPES_H_ */