Use signals for delivering input events

This patch changes both the Input::Session interface and the skeleton
for the server-side implementation of this interface
('input/component.h').

The Input::Session interface offers a new 'sigh' function, which can be
called be the client to register a signal handler. The signal handler
gets notified on the arrival of new input. This alleviates the need to
poll for input events at the client side.

The server-side skeleton for implementing input services underwent a
redesign to make it more modular and robust. I.e., there are no
global functions needed at the server side and the event-queue
enable/disable mechanism is implemented at a central place (in the root
component) rather than inside each driver.

Fixes #46
This commit is contained in:
Norman Feske 2014-05-07 10:33:20 +02:00 committed by Christian Helmuth
parent 6c10bfe049
commit 0ed68a56b7
39 changed files with 643 additions and 733 deletions

View File

@ -15,7 +15,7 @@
#include <base/printf.h>
#include <base/rpc_server.h>
#include <input/component.h>
#include <input/root.h>
#include <os/ring_buffer.h>
#include <lx_emul.h>
@ -25,19 +25,27 @@
using namespace Genode;
/*********************
** Input component **
*********************/
/**
* Return singleton instance of input-session component
*/
static Input::Session_component &input_session()
{
static Input::Session_component inst;
return inst;
}
typedef Ring_buffer<Input::Event, 512> Input_ring_buffer;
static Input_ring_buffer ev_queue;
namespace Input {
void event_handling(bool enable) { }
bool event_pending() { return !ev_queue.empty(); }
Event get_event() { return ev_queue.get(); }
/**
* Return singleton instance of input-root component
*
* On the first call (from 'start_input_service'), the 'ep' argument is
* specified. All subsequent calls (from 'input_callback') just return the
* reference to the singleton instance.
*/
static Input::Root_component &input_root(Rpc_entrypoint *ep = 0)
{
static Input::Root_component root(*ep, input_session());
return root;
}
@ -58,20 +66,20 @@ static void input_callback(enum input_event_type type,
}
try {
ev_queue.add(Input::Event(t, code,
absolute_x, absolute_y,
relative_x, relative_y));
} catch (Input_ring_buffer::Overflow) {
input_session().submit(Input::Event(t, code,
absolute_x, absolute_y,
relative_x, relative_y));
} catch (Input::Event_queue::Overflow) {
PWRN("input ring buffer overflow");
}
}
void start_input_service(void *ep)
void start_input_service(void *ep_ptr)
{
Rpc_entrypoint *e = static_cast<Rpc_entrypoint *>(ep);
static Input::Root input_root(e, env()->heap());
env()->parent()->announce(e->manage(&input_root));
Rpc_entrypoint *ep = static_cast<Rpc_entrypoint *>(ep_ptr);
env()->parent()->announce(ep->manage(&input_root(ep)));
genode_input_register(input_callback);
}

View File

@ -11,77 +11,30 @@
* under the terms of the GNU General Public License version 2.
*/
/* Genode include */
#include <base/env.h>
#include <base/semaphore.h>
#include <base/rpc_server.h>
#include <framebuffer_session/framebuffer_session.h>
#include <input/component.h>
#include <input/root.h>
#include <nitpicker_gfx/texture_painter.h>
#include <os/pixel_rgb565.h>
#include <os/static_root.h>
/* local includes */
#include "services.h"
typedef Genode::Texture<Genode::Pixel_rgb565> Texture_rgb565;
/*****************
** Event queue **
*****************/
class Event_queue
/**
* Return singleton instance of input session component
*/
Input::Session_component &input_session()
{
private:
enum { QUEUE_SIZE = 1024 };
Input::Event _queue[QUEUE_SIZE];
int _head;
int _tail;
Genode::Semaphore _sem;
public:
/**
* Constructor
*/
Event_queue(): _head(0), _tail(0)
{
Scout::memset(_queue, 0, sizeof(_queue));
}
void post(Input::Event ev)
{
if ((_head + 1)%QUEUE_SIZE != _tail) {
_queue[_head] = ev;
_head = (_head + 1)%QUEUE_SIZE;
_sem.up();
}
}
Input::Event get()
{
_sem.down();
Input::Event dst_ev = _queue[_tail];
_tail = (_tail + 1)%QUEUE_SIZE;
return dst_ev;
}
int pending() { return _head != _tail; }
} _ev_queue;
/***************************
** Input service backend **
***************************/
namespace Input {
void event_handling(bool enable) { }
bool event_pending() { return _ev_queue.pending(); }
Event get_event() { return _ev_queue.get(); }
static Input::Session_component inst;
return inst;
}
@ -93,16 +46,16 @@ class Window_content : public Scout::Element
{
private:
Event_queue *_ev_queue;
Scout::Point _old_mouse_position;
Element *_element;
Input::Session_component &_input_session;
Scout::Point _old_mouse_position;
Element *_element;
public:
Content_event_handler(Event_queue *ev_queue,
Content_event_handler(Input::Session_component &input_session,
Scout::Element *element)
:
_ev_queue(ev_queue), _element(element) { }
_input_session(input_session),_element(element) { }
void handle(Scout::Event &ev)
{
@ -123,10 +76,10 @@ class Window_content : public Scout::Element
: Input::Event::INVALID;
if (type != Input::Event::INVALID)
_ev_queue->post(Input::Event(type, code, mouse_position.x(),
mouse_position.y(),
mouse_position.x() - _old_mouse_position.x(),
mouse_position.y() - _old_mouse_position.y()));
_input_session.submit(Input::Event(type, code, mouse_position.x(),
mouse_position.y(),
mouse_position.x() - _old_mouse_position.x(),
mouse_position.y() - _old_mouse_position.y()));
_old_mouse_position = mouse_position;
}
@ -173,9 +126,9 @@ class Window_content : public Scout::Element
};
bool _config_alpha;
Content_event_handler _ev_handler;
Fb_texture *_fb;
bool _config_alpha;
Content_event_handler _ev_handler;
Fb_texture *_fb;
/**
* Size of the framebuffer handed out by the next call of 'dataspace'
@ -198,11 +151,12 @@ class Window_content : public Scout::Element
public:
Window_content(unsigned fb_w, unsigned fb_h, Event_queue *ev_queue,
Window_content(unsigned fb_w, unsigned fb_h,
Input::Session_component &input_session,
bool config_alpha)
:
_config_alpha(config_alpha),
_ev_handler(ev_queue, this),
_ev_handler(input_session, this),
_fb(new (Genode::env()->heap()) Fb_texture(fb_w, fb_h, _config_alpha)),
_next_size(fb_w, fb_h),
_designated_size(_next_size)
@ -268,76 +222,52 @@ Scout::Element *window_content() { return _window_content; }
** Implementation of the framebuffer service **
***********************************************/
namespace Framebuffer
namespace Framebuffer { class Session_component; }
class Framebuffer::Session_component : public Genode::Rpc_object<Session>
{
class Session_component : public Genode::Rpc_object<Session>
{
private:
private:
Window_content &_window_content;
Window_content &_window_content;
Genode::Signal_context_capability _sync_sigh;
Genode::Signal_context_capability _sync_sigh;
public:
public:
Session_component(Window_content &window_content)
: _window_content(window_content) { }
Session_component(Window_content &window_content)
: _window_content(window_content) { }
Genode::Dataspace_capability dataspace() override
{
_window_content.realloc_framebuffer();
return _window_content.fb_ds_cap();
}
Genode::Dataspace_capability dataspace() override
{
_window_content.realloc_framebuffer();
return _window_content.fb_ds_cap();
}
Mode mode() const override
{
return Mode(_window_content.mode_size().w(),
_window_content.mode_size().h(), Mode::RGB565);
}
Mode mode() const override
{
return Mode(_window_content.mode_size().w(),
_window_content.mode_size().h(), Mode::RGB565);
}
void mode_sigh(Genode::Signal_context_capability sigh) override {
_window_content.mode_sigh(sigh); }
void mode_sigh(Genode::Signal_context_capability sigh) override {
_window_content.mode_sigh(sigh); }
void sync_sigh(Genode::Signal_context_capability sigh) override {
_sync_sigh = sigh; }
void sync_sigh(Genode::Signal_context_capability sigh) override {
_sync_sigh = sigh; }
void refresh(int x, int y, int w, int h) override
{
_window_content.redraw_area(x, y, w, h);
void refresh(int x, int y, int w, int h) override
{
_window_content.redraw_area(x, y, w, h);
if (_sync_sigh.valid())
Genode::Signal_transmitter(_sync_sigh).submit();
}
};
class Root : public Genode::Root_component<Session_component>
{
private:
Window_content &_window_content;
protected:
Session_component *_create_session(const char *args) override {
return new (md_alloc()) Session_component(_window_content); }
public:
Root(Genode::Rpc_entrypoint *session_ep,
Genode::Allocator *md_alloc,
Window_content &window_content)
:
Genode::Root_component<Session_component>(session_ep, md_alloc),
_window_content(window_content)
{ }
};
}
if (_sync_sigh.valid())
Genode::Signal_transmitter(_sync_sigh).submit();
}
};
void init_window_content(unsigned fb_w, unsigned fb_h, bool config_alpha)
{
static Window_content content(fb_w, fb_h, &_ev_queue, config_alpha);
static Window_content content(fb_w, fb_h, input_session(), config_alpha);
_window_content = &content;
}
@ -346,11 +276,10 @@ void init_services(Genode::Rpc_entrypoint &ep)
{
using namespace Genode;
/*
* Let the entry point serve the framebuffer and input root interfaces
*/
static Framebuffer::Root fb_root(&ep, env()->heap(), *_window_content);
static Input::Root input_root(&ep, env()->heap());
static Framebuffer::Session_component fb_session(*_window_content);
static Static_root<Framebuffer::Session> fb_root(ep.manage(&fb_session));
static Input::Root_component input_root(ep, input_session());
/*
* Now, the root interfaces are ready to accept requests.

View File

@ -110,6 +110,14 @@ namespace Input {
* Flush input events
*/
Genode::size_t flush() { return _client.flush(); }
/**
* Register signal handler for input notifications
*/
void sigh(Genode::Signal_context_capability sigh)
{
_client.sigh(sigh);
}
};
@ -183,6 +191,12 @@ namespace Input {
}
return dst_count;
}
void sigh(Genode::Signal_context_capability sigh)
{
for (Source *e = _sources.first(); e; e = e->next())
e->sigh(sigh);
}
};
@ -214,18 +228,23 @@ namespace Input {
** Input-session interface **
*****************************/
Genode::Dataspace_capability dataspace() { return _ev_ds.cap(); }
Genode::Dataspace_capability dataspace() override { return _ev_ds.cap(); }
bool is_pending() const
bool is_pending() const override
{
return _source_registry.any_source_has_pending_input();
}
int flush()
int flush() override
{
return _source_registry.flush_sources(_ev_ds.local_addr<Event>(),
MAX_EVENTS);
}
void sigh(Genode::Signal_context_capability sigh) override
{
_source_registry.sigh(sigh);
}
};
/**

View File

@ -17,22 +17,22 @@
/* Qoost includes */
#include <qoost/style.h>
#include "input_service.h"
/* local includes */
#include "main_window.h"
void Control_bar::_rewind()
{
/* mouse click at horizontal position 0 */
ev_queue.add(Input::Event(Input::Event::PRESS, Input::BTN_LEFT, 0, 0, 0, 0));
ev_queue.add(Input::Event(Input::Event::RELEASE, Input::BTN_LEFT, 0, 0, 0, 0));
_event_queue.add(Input::Event(Input::Event::PRESS, Input::BTN_LEFT, 0, 0, 0, 0));
_event_queue.add(Input::Event(Input::Event::RELEASE, Input::BTN_LEFT, 0, 0, 0, 0));
}
void Control_bar::_pause_resume()
{
ev_queue.add(Input::Event(Input::Event::PRESS, Input::KEY_SPACE, 0, 0, 0, 0));
ev_queue.add(Input::Event(Input::Event::RELEASE, Input::KEY_SPACE, 0, 0, 0, 0));
_event_queue.add(Input::Event(Input::Event::PRESS, Input::KEY_SPACE, 0, 0, 0, 0));
_event_queue.add(Input::Event(Input::Event::RELEASE, Input::KEY_SPACE, 0, 0, 0, 0));
_playing = !_playing;
if (_playing)
@ -51,8 +51,9 @@ void Control_bar::_stop()
}
Control_bar::Control_bar()
: _playing(true)
Control_bar::Control_bar(Input::Event_queue &event_queue)
:
_event_queue(event_queue), _playing(true)
{
update_style_id(_play_pause_button, "play");

View File

@ -22,6 +22,9 @@
#include <qoost/compound_widget.h>
#include <qoost/qmember.h>
/* Genode includes */
#include <input/event_queue.h>
struct Play_pause_button : QPushButton { Q_OBJECT };
struct Stop_button : QPushButton { Q_OBJECT };
struct Volume_label : QLabel { Q_OBJECT };
@ -33,6 +36,8 @@ class Control_bar : public Compound_widget<QWidget, QHBoxLayout>
private:
Input::Event_queue &_event_queue;
QMember<Play_pause_button> _play_pause_button;
QMember<Stop_button> _stop_button;
QMember<Volume_label> _volume_label;
@ -49,7 +54,7 @@ class Control_bar : public Compound_widget<QWidget, QHBoxLayout>
public:
Control_bar();
Control_bar(Input::Event_queue &event_queue);
Q_SIGNALS:

View File

@ -1,40 +0,0 @@
/*
* \brief Input service
* \author Christian Prochaska
* \date 2012-03-29
*/
/*
* Copyright (C) 2012-2013 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_service.h"
using namespace Genode;
Event_queue ev_queue;
namespace Input {
/*
* Event handling is disabled on queue creation and will be enabled later if a
* session is created.
*/
void event_handling(bool enable)
{
if (enable)
ev_queue.enable();
else
ev_queue.disable();
}
bool event_pending() { return !ev_queue.empty(); }
Event get_event() { return ev_queue.get(); }
}

View File

@ -1,24 +0,0 @@
/*
* \brief Input service
* \author Christian Prochaska
* \date 2012-03-29
*/
/*
* Copyright (C) 2012-2013 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 _INPUT_SERVICE_H_
#define _INPUT_SERVICE_H_
/* Genode includes */
#include <input/event_queue.h>
extern Event_queue ev_queue;
extern void create_input_service();
#endif /* _INPUT_SERVICE_H_ */

View File

@ -17,6 +17,11 @@
/* qt_avplay includes */
#include "main_window.h"
/* Genode includes */
#include <rom_session/connection.h>
#include <base/process.h>
#include <base/printf.h>
static inline void load_stylesheet()
{
@ -37,6 +42,14 @@ int main(int argc, char *argv[])
load_stylesheet();
/* look for dynamic linker */
try {
static Genode::Rom_connection ldso_rom("ld.lib.so");
Genode::Process::dynamic_linker(ldso_rom.dataspace());
} catch (...) {
PERR("ld.lib.so not found");
}
QMember<Main_window> main_window;
main_window->show();

View File

@ -11,17 +11,10 @@
* under the terms of the GNU General Public License version 2.
*/
/* Genode includes */
#include <cap_session/connection.h>
#include <input/component.h>
#include <os/config.h>
#include <rom_session/connection.h>
/* qt_avplay includes */
#include "avplay_policy.h"
#include "filter_framebuffer_policy.h"
#include "framebuffer_root.h"
#include "input_service.h"
#include "main_window.h"
@ -30,49 +23,23 @@ using namespace Genode;
struct Framebuffer_filter
{
enum { MAX_FILTER_NAME_SIZE = 32 };
char name[MAX_FILTER_NAME_SIZE];
Genode::Number_of_bytes ram_quota;
enum { MAX_FILTER_NAME_SIZE = 32 };
char name[MAX_FILTER_NAME_SIZE];
Genode::Number_of_bytes ram_quota;
Service_registry *framebuffer_out_registry;
Rpc_entrypoint *ep;
Filter_framebuffer_policy *policy;
Slave *slave;
Service_registry *framebuffer_out_registry;
Rpc_entrypoint *ep;
Filter_framebuffer_policy *policy;
Slave *slave;
};
Main_window::Main_window()
:
_control_bar(_input_session.event_queue())
{
/* look for dynamic linker */
try {
static Rom_connection ldso_rom("ld.lib.so");
Process::dynamic_linker(ldso_rom.dataspace());
} catch (...) {
PERR("ld.lib.so not found");
}
/* get the name of the media file from the config file */
enum { MAX_LEN_MEDIAFILE_NAME = 256 };
static char mediafile[MAX_LEN_MEDIAFILE_NAME] = "mediafile";
try {
config()->xml_node().sub_node("mediafile").attribute("name").value(mediafile, sizeof(mediafile));
} catch(...) {
PWRN("no <mediafile> config node found, using \"mediafile\"");
}
/* create local services */
enum { STACK_SIZE = 2*sizeof(addr_t)*1024 };
static Cap_connection cap;
static Rpc_entrypoint avplay_ep(&cap, STACK_SIZE, "avplay_ep");
static Service_registry input_registry;
static Service_registry nitpicker_framebuffer_registry;
static Input::Root input_root(&avplay_ep, env()->heap());
static Local_service input_service(Input::Session::service_name(), &input_root);
input_registry.insert(&input_service);
avplay_ep.manage(&input_root);
_input_registry.insert(&_input_service);
_ep.manage(&_input_root);
/* find out which filtering framebuffer services to start and sort them in reverse order */
@ -90,15 +57,15 @@ Main_window::Main_window()
/* start the filtering framebuffer services */
Service_registry *framebuffer_in_registry = &nitpicker_framebuffer_registry;
Service_registry *framebuffer_in_registry = &_nitpicker_framebuffer_registry;
Q_FOREACH(Framebuffer_filter *framebuffer_filter, framebuffer_filters) {
framebuffer_filter->framebuffer_out_registry = new Service_registry;
framebuffer_filter->ep = new Rpc_entrypoint(&cap, STACK_SIZE, "filter_fb_ep");
framebuffer_filter->ep = new Rpc_entrypoint(&_cap, STACK_SIZE, "filter_fb_ep");
framebuffer_filter->policy = new Filter_framebuffer_policy(framebuffer_filter->name,
*framebuffer_filter->ep,
*framebuffer_in_registry,
*framebuffer_filter->framebuffer_out_registry);
*framebuffer_in_registry,
*framebuffer_filter->framebuffer_out_registry);
framebuffer_filter->slave = new Slave(*framebuffer_filter->ep,
*framebuffer_filter->policy,
framebuffer_filter->ram_quota);
@ -106,17 +73,17 @@ Main_window::Main_window()
}
Rpc_entrypoint *local_framebuffer_ep = framebuffer_filters.isEmpty() ?
&avplay_ep :
&_ep :
framebuffer_filters.at(0)->ep;
static Framebuffer::Root framebuffer_root(local_framebuffer_ep, env()->heap(), *_avplay_widget, 640, 480);
static Local_service framebuffer_service(Framebuffer::Session::service_name(), &framebuffer_root);
nitpicker_framebuffer_registry.insert(&framebuffer_service);
_nitpicker_framebuffer_registry.insert(&framebuffer_service);
/* start avplay */
static Avplay_policy avplay_policy(avplay_ep, input_registry, *framebuffer_in_registry, mediafile);
static Genode::Slave avplay_slave(avplay_ep, avplay_policy, 32*1024*1024);
static Avplay_policy avplay_policy(_ep, _input_registry, *framebuffer_in_registry, _mediafile_name.buf);
static Genode::Slave avplay_slave(_ep, avplay_policy, 32*1024*1024);
/* add widgets to layout */

View File

@ -23,6 +23,14 @@
#include <qoost/compound_widget.h>
#include <qoost/qmember.h>
/* Genode includes */
#include <base/service.h>
#include <cap_session/connection.h>
#include <input/root.h>
#include <os/config.h>
#include <rom_session/connection.h>
/* local includes */
#include "control_bar.h"
@ -32,6 +40,35 @@ class Main_window : public Compound_widget<QWidget, QVBoxLayout>
private:
struct Mediafile_name
{
/* get the name of the media file from the config file */
enum { MAX_LEN_MEDIAFILE_NAME = 256 };
char buf[MAX_LEN_MEDIAFILE_NAME];
Mediafile_name()
{
Genode::strncpy(buf, "mediafile", sizeof(buf));
try {
Genode::config()->xml_node().sub_node("mediafile")
.attribute("name").value(buf, sizeof(buf));
} catch(...) {
PWRN("no <mediafile> config node found, using \"mediafile\"");
}
}
} _mediafile_name;
enum { STACK_SIZE = 2*sizeof(Genode::addr_t)*1024 };
Genode::Cap_connection _cap;
Genode::Rpc_entrypoint _ep { &_cap, STACK_SIZE, "avplay_ep" };
Genode::Service_registry _input_registry;
Genode::Service_registry _nitpicker_framebuffer_registry;
Input::Session_component _input_session;
Input::Root_component _input_root { _ep, _input_session };
Genode::Local_service _input_service { Input::Session::service_name(), &_input_root };
QMember<QNitpickerViewWidget> _avplay_widget;
QMember<Control_bar> _control_bar;

View File

@ -6,7 +6,6 @@ HEADERS = avplay_policy.h \
main_window.h
SOURCES = control_bar.cpp \
framebuffer_session_component.cc \
input_service.cpp \
main.cpp \
main_window.cpp
RESOURCES = style.qrc

View File

@ -17,100 +17,61 @@
#include <base/env.h>
#include <base/rpc_server.h>
#include <os/attached_ram_dataspace.h>
#include <os/ring_buffer.h>
#include <root/component.h>
#include <input_session/input_session.h>
#include <input/event.h>
#include <input/event_queue.h>
namespace Input {
namespace Input { class Session_component; }
/********************
** Input back end **
********************/
class Input::Session_component : public Genode::Rpc_object<Input::Session>
{
private:
/**
* Enable/disable input event handling
*
* \param enable enable (true) or disable (false) back end
*
* The front end informs the back end about when to start capturing input
* events for an open session. Later, the back end may be deactivated on
* session destruction.
*/
void event_handling(bool enable);
Genode::Attached_ram_dataspace _ds { Genode::env()->ram_session(),
Event_queue::QUEUE_SIZE*sizeof(Input::Event) };
/**
* Check if an event is pending
*/
bool event_pending();
Event_queue _event_queue;
/**
* Wait for an event, Zzz...zz..
*/
Input::Event get_event();
public:
/**
* Return reference to event queue of the session
*/
Event_queue &event_queue() { return _event_queue; }
/**
* Submit input event to event queue
*
* \throw Input::Event_queue::Overflow
*/
void submit(Input::Event event) { _event_queue.add(event); }
/*****************************
** Input service front end **
*****************************/
/******************************
** Input::Session interface **
******************************/
class Session_component : public Genode::Rpc_object<Session>
{
private:
Genode::Dataspace_capability dataspace() override { return _ds.cap(); }
/*
* Input event buffer that is shared with the client
*/
enum { MAX_EVENTS = 1000 };
bool is_pending() const override { return !_event_queue.empty(); }
Genode::Attached_ram_dataspace _ev_ds;
int flush() override
{
Input::Event *dst = _ds.local_addr<Input::Event>();
unsigned cnt = 0;
for (; cnt < Event_queue::QUEUE_SIZE && !_event_queue.empty(); cnt++)
*dst++ = _event_queue.get();
public:
return cnt;
}
Session_component()
: _ev_ds(Genode::env()->ram_session(), MAX_EVENTS*sizeof(Event)) {
event_handling(true); }
~Session_component() {
event_handling(false); }
Genode::Dataspace_capability dataspace() { return _ev_ds.cap(); }
bool is_pending() const { return event_pending(); }
int flush()
{
/* dump events into event buffer dataspace */
int i;
Input::Event *ev_ds_buf = _ev_ds.local_addr<Input::Event>();
for (i = 0; (i < MAX_EVENTS) && event_pending(); ++i)
ev_ds_buf[i] = get_event();
/* return number of flushed events */
return i;
}
};
/**
* Shortcut for single-client root component
*/
typedef Genode::Root_component<Session_component, Genode::Single_client> Root_component;
class Root : public Root_component
{
protected:
Session_component *_create_session(const char *args) {
return new (md_alloc()) Session_component(); }
public:
Root(Genode::Rpc_entrypoint *session_ep,
Genode::Allocator *md_alloc)
: Root_component(session_ep, md_alloc) { }
};
}
void sigh(Genode::Signal_context_capability sigh) override
{
_event_queue.sigh(sigh);
}
};
#endif /* _INCLUDE__INPUT__COMPONENT_H_ */

View File

@ -5,7 +5,7 @@
*/
/*
* Copyright (C) 2007-2013 Genode Labs GmbH
* Copyright (C) 2007-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.
@ -14,57 +14,70 @@
#ifndef _EVENT_QUEUE_H_
#define _EVENT_QUEUE_H_
#include <base/printf.h>
#include <base/signal.h>
#include <input/event.h>
#include <os/ring_buffer.h>
/**
* Input event queue
*
* We expect the client to fetch events circa each 10ms. The PS/2 driver queues
* up to 255 events, which should be enough. Normally, PS/2 generates not more
* than 16Kbit/s, which would correspond to ca. 66 mouse events per 10ms.
*/
class Event_queue
namespace Input { class Event_queue; };
class Input::Event_queue
{
public:
/**
* Input event queue
*
* We expect the client to fetch events circa each 10ms. The PS/2 driver
* queues up to 255 events, which should be enough. Normally, PS/2
* generates not more than 16Kbit/s, which would correspond to ca. 66 mouse
* events per 10ms.
*/
enum { QUEUE_SIZE = 512U };
private:
bool _enabled;
Ring_buffer<Input::Event, 512> _ev_queue;
Ring_buffer<Input::Event, QUEUE_SIZE> _queue;
bool _enabled = false;
Genode::Signal_context_capability _sigh;
public:
Event_queue() : _enabled(false), _ev_queue() { }
typedef typename Ring_buffer<Input::Event, QUEUE_SIZE>::Overflow Overflow;
void enable() { _enabled = true; }
void disable() { _enabled = false; }
void enabled(bool enabled) { _enabled = enabled; }
void add(Input::Event e)
bool enabled() const { return _enabled; }
void sigh(Genode::Signal_context_capability sigh) { _sigh = sigh; }
void submit_signal()
{
if (!_enabled) return;
try {
_ev_queue.add(e);
} catch (Ring_buffer<Input::Event, 512>::Overflow) {
PWRN("event buffer overflow");
}
if (_sigh.valid())
Genode::Signal_transmitter(_sigh).submit();
}
Input::Event get()
/**
* \throw Overflow
*/
void add(Input::Event ev, bool submit_signal_immediately = true)
{
if (_enabled)
return _ev_queue.get();
else
return Input::Event();
if (!_enabled)
return;
_queue.add(ev);
if (submit_signal_immediately)
submit_signal();
}
bool empty()
{
if (_enabled)
return _ev_queue.empty();
else
return true;
}
Input::Event get() { return _queue.get(); }
bool empty() const { return _queue.empty(); }
int avail_capacity() const { return _queue.avail_capacity(); }
};
#endif /* _EVENT_QUEUE_H_ */

View File

@ -0,0 +1,70 @@
/*
* \brief Input root component
* \author Norman Feske
* \date 2014-05-31
*/
/*
* 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 _INPUT__ROOT_H_
#define _INPUT__ROOT_H_
/* Genode includes */
#include <os/static_root.h>
#include <input/component.h>
namespace Input { class Root_component; }
/*
* This input root component tracks if the session has been opened. If a client
* is connected, the 'Event_queue::enabled' gets enabled. This is useful to
* omit the enqueuing of input events into the event queue before any client is
* interested in receiving input events. If we would not drop such early input
* events, the queue might overflow when input events are generated at boot
* times.
*/
class Input::Root_component : public Genode::Static_root<Input::Session>
{
private:
Genode::Rpc_entrypoint &_ep;
Input::Session_component &_session;
public:
Root_component(Genode::Rpc_entrypoint &ep, Input::Session_component &session)
:
Static_root<Input::Session>(ep.manage(&session)),
_ep(ep), _session(session)
{ }
~Root_component()
{
_ep.dissolve(&_session);
}
Genode::Capability<Genode::Session>
session(Genode::Root::Session_args const &args,
Genode::Affinity const &affinity) override
{
if (_session.event_queue().enabled())
throw Root::Unavailable();
_session.event_queue().enabled(true);
return Static_root<Input::Session>::session(args, affinity);
}
void close(Genode::Capability<Session>)
{
_session.event_queue().enabled(false);
}
};
#endif /* _INPUT__ROOT_H_ */

View File

@ -24,14 +24,17 @@ namespace Input {
explicit Session_client(Session_capability session)
: Genode::Rpc_client<Session>(session) { }
Genode::Dataspace_capability dataspace() {
Genode::Dataspace_capability dataspace() override {
return call<Rpc_dataspace>(); }
bool is_pending() const {
bool is_pending() const override {
return call<Rpc_is_pending>(); }
int flush() {
int flush() override {
return call<Rpc_flush>(); }
void sigh(Genode::Signal_context_capability sigh) override {
call<Rpc_sigh>(sigh); }
};
}

View File

@ -17,6 +17,7 @@
#include <dataspace/capability.h>
#include <base/rpc_server.h>
#include <session/session.h>
#include <base/signal.h>
namespace Input {
@ -45,6 +46,11 @@ namespace Input {
*/
virtual int flush() = 0;
/**
* Register signal handler to be notified on arrival of new input
*/
virtual void sigh(Genode::Signal_context_capability) = 0;
/*********************
** RPC declaration **
@ -53,8 +59,9 @@ namespace Input {
GENODE_RPC(Rpc_dataspace, Genode::Dataspace_capability, dataspace);
GENODE_RPC(Rpc_is_pending, bool, is_pending);
GENODE_RPC(Rpc_flush, int, flush);
GENODE_RPC(Rpc_sigh, void, sigh, Genode::Signal_context_capability);
GENODE_RPC_INTERFACE(Rpc_dataspace, Rpc_is_pending, Rpc_flush);
GENODE_RPC_INTERFACE(Rpc_dataspace, Rpc_is_pending, Rpc_flush, Rpc_sigh);
};
}

View File

@ -19,10 +19,12 @@
#include <base/env.h>
#include <base/sleep.h>
#include <base/rpc_server.h>
#include <root/component.h>
#include <framebuffer_session/framebuffer_session.h>
#include <cap_session/connection.h>
#include <input/component.h>
#include <input/root.h>
/* local includes */
#include <input.h>
/*
@ -44,85 +46,63 @@ static void *fb_ds_addr;
** Implementation of the framebuffer service **
***********************************************/
namespace Framebuffer {
namespace Framebuffer { class Session_component; }
class Session_component : public Genode::Rpc_object<Session>
{
private:
class Framebuffer::Session_component : public Genode::Rpc_object<Session>
{
private:
Mode _mode;
Mode _mode;
Genode::Signal_context_capability _sync_sigh;
Genode::Signal_context_capability _sync_sigh;
public:
public:
/**
* Constructor
*/
Session_component() : _mode(scr_width, scr_height, Mode::RGB565) { }
/**
* Constructor
*/
Session_component() : _mode(scr_width, scr_height, Mode::RGB565) { }
Genode::Dataspace_capability dataspace() override { return fb_ds_cap; }
Genode::Dataspace_capability dataspace() override { return fb_ds_cap; }
Mode mode() const override { return _mode; }
Mode mode() const override { return _mode; }
void mode_sigh(Genode::Signal_context_capability) override { }
void mode_sigh(Genode::Signal_context_capability) override { }
void sync_sigh(Genode::Signal_context_capability sigh) override
{
_sync_sigh = sigh;
void sync_sigh(Genode::Signal_context_capability sigh) override
{
_sync_sigh = sigh;
}
void refresh(int x, int y, int w, int h) override
{
/* clip refresh area to screen boundaries */
int x1 = Genode::max(x, 0);
int y1 = Genode::max(y, 0);
int x2 = Genode::min(x + w - 1, scr_width - 1);
int y2 = Genode::min(y + h - 1, scr_height - 1);
if (x1 <= x2 && y1 <= y2) {
/* copy pixels from shared dataspace to sdl surface */
const int start_offset = _mode.bytes_per_pixel()*(y1*scr_width + x1);
const int line_len = _mode.bytes_per_pixel()*(x2 - x1 + 1);
const int pitch = _mode.bytes_per_pixel()*scr_width;
char *src = (char *)fb_ds_addr + start_offset;
char *dst = (char *)screen->pixels + start_offset;
for (int i = y1; i <= y2; i++, src += pitch, dst += pitch)
Genode::memcpy(dst, src, line_len);
/* flush pixels in sdl window */
SDL_UpdateRect(screen, x1, y1, x2 - x1 + 1, y2 - y1 + 1);
}
void refresh(int x, int y, int w, int h) override
{
/* clip refresh area to screen boundaries */
int x1 = Genode::max(x, 0);
int y1 = Genode::max(y, 0);
int x2 = Genode::min(x + w - 1, scr_width - 1);
int y2 = Genode::min(y + h - 1, scr_height - 1);
if (x1 <= x2 && y1 <= y2) {
/* copy pixels from shared dataspace to sdl surface */
const int start_offset = _mode.bytes_per_pixel()*(y1*scr_width + x1);
const int line_len = _mode.bytes_per_pixel()*(x2 - x1 + 1);
const int pitch = _mode.bytes_per_pixel()*scr_width;
char *src = (char *)fb_ds_addr + start_offset;
char *dst = (char *)screen->pixels + start_offset;
for (int i = y1; i <= y2; i++, src += pitch, dst += pitch)
Genode::memcpy(dst, src, line_len);
/* flush pixels in sdl window */
SDL_UpdateRect(screen, x1, y1, x2 - x1 + 1, y2 - y1 + 1);
}
if (_sync_sigh.valid())
Genode::Signal_transmitter(_sync_sigh).submit();
}
};
/**
* Shortcut for single-client root component
*/
typedef Genode::Root_component<Session_component, Genode::Single_client> Root_component;
class Root : public Root_component
{
protected:
Session_component *_create_session(const char *args) override {
return new (md_alloc()) Session_component(); }
public:
Root(Genode::Rpc_entrypoint *session_ep,
Genode::Allocator *md_alloc)
: Root_component(session_ep, md_alloc) { }
};
}
if (_sync_sigh.valid())
Genode::Signal_transmitter(_sync_sigh).submit();
}
};
/**
@ -172,19 +152,21 @@ extern "C" int main(int, char**)
static Cap_connection cap;
static Rpc_entrypoint ep(&cap, STACK_SIZE, "fb_ep");
/*
* Let the entry point serve the framebuffer and input root interfaces
*/
static Framebuffer::Root framebuffer_root(&ep, env()->heap());
static Input::Root input_root(&ep, env()->heap());
static Input::Session_component input_session;
static Input::Root_component input_root(ep, input_session);
static Framebuffer::Session_component fb_session;
static Static_root<Framebuffer::Session> fb_root(ep.manage(&fb_session));
/*
* Now, the root interfaces are ready to accept requests.
* This is the right time to tell mummy about our services.
*/
env()->parent()->announce(ep.manage(&framebuffer_root));
env()->parent()->announce(ep.manage(&fb_root));
env()->parent()->announce(ep.manage(&input_root));
sleep_forever();
for (;;)
input_session.submit(wait_for_event());
return 0;
}

View File

@ -16,12 +16,11 @@
/* Genode */
#include <input/keycodes.h>
/* Local */
#include <input/component.h>
#include <base/printf.h>
/* local */
#include <input.h>
/**
* Convert SDL keycode to Genode keycode
*/
@ -139,14 +138,7 @@ static long convert_keycode(int sdl_keycode)
};
void Input::event_handling(bool enable) { }
bool Input::event_pending() { return SDL_PollEvent(0); }
/**
* Wait for an event, Zzz...zz..
*/
Input::Event Input::get_event()
Input::Event wait_for_event()
{
using namespace Input;

View File

@ -0,0 +1,24 @@
/*
* \brief SDL input support
* \author Norman Feske
* \date 2006-08-16
*/
/*
* Copyright (C) 2006-2013 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 _INPUT_H_
#define _INPUT_H_
#include <input/event.h>
/**
* Wait for an event, Zzz...zz..
*/
Input::Event wait_for_event();
#endif /* _INPUT_H_ */

View File

@ -3,13 +3,4 @@ LIBS = lx_hybrid
REQUIRES = linux sdl
SRC_CC = fb_sdl.cc input.cc
LX_LIBS = sdl
#
# Explicitly add host headers to the include-search location. Even though this
# path happens to be added via the 'lx_hybrid' library via the 'HOST_INC_DIR'
# variable, we want to give /usr/include preference for resolving 'SDL/*'
# headers. Otherwise, if libSDL is prepared in 'libports', the build system
# would pull-in the SDL headers from libports.
#
INC_DIR += /usr/include
INC_DIR += $(PRG_DIR)

View File

@ -15,6 +15,7 @@
/* Genode */
#include <base/env.h>
#include <base/sleep.h>
#include <base/signal.h>
#include <base/rpc_server.h>
#include <root/component.h>
#include <cap_session/connection.h>
@ -41,15 +42,17 @@ namespace Input {
{
public:
Dataspace_capability dataspace() { return ev_ds_cap; }
Dataspace_capability dataspace() override { return ev_ds_cap; }
bool is_pending() const { return 0; }
bool is_pending() const override { return 0; }
int flush()
int flush() override
{
/* return number of flushed events */
return 0;
}
void sigh(Genode::Signal_context_capability) override { }
};

View File

@ -13,41 +13,21 @@
* under the terms of the GNU General Public License version 2.
*/
/* Genode */
/* Genode includes */
#include <base/env.h>
#include <base/sleep.h>
#include <base/rpc_server.h>
#include <root/component.h>
#include <cap_session/connection.h>
#include <platform_session/connection.h>
#include <input/component.h>
#include <input/root.h>
#include <base/printf.h>
/* local includes */
#include <driver.h>
using namespace Genode;
static Event_queue ev_queue;
namespace Input {
/*
* Event handling is disabled on queue creation and will be enabled later if a
* session is created.
*/
void event_handling(bool enable)
{
if (enable)
ev_queue.enable();
else
ev_queue.disable();
}
bool event_pending() { return !ev_queue.empty(); }
Event get_event() { return ev_queue.get(); }
}
int main(int argc, char **argv)
{
/* initialize server entry point */
@ -55,23 +35,25 @@ int main(int argc, char **argv)
static Cap_connection cap;
static Rpc_entrypoint ep(&cap, STACK_SIZE, "input_ep");
static Input::Session_component session;
Platform::Connection plat_drv;
switch (plat_drv.revision()) {
case Platform::Session::SMD:
plat_drv.enable(Platform::Session::I2C_2);
plat_drv.enable(Platform::Session::I2C_3);
plat_drv.enable(Platform::Session::BUTTONS);
Input::Tablet_driver::factory(ev_queue);
Input::Tablet_driver::factory(session.event_queue());
break;
default:
PWRN("No input driver available for this board");
}
/* entry point serving input root interface */
static Input::Root input_root(&ep, env()->heap());
static Input::Root_component root(ep, session);
/* tell parent about the service */
env()->parent()->announce(ep.manage(&input_root));
env()->parent()->announce(ep.manage(&root));
/* main's done - go to sleep */
sleep_forever();

View File

@ -11,12 +11,15 @@
* under the terms of the GNU General Public License version 2.
*/
/* Genode includes */
#include <base/env.h>
#include <base/printf.h>
#include <base/sleep.h>
#include <input/component.h>
#include <input/root.h>
#include <cap_session/connection.h>
/* local includes */
#include "ps2_keyboard.h"
#include "ps2_mouse.h"
#include "irq_handler.h"
@ -24,26 +27,6 @@
using namespace Genode;
static Event_queue ev_queue;
namespace Input {
/*
* Event handling is disabled on queue creation and will be enabled later if a
* session is created.
*/
void event_handling(bool enable)
{
if (enable)
ev_queue.enable();
else
ev_queue.disable();
}
bool event_pending() { return !ev_queue.empty(); }
Event get_event() { return ev_queue.get(); }
}
int main(int argc, char **argv)
{
@ -52,12 +35,6 @@ int main(int argc, char **argv)
Serial_interface *kbd = pl050.kbd_interface();
Serial_interface *aux = pl050.aux_interface();
Ps2_mouse ps2_mouse(*aux, ev_queue);
Ps2_keyboard ps2_keybd(*kbd, ev_queue, true);
Irq_handler ps2_mouse_irq(PL050_MOUSE_IRQ, aux, ps2_mouse);
Irq_handler ps2_keybd_irq(PL050_KEYBD_IRQ, kbd, ps2_keybd);
/*
* Initialize server entry point
*/
@ -65,11 +42,19 @@ int main(int argc, char **argv)
static Cap_connection cap;
static Rpc_entrypoint ep(&cap, STACK_SIZE, "ps2_ep");
static Input::Session_component session;
static Input::Root_component root(ep, session);
Ps2_mouse ps2_mouse(*aux, session.event_queue());
Ps2_keyboard ps2_keybd(*kbd, session.event_queue(), true);
Irq_handler ps2_mouse_irq(PL050_MOUSE_IRQ, aux, ps2_mouse);
Irq_handler ps2_keybd_irq(PL050_KEYBD_IRQ, kbd, ps2_keybd);
/*
* Let the entry point serve the input root interface
*/
static Input::Root input_root(&ep, env()->heap());
env()->parent()->announce(ep.manage(&input_root));
env()->parent()->announce(ep.manage(&root));
Genode::sleep_forever();
return 0;

View File

@ -30,9 +30,9 @@ class Ps2_keyboard : public Input_driver
static const bool verbose = false;
static const bool verbose_scan_codes = false;
Serial_interface &_kbd;
Event_queue &_ev_queue;
bool _xlate_mode;
Serial_interface &_kbd;
Input::Event_queue &_ev_queue;
bool _xlate_mode;
/**
* Array for tracking the current keyboard state
@ -363,7 +363,7 @@ class Ps2_keyboard : public Input_driver
* If 'xlate_mode' is true, we do not attempt to manually switch the
* keyboard to scan code set 2 but just decode the scan-code set 1.
*/
Ps2_keyboard(Serial_interface &kbd, Event_queue &ev_queue, bool xlate_mode)
Ps2_keyboard(Serial_interface &kbd, Input::Event_queue &ev_queue, bool xlate_mode)
:
_kbd(kbd), _ev_queue(ev_queue), _xlate_mode(xlate_mode)
{

View File

@ -71,12 +71,12 @@ class Ps2_mouse : public Input_driver
static const bool verbose = false;
Serial_interface &_aux;
Event_queue &_ev_queue;
Serial_interface &_aux;
Input::Event_queue &_ev_queue;
Type _type;
Type _type;
bool _button_state[NUM_BUTTONS];
bool _button_state[NUM_BUTTONS];
unsigned char _packet[MAX_PACKET_LEN];
int _packet_len;
@ -149,9 +149,10 @@ class Ps2_mouse : public Input_driver
public:
Ps2_mouse(Serial_interface &aux, Event_queue &ev_queue)
Ps2_mouse(Serial_interface &aux, Input::Event_queue &ev_queue)
:
_aux(aux), _ev_queue(ev_queue), _type(PS2),
_aux(aux),
_ev_queue(ev_queue), _type(PS2),
_packet_len(PS2_PACKET_LEN), _packet_idx(0)
{
for (unsigned i = 0; i < NUM_BUTTONS; ++i)

View File

@ -15,6 +15,7 @@
#include <base/printf.h>
#include <base/sleep.h>
#include <input/component.h>
#include <input/root.h>
#include <cap_session/connection.h>
#include "i8042.h"
@ -24,26 +25,6 @@
using namespace Genode;
static Event_queue ev_queue;
namespace Input {
/*
* Event handling is disabled on queue creation and will be enabled later if a
* session is created.
*/
void event_handling(bool enable)
{
if (enable)
ev_queue.enable();
else
ev_queue.disable();
}
bool event_pending() { return !ev_queue.empty(); }
Event get_event() { return ev_queue.get(); }
}
int main(int argc, char **argv)
{
@ -52,24 +33,23 @@ int main(int argc, char **argv)
Serial_interface *kbd = i8042.kbd_interface();
Serial_interface *aux = i8042.aux_interface();
Ps2_mouse ps2_mouse(*aux, ev_queue);
Ps2_keyboard ps2_keybd(*kbd, ev_queue, i8042.kbd_xlate());
/*
* Initialize server entry point
*/
enum { STACK_SIZE = 4096 };
static Cap_connection cap;
static Rpc_entrypoint ep(&cap, STACK_SIZE, "ps2_ep");
static Input::Session_component session;
static Input::Root_component root(ep, session);
Ps2_mouse ps2_mouse(*aux, session.event_queue());
Ps2_keyboard ps2_keybd(*kbd, session.event_queue(), i8042.kbd_xlate());
Irq_handler ps2_mouse_irq(12, ps2_mouse);
Irq_handler ps2_keybd_irq( 1, ps2_keybd);
/*
* Initialize server entry point
*/
enum { STACK_SIZE = sizeof(addr_t)*1024 };
static Cap_connection cap;
static Rpc_entrypoint ep(&cap, STACK_SIZE, "ps2_ep");
/*
* Let the entry point serve the input root interface
*/
static Input::Root input_root(&ep, env()->heap());
env()->parent()->announce(ep.manage(&input_root));
env()->parent()->announce(ep.manage(&root));
Genode::sleep_forever();
return 0;

View File

@ -66,11 +66,11 @@ namespace Input {
** Input session interface **
*****************************/
Dataspace_capability dataspace() { return _real_input.dataspace(); }
Dataspace_capability dataspace() override { return _real_input.dataspace(); }
bool is_pending() const { return _real_input.is_pending(); }
bool is_pending() const override { return _real_input.is_pending(); }
int flush()
int flush() override
{
/* translate mouse position to child's coordinate system */
Transformer::Delta delta = _transformer.delta();
@ -97,6 +97,11 @@ namespace Input {
return num_ev;
}
void sigh(Signal_context_capability sigh) override
{
_real_input.sigh(sigh);
}
};
}

View File

@ -82,11 +82,11 @@ namespace Input {
** Input session interface **
*****************************/
Genode::Dataspace_capability dataspace() { return _to_input_ds; }
Genode::Dataspace_capability dataspace() override { return _to_input_ds; }
bool is_pending() const { return _from_input->is_pending(); }
bool is_pending() const override { return _from_input->is_pending(); }
int flush()
int flush() override
{
/* flush events at input session */
int num_events = _from_input->flush();
@ -103,6 +103,11 @@ namespace Input {
}
return num_events;
}
void sigh(Genode::Signal_context_capability sigh) override
{
_from_input->sigh(sigh);
}
};
}

View File

@ -257,8 +257,19 @@ class Input::Session_component : public Genode::Rpc_object<Session>
Event _ev_buf[MAX_EVENTS];
unsigned _num_ev = 0;
Signal_context_capability _sigh;
public:
/**
* Wake up client
*/
void submit_signal()
{
if (_sigh.valid())
Signal_transmitter(_sigh).submit();
}
/**
* Enqueue event into local event buffer of the input session
*/
@ -269,6 +280,8 @@ class Input::Session_component : public Genode::Rpc_object<Session>
/* insert event into local event buffer */
_ev_buf[_num_ev++] = *ev;
submit_signal();
}
@ -276,11 +289,11 @@ class Input::Session_component : public Genode::Rpc_object<Session>
** Input session interface **
*****************************/
Dataspace_capability dataspace() { return _ev_ram_ds.cap(); }
Dataspace_capability dataspace() override { return _ev_ram_ds.cap(); }
bool is_pending() const { return _num_ev > 0; }
bool is_pending() const override { return _num_ev > 0; }
int flush()
int flush() override
{
unsigned ev_cnt;
@ -292,6 +305,8 @@ class Input::Session_component : public Genode::Rpc_object<Session>
_num_ev = 0;
return ev_cnt;
}
void sigh(Genode::Signal_context_capability sigh) override { _sigh = sigh; }
};

View File

@ -54,6 +54,25 @@ class Avplay_policy : public QObject, public Genode::Slave_policy
arg1_node.setAttribute("value", _mediafile);
config_node.appendChild(arg1_node);
/*
* Configure libc of avplay to direct output to LOG and to obtain
* the mediafile from ROM.
*/
QDomElement libc_node = config_doc.createElement("libc");
libc_node.setAttribute("stdout", "/dev/log");
libc_node.setAttribute("stderr", "/dev/log");
QDomElement libc_vfs_node = config_doc.createElement("vfs");
QDomElement libc_vfs_dev_node = config_doc.createElement("dir");
libc_vfs_dev_node.setAttribute("name", "dev");
QDomElement libc_vfs_dev_log_node = config_doc.createElement("log");
libc_vfs_dev_node.appendChild(libc_vfs_dev_log_node);
libc_vfs_node.appendChild(libc_vfs_dev_node);
QDomElement libc_vfs_mediafile_node = config_doc.createElement("rom");
libc_vfs_mediafile_node.setAttribute("name", "mediafile");
libc_vfs_node.appendChild(libc_vfs_mediafile_node);
libc_node.appendChild(libc_vfs_node);
config_node.appendChild(libc_node);
QDomElement sdl_audio_volume_node = config_doc.createElement("sdl_audio_volume");
sdl_audio_volume_node.setAttribute("value", QString::number(_sdl_audio_volume));
config_node.appendChild(sdl_audio_volume_node);

View File

@ -17,22 +17,22 @@
/* Qoost includes */
#include <qoost/style.h>
#include "input_service.h"
/* local includes */
#include "main_window.h"
void Control_bar::_rewind()
{
/* mouse click at horizontal position 0 */
ev_queue.add(Input::Event(Input::Event::PRESS, Input::BTN_LEFT, 0, 0, 0, 0));
ev_queue.add(Input::Event(Input::Event::RELEASE, Input::BTN_LEFT, 0, 0, 0, 0));
_event_queue.add(Input::Event(Input::Event::PRESS, Input::BTN_LEFT, 0, 0, 0, 0));
_event_queue.add(Input::Event(Input::Event::RELEASE, Input::BTN_LEFT, 0, 0, 0, 0));
}
void Control_bar::_pause_resume()
{
ev_queue.add(Input::Event(Input::Event::PRESS, Input::KEY_SPACE, 0, 0, 0, 0));
ev_queue.add(Input::Event(Input::Event::RELEASE, Input::KEY_SPACE, 0, 0, 0, 0));
_event_queue.add(Input::Event(Input::Event::PRESS, Input::KEY_SPACE, 0, 0, 0, 0));
_event_queue.add(Input::Event(Input::Event::RELEASE, Input::KEY_SPACE, 0, 0, 0, 0));
_playing = !_playing;
if (_playing)
@ -51,8 +51,9 @@ void Control_bar::_stop()
}
Control_bar::Control_bar()
: _playing(true)
Control_bar::Control_bar(Input::Event_queue &event_queue)
:
_event_queue(event_queue), _playing(true)
{
update_style_id(_play_pause_button, "play");

View File

@ -21,6 +21,9 @@
#include <qoost/compound_widget.h>
#include <qoost/qmember.h>
/* Genode includes */
#include <input/event_queue.h>
struct Play_pause_button : QPushButton { Q_OBJECT };
struct Stop_button : QPushButton { Q_OBJECT };
struct Volume_label : QLabel { Q_OBJECT };
@ -32,6 +35,8 @@ class Control_bar : public Compound_widget<QWidget, QHBoxLayout>
private:
Input::Event_queue &_event_queue;
QMember<Play_pause_button> _play_pause_button;
QMember<Stop_button> _stop_button;
QMember<Volume_label> _volume_label;
@ -48,7 +53,7 @@ class Control_bar : public Compound_widget<QWidget, QHBoxLayout>
public:
Control_bar();
Control_bar(Input::Event_queue &event_queue);
Q_SIGNALS:

View File

@ -1,40 +0,0 @@
/*
* \brief Input service
* \author Christian Prochaska
* \date 2012-03-29
*/
/*
* Copyright (C) 2012-2013 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_service.h"
using namespace Genode;
Event_queue ev_queue;
namespace Input {
/*
* Event handling is disabled on queue creation and will be enabled later if a
* session is created.
*/
void event_handling(bool enable)
{
if (enable)
ev_queue.enable();
else
ev_queue.disable();
}
bool event_pending() { return !ev_queue.empty(); }
Event get_event() { return ev_queue.get(); }
}

View File

@ -1,24 +0,0 @@
/*
* \brief Input service
* \author Christian Prochaska
* \date 2012-03-29
*/
/*
* Copyright (C) 2012-2013 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 _INPUT_SERVICE_H_
#define _INPUT_SERVICE_H_
/* Genode includes */
#include <input/event_queue.h>
extern Event_queue ev_queue;
extern void create_input_service();
#endif /* _INPUT_SERVICE_H_ */

View File

@ -17,6 +17,11 @@
/* qt_avplay includes */
#include "main_window.h"
/* Genode includes */
#include <rom_session/connection.h>
#include <base/process.h>
#include <base/printf.h>
static inline void load_stylesheet()
{
@ -37,6 +42,14 @@ int main(int argc, char *argv[])
load_stylesheet();
/* look for dynamic linker */
try {
static Genode::Rom_connection ldso_rom("ld.lib.so");
Genode::Process::dynamic_linker(ldso_rom.dataspace());
} catch (...) {
PERR("ld.lib.so not found");
}
QMember<Main_window> main_window;
main_window->show();

View File

@ -11,17 +11,10 @@
* under the terms of the GNU General Public License version 2.
*/
/* Genode includes */
#include <cap_session/connection.h>
#include <input/component.h>
#include <os/config.h>
#include <rom_session/connection.h>
/* qt_avplay includes */
#include "avplay_policy.h"
#include "filter_framebuffer_policy.h"
#include "framebuffer_root.h"
#include "input_service.h"
#include "main_window.h"
@ -30,49 +23,23 @@ using namespace Genode;
struct Framebuffer_filter
{
enum { MAX_FILTER_NAME_SIZE = 32 };
char name[MAX_FILTER_NAME_SIZE];
Genode::Number_of_bytes ram_quota;
enum { MAX_FILTER_NAME_SIZE = 32 };
char name[MAX_FILTER_NAME_SIZE];
Genode::Number_of_bytes ram_quota;
Service_registry *framebuffer_out_registry;
Rpc_entrypoint *ep;
Filter_framebuffer_policy *policy;
Slave *slave;
Service_registry *framebuffer_out_registry;
Rpc_entrypoint *ep;
Filter_framebuffer_policy *policy;
Slave *slave;
};
Main_window::Main_window()
:
_control_bar(_input_session.event_queue())
{
/* look for dynamic linker */
try {
static Rom_connection ldso_rom("ld.lib.so");
Process::dynamic_linker(ldso_rom.dataspace());
} catch (...) {
PERR("ld.lib.so not found");
}
/* get the name of the media file from the config file */
enum { MAX_LEN_MEDIAFILE_NAME = 256 };
static char mediafile[MAX_LEN_MEDIAFILE_NAME] = "mediafile";
try {
config()->xml_node().sub_node("mediafile").attribute("name").value(mediafile, sizeof(mediafile));
} catch(...) {
PWRN("no <mediafile> config node found, using \"mediafile\"");
}
/* create local services */
enum { STACK_SIZE = 2*sizeof(addr_t)*1024 };
static Cap_connection cap;
static Rpc_entrypoint avplay_ep(&cap, STACK_SIZE, "avplay_ep");
static Service_registry input_registry;
static Service_registry nitpicker_framebuffer_registry;
static Input::Root input_root(&avplay_ep, env()->heap());
static Local_service input_service(Input::Session::service_name(), &input_root);
input_registry.insert(&input_service);
avplay_ep.manage(&input_root);
_input_registry.insert(&_input_service);
_ep.manage(&_input_root);
/* find out which filtering framebuffer services to start and sort them in reverse order */
@ -90,15 +57,15 @@ Main_window::Main_window()
/* start the filtering framebuffer services */
Service_registry *framebuffer_in_registry = &nitpicker_framebuffer_registry;
Service_registry *framebuffer_in_registry = &_nitpicker_framebuffer_registry;
Q_FOREACH(Framebuffer_filter *framebuffer_filter, framebuffer_filters) {
framebuffer_filter->framebuffer_out_registry = new Service_registry;
framebuffer_filter->ep = new Rpc_entrypoint(&cap, STACK_SIZE, "filter_fb_ep");
framebuffer_filter->ep = new Rpc_entrypoint(&_cap, STACK_SIZE, "filter_fb_ep");
framebuffer_filter->policy = new Filter_framebuffer_policy(framebuffer_filter->name,
*framebuffer_filter->ep,
*framebuffer_in_registry,
*framebuffer_filter->framebuffer_out_registry);
*framebuffer_in_registry,
*framebuffer_filter->framebuffer_out_registry);
framebuffer_filter->slave = new Slave(*framebuffer_filter->ep,
*framebuffer_filter->policy,
framebuffer_filter->ram_quota);
@ -106,17 +73,17 @@ Main_window::Main_window()
}
Rpc_entrypoint *local_framebuffer_ep = framebuffer_filters.isEmpty() ?
&avplay_ep :
&_ep :
framebuffer_filters.at(0)->ep;
static Framebuffer::Root framebuffer_root(local_framebuffer_ep, env()->heap(), *_avplay_widget, 640, 480);
static Local_service framebuffer_service(Framebuffer::Session::service_name(), &framebuffer_root);
nitpicker_framebuffer_registry.insert(&framebuffer_service);
_nitpicker_framebuffer_registry.insert(&framebuffer_service);
/* start avplay */
static Avplay_policy avplay_policy(avplay_ep, input_registry, *framebuffer_in_registry, mediafile);
static Genode::Slave avplay_slave(avplay_ep, avplay_policy, 32*1024*1024);
static Avplay_policy avplay_policy(_ep, _input_registry, *framebuffer_in_registry, _mediafile_name.buf);
static Genode::Slave avplay_slave(_ep, avplay_policy, 32*1024*1024);
/* add widgets to layout */

View File

@ -23,6 +23,14 @@
#include <qoost/compound_widget.h>
#include <qoost/qmember.h>
/* Genode includes */
#include <base/service.h>
#include <cap_session/connection.h>
#include <input/root.h>
#include <os/config.h>
#include <rom_session/connection.h>
/* local includes */
#include "control_bar.h"
@ -32,6 +40,35 @@ class Main_window : public Compound_widget<QWidget, QVBoxLayout>
private:
struct Mediafile_name
{
/* get the name of the media file from the config file */
enum { MAX_LEN_MEDIAFILE_NAME = 256 };
char buf[MAX_LEN_MEDIAFILE_NAME];
Mediafile_name()
{
Genode::strncpy(buf, "mediafile", sizeof(buf));
try {
Genode::config()->xml_node().sub_node("mediafile")
.attribute("name").value(buf, sizeof(buf));
} catch(...) {
PWRN("no <mediafile> config node found, using \"mediafile\"");
}
}
} _mediafile_name;
enum { STACK_SIZE = 2*sizeof(Genode::addr_t)*1024 };
Genode::Cap_connection _cap;
Genode::Rpc_entrypoint _ep { &_cap, STACK_SIZE, "avplay_ep" };
Genode::Service_registry _input_registry;
Genode::Service_registry _nitpicker_framebuffer_registry;
Input::Session_component _input_session;
Input::Root_component _input_root { _ep, _input_session };
Genode::Local_service _input_service { Input::Session::service_name(), &_input_root };
QMember<QNitpickerViewWidget> _avplay_widget;
QMember<Control_bar> _control_bar;

View File

@ -6,7 +6,6 @@ HEADERS = avplay_policy.h \
main_window.h
SOURCES = control_bar.cpp \
framebuffer_session_component.cc \
input_service.cpp \
main.cpp \
main_window.cpp
RESOURCES = style.qrc

View File

@ -6,4 +6,4 @@ include $(QT4_REP_DIR)/src/app/tmpl/target_defaults.inc
include $(QT4_REP_DIR)/src/app/tmpl/target_final.inc
LIBS += qnitpickerviewwidget
LIBS += qnitpickerviewwidget qoost