mirror of
https://github.com/genodelabs/genode.git
synced 2025-06-18 07:08:18 +00:00
nitpicker: New signal handling, bg color config
This patch overhauls the signal handling of nitpicker to clear the way towards dynamic reconfiguration. Furthermore, it moves the implementation of the global-keys handling and input utilities to separate files.
This commit is contained in:
@ -65,3 +65,10 @@ the "launchpad -> testnit" program is running. As soon as testnit gets started
|
|||||||
by launchpad, testnit will receive the events. If the order was reversed,
|
by launchpad, testnit will receive the events. If the order was reversed,
|
||||||
launchpad would always receive the events.
|
launchpad would always receive the events.
|
||||||
|
|
||||||
|
Background color
|
||||||
|
----------------
|
||||||
|
|
||||||
|
The background color can be defined via the '<background>' config node:
|
||||||
|
|
||||||
|
! <background color="#112233" />
|
||||||
|
|
||||||
|
90
os/src/server/nitpicker/genode/global_keys.cc
Normal file
90
os/src/server/nitpicker/genode/global_keys.cc
Normal file
@ -0,0 +1,90 @@
|
|||||||
|
/*
|
||||||
|
* \brief Global keys handling
|
||||||
|
* \author Norman Feske
|
||||||
|
* \date 2013-09-07
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Copyright (C) 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 <os/config.h>
|
||||||
|
|
||||||
|
/* local includes */
|
||||||
|
#include "global_keys.h"
|
||||||
|
|
||||||
|
|
||||||
|
Global_keys::Policy *Global_keys::_lookup_policy(char const *key_name)
|
||||||
|
{
|
||||||
|
for (unsigned i = 0; i < NUM_POLICIES; i++)
|
||||||
|
if (Genode::strcmp(key_name, Input::key_name((Input::Keycode)i)) == 0)
|
||||||
|
return &_policies[i];
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void Global_keys::apply_config(Session_list &session_list)
|
||||||
|
{
|
||||||
|
for (unsigned i = 0; i < NUM_POLICIES; i++)
|
||||||
|
_policies[i].undefine();
|
||||||
|
|
||||||
|
using Genode::Xml_node;
|
||||||
|
try {
|
||||||
|
Xml_node node = Genode::config()->xml_node().sub_node("global-keys").sub_node("key");
|
||||||
|
|
||||||
|
for (; ; node = node.next("key")) {
|
||||||
|
|
||||||
|
if (!node.has_attribute("name")) {
|
||||||
|
PWRN("attribute 'name' missing in <key> config node");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
char name[32]; name[0] = 0;
|
||||||
|
node.attribute("name").value(name, sizeof(name));
|
||||||
|
|
||||||
|
Policy * policy = _lookup_policy(name);
|
||||||
|
if (!policy) {
|
||||||
|
PWRN("invalid key name \"%s\"", name);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* if two policies match, give precedence to policy defined first */
|
||||||
|
if (policy->defined())
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (node.has_attribute("operation")) {
|
||||||
|
Xml_node::Attribute operation = node.attribute("operation");
|
||||||
|
|
||||||
|
if (operation.has_value("kill")) {
|
||||||
|
policy->operation_kill();
|
||||||
|
continue;
|
||||||
|
} else if (operation.has_value("xray")) {
|
||||||
|
policy->operation_xray();
|
||||||
|
continue;
|
||||||
|
} else {
|
||||||
|
char buf[32]; buf[0] = 0;
|
||||||
|
operation.value(buf, sizeof(buf));
|
||||||
|
PWRN("unknown operation \"%s\" for key %s", buf, name);
|
||||||
|
}
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!node.has_attribute("label")) {
|
||||||
|
PWRN("missing 'label' attribute for key %s", name);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* assign policy to matching client session */
|
||||||
|
for (Session *s = session_list.first(); s; s = s->next())
|
||||||
|
if (node.attribute("label").has_value(s->label()))
|
||||||
|
policy->client(s);
|
||||||
|
}
|
||||||
|
|
||||||
|
} catch (Xml_node::Nonexistent_sub_node) { }
|
||||||
|
}
|
||||||
|
|
@ -31,15 +31,24 @@
|
|||||||
#include <nitpicker_gfx/pixel_rgb565.h>
|
#include <nitpicker_gfx/pixel_rgb565.h>
|
||||||
#include <nitpicker_gfx/string.h>
|
#include <nitpicker_gfx/string.h>
|
||||||
#include <os/session_policy.h>
|
#include <os/session_policy.h>
|
||||||
|
#include <os/signal_rpc_dispatcher.h>
|
||||||
|
|
||||||
/* local includes */
|
/* local includes */
|
||||||
|
#include "input.h"
|
||||||
#include "big_mouse.h"
|
#include "big_mouse.h"
|
||||||
#include "background.h"
|
#include "background.h"
|
||||||
#include "user_state.h"
|
|
||||||
#include "clip_guard.h"
|
#include "clip_guard.h"
|
||||||
#include "mouse_cursor.h"
|
#include "mouse_cursor.h"
|
||||||
#include "chunky_menubar.h"
|
#include "chunky_menubar.h"
|
||||||
|
|
||||||
|
namespace Input { using namespace Genode; }
|
||||||
|
namespace Input { class Session_component; }
|
||||||
|
namespace Framebuffer { using namespace Genode; }
|
||||||
|
namespace Framebuffer { class Session_component; }
|
||||||
|
namespace Nitpicker { using namespace Genode; }
|
||||||
|
namespace Nitpicker { class Session_component; }
|
||||||
|
namespace Nitpicker { template <typename> class Root; }
|
||||||
|
|
||||||
|
|
||||||
/***************
|
/***************
|
||||||
** Utilities **
|
** Utilities **
|
||||||
@ -53,16 +62,16 @@
|
|||||||
*/
|
*/
|
||||||
static Color session_color(char const *session_args)
|
static Color session_color(char const *session_args)
|
||||||
{
|
{
|
||||||
|
using namespace Genode;
|
||||||
|
|
||||||
/* use white by default */
|
/* use white by default */
|
||||||
Color color = WHITE;
|
Color color = WHITE;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
Genode::Session_policy policy(session_args);
|
Session_policy policy(session_args);
|
||||||
|
|
||||||
/* read color attribute */
|
/* read color attribute */
|
||||||
char color_buf[8];
|
policy.attribute("color").value(&color);
|
||||||
policy.attribute("color").value(color_buf, sizeof(color_buf));
|
|
||||||
Genode::ascii_to(color_buf, &color);
|
|
||||||
} catch (...) { }
|
} catch (...) { }
|
||||||
|
|
||||||
return color;
|
return color;
|
||||||
@ -207,9 +216,7 @@ class Chunky_dataspace_texture : public Buffer, public Chunky_texture<PT>
|
|||||||
** Input sub session **
|
** Input sub session **
|
||||||
***********************/
|
***********************/
|
||||||
|
|
||||||
namespace Input {
|
class Input::Session_component : public Genode::Rpc_object<Session>
|
||||||
|
|
||||||
class Session_component : public Genode::Rpc_object<Session>
|
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
|
||||||
@ -220,7 +227,7 @@ namespace Input {
|
|||||||
/*
|
/*
|
||||||
* Exported event buffer dataspace
|
* Exported event buffer dataspace
|
||||||
*/
|
*/
|
||||||
Genode::Attached_ram_dataspace _ev_ram_ds;
|
Attached_ram_dataspace _ev_ram_ds;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Local event buffer that is copied
|
* Local event buffer that is copied
|
||||||
@ -232,14 +239,14 @@ namespace Input {
|
|||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
static Genode::size_t ev_ds_size() {
|
static size_t ev_ds_size() {
|
||||||
return Genode::align_addr(MAX_EVENTS*sizeof(Event), 12); }
|
return align_addr(MAX_EVENTS*sizeof(Event), 12); }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructor
|
* Constructor
|
||||||
*/
|
*/
|
||||||
Session_component():
|
Session_component():
|
||||||
_ev_ram_ds(Genode::env()->ram_session(), ev_ds_size()),
|
_ev_ram_ds(env()->ram_session(), ev_ds_size()),
|
||||||
_num_ev(0) { }
|
_num_ev(0) { }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -259,7 +266,7 @@ namespace Input {
|
|||||||
** Input session interface **
|
** Input session interface **
|
||||||
*****************************/
|
*****************************/
|
||||||
|
|
||||||
Genode::Dataspace_capability dataspace() { return _ev_ram_ds.cap(); }
|
Dataspace_capability dataspace() { return _ev_ram_ds.cap(); }
|
||||||
|
|
||||||
bool is_pending() const { return _num_ev > 0; }
|
bool is_pending() const { return _num_ev > 0; }
|
||||||
|
|
||||||
@ -276,16 +283,13 @@ namespace Input {
|
|||||||
return ev_cnt;
|
return ev_cnt;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/*****************************
|
/*****************************
|
||||||
** Framebuffer sub session **
|
** Framebuffer sub session **
|
||||||
*****************************/
|
*****************************/
|
||||||
|
|
||||||
namespace Framebuffer {
|
class Framebuffer::Session_component : public Genode::Rpc_object<Session>
|
||||||
|
|
||||||
class Session_component : public Genode::Rpc_object<Session>
|
|
||||||
{
|
{
|
||||||
private:
|
private:
|
||||||
|
|
||||||
@ -309,7 +313,7 @@ namespace Framebuffer {
|
|||||||
_buffer(buffer), _view_stack(view_stack), _session(session),
|
_buffer(buffer), _view_stack(view_stack), _session(session),
|
||||||
_flush_merger(flush_merger), _framebuffer(framebuffer) { }
|
_flush_merger(flush_merger), _framebuffer(framebuffer) { }
|
||||||
|
|
||||||
Genode::Dataspace_capability dataspace() { return _buffer.ds_cap(); }
|
Dataspace_capability dataspace() { return _buffer.ds_cap(); }
|
||||||
|
|
||||||
void release() { }
|
void release() { }
|
||||||
|
|
||||||
@ -319,7 +323,7 @@ namespace Framebuffer {
|
|||||||
_buffer.format());
|
_buffer.format());
|
||||||
}
|
}
|
||||||
|
|
||||||
void mode_sigh(Genode::Signal_context_capability) { }
|
void mode_sigh(Signal_context_capability) { }
|
||||||
|
|
||||||
void refresh(int x, int y, int w, int h)
|
void refresh(int x, int y, int w, int h)
|
||||||
{
|
{
|
||||||
@ -335,7 +339,6 @@ namespace Framebuffer {
|
|||||||
_flush_merger.defer = true;
|
_flush_merger.defer = true;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
class View_component : public Genode::List<View_component>::Element,
|
class View_component : public Genode::List<View_component>::Element,
|
||||||
@ -343,9 +346,11 @@ class View_component : public Genode::List<View_component>::Element,
|
|||||||
{
|
{
|
||||||
private:
|
private:
|
||||||
|
|
||||||
|
typedef Genode::Rpc_entrypoint Rpc_entrypoint;
|
||||||
|
|
||||||
View_stack &_view_stack;
|
View_stack &_view_stack;
|
||||||
::View _view;
|
::View _view;
|
||||||
Genode::Rpc_entrypoint &_ep;
|
Rpc_entrypoint &_ep;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
@ -353,7 +358,7 @@ class View_component : public Genode::List<View_component>::Element,
|
|||||||
* Constructor
|
* Constructor
|
||||||
*/
|
*/
|
||||||
View_component(::Session &session, View_stack &view_stack,
|
View_component(::Session &session, View_stack &view_stack,
|
||||||
Genode::Rpc_entrypoint &ep):
|
Rpc_entrypoint &ep):
|
||||||
_view_stack(view_stack),
|
_view_stack(view_stack),
|
||||||
_view(session,
|
_view(session,
|
||||||
session.stay_top() ? ::View::STAY_TOP : ::View::NOT_STAY_TOP,
|
session.stay_top() ? ::View::STAY_TOP : ::View::NOT_STAY_TOP,
|
||||||
@ -380,7 +385,9 @@ class View_component : public Genode::List<View_component>::Element,
|
|||||||
|
|
||||||
int stack(Nitpicker::View_capability neighbor_cap, bool behind, bool redraw)
|
int stack(Nitpicker::View_capability neighbor_cap, bool behind, bool redraw)
|
||||||
{
|
{
|
||||||
Genode::Object_pool<View_component>::Guard nvc(_ep.lookup_and_lock(neighbor_cap));
|
using namespace Genode;
|
||||||
|
|
||||||
|
Object_pool<View_component>::Guard nvc(_ep.lookup_and_lock(neighbor_cap));
|
||||||
|
|
||||||
::View *neighbor_view = nvc ? &nvc->view() : 0;
|
::View *neighbor_view = nvc ? &nvc->view() : 0;
|
||||||
|
|
||||||
@ -400,9 +407,8 @@ class View_component : public Genode::List<View_component>::Element,
|
|||||||
** Implementation of Nitpicker service **
|
** Implementation of Nitpicker service **
|
||||||
*****************************************/
|
*****************************************/
|
||||||
|
|
||||||
namespace Nitpicker {
|
class Nitpicker::Session_component : public Genode::Rpc_object<Session>,
|
||||||
|
public ::Session
|
||||||
class Session_component : public Genode::Rpc_object<Session>, public ::Session
|
|
||||||
{
|
{
|
||||||
private:
|
private:
|
||||||
|
|
||||||
@ -416,11 +422,11 @@ namespace Nitpicker {
|
|||||||
* Entrypoint that is used for the views, input session,
|
* Entrypoint that is used for the views, input session,
|
||||||
* and framebuffer session.
|
* and framebuffer session.
|
||||||
*/
|
*/
|
||||||
Genode::Rpc_entrypoint &_ep;
|
Rpc_entrypoint &_ep;
|
||||||
|
|
||||||
View_stack &_view_stack;
|
View_stack &_view_stack;
|
||||||
|
|
||||||
Genode::List<View_component> _view_list;
|
List<View_component> _view_list;
|
||||||
|
|
||||||
/* capabilities for sub sessions */
|
/* capabilities for sub sessions */
|
||||||
Framebuffer::Session_capability _framebuffer_session_cap;
|
Framebuffer::Session_capability _framebuffer_session_cap;
|
||||||
@ -437,7 +443,7 @@ namespace Nitpicker {
|
|||||||
::Buffer &buffer,
|
::Buffer &buffer,
|
||||||
Texture const &texture,
|
Texture const &texture,
|
||||||
View_stack &view_stack,
|
View_stack &view_stack,
|
||||||
Genode::Rpc_entrypoint &ep,
|
Rpc_entrypoint &ep,
|
||||||
Flush_merger &flush_merger,
|
Flush_merger &flush_merger,
|
||||||
Framebuffer::Session &framebuffer,
|
Framebuffer::Session &framebuffer,
|
||||||
int v_offset,
|
int v_offset,
|
||||||
@ -503,7 +509,7 @@ namespace Nitpicker {
|
|||||||
* FIXME: Do not allocate View meta data from Heap!
|
* FIXME: Do not allocate View meta data from Heap!
|
||||||
* Use a heap partition!
|
* Use a heap partition!
|
||||||
*/
|
*/
|
||||||
View_component *view = new (Genode::env()->heap())
|
View_component *view = new (env()->heap())
|
||||||
View_component(*this, _view_stack, _ep);
|
View_component(*this, _view_stack, _ep);
|
||||||
|
|
||||||
_view_list.insert(view);
|
_view_list.insert(view);
|
||||||
@ -518,13 +524,13 @@ namespace Nitpicker {
|
|||||||
_view_stack.remove_view(vc->view());
|
_view_stack.remove_view(vc->view());
|
||||||
_ep.dissolve(vc);
|
_ep.dissolve(vc);
|
||||||
_view_list.remove(vc);
|
_view_list.remove(vc);
|
||||||
destroy(Genode::env()->heap(), vc);
|
destroy(env()->heap(), vc);
|
||||||
}
|
}
|
||||||
|
|
||||||
int background(View_capability view_cap)
|
int background(View_capability view_cap)
|
||||||
{
|
{
|
||||||
if (_provides_default_bg) {
|
if (_provides_default_bg) {
|
||||||
Genode::Object_pool<View_component>::Guard vc(_ep.lookup_and_lock(view_cap));
|
Object_pool<View_component>::Guard vc(_ep.lookup_and_lock(view_cap));
|
||||||
vc->view().background(true);
|
vc->view().background(true);
|
||||||
_view_stack.default_background(vc->view());
|
_view_stack.default_background(vc->view());
|
||||||
return 0;
|
return 0;
|
||||||
@ -534,7 +540,7 @@ namespace Nitpicker {
|
|||||||
if (::Session::background()) ::Session::background()->background(false);
|
if (::Session::background()) ::Session::background()->background(false);
|
||||||
|
|
||||||
/* assign session background */
|
/* assign session background */
|
||||||
Genode::Object_pool<View_component>::Guard vc(_ep.lookup_and_lock(view_cap));
|
Object_pool<View_component>::Guard vc(_ep.lookup_and_lock(view_cap));
|
||||||
::Session::background(&vc->view());
|
::Session::background(&vc->view());
|
||||||
|
|
||||||
/* switch background view to background mode */
|
/* switch background view to background mode */
|
||||||
@ -546,7 +552,7 @@ namespace Nitpicker {
|
|||||||
|
|
||||||
|
|
||||||
template <typename PT>
|
template <typename PT>
|
||||||
class Root : public Genode::Root_component<Session_component>
|
class Nitpicker::Root : public Genode::Root_component<Session_component>
|
||||||
{
|
{
|
||||||
private:
|
private:
|
||||||
|
|
||||||
@ -563,36 +569,36 @@ namespace Nitpicker {
|
|||||||
Session_component *_create_session(const char *args)
|
Session_component *_create_session(const char *args)
|
||||||
{
|
{
|
||||||
PINF("create session with args: %s\n", args);
|
PINF("create session with args: %s\n", args);
|
||||||
Genode::size_t ram_quota = Genode::Arg_string::find_arg(args, "ram_quota").ulong_value(0);
|
size_t ram_quota = Arg_string::find_arg(args, "ram_quota").ulong_value(0);
|
||||||
|
|
||||||
int v_offset = _default_v_offset;
|
int v_offset = _default_v_offset;
|
||||||
|
|
||||||
/* determine buffer size of the session */
|
/* determine buffer size of the session */
|
||||||
Area size(Genode::Arg_string::find_arg(args, "fb_width" ).long_value(_scr_size.w()),
|
Area size(Arg_string::find_arg(args, "fb_width" ).long_value(_scr_size.w()),
|
||||||
Genode::Arg_string::find_arg(args, "fb_height").long_value(_scr_size.h() - v_offset));
|
Arg_string::find_arg(args, "fb_height").long_value(_scr_size.h() - v_offset));
|
||||||
|
|
||||||
char label_buf[::Session::LABEL_LEN];
|
char label_buf[::Session::LABEL_LEN];
|
||||||
Genode::Arg_string::find_arg(args, "label").string(label_buf, sizeof(label_buf), "<unlabeled>");
|
Arg_string::find_arg(args, "label").string(label_buf, sizeof(label_buf), "<unlabeled>");
|
||||||
|
|
||||||
bool use_alpha = Genode::Arg_string::find_arg(args, "alpha").bool_value(false);
|
bool use_alpha = Arg_string::find_arg(args, "alpha").bool_value(false);
|
||||||
bool stay_top = Genode::Arg_string::find_arg(args, "stay_top").bool_value(false);
|
bool stay_top = Arg_string::find_arg(args, "stay_top").bool_value(false);
|
||||||
|
|
||||||
Genode::size_t texture_num_bytes = Chunky_dataspace_texture<PT>::calc_num_bytes(size, use_alpha);
|
size_t texture_num_bytes = Chunky_dataspace_texture<PT>::calc_num_bytes(size, use_alpha);
|
||||||
|
|
||||||
Genode::size_t required_quota = texture_num_bytes
|
size_t required_quota = texture_num_bytes
|
||||||
+ Input::Session_component::ev_ds_size();
|
+ Input::Session_component::ev_ds_size();
|
||||||
|
|
||||||
if (ram_quota < required_quota) {
|
if (ram_quota < required_quota) {
|
||||||
PWRN("Insufficient dontated ram_quota (%zd bytes), require %zd bytes",
|
PWRN("Insufficient dontated ram_quota (%zd bytes), require %zd bytes",
|
||||||
ram_quota, required_quota);
|
ram_quota, required_quota);
|
||||||
throw Genode::Root::Quota_exceeded();
|
throw Root::Quota_exceeded();
|
||||||
}
|
}
|
||||||
|
|
||||||
/* allocate texture */
|
/* allocate texture */
|
||||||
Chunky_dataspace_texture<PT> *cdt;
|
Chunky_dataspace_texture<PT> *cdt;
|
||||||
cdt = new (md_alloc()) Chunky_dataspace_texture<PT>(size, use_alpha);
|
cdt = new (md_alloc()) Chunky_dataspace_texture<PT>(size, use_alpha);
|
||||||
|
|
||||||
bool provides_default_bg = (Genode::strcmp(label_buf, "backdrop") == 0);
|
bool provides_default_bg = (strcmp(label_buf, "backdrop") == 0);
|
||||||
|
|
||||||
Session_component *session = new (md_alloc())
|
Session_component *session = new (md_alloc())
|
||||||
Session_component(label_buf, *cdt, *cdt, _view_stack, *ep(),
|
Session_component(label_buf, *cdt, *cdt, _view_stack, *ep(),
|
||||||
@ -628,251 +634,43 @@ namespace Nitpicker {
|
|||||||
* Constructor
|
* Constructor
|
||||||
*/
|
*/
|
||||||
Root(Session_list &session_list, Global_keys &global_keys,
|
Root(Session_list &session_list, Global_keys &global_keys,
|
||||||
Genode::Rpc_entrypoint &session_ep, Area scr_size,
|
Rpc_entrypoint &session_ep, Area scr_size,
|
||||||
View_stack &view_stack, Genode::Allocator &md_alloc,
|
View_stack &view_stack, Allocator &md_alloc,
|
||||||
Flush_merger &flush_merger,
|
Flush_merger &flush_merger,
|
||||||
Framebuffer::Session &framebuffer, int default_v_offset)
|
Framebuffer::Session &framebuffer, int default_v_offset)
|
||||||
:
|
:
|
||||||
Genode::Root_component<Session_component>(&session_ep, &md_alloc),
|
Root_component<Session_component>(&session_ep, &md_alloc),
|
||||||
_session_list(session_list), _global_keys(global_keys),
|
_session_list(session_list), _global_keys(global_keys),
|
||||||
_scr_size(scr_size), _view_stack(view_stack), _flush_merger(flush_merger),
|
_scr_size(scr_size), _view_stack(view_stack), _flush_merger(flush_merger),
|
||||||
_framebuffer(framebuffer), _default_v_offset(default_v_offset) { }
|
_framebuffer(framebuffer), _default_v_offset(default_v_offset) { }
|
||||||
};
|
};
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/*******************
|
void wait_and_dispatch_one_signal(Genode::Signal_receiver &sig_rec)
|
||||||
** Input handler **
|
|
||||||
*******************/
|
|
||||||
|
|
||||||
struct Input_handler
|
|
||||||
{
|
{
|
||||||
GENODE_RPC(Rpc_do_input_handling, void, do_input_handling);
|
using namespace Genode;
|
||||||
GENODE_RPC_INTERFACE(Rpc_do_input_handling);
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
class Input_handler_component : public Genode::Rpc_object<Input_handler,
|
|
||||||
Input_handler_component>
|
|
||||||
{
|
|
||||||
private:
|
|
||||||
|
|
||||||
User_state &_user_state;
|
|
||||||
View &_mouse_cursor;
|
|
||||||
Area const _mouse_size;
|
|
||||||
Flush_merger &_flush_merger;
|
|
||||||
Input::Session &_input;
|
|
||||||
Input::Event *_ev_buf;
|
|
||||||
Framebuffer::Session &_framebuffer;
|
|
||||||
Genode::Signal_receiver &_sig_rec;
|
|
||||||
|
|
||||||
public:
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Constructor
|
|
||||||
*/
|
|
||||||
Input_handler_component(User_state &user_state, View &mouse_cursor,
|
|
||||||
Area mouse_size, Flush_merger &flush_merger,
|
|
||||||
Input::Session &input,
|
|
||||||
Framebuffer::Session &framebuffer,
|
|
||||||
Genode::Signal_receiver &sig_rec)
|
|
||||||
:
|
|
||||||
_user_state(user_state), _mouse_cursor(mouse_cursor),
|
|
||||||
_mouse_size(mouse_size), _flush_merger(flush_merger),
|
|
||||||
_input(input),
|
|
||||||
_ev_buf(Genode::env()->rm_session()->attach(_input.dataspace())),
|
|
||||||
_framebuffer(framebuffer), _sig_rec(sig_rec)
|
|
||||||
{ }
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Determine number of events that can be merged into one
|
|
||||||
*
|
|
||||||
* \param ev pointer to first event array element to check
|
|
||||||
* \param max size of the event array
|
|
||||||
* \return number of events subjected to merge
|
|
||||||
*/
|
|
||||||
unsigned _num_consecutive_events(Input::Event const *ev, unsigned max)
|
|
||||||
{
|
|
||||||
if (max < 1) return 0;
|
|
||||||
if (ev->type() != Input::Event::MOTION) return 1;
|
|
||||||
|
|
||||||
bool first_is_absolute = ev->is_absolute_motion();
|
|
||||||
|
|
||||||
/* iterate until we get a different event type, start at second */
|
|
||||||
unsigned cnt = 1;
|
|
||||||
for (ev++ ; cnt < max; cnt++, ev++) {
|
|
||||||
if (ev->type() != Input::Event::MOTION) break;
|
|
||||||
if (first_is_absolute != ev->is_absolute_motion()) break;
|
|
||||||
}
|
|
||||||
return cnt;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Merge consecutive motion events
|
|
||||||
*
|
|
||||||
* \param ev event array to merge
|
|
||||||
* \param n number of events to merge
|
|
||||||
* \return merged motion event
|
|
||||||
*/
|
|
||||||
static Input::Event _merge_motion_events(Input::Event const *ev, unsigned n)
|
|
||||||
{
|
|
||||||
Input::Event res;
|
|
||||||
for (unsigned i = 0; i < n; i++, ev++)
|
|
||||||
res = Input::Event(Input::Event::MOTION, 0, ev->ax(), ev->ay(),
|
|
||||||
res.rx() + ev->rx(), res.ry() + ev->ry());
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
|
|
||||||
void _import_input_events(unsigned num_ev)
|
|
||||||
{
|
|
||||||
/*
|
|
||||||
* Take events from input event buffer, merge consecutive motion
|
|
||||||
* events, and pass result to the user state.
|
|
||||||
*/
|
|
||||||
for (unsigned src_ev_cnt = 0; src_ev_cnt < num_ev; src_ev_cnt++) {
|
|
||||||
|
|
||||||
Input::Event *e = &_ev_buf[src_ev_cnt];
|
|
||||||
Input::Event curr = *e;
|
|
||||||
|
|
||||||
if (e->type() == Input::Event::MOTION) {
|
|
||||||
unsigned n = _num_consecutive_events(e, num_ev - src_ev_cnt);
|
|
||||||
curr = _merge_motion_events(e, n);
|
|
||||||
|
|
||||||
/* skip merged events */
|
|
||||||
src_ev_cnt += n - 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* If subsequential relative motion events are merged to
|
* We call the signal dispatcher outside of the scope of 'Signal'
|
||||||
* a zero-motion event, drop it. Otherwise, it would be
|
* object because we block the RPC interface in the input handler
|
||||||
* misinterpreted as absolute event pointing to (0, 0).
|
* when the kill mode gets actived. While kill mode is active, we
|
||||||
|
* do not serve incoming RPC requests but we need to stay responsive
|
||||||
|
* to user input. Hence, we wait for signals in the input dispatcher
|
||||||
|
* in this case. An already existing 'Signal' object would lock the
|
||||||
|
* signal receiver and thereby prevent this nested way of signal
|
||||||
|
* handling.
|
||||||
*/
|
*/
|
||||||
if (e->is_relative_motion() && curr.rx() == 0 && curr.ry() == 0)
|
Signal_dispatcher_base *dispatcher = 0;
|
||||||
continue;
|
unsigned num = 0;
|
||||||
|
|
||||||
/* pass event to user state */
|
|
||||||
_user_state.handle_event(curr);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This function is called periodically from the timer loop
|
|
||||||
*/
|
|
||||||
void do_input_handling()
|
|
||||||
{
|
{
|
||||||
do {
|
Signal sig = sig_rec.wait_for_signal();
|
||||||
Point old_mouse_pos = _user_state.mouse_pos();
|
dispatcher = dynamic_cast<Signal_dispatcher_base *>(sig.context());
|
||||||
|
num = sig.num();
|
||||||
/* handle batch of pending events */
|
|
||||||
if (_input.is_pending())
|
|
||||||
_import_input_events(_input.flush());
|
|
||||||
|
|
||||||
Point new_mouse_pos = _user_state.mouse_pos();
|
|
||||||
|
|
||||||
/* update mouse cursor */
|
|
||||||
if (old_mouse_pos != new_mouse_pos)
|
|
||||||
_user_state.viewport(_mouse_cursor,
|
|
||||||
Rect(new_mouse_pos, _mouse_size),
|
|
||||||
Point(), true);
|
|
||||||
|
|
||||||
/* flush dirty pixels to physical frame buffer */
|
|
||||||
if (_flush_merger.defer == false) {
|
|
||||||
Rect r = _flush_merger.to_be_flushed();
|
|
||||||
if (r.valid())
|
|
||||||
_framebuffer.refresh(r.x1(), r.y1(), r.w(), r.h());
|
|
||||||
_flush_merger.reset();
|
|
||||||
}
|
|
||||||
_flush_merger.defer = false;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* In kill mode, we never leave the dispatch function to block
|
|
||||||
* RPC calls from Nitpicker clients. We block for signals here
|
|
||||||
* to make the spinning for the end of the kill mode less
|
|
||||||
* painful for all non-blocked processes.
|
|
||||||
*/
|
|
||||||
if (_user_state.kill())
|
|
||||||
_sig_rec.wait_for_signal();
|
|
||||||
|
|
||||||
} while (_user_state.kill());
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
typedef Pixel_rgb565 PT; /* physical pixel type */
|
|
||||||
|
|
||||||
|
|
||||||
/*****************************
|
|
||||||
** Handling of global keys **
|
|
||||||
*****************************/
|
|
||||||
|
|
||||||
Global_keys::Policy *Global_keys::_lookup_policy(char const *key_name)
|
|
||||||
{
|
|
||||||
for (unsigned i = 0; i < NUM_POLICIES; i++)
|
|
||||||
if (Genode::strcmp(key_name, Input::key_name((Input::Keycode)i)) == 0)
|
|
||||||
return &_policies[i];
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (dispatcher)
|
||||||
void Global_keys::apply_config(Session_list &session_list)
|
dispatcher->dispatch(num);
|
||||||
{
|
|
||||||
for (unsigned i = 0; i < NUM_POLICIES; i++)
|
|
||||||
_policies[i].undefine();
|
|
||||||
|
|
||||||
using Genode::Xml_node;
|
|
||||||
try {
|
|
||||||
Xml_node node = Genode::config()->xml_node().sub_node("global-keys").sub_node("key");
|
|
||||||
|
|
||||||
for (; ; node = node.next("key")) {
|
|
||||||
|
|
||||||
if (!node.has_attribute("name")) {
|
|
||||||
PWRN("attribute 'name' missing in <key> config node");
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
char name[32]; name[0] = 0;
|
|
||||||
node.attribute("name").value(name, sizeof(name));
|
|
||||||
|
|
||||||
Policy * policy = _lookup_policy(name);
|
|
||||||
if (!policy) {
|
|
||||||
PWRN("invalid key name \"%s\"", name);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* if two policies match, give precedence to policy defined first */
|
|
||||||
if (policy->defined())
|
|
||||||
continue;
|
|
||||||
|
|
||||||
if (node.has_attribute("operation")) {
|
|
||||||
Xml_node::Attribute operation = node.attribute("operation");
|
|
||||||
|
|
||||||
if (operation.has_value("kill")) {
|
|
||||||
policy->operation_kill();
|
|
||||||
continue;
|
|
||||||
} else if (operation.has_value("xray")) {
|
|
||||||
policy->operation_xray();
|
|
||||||
continue;
|
|
||||||
} else {
|
|
||||||
char buf[32]; buf[0] = 0;
|
|
||||||
operation.value(buf, sizeof(buf));
|
|
||||||
PWRN("unknown operation \"%s\" for key %s", buf, name);
|
|
||||||
}
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!node.has_attribute("label")) {
|
|
||||||
PWRN("missing 'label' attribute for key %s", name);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* assign policy to matching client session */
|
|
||||||
for (Session *s = session_list.first(); s; s = s->next())
|
|
||||||
if (node.attribute("label").has_value(s->label()))
|
|
||||||
policy->client(s);
|
|
||||||
}
|
|
||||||
|
|
||||||
} catch (Xml_node::Nonexistent_sub_node) { }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -880,6 +678,9 @@ void Global_keys::apply_config(Session_list &session_list)
|
|||||||
** Main program **
|
** Main program **
|
||||||
******************/
|
******************/
|
||||||
|
|
||||||
|
typedef Pixel_rgb565 PT; /* physical pixel type */
|
||||||
|
|
||||||
|
|
||||||
int main(int argc, char **argv)
|
int main(int argc, char **argv)
|
||||||
{
|
{
|
||||||
using namespace Genode;
|
using namespace Genode;
|
||||||
@ -891,6 +692,9 @@ int main(int argc, char **argv)
|
|||||||
static Input::Connection input;
|
static Input::Connection input;
|
||||||
static Cap_connection cap;
|
static Cap_connection cap;
|
||||||
|
|
||||||
|
static Input::Event * const ev_buf =
|
||||||
|
env()->rm_session()->attach(input.dataspace());
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Initialize server entry point
|
* Initialize server entry point
|
||||||
*/
|
*/
|
||||||
@ -922,13 +726,6 @@ int main(int argc, char **argv)
|
|||||||
|
|
||||||
static Session_list session_list;
|
static Session_list session_list;
|
||||||
|
|
||||||
/*
|
|
||||||
* Apply initial global-key policy to turn X-ray and kill keys into
|
|
||||||
* effect. The policy will be updated each time the config changes,
|
|
||||||
* or when a session appears or disappears.
|
|
||||||
*/
|
|
||||||
global_keys.apply_config(session_list);
|
|
||||||
|
|
||||||
static User_state user_state(global_keys, screen, menubar);
|
static User_state user_state(global_keys, screen, menubar);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -958,35 +755,98 @@ int main(int argc, char **argv)
|
|||||||
screen, framebuffer,
|
screen, framebuffer,
|
||||||
MENUBAR_HEIGHT);
|
MENUBAR_HEIGHT);
|
||||||
|
|
||||||
env()->parent()->announce(ep.manage(&np_root));
|
static Signal_receiver sig_rec;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Schedule periodic timer signals every 10 milliseconds
|
* Configuration-update dispatcher, executed in the context of the RPC
|
||||||
|
* entrypoint.
|
||||||
|
*
|
||||||
|
* In addition to installing the signal dispatcher, we trigger first signal
|
||||||
|
* manually to turn the initial configuration into effect.
|
||||||
|
*/
|
||||||
|
static auto config_func = [&](unsigned)
|
||||||
|
{
|
||||||
|
config()->reload();
|
||||||
|
global_keys.apply_config(session_list);
|
||||||
|
try {
|
||||||
|
config()->xml_node().sub_node("background")
|
||||||
|
.attribute("color").value(&background.color);
|
||||||
|
} catch (...) { }
|
||||||
|
user_state.update_all_views();
|
||||||
|
};
|
||||||
|
|
||||||
|
auto config_dispatcher = signal_rpc_dispatcher(config_func);
|
||||||
|
|
||||||
|
Signal_context_capability config_sigh = config_dispatcher.manage(sig_rec, ep);
|
||||||
|
|
||||||
|
config()->sigh(config_sigh);
|
||||||
|
|
||||||
|
Signal_transmitter(config_sigh).submit();
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Input dispatcher, executed in the contect of the RPC entrypoint
|
||||||
|
*/
|
||||||
|
static auto input_func = [&](unsigned num)
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
* If kill mode is already active, we got recursively called from
|
||||||
|
* within this 'input_func' (via 'wait_and_dispatch_one_signal').
|
||||||
|
* In this case, return immediately. New input events will be
|
||||||
|
* processed in the local 'do' loop.
|
||||||
|
*/
|
||||||
|
if (user_state.kill())
|
||||||
|
return;
|
||||||
|
|
||||||
|
do {
|
||||||
|
Point const old_mouse_pos = user_state.mouse_pos();
|
||||||
|
|
||||||
|
/* handle batch of pending events */
|
||||||
|
if (input.is_pending())
|
||||||
|
import_input_events(ev_buf, input.flush(), user_state);
|
||||||
|
|
||||||
|
Point const new_mouse_pos = user_state.mouse_pos();
|
||||||
|
|
||||||
|
/* update mouse cursor */
|
||||||
|
if (old_mouse_pos != new_mouse_pos)
|
||||||
|
user_state.viewport(mouse_cursor,
|
||||||
|
Rect(new_mouse_pos, mouse_size),
|
||||||
|
Point(), true);
|
||||||
|
|
||||||
|
/* flush dirty pixels to physical frame buffer */
|
||||||
|
if (screen.defer == false) {
|
||||||
|
Rect const r = screen.to_be_flushed();
|
||||||
|
if (r.valid())
|
||||||
|
framebuffer.refresh(r.x1(), r.y1(), r.w(), r.h());
|
||||||
|
screen.reset();
|
||||||
|
}
|
||||||
|
screen.defer = false;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* In kill mode, we do not leave the dispatch function in order to
|
||||||
|
* block RPC calls from Nitpicker clients. We block for signals
|
||||||
|
* here to stay responsive to user input and configuration changes.
|
||||||
|
* Nested calls of 'input_func' are prevented by the condition
|
||||||
|
* check for 'user_state.kill()' at the beginning of the handler.
|
||||||
|
*/
|
||||||
|
if (user_state.kill())
|
||||||
|
wait_and_dispatch_one_signal(sig_rec);
|
||||||
|
|
||||||
|
} while (user_state.kill());
|
||||||
|
};
|
||||||
|
|
||||||
|
auto input_dispatcher = signal_rpc_dispatcher(input_func);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Dispatch input on periodic timer signals every 10 milliseconds
|
||||||
*/
|
*/
|
||||||
static Timer::Connection timer;
|
static Timer::Connection timer;
|
||||||
static Signal_receiver sig_rec;
|
timer.sigh(input_dispatcher.manage(sig_rec, ep));
|
||||||
Signal_context timer_sig_ctx;
|
|
||||||
|
|
||||||
timer.sigh(sig_rec.manage(&timer_sig_ctx));
|
|
||||||
timer.trigger_periodic(10*1000);
|
timer.trigger_periodic(10*1000);
|
||||||
|
|
||||||
/*
|
env()->parent()->announce(ep.manage(&np_root));
|
||||||
* Initialize input handling
|
|
||||||
*
|
|
||||||
* We serialize the input handling with the client interfaces via
|
|
||||||
* Nitpicker's entry point. For this, we implement the input handling
|
|
||||||
* as a 'Rpc_object' and perform RPC calls to this local object in a
|
|
||||||
* periodic fashion.
|
|
||||||
*/
|
|
||||||
static Input_handler_component
|
|
||||||
input_handler(user_state, mouse_cursor, mouse_size,
|
|
||||||
screen, input, framebuffer, sig_rec);
|
|
||||||
|
|
||||||
Capability<Input_handler> input_handler_cap = ep.manage(&input_handler);
|
for (;;)
|
||||||
|
wait_and_dispatch_one_signal(sig_rec);
|
||||||
|
|
||||||
for (;;) {
|
|
||||||
sig_rec.wait_for_signal();
|
|
||||||
input_handler_cap.call<Input_handler::Rpc_do_input_handling>();
|
|
||||||
}
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -3,9 +3,13 @@ LIBS = base blit config
|
|||||||
SRC_CC = main.cc \
|
SRC_CC = main.cc \
|
||||||
view_stack.cc \
|
view_stack.cc \
|
||||||
view.cc \
|
view.cc \
|
||||||
user_state.cc
|
user_state.cc \
|
||||||
|
global_keys.cc
|
||||||
SRC_BIN = default.tff
|
SRC_BIN = default.tff
|
||||||
|
|
||||||
|
# enable C++11 support
|
||||||
|
CC_CXX_OPT += -std=gnu++11
|
||||||
|
|
||||||
INC_DIR = $(PRG_DIR)/../include \
|
INC_DIR = $(PRG_DIR)/../include \
|
||||||
$(PRG_DIR)/../data
|
$(PRG_DIR)/../data
|
||||||
|
|
||||||
|
@ -19,6 +19,8 @@
|
|||||||
|
|
||||||
struct Background : private Texture, Session, View
|
struct Background : private Texture, Session, View
|
||||||
{
|
{
|
||||||
|
Color color;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* The background uses no texture. Therefore
|
* The background uses no texture. Therefore
|
||||||
* we can pass a null pointer as texture argument
|
* we can pass a null pointer as texture argument
|
||||||
@ -28,7 +30,8 @@ struct Background : private Texture, Session, View
|
|||||||
:
|
:
|
||||||
Texture(Area(0, 0)), Session("", *this, 0, BLACK),
|
Texture(Area(0, 0)), Session("", *this, 0, BLACK),
|
||||||
View(*this, View::NOT_STAY_TOP, View::NOT_TRANSPARENT,
|
View(*this, View::NOT_STAY_TOP, View::NOT_TRANSPARENT,
|
||||||
View::BACKGROUND, Rect(Point(0, 0), size))
|
View::BACKGROUND, Rect(Point(0, 0), size)),
|
||||||
|
color(25, 37, 50)
|
||||||
{ }
|
{ }
|
||||||
|
|
||||||
|
|
||||||
@ -49,7 +52,7 @@ struct Background : private Texture, Session, View
|
|||||||
void draw(Canvas &canvas, Mode const &mode) const
|
void draw(Canvas &canvas, Mode const &mode) const
|
||||||
{
|
{
|
||||||
Clip_guard clip_guard(canvas, *this);
|
Clip_guard clip_guard(canvas, *this);
|
||||||
canvas.draw_box(*this, Color(25, 37, 50));
|
canvas.draw_box(*this, color);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
98
os/src/server/nitpicker/include/input.h
Normal file
98
os/src/server/nitpicker/include/input.h
Normal file
@ -0,0 +1,98 @@
|
|||||||
|
/*
|
||||||
|
* \brief Input handling utilities
|
||||||
|
* \author Norman Feske
|
||||||
|
* \date 2013-09-07
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Copyright (C) 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_
|
||||||
|
|
||||||
|
/* Genode includes */
|
||||||
|
#include <input/event.h>
|
||||||
|
|
||||||
|
/* local includes */
|
||||||
|
#include "user_state.h"
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Determine number of events that can be merged into one
|
||||||
|
*
|
||||||
|
* \param ev pointer to first event array element to check
|
||||||
|
* \param max size of the event array
|
||||||
|
* \return number of events subjected to merge
|
||||||
|
*/
|
||||||
|
static unsigned num_consecutive_events(Input::Event const *ev, unsigned max)
|
||||||
|
{
|
||||||
|
if (max < 1) return 0;
|
||||||
|
if (ev->type() != Input::Event::MOTION) return 1;
|
||||||
|
|
||||||
|
bool first_is_absolute = ev->is_absolute_motion();
|
||||||
|
|
||||||
|
/* iterate until we get a different event type, start at second */
|
||||||
|
unsigned cnt = 1;
|
||||||
|
for (ev++ ; cnt < max; cnt++, ev++) {
|
||||||
|
if (ev->type() != Input::Event::MOTION) break;
|
||||||
|
if (first_is_absolute != ev->is_absolute_motion()) break;
|
||||||
|
}
|
||||||
|
return cnt;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Merge consecutive motion events
|
||||||
|
*
|
||||||
|
* \param ev event array to merge
|
||||||
|
* \param n number of events to merge
|
||||||
|
* \return merged motion event
|
||||||
|
*/
|
||||||
|
static Input::Event merge_motion_events(Input::Event const *ev, unsigned n)
|
||||||
|
{
|
||||||
|
Input::Event res;
|
||||||
|
for (unsigned i = 0; i < n; i++, ev++)
|
||||||
|
res = Input::Event(Input::Event::MOTION, 0, ev->ax(), ev->ay(),
|
||||||
|
res.rx() + ev->rx(), res.ry() + ev->ry());
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void import_input_events(Input::Event *ev_buf, unsigned num_ev,
|
||||||
|
User_state &user_state)
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
* Take events from input event buffer, merge consecutive motion
|
||||||
|
* events, and pass result to the user state.
|
||||||
|
*/
|
||||||
|
for (unsigned src_ev_cnt = 0; src_ev_cnt < num_ev; src_ev_cnt++) {
|
||||||
|
|
||||||
|
Input::Event *e = &ev_buf[src_ev_cnt];
|
||||||
|
Input::Event curr = *e;
|
||||||
|
|
||||||
|
if (e->type() == Input::Event::MOTION) {
|
||||||
|
unsigned n = num_consecutive_events(e, num_ev - src_ev_cnt);
|
||||||
|
curr = merge_motion_events(e, n);
|
||||||
|
|
||||||
|
/* skip merged events */
|
||||||
|
src_ev_cnt += n - 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* If subsequential relative motion events are merged to
|
||||||
|
* a zero-motion event, drop it. Otherwise, it would be
|
||||||
|
* misinterpreted as absolute event pointing to (0, 0).
|
||||||
|
*/
|
||||||
|
if (e->is_relative_motion() && curr.rx() == 0 && curr.ry() == 0)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
/* pass event to user state */
|
||||||
|
user_state.handle_event(curr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif /* _INPUT_H_ */
|
@ -17,6 +17,9 @@
|
|||||||
/* Genode includes */
|
/* Genode includes */
|
||||||
#include <util/list.h>
|
#include <util/list.h>
|
||||||
#include <util/string.h>
|
#include <util/string.h>
|
||||||
|
#include <nitpicker_gfx/color.h>
|
||||||
|
#include <nitpicker_gfx/geometry.h>
|
||||||
|
#include <nitpicker_gfx/canvas.h>
|
||||||
|
|
||||||
class Texture;
|
class Texture;
|
||||||
class View;
|
class View;
|
||||||
|
Reference in New Issue
Block a user