pointer: custom pointer shape support

Make the revised 'vbox_pointer' component the new 'pointer' component.

Fixes #2585
This commit is contained in:
Christian Prochaska
2017-11-24 18:56:25 +01:00
committed by Christian Helmuth
parent 18993b5ede
commit dd98bd67a0
22 changed files with 434 additions and 534 deletions

View File

@ -0,0 +1,39 @@
Pointer for Nitpicker with optional hover-sensitive shape support
Per default the standard "big mouse" pointer is rendered on screen.
Additionally, 'pointer' supports to render "pointer shapes" when hovering
Nitpicker sessions for which a shape was reported. This feature must be
enabled with the '<config shapes="yes"/>' option. When enabled, the
'pointer' component announces a 'Report' service for custom pointer shapes
and requests ROM sessions for Nitpicker's 'hover' and 'xray' reports. The
mapping between hovered Nitpicker sessions and applications can be achieved
with report session label rewriting:
! <start name="shape-arrow">
! <binary name="test-pointer"/>
! <resource name="RAM" quantum="2M"/>
! <config shape="arrow"/>
! <route>
! <service name="PD"> <parent/> </service>
! <service name="ROM"> <parent/> </service>
! <service name="CPU"> <parent/> </service>
! <service name="LOG"> <parent/> </service>
! <service name="Report" label="shape">
! <child name="pointer" label="test-label-arrow -> testnit"/>
! </service>
! </route>
! </start>
In the example above, which is from 'pointer.run', the 'shape-arrow' component
reports an arrow shape with the label "shape". By rewriting the label of the
report, the shape will be drawn for the 'test-label-arrow' component, which
is reported by Nitpicker with the label 'test-label-arror -> testnit' when
hovered.
When configured with '<config shapes="yes" verbose="yes"/>', the 'pointer'
component prints the labels of hovered Nitpicker sessions and received shape
reports to the 'LOG' service.
The most common use cases for pointer shapes are VirtualBox, which reports
the guest-pointer shapes if Guest Additions are installed, and Qt applications.

View File

@ -1,6 +1,8 @@
/*
* \brief Minimalistic nitpicker pointer
* \brief Nitpicker pointer with support for VirtualBox-defined shapes
* \author Norman Feske
* \author Christian Helmuth
* \author Christian Prochaska
* \date 2014-07-02
*/
@ -12,18 +14,29 @@
*/
/* Genode includes */
#include <nitpicker_session/connection.h>
#include <os/surface.h>
#include <os/pixel_rgb565.h>
#include <base/attached_dataspace.h>
#include <base/component.h>
#include <base/heap.h>
#include <base/attached_rom_dataspace.h>
#include <os/pixel_alpha8.h>
#include <os/pixel_rgb565.h>
#include <os/pixel_rgb888.h>
#include <os/surface.h>
#include <os/texture_rgb888.h>
#include <nitpicker_session/connection.h>
#include <report_rom/report_service.h>
#include <pointer/dither_painter.h>
#include <pointer/shape_report.h>
/* local includes */
#include "util.h"
#include "rom_registry.h"
#include "big_mouse.h"
namespace Pointer { class Main; }
template <typename PT>
void convert_cursor_data_to_pixels(PT *pixel, Nitpicker::Area size)
void convert_default_pointer_data_to_pixels(PT *pixel, Nitpicker::Area size)
{
unsigned char *alpha = (unsigned char *)(pixel + size.count());
@ -42,25 +55,324 @@ void convert_cursor_data_to_pixels(PT *pixel, Nitpicker::Area size)
}
void Component::construct(Genode::Env &env)
class Pointer::Main : public Rom::Reader
{
static Nitpicker::Connection nitpicker { env, "cursor" };
private:
Nitpicker::Area const cursor_size(big_mouse.w, big_mouse.h);
typedef Pointer::String String;
Framebuffer::Mode const mode(cursor_size.w(), cursor_size.h(),
Framebuffer::Mode::RGB565);
nitpicker.buffer(mode, true);
Genode::Env &_env;
Genode::Attached_dataspace ds(
env.rm(), nitpicker.framebuffer()->dataspace());
Genode::Attached_rom_dataspace _config { _env, "config" };
convert_cursor_data_to_pixels(
ds.local_addr<Genode::Pixel_rgb565>(), cursor_size);
bool _verbose = _config.xml().attribute_value("verbose", false);
Nitpicker::Session::View_handle view = nitpicker.create_view();
Nitpicker::Rect geometry(Nitpicker::Point(0, 0), cursor_size);
nitpicker.enqueue<Nitpicker::Session::Command::Geometry>(view, geometry);
nitpicker.enqueue<Nitpicker::Session::Command::To_front>(view);
nitpicker.execute();
Nitpicker::Connection _nitpicker { _env };
Nitpicker::Session::View_handle _view = _nitpicker.create_view();
bool _default_pointer_visible = false;
Nitpicker::Area _current_pointer_size;
Genode::Dataspace_capability _pointer_ds;
void _resize_nitpicker_buffer_if_needed(Nitpicker::Area pointer_size);
void _show_default_pointer();
void _update_pointer();
/* custom shape support */
bool _shapes_enabled = _config.xml().attribute_value("shapes", false);
bool _xray = false;
Genode::Constructible<Genode::Attached_rom_dataspace> _hover_ds;
Genode::Constructible<Genode::Attached_rom_dataspace> _xray_ds;
Genode::Signal_handler<Main> _hover_signal_handler {
_env.ep(), *this, &Main::_handle_hover };
Genode::Signal_handler<Main> _xray_signal_handler {
_env.ep(), *this, &Main::_handle_xray };
Genode::Sliced_heap _sliced_heap { _env.ram(), _env.rm() };
Rom::Registry _rom_registry { _sliced_heap, _env.ram(), _env.rm(), *this };
Report::Root _report_root { _env, _sliced_heap, _rom_registry, _verbose };
String _hovered_label;
Genode::Attached_ram_dataspace _texture_pixel_ds { _env.ram(), _env.rm(),
Pointer::MAX_WIDTH *
Pointer::MAX_HEIGHT *
sizeof(Genode::Pixel_rgb888) };
Genode::Attached_ram_dataspace _texture_alpha_ds { _env.ram(), _env.rm(),
Pointer::MAX_WIDTH *
Pointer::MAX_HEIGHT };
void _show_shape_pointer(Shape_report &shape_report);
void _handle_hover();
void _handle_xray();
public:
/**
* Reader interface
*/
void notify_module_changed() override
{
_update_pointer();
}
void notify_module_invalidated() override
{
_update_pointer();
}
Main(Genode::Env &);
};
void Pointer::Main::_resize_nitpicker_buffer_if_needed(Nitpicker::Area pointer_size)
{
if (pointer_size == _current_pointer_size)
return;
Framebuffer::Mode const mode { (int)pointer_size.w(),
(int)pointer_size.h(),
Framebuffer::Mode::RGB565 };
_nitpicker.buffer(mode, true /* use alpha */);
_pointer_ds = _nitpicker.framebuffer()->dataspace();
_current_pointer_size = pointer_size;
}
void Pointer::Main::_show_default_pointer()
{
/* only draw default pointer if not already drawn */
if (_default_pointer_visible)
return;
Nitpicker::Area const pointer_size { big_mouse.w, big_mouse.h };
try {
_resize_nitpicker_buffer_if_needed(pointer_size);
} catch (...) {
Genode::error(__func__, ": could not resize the pointer buffer "
"for ", pointer_size.w(), "x", pointer_size.h(), " pixels");
return;
}
Genode::Attached_dataspace ds { _env.rm(), _pointer_ds };
convert_default_pointer_data_to_pixels(ds.local_addr<Genode::Pixel_rgb565>(),
pointer_size);
_nitpicker.framebuffer()->refresh(0, 0, pointer_size.w(), pointer_size.h());
Nitpicker::Rect geometry(Nitpicker::Point(0, 0), pointer_size);
_nitpicker.enqueue<Nitpicker::Session::Command::Geometry>(_view, geometry);
_nitpicker.execute();
_default_pointer_visible = true;
}
void Pointer::Main::_show_shape_pointer(Shape_report &shape_report)
{
Nitpicker::Area shape_size { shape_report.width, shape_report.height };
Nitpicker::Point shape_hot { (int)-shape_report.x_hot, (int)-shape_report.y_hot };
try {
_resize_nitpicker_buffer_if_needed(shape_size);
} catch (...) {
error(__func__, ": could not resize the pointer buffer "
"for ", shape_size, " pixels");
throw;
}
if (shape_report.visible) {
using namespace Genode;
/* import shape into texture */
Texture<Pixel_rgb888>
texture(_texture_pixel_ds.local_addr<Pixel_rgb888>(),
_texture_alpha_ds.local_addr<unsigned char>(),
shape_size);
for (unsigned int y = 0; y < shape_size.h(); y++) {
/* import the RGBA-encoded line into the texture */
unsigned char *shape = shape_report.shape;
unsigned char *line = &shape[y * shape_size.w() * 4];
texture.rgba(line, shape_size.w(), y);
}
/* draw texture */
Attached_dataspace ds { _env.rm(), _pointer_ds };
Pixel_rgb565 *pixel = ds.local_addr<Pixel_rgb565>();
Pixel_alpha8 *alpha =
reinterpret_cast<Pixel_alpha8 *>(pixel + shape_size.count());
Surface<Pixel_rgb565> pixel_surface(pixel, shape_size);
Surface<Pixel_alpha8> alpha_surface(alpha, shape_size);
Dither_painter::paint(pixel_surface, texture);
Dither_painter::paint(alpha_surface, texture);
}
_nitpicker.framebuffer()->refresh(0, 0, shape_size.w(), shape_size.h());
Nitpicker::Rect geometry(shape_hot, shape_size);
_nitpicker.enqueue<Nitpicker::Session::Command::Geometry>(_view, geometry);
_nitpicker.execute();
_default_pointer_visible = false;
}
void Pointer::Main::_update_pointer()
{
if (!_shapes_enabled || _xray) {
_show_default_pointer();
return;
}
try {
Rom::Readable_module &shape_module =
_rom_registry.lookup(*this, _hovered_label);
try {
Shape_report shape_report;
shape_module.read_content(*this, (char*)&shape_report, sizeof(shape_report));
if (shape_report.visible) {
if ((shape_report.width == 0) ||
(shape_report.height == 0) ||
(shape_report.width > MAX_WIDTH) ||
(shape_report.height > MAX_HEIGHT))
throw Genode::Exception();
_show_shape_pointer(shape_report);
}
} catch (...) {
_rom_registry.release(*this, shape_module);
throw;
}
_rom_registry.release(*this, shape_module);
} catch (...) {
_show_default_pointer();
}
}
void Pointer::Main::_handle_hover()
{
using Pointer::read_string_attribute;
_hover_ds->update();
if (!_hover_ds->valid())
return;
/* read new hover information from nitpicker's hover report */
try {
Genode::Xml_node node(_hover_ds->local_addr<char>());
String hovered_label = read_string_attribute(node, "label", String());
if (_verbose)
Genode::log("hovered_label: ", hovered_label);
/* update pointer if hovered label changed */
if (hovered_label != _hovered_label) {
_hovered_label = hovered_label;
_update_pointer();
}
}
catch (...) {
Genode::warning("could not parse hover report");
}
}
void Pointer::Main::_handle_xray()
{
_xray_ds->update();
if (!_xray_ds->valid())
return;
try {
Genode::Xml_node node(_xray_ds->local_addr<char>());
bool xray = node.attribute_value("enabled", false);
/* update pointer if xray status changed */
if (xray != _xray) {
_xray = xray;
_update_pointer();
}
}
catch (...) {
Genode::warning("could not parse xray report");
}
}
Pointer::Main::Main(Genode::Env &env) : _env(env)
{
/*
* Try to allocate the Nitpicker buffer for the maximum supported
* pointer size to let the user know right from the start if the
* RAM quota is too low.
*/
Framebuffer::Mode const mode { Pointer::MAX_WIDTH, Pointer::MAX_HEIGHT,
Framebuffer::Mode::RGB565 };
_nitpicker.buffer(mode, true /* use alpha */);
if (_shapes_enabled) {
try {
_hover_ds.construct(_env, "hover");
_hover_ds->sigh(_hover_signal_handler);
_handle_hover();
} catch (Genode::Rom_connection::Rom_connection_failed) {
Genode::warning("Could not open ROM session for \"hover\".",
" This ROM is used for custom pointer shape support.");
}
try {
_xray_ds.construct(_env, "xray");
_xray_ds->sigh(_xray_signal_handler);
_handle_xray();
} catch (Genode::Rom_connection::Rom_connection_failed) {
Genode::warning("Could not open ROM session for \"xray\".",
" This ROM is used for custom pointer shape support.");
}
}
_nitpicker.enqueue<Nitpicker::Session::Command::To_front>(_view);
_nitpicker.execute();
_update_pointer();
if (_shapes_enabled) {
/* announce 'Report' service */
env.parent().announce(env.ep().manage(_report_root));
}
}
void Component::construct(Genode::Env &env) { static Pointer::Main main(env); }

View File

@ -0,0 +1,137 @@
/*
* \brief Registry of ROM modules
* \author Norman Feske
* \date 2014-01-11
*/
/*
* Copyright (C) 2014-2017 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU Affero General Public License version 3.
*/
#ifndef _ROM_REGISTRY_H_
#define _ROM_REGISTRY_H_
/* Genode includes */
#include <report_rom/rom_registry.h>
#include <os/session_policy.h>
namespace Rom { struct Registry; }
struct Rom::Registry : Registry_for_reader, Registry_for_writer, Genode::Noncopyable
{
private:
Genode::Allocator &_md_alloc;
Genode::Ram_session &_ram;
Genode::Region_map &_rm;
Reader &_reader;
Module_list _modules;
struct Read_write_policy : Module::Read_policy, Module::Write_policy
{
bool read_permitted(Module const &,
Writer const &,
Reader const &) const override
{
/*
* The pointer application is always allowed to read the ROM content.
*/
return true;
}
bool write_permitted(Module const &, Writer const &) const override
{
/*
* Because the report-session label is used as the module name
* for the writer, each report session refers to a distinct
* module. Report client can write to their respective modules
* at any time.
*/
return true;
}
} _read_write_policy;
Module &_lookup(Module::Name const name, bool create_if_not_found)
{
for (Module *m = _modules.first(); m; m = m->next())
if (m->_has_name(name))
return *m;
if (!create_if_not_found)
throw Genode::Service_denied();
/* module does not exist yet, create one */
/* XXX proper accounting for the used memory is missing */
/* XXX if we run out of memory, the server will abort */
Module * const module = new (&_md_alloc)
Module(_ram, _rm, name, _read_write_policy, _read_write_policy);
_modules.insert(module);
return *module;
}
void _try_to_destroy(Module const &module)
{
if (module._in_use())
return;
_modules.remove(&module);
Genode::destroy(&_md_alloc, const_cast<Module *>(&module));
}
public:
Registry(Genode::Allocator &md_alloc,
Genode::Ram_session &ram, Genode::Region_map &rm,
Reader &reader)
:
_md_alloc(md_alloc), _ram(ram), _rm(rm), _reader(reader)
{ }
Module &lookup(Writer &writer, Module::Name const &name) override
{
Module &module = _lookup(name, true);
module._register(writer);
/*
* Enforce invariant that each module can have only one writer at a
* time.
*/
if (module._num_writers() > 1) {
release(writer, module);
throw Genode::Service_denied();
}
module._register(_reader);
return module;
}
void release(Writer &writer, Module &module) override
{
module._unregister(_reader);
module._unregister(writer);
_try_to_destroy(module);
}
Readable_module &lookup(Reader &reader, Module::Name const &rom_label) override
{
return _lookup(rom_label, false);
}
void release(Reader &reader, Readable_module &module) override
{
_try_to_destroy(static_cast<Module&>(module));
}
};
#endif /* _ROM_REGISTRY_H_ */

View File

@ -0,0 +1,42 @@
/*
* \brief VirtualBox pointer utilities
* \author Christian Helmuth
* \date 2015-06-08
*/
/*
* Copyright (C) 2015-2017 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU Affero General Public License version 3.
*/
#ifndef _POINTER_UTIL_H_
#define _POINTER_UTIL_H_
/* Genode includes */
#include <util/xml_node.h>
#include <util/string.h>
namespace Pointer {
typedef Genode::String<64> String;
inline String read_string_attribute(Genode::Xml_node const &node,
char const *attr,
String const &default_value);
}
Pointer::String Pointer::read_string_attribute(Genode::Xml_node const &node,
char const *attr,
String const &default_value)
{
try {
char buf[String::capacity()];
node.attribute(attr).value(buf, sizeof(buf));
return String(Genode::Cstring(buf));
} catch (...) { return default_value; }
}
#endif /* _POINTER_UTIL_H_ */

View File

@ -0,0 +1,194 @@
/*
* \brief Pointer shape reporter test
* \author Christian Helmuth
* \date 2015-06-03
*/
/*
* Copyright (C) 2015-2017 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU Affero General Public License version 3.
*/
#include <base/component.h>
#include <base/attached_rom_dataspace.h>
#include <util/string.h>
#include <os/reporter.h>
#include <pointer/shape_report.h>
struct Shape
{
enum { WIDTH = 16, HEIGHT = 16 };
typedef Genode::String<16> Id;
Id const id;
unsigned const x_hot;
unsigned const y_hot;
unsigned char const map[WIDTH*HEIGHT];
void print(Genode::Output &output) const
{
Genode::print(output, ".", id, ".", x_hot, ".", y_hot, ".");
}
};
static Shape const shape[] = {
{ "arrow", 0, 0, {
1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,
0,0,1,1,1,1,1,0,0,0,0,0,0,0,0,0,
0,0,1,1,1,1,0,0,0,0,0,0,0,0,0,0,
0,0,0,1,1,1,0,0,0,0,0,0,0,0,0,0,
0,0,0,1,0,0,1,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,1,1,1,1,0,0,0,0,
0,0,0,0,0,0,0,0,1,1,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,1,0,1,1,1,1,0,0,
0,0,0,0,0,0,0,0,1,0,1,1,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,1,0,1,1,1,0,
0,0,0,0,0,0,0,0,0,0,1,0,1,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 } },
{ "blade", 0, 0, {
1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
1,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,1,0,1,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,1,0,1,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,1,0,1,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,1,0,1,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,1,0,1,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,1,0,1,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,1,0,1,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,1,0,1,0,1,1,0,0,
0,0,0,0,0,0,0,0,0,1,1,1,1,1,0,0,
0,0,0,0,0,0,0,0,0,0,1,1,1,0,0,0,
0,0,0,0,0,0,0,0,0,1,1,1,1,1,0,0,
0,0,0,0,0,0,0,0,0,1,1,0,1,1,1,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 } },
{ "bladex", 8, 8, {
1,1,0,0,0,0,0,0,0,0,0,0,0,0,1,1,
1,0,1,0,0,0,0,0,0,0,0,0,0,1,0,1,
0,1,0,1,0,0,0,0,0,0,0,0,1,0,1,0,
0,0,1,0,1,0,0,0,0,0,0,1,0,1,0,0,
0,0,0,1,0,1,0,0,0,0,1,0,1,0,0,0,
0,0,0,0,1,0,1,0,0,1,0,1,0,0,0,0,
0,0,0,0,0,1,0,1,1,0,1,0,0,0,0,0,
0,0,0,0,0,0,1,0,1,1,0,0,0,0,0,0,
0,0,0,0,0,0,1,1,0,1,0,0,0,0,0,0,
0,0,1,1,0,1,0,1,1,0,1,0,1,1,0,0,
0,0,1,1,1,1,1,0,0,1,1,1,1,1,0,0,
0,0,0,1,1,1,0,0,0,0,1,1,1,0,0,0,
0,0,1,1,1,1,1,0,0,1,1,1,1,1,0,0,
0,1,1,1,0,1,1,0,0,1,1,0,1,1,1,0,
0,1,1,0,0,0,0,0,0,0,0,0,0,1,1,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 } },
{ "smiley", 8, 8, {
0,0,0,0,0,1,1,1,1,1,1,0,0,0,0,0,
0,0,0,1,1,0,0,0,0,0,0,1,1,0,0,0,
0,0,1,0,0,0,0,0,0,0,0,0,0,1,0,0,
0,1,0,0,0,0,0,0,0,0,0,0,0,0,1,0,
0,1,0,0,0,1,1,0,0,1,1,0,0,0,1,0,
1,0,0,0,0,1,1,0,0,1,1,0,0,0,0,1,
1,0,0,0,0,1,1,0,0,1,1,0,0,0,0,1,
1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,
1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,
1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,
1,0,0,1,0,0,0,0,0,0,0,0,1,0,0,1,
0,1,0,0,1,1,0,0,0,0,1,1,0,0,1,0,
0,1,0,0,0,0,1,1,1,1,0,0,0,0,1,0,
0,0,1,0,0,0,0,0,0,0,0,0,0,1,0,0,
0,0,0,1,1,0,0,0,0,0,0,1,1,0,0,0,
0,0,0,0,0,1,1,1,1,1,1,0,0,0,0,0 } },
{ "yelims", 8, 8, {
0,0,0,0,0,1,1,1,1,1,1,0,0,0,0,0,
0,0,0,1,1,0,0,0,0,0,0,1,1,0,0,0,
0,0,1,0,0,0,0,0,0,0,0,0,0,1,0,0,
0,1,0,0,0,0,0,0,0,0,0,0,0,0,1,0,
0,1,0,0,0,1,1,0,0,1,1,0,0,0,1,0,
1,0,0,0,0,1,1,0,0,1,1,0,0,0,0,1,
1,0,0,0,0,1,1,0,0,1,1,0,0,0,0,1,
1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,
1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,
1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,
1,0,0,0,0,0,1,1,1,1,0,0,0,0,0,1,
0,1,0,0,1,1,0,0,0,0,1,1,0,0,1,0,
0,1,0,1,0,0,0,0,0,0,0,0,1,0,1,0,
0,0,1,0,0,0,0,0,0,0,0,0,0,1,0,0,
0,0,0,1,1,0,0,0,0,0,0,1,1,0,0,0,
0,0,0,0,0,1,1,1,1,1,1,0,0,0,0,0 } }
};
static Shape const &select_shape(Genode::Xml_node config)
{
Shape::Id const id = config.attribute_value("shape", Shape::Id("arrow"));
for (Shape const &s : shape)
if (s.id == id)
return s;
/* not found -> use first as default */
return shape[0];
}
struct Main
{
Genode::Env &_env;
Pointer::Shape_report _shape_report {
true, 0, 0, Shape::WIDTH, Shape::HEIGHT, { 0 } };
Genode::Reporter _reporter {
_env, "shape", "shape", sizeof(Pointer::Shape_report) };
Genode::Signal_handler<Main> _config_handler {
_env.ep(), *this, &Main::_handle_config };
Genode::Attached_rom_dataspace _config { _env, "config" };
void _handle_config()
{
_config.update();
Shape const &shape = select_shape(_config.xml());
_shape_report.x_hot = shape.x_hot;
_shape_report.y_hot = shape.y_hot;
unsigned const w = Shape::WIDTH;
unsigned const h = Shape::HEIGHT;
for (unsigned y = 0; y < h; ++y) {
for (unsigned x = 0; x < w; ++x) {
_shape_report.shape[(y*w + x)*4 + 0] = 0xff;
_shape_report.shape[(y*w + x)*4 + 1] = 0xff;
_shape_report.shape[(y*w + x)*4 + 2] = 0xff;
_shape_report.shape[(y*w + x)*4 + 3] = shape.map[y*w +x] ? 0xe0 : 0;
}
}
_reporter.report(&_shape_report, sizeof(Pointer::Shape_report));
}
Main(Genode::Env &env) : _env(env)
{
_reporter.enabled(true);
_config.sigh(_config_handler);
_handle_config();
}
};
void Component::construct(Genode::Env &env)
{
/* XXX execute constructors of global statics */
env.exec_static_constructors();
static Main main(env);
}

View File

@ -0,0 +1,3 @@
TARGET = test-pointer
SRC_CC = main.cc
LIBS = base