genode/repos/os/src/server/input_merger/main.cc

170 lines
3.6 KiB
C++

/*
* \brief Input event merger
* \author Christian Prochaska
* \date 2014-09-29
*/
/*
* 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 <input/component.h>
#include <input_session/connection.h>
#include <os/attached_dataspace.h>
#include <os/config.h>
#include <os/server.h>
#include <os/static_root.h>
#include <util/list.h>
namespace Input_merger
{
using namespace Genode;
class Input_source : public List<Input_source>::Element
{
private:
Input::Session_capability _create_session(const char *label)
{
char session_args[sizeof(Parent::Session_args)];
Arg_string::set_arg(session_args, sizeof(Parent::Session_args),
"ram_quota", "16K");
Arg_string::set_arg(session_args, sizeof(Parent::Session_args),
"label", label);
return env()->parent()->session<Input::Session>(session_args);
}
public:
Input::Session_client session_client;
Attached_dataspace dataspace;
Input_source(const char *label)
: session_client(_create_session(label)),
dataspace(session_client.dataspace()) { }
~Input_source()
{
env()->parent()->close(session_client);
}
};
struct Main;
}
/******************
** Main program **
******************/
struct Input_merger::Main
{
Server::Entrypoint &ep;
List<Input_source> input_source_list;
/*
* Input session provided to our client
*/
Input::Session_component input_session_component;
/*
* Attach root interface to the entry point
*/
Static_root<Input::Session> input_root { ep.manage(input_session_component) };
void handle_input(unsigned)
{
for (Input_source *input_source = input_source_list.first();
input_source;
input_source = input_source->next()) {
Input::Event const * const events =
input_source->dataspace.local_addr<Input::Event>();
unsigned const num = input_source->session_client.flush();
for (unsigned i = 0; i < num; i++)
input_session_component.submit(events[i]);
}
}
Signal_rpc_member<Main> input_dispatcher =
{ ep, *this, &Main::handle_input};
void handle_config_update(unsigned)
{
Genode::config()->reload();
for (Input_source *input_source;
(input_source = input_source_list.first()); ) {
input_source_list.remove(input_source);
destroy(env()->heap(), input_source);
}
try {
for (Xml_node input_node = config()->xml_node().sub_node("input");
;
input_node = input_node.next("input")) {
char label_buf[128];
input_node.attribute("label").value(label_buf, sizeof(label_buf));
Input_source *input_source(new (env()->heap()) Input_source(label_buf));
input_source_list.insert(input_source);
input_source->session_client.sigh(input_dispatcher);
}
} catch (Xml_node::Nonexistent_sub_node) { }
}
Signal_rpc_member<Main> config_update_dispatcher =
{ ep, *this, &Main::handle_config_update};
/**
* Constructor
*/
Main(Server::Entrypoint &ep) : ep(ep)
{
input_session_component.event_queue().enabled(true);
/*
* Apply initial configuration
*/
handle_config_update(0);
/*
* Register signal handler
*/
Genode::config()->sigh(config_update_dispatcher);
/*
* Announce service
*/
Genode::env()->parent()->announce(ep.manage(input_root));
}
};
/************
** Server **
************/
namespace Server {
char const *name() { return "input_merger_ep"; }
size_t stack_size() { return 4*1024*sizeof(addr_t); }
void construct(Entrypoint &ep) { static Input_merger::Main inst(ep); }
}