gems: launcher application
This commit is contained in:
parent
cc303c4671
commit
6244c6ec97
|
@ -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 {
|
||||
<config>
|
||||
<parent-provides>
|
||||
<service name="ROM"/>
|
||||
<service name="CPU"/>
|
||||
<service name="PD"/>
|
||||
<service name="RAM"/>
|
||||
<service name="RM"/>
|
||||
<service name="LOG"/>
|
||||
<service name="IRQ"/>
|
||||
<service name="IO_MEM"/>
|
||||
<service name="IO_PORT"/>
|
||||
<service name="CAP"/>
|
||||
<service name="SIGNAL"/>
|
||||
</parent-provides>
|
||||
<default-route>
|
||||
<any-service> <parent/> <any-child/> </any-service>
|
||||
</default-route>}
|
||||
|
||||
append_if [have_spec sdl] config {
|
||||
<start name="fb_sdl">
|
||||
<resource name="RAM" quantum="4M"/>
|
||||
<provides>
|
||||
<service name="Input"/>
|
||||
<service name="Framebuffer"/>
|
||||
</provides>
|
||||
</start>}
|
||||
|
||||
append_if [have_spec pci] config {
|
||||
<start name="pci_drv">
|
||||
<resource name="RAM" quantum="1M"/>
|
||||
<provides><service name="PCI"/></provides>
|
||||
</start>}
|
||||
|
||||
append_if [have_spec framebuffer] config {
|
||||
<start name="fb_drv">
|
||||
<resource name="RAM" quantum="4M"/>
|
||||
<provides><service name="Framebuffer"/></provides>
|
||||
<config buffered="yes" />
|
||||
</start>}
|
||||
|
||||
append_if [have_spec ps2] config {
|
||||
<start name="ps2_drv">
|
||||
<resource name="RAM" quantum="1M"/>
|
||||
<provides><service name="Input"/></provides>
|
||||
</start>}
|
||||
|
||||
append config {
|
||||
<start name="timer">
|
||||
<resource name="RAM" quantum="1M"/>
|
||||
<provides><service name="Timer"/></provides>
|
||||
</start>
|
||||
<start name="nitpicker">
|
||||
<resource name="RAM" quantum="1M"/>
|
||||
<provides><service name="Nitpicker"/></provides>
|
||||
<config>
|
||||
<report xray="yes" />
|
||||
<domain name="pointer" layer="1" xray="no" origin="pointer" />
|
||||
<domain name="panel" layer="2" xray="no" />
|
||||
<domain name="" layer="3" />
|
||||
|
||||
<policy label="pointer" domain="pointer"/>
|
||||
<policy label="launcher -> menu" domain="panel"/>
|
||||
<policy label="" domain=""/>
|
||||
|
||||
<global-key name="KEY_SCROLLLOCK" operation="xray" />
|
||||
<global-key name="KEY_SYSRQ" operation="kill" />
|
||||
<global-key name="KEY_PRINT" operation="kill" />
|
||||
<global-key name="KEY_F11" operation="kill" />
|
||||
<global-key name="KEY_F12" operation="xray" />
|
||||
</config>
|
||||
</start>
|
||||
<start name="pointer">
|
||||
<resource name="RAM" quantum="1M"/>
|
||||
<route>
|
||||
<service name="Nitpicker"> <child name="nitpicker" /> </service>
|
||||
<any-service> <parent/> <any-child/> </any-service>
|
||||
</route>
|
||||
</start>
|
||||
<start name="report_rom">
|
||||
<resource name="RAM" quantum="1M"/>
|
||||
<provides> <service name="Report"/> <service name="ROM"/> </provides>
|
||||
<config>
|
||||
<rom>
|
||||
<policy label="launcher -> xray" report="nitpicker -> xray"/>
|
||||
</rom>
|
||||
</config>
|
||||
</start>
|
||||
<start name="launcher">
|
||||
<resource name="RAM" quantum="60M" />
|
||||
<config visibility="xray">
|
||||
<subsystem name="scout" title="Scout">
|
||||
<resource name="RAM" quantum="20M" />
|
||||
<binary name="scout" />
|
||||
</subsystem>
|
||||
<subsystem name="testnit1" title="Nitpicker Test">
|
||||
<resource name="RAM" quantum="2M" />
|
||||
<binary name="testnit" />
|
||||
</subsystem>
|
||||
<subsystem name="testnit2" title="Nitpicker Test 2">
|
||||
<resource name="RAM" quantum="2M" />
|
||||
<binary name="testnit" />
|
||||
</subsystem>
|
||||
<subsystem name="testnit3" title="Nitpicker Test 3">
|
||||
<resource name="RAM" quantum="2M" />
|
||||
<binary name="testnit" />
|
||||
</subsystem>
|
||||
<subsystem name="scout2" title="Scoutx">
|
||||
<resource name="RAM" quantum="20M" />
|
||||
<binary name="scout" />
|
||||
</subsystem>
|
||||
<subsystem name="testnit4" title="Nitpicker Testx">
|
||||
<resource name="RAM" quantum="2M" />
|
||||
<binary name="testnit" />
|
||||
</subsystem>
|
||||
<subsystem name="testnit5">
|
||||
<resource name="RAM" quantum="2M" />
|
||||
<binary name="testnit" />
|
||||
</subsystem>
|
||||
<subsystem name="testnit6">
|
||||
<resource name="RAM" quantum="2M" />
|
||||
<binary name="testnit" />
|
||||
</subsystem>
|
||||
</config>
|
||||
<route>
|
||||
<service name="ROM"> <if-arg key="label" value="xray"/>
|
||||
<child name="report_rom" />
|
||||
</service>
|
||||
<any-service> <parent/> <any-child/> </any-service>
|
||||
</route>
|
||||
</start>
|
||||
</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
|
|
@ -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 <fading_dialog.h>
|
||||
|
||||
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>::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<Element> _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_ */
|
|
@ -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 <util/string.h>
|
||||
#include <os/attached_dataspace.h>
|
||||
#include <nitpicker_session/nitpicker_session.h>
|
||||
#include <input_session/client.h>
|
||||
#include <input/event.h>
|
||||
#include <input/component.h>
|
||||
|
||||
/* gems includes */
|
||||
#include <gems/wrapped_nitpicker_session.h>
|
||||
|
||||
/* local includes */
|
||||
#include <types.h>
|
||||
|
||||
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<Dialog_nitpicker_session>
|
||||
_input_dispatcher { _ep, *this, &Dialog_nitpicker_session::_input_handler };
|
||||
|
||||
Input::Session_component _input_session;
|
||||
|
||||
Capability<Input::Session> _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<Input::Event>();
|
||||
|
||||
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_ */
|
|
@ -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 <gems/report_rom_slave.h>
|
||||
#include <gems/local_reporter.h>
|
||||
|
||||
/* local includes */
|
||||
#include <nit_fader_slave.h>
|
||||
#include <menu_view_slave.h>
|
||||
#include <dialog_nitpicker.h>
|
||||
#include <types.h>
|
||||
|
||||
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<Report::Session> _dialog_report;
|
||||
|
||||
Rom_session_client _hover_rom;
|
||||
|
||||
Lazy_volatile_object<Attached_dataspace> _hover_ds;
|
||||
|
||||
/* hovered element reported by menu view */
|
||||
Capability<Report::Session> _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<char>());
|
||||
|
||||
_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<Fading_dialog> _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<Nitpicker::Session> 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_ */
|
|
@ -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 <os/server.h>
|
||||
#include <os/config.h>
|
||||
#include <cap_session/connection.h>
|
||||
#include <decorator/xml_utils.h>
|
||||
#include <util/volatile_object.h>
|
||||
#include <os/attached_rom_dataspace.h>
|
||||
#include <nitpicker_session/connection.h>
|
||||
|
||||
/* local includes */
|
||||
#include <menu_dialog.h>
|
||||
|
||||
|
||||
namespace Launcher { struct Main; }
|
||||
|
||||
struct Launcher::Main
|
||||
{
|
||||
Server::Entrypoint ep;
|
||||
|
||||
Genode::Cap_connection cap;
|
||||
|
||||
char const *report_rom_config =
|
||||
"<config> <rom>"
|
||||
" <policy label=\"menu_dialog\" report=\"menu_dialog\"/>"
|
||||
" <policy label=\"menu_hover\" report=\"menu_hover\"/>"
|
||||
" <policy label=\"context_dialog\" report=\"context_dialog\"/>"
|
||||
" <policy label=\"context_hover\" report=\"context_hover\"/>"
|
||||
"</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<Attached_rom_dataspace> xray_rom_ds;
|
||||
|
||||
enum Visibility { VISIBILITY_ALWAYS, VISIBILITY_XRAY };
|
||||
|
||||
Visibility visibility = VISIBILITY_ALWAYS;
|
||||
|
||||
void handle_config(unsigned);
|
||||
|
||||
Genode::Signal_rpc_member<Main> 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<char>());
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
|
@ -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 <timer_session/connection.h>
|
||||
|
||||
/* local includes */
|
||||
#include <fading_dialog.h>
|
||||
#include <subsystem_manager.h>
|
||||
#include <context_dialog.h>
|
||||
|
||||
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>::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<Element> _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<Menu_dialog> _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_ */
|
|
@ -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 <os/slave.h>
|
||||
#include <nitpicker_session/nitpicker_session.h>
|
||||
|
||||
/* gems includes */
|
||||
#include <gems/single_session_service.h>
|
||||
|
||||
/* local includes */
|
||||
#include <types.h>
|
||||
|
||||
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<Root> _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),
|
||||
"<config xpos=\"%d\" ypos=\"%d\">\n"
|
||||
" <report hover=\"yes\"/>\n"
|
||||
" <libc>\n"
|
||||
" <vfs>\n"
|
||||
" <tar name=\"menu_view_styles.tar\" />\n"
|
||||
" </vfs>\n"
|
||||
" </libc>\n"
|
||||
"</config>",
|
||||
pos.x(), pos.y());
|
||||
|
||||
configure(config);
|
||||
}
|
||||
|
||||
public:
|
||||
|
||||
Policy(Genode::Rpc_entrypoint &entrypoint,
|
||||
Genode::Ram_session &ram,
|
||||
Capability<Nitpicker::Session> nitpicker_session,
|
||||
Capability<Rom_session> dialog_rom_session,
|
||||
Capability<Report::Session> 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> nitpicker_session,
|
||||
Capability<Rom_session> dialog_rom_session,
|
||||
Capability<Report::Session> 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_ */
|
|
@ -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 <os/slave.h>
|
||||
#include <nitpicker_session/nitpicker_session.h>
|
||||
|
||||
/* local includes */
|
||||
#include <types.h>
|
||||
|
||||
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<Root> _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),
|
||||
"<config alpha=\"%d\" />", 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> 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<Nitpicker::Session>(session_cap);
|
||||
}
|
||||
|
||||
void visible(bool visible)
|
||||
{
|
||||
_policy.visible(visible);
|
||||
}
|
||||
};
|
||||
|
||||
#endif /* _NIT_FADER_SLAVE_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 <os/server.h>
|
||||
#include <decorator/xml_utils.h>
|
||||
|
||||
/* CLI-monitor includes */
|
||||
#include <cli_monitor/child.h>
|
||||
|
||||
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<Child>::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<Child> _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<Subsystem_manager> _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<Subsystem_manager> _resource_avail_dispatcher =
|
||||
{ _ep, *this, &Subsystem_manager::_handle_resource_avail };
|
||||
|
||||
void _handle_resource_avail(unsigned)
|
||||
{
|
||||
_try_response_to_resource_request();
|
||||
}
|
||||
|
||||
Genode::Signal_rpc_member<Subsystem_manager> _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 <binary> 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_ */
|
|
@ -0,0 +1,4 @@
|
|||
TARGET = launcher
|
||||
SRC_CC = main.cc
|
||||
LIBS = base server config
|
||||
INC_DIR += $(PRG_DIR)
|
|
@ -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 <decorator/xml_utils.h>
|
||||
#include <nitpicker_session/nitpicker_session.h>
|
||||
|
||||
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_ */
|
Loading…
Reference in New Issue