mirror of
https://github.com/genodelabs/genode.git
synced 2025-04-08 11:55:24 +00:00
parent
178f2c0e88
commit
7897e52235
342
repos/ports/run/vbox_pointer.run
Normal file
342
repos/ports/run/vbox_pointer.run
Normal file
@ -0,0 +1,342 @@
|
||||
#
|
||||
# Build
|
||||
#
|
||||
# for ldso debugging: <config ld_verbose="yes"/>
|
||||
#
|
||||
|
||||
assert_spec linux
|
||||
|
||||
set build_components {
|
||||
core init
|
||||
drivers/timer
|
||||
drivers/framebuffer/sdl
|
||||
server/report_rom
|
||||
server/dynamic_rom
|
||||
server/nitpicker
|
||||
app/vbox_pointer
|
||||
test/vbox_pointer
|
||||
test/nitpicker
|
||||
}
|
||||
|
||||
build $build_components
|
||||
|
||||
create_boot_directory
|
||||
|
||||
#
|
||||
# Generate config
|
||||
#
|
||||
|
||||
set config {
|
||||
<config>
|
||||
<parent-provides>
|
||||
<service name="ROM"/>
|
||||
<service name="RAM"/>
|
||||
<service name="IRQ"/>
|
||||
<service name="IO_MEM"/>
|
||||
<service name="IO_PORT"/>
|
||||
<service name="CAP"/>
|
||||
<service name="PD"/>
|
||||
<service name="RM"/>
|
||||
<service name="CPU"/>
|
||||
<service name="LOG"/>
|
||||
<service name="SIGNAL"/>
|
||||
</parent-provides>
|
||||
|
||||
<start name="timer">
|
||||
<resource name="RAM" quantum="1M"/>
|
||||
<provides> <service name="Timer"/> </provides>
|
||||
<route>
|
||||
<service name="RM"> <parent/> </service>
|
||||
<service name="LOG"> <parent/> </service>
|
||||
<service name="SIGNAL"> <parent/> </service>
|
||||
<service name="CAP"> <parent/> </service>
|
||||
<service name="ROM"> <parent/> </service>
|
||||
</route>
|
||||
</start>
|
||||
<start name="fb_sdl">
|
||||
<resource name="RAM" quantum="6M"/>
|
||||
<provides>
|
||||
<service name="Framebuffer"/>
|
||||
<service name="Input"/>
|
||||
</provides>
|
||||
<config buffered="yes" width="1280" height="720" depth="16"/>
|
||||
<!--<config buffered="yes" width="1440" height="900" depth="16"/>-->
|
||||
<route>
|
||||
<service name="RM"> <parent/> </service>
|
||||
<service name="LOG"> <parent/> </service>
|
||||
<service name="SIGNAL"> <parent/> </service>
|
||||
<service name="CAP"> <parent/> </service>
|
||||
</route>
|
||||
</start>
|
||||
<alias name="input_drv" child="fb_sdl"/>
|
||||
<alias name="fb_drv" child="fb_sdl"/>
|
||||
|
||||
<start name="report_rom_nitpicker">
|
||||
<binary name="report_rom"/>
|
||||
<resource name="RAM" quantum="1M"/>
|
||||
<provides> <service name="Report"/> <service name="ROM"/> </provides>
|
||||
<config>
|
||||
<rom>
|
||||
<policy label="pointer -> hover" report="nitpicker -> hover"/>
|
||||
<policy label="pointer -> xray" report="nitpicker -> xray"/>
|
||||
<policy label="pointer -> focus" report="nitpicker -> focus"/>
|
||||
</rom>
|
||||
</config>
|
||||
<route>
|
||||
<service name="RM"> <parent/> </service>
|
||||
<service name="LOG"> <parent/> </service>
|
||||
<service name="SIGNAL"> <parent/> </service>
|
||||
<service name="CAP"> <parent/> </service>
|
||||
</route>
|
||||
</start>
|
||||
<start name="nitpicker">
|
||||
<resource name="RAM" quantum="4M"/>
|
||||
<provides><service name="Nitpicker"/></provides>
|
||||
<config>
|
||||
<report focus="yes" hover="yes" xray="yes"/>
|
||||
<domain name="pointer" layer="1" xray="no" origin="pointer"/>
|
||||
<domain name="smiley" layer="3"/>
|
||||
<domain name="" layer="3"/>
|
||||
|
||||
<policy label="pointer" domain="pointer"/>
|
||||
<policy label="test-domain-smiley" domain="smiley"/>
|
||||
<policy label="" domain=""/>
|
||||
|
||||
<global-key name="KEY_F12" operation="xray"/>
|
||||
<background color="#00426f"/> <!-- indigo -->
|
||||
</config>
|
||||
<route>
|
||||
<service name="RM"> <parent/> </service>
|
||||
<service name="LOG"> <parent/> </service>
|
||||
<service name="SIGNAL"> <parent/> </service>
|
||||
<service name="CAP"> <parent/> </service>
|
||||
<service name="Timer"> <child name="timer"/> </service>
|
||||
<service name="Framebuffer"> <child name="fb_drv"/> </service>
|
||||
<service name="Input"> <child name="input_drv"/> </service>
|
||||
<service name="Report"> <child name="report_rom_nitpicker"/> </service>
|
||||
</route>
|
||||
</start>
|
||||
|
||||
<start name="report_rom_shapes">
|
||||
<binary name="report_rom"/>
|
||||
<resource name="RAM" quantum="1M"/>
|
||||
<provides> <service name="Report"/> <service name="ROM"/> </provides>
|
||||
<config>
|
||||
<rom>
|
||||
<policy label="pointer -> arrow" report="shape-arrow -> shape"/>
|
||||
<policy label="pointer -> blade" report="shape-blade -> shape"/>
|
||||
<policy label="pointer -> bladex" report="shape-bladex -> shape"/>
|
||||
<policy label="pointer -> smiley" report="shape-smiley -> shape"/>
|
||||
</rom>
|
||||
</config>
|
||||
<route>
|
||||
<service name="RM"> <parent/> </service>
|
||||
<service name="LOG"> <parent/> </service>
|
||||
<service name="SIGNAL"> <parent/> </service>
|
||||
<service name="CAP"> <parent/> </service>
|
||||
</route>
|
||||
</start>
|
||||
<start name="shape-arrow">
|
||||
<binary name="test-vbox_pointer"/>
|
||||
<resource name="RAM" quantum="2M"/>
|
||||
<config shape="arrow"/>
|
||||
<route>
|
||||
<service name="LOG"> <parent/> </service>
|
||||
<service name="SIGNAL"> <parent/> </service>
|
||||
<service name="Report"> <child name="report_rom_shapes"/> </service>
|
||||
</route>
|
||||
</start>
|
||||
<start name="shape-blade">
|
||||
<binary name="test-vbox_pointer"/>
|
||||
<resource name="RAM" quantum="2M"/>
|
||||
<config shape="blade"/>
|
||||
<route>
|
||||
<service name="LOG"> <parent/> </service>
|
||||
<service name="SIGNAL"> <parent/> </service>
|
||||
<service name="Report"> <child name="report_rom_shapes"/> </service>
|
||||
</route>
|
||||
</start>
|
||||
<start name="shape-bladex">
|
||||
<binary name="test-vbox_pointer"/>
|
||||
<resource name="RAM" quantum="2M"/>
|
||||
<config shape="bladex"/>
|
||||
<route>
|
||||
<service name="LOG"> <parent/> </service>
|
||||
<service name="SIGNAL"> <parent/> </service>
|
||||
<service name="Report"> <child name="report_rom_shapes"/> </service>
|
||||
</route>
|
||||
</start>
|
||||
<start name="shape-smiley-config">
|
||||
<binary name="dynamic_rom"/>
|
||||
<resource name="RAM" quantum="1M"/>
|
||||
<provides> <service name="ROM"/> </provides>
|
||||
<config>
|
||||
<rom name="smiley.config">
|
||||
<inline description="smiley">
|
||||
<config shape="smiley"/>
|
||||
</inline>
|
||||
<sleep milliseconds="500" />
|
||||
<inline description="yelims">
|
||||
<config shape="yelims"/>
|
||||
</inline>
|
||||
<sleep milliseconds="500" />
|
||||
</rom>
|
||||
</config>
|
||||
<route>
|
||||
<service name="RM"> <parent/> </service>
|
||||
<service name="LOG"> <parent/> </service>
|
||||
<service name="SIGNAL"> <parent/> </service>
|
||||
<service name="CAP"> <parent/> </service>
|
||||
<service name="Timer"> <child name="timer"/> </service>
|
||||
</route>
|
||||
</start>
|
||||
<start name="shape-smiley">
|
||||
<binary name="test-vbox_pointer"/>
|
||||
<resource name="RAM" quantum="2M"/>
|
||||
<configfile name="smiley.config"/>
|
||||
<route>
|
||||
<service name="LOG"> <parent/> </service>
|
||||
<service name="SIGNAL"> <parent/> </service>
|
||||
<service name="ROM"> <if-args key="label" value="smiley.config"/>
|
||||
<child name="shape-smiley-config"/> </service>
|
||||
<service name="Report"> <child name="report_rom_shapes"/> </service>
|
||||
</route>
|
||||
</start>
|
||||
|
||||
<start name="pointer">
|
||||
<binary name="vbox_pointer"/>
|
||||
<resource name="RAM" quantum="1M"/>
|
||||
<config>
|
||||
<policy domain="smiley" rom="smiley"/>
|
||||
<policy label="test-label-arrow" rom="arrow"/>
|
||||
<policy label="test-label-blade" rom="blade"/>
|
||||
<policy label="test-label-bladex" rom="bladex"/>
|
||||
</config>
|
||||
<route>
|
||||
<service name="RM"> <parent/> </service>
|
||||
<service name="LOG"> <parent/> </service>
|
||||
<service name="SIGNAL"> <parent/> </service>
|
||||
<service name="Nitpicker"> <child name="nitpicker"/> </service>
|
||||
<service name="ROM"> <if-arg key="label" value="xray"/>
|
||||
<child name="report_rom_nitpicker"/> </service>
|
||||
<service name="ROM"> <if-arg key="label" value="hover"/>
|
||||
<child name="report_rom_nitpicker"/> </service>
|
||||
<service name="ROM"> <child name="report_rom_shapes"/> </service>
|
||||
</route>
|
||||
</start>
|
||||
|
||||
<start name="test-no-match">
|
||||
<binary name="testnit"/>
|
||||
<resource name="RAM" quantum="2M"/>
|
||||
<route>
|
||||
<service name="RM"> <parent/> </service>
|
||||
<service name="LOG"> <parent/> </service>
|
||||
<service name="SIGNAL"> <parent/> </service>
|
||||
<service name="CAP"> <parent/> </service>
|
||||
<service name="PD"> <parent/> </service>
|
||||
<service name="CPU"> <parent/> </service>
|
||||
<service name="RAM"> <parent/> </service>
|
||||
<service name="Timer"> <child name="timer"/> </service>
|
||||
<service name="Nitpicker"> <child name="nitpicker"/> </service>
|
||||
</route>
|
||||
</start>
|
||||
<start name="test-domain-smiley">
|
||||
<binary name="testnit"/>
|
||||
<resource name="RAM" quantum="2M"/>
|
||||
<route>
|
||||
<service name="RM"> <parent/> </service>
|
||||
<service name="LOG"> <parent/> </service>
|
||||
<service name="SIGNAL"> <parent/> </service>
|
||||
<service name="CAP"> <parent/> </service>
|
||||
<service name="PD"> <parent/> </service>
|
||||
<service name="CPU"> <parent/> </service>
|
||||
<service name="RAM"> <parent/> </service>
|
||||
<service name="Timer"> <child name="timer"/> </service>
|
||||
<service name="Nitpicker"> <child name="nitpicker"/> </service>
|
||||
</route>
|
||||
</start>
|
||||
<start name="test-label-arrow">
|
||||
<binary name="testnit"/>
|
||||
<resource name="RAM" quantum="2M"/>
|
||||
<route>
|
||||
<service name="RM"> <parent/> </service>
|
||||
<service name="LOG"> <parent/> </service>
|
||||
<service name="SIGNAL"> <parent/> </service>
|
||||
<service name="CAP"> <parent/> </service>
|
||||
<service name="PD"> <parent/> </service>
|
||||
<service name="CPU"> <parent/> </service>
|
||||
<service name="RAM"> <parent/> </service>
|
||||
<service name="Timer"> <child name="timer"/> </service>
|
||||
<service name="Nitpicker"> <child name="nitpicker"/> </service>
|
||||
</route>
|
||||
</start>
|
||||
<start name="test-label-blade">
|
||||
<binary name="testnit"/>
|
||||
<resource name="RAM" quantum="2M"/>
|
||||
<route>
|
||||
<service name="RM"> <parent/> </service>
|
||||
<service name="LOG"> <parent/> </service>
|
||||
<service name="SIGNAL"> <parent/> </service>
|
||||
<service name="CAP"> <parent/> </service>
|
||||
<service name="PD"> <parent/> </service>
|
||||
<service name="CPU"> <parent/> </service>
|
||||
<service name="RAM"> <parent/> </service>
|
||||
<service name="Timer"> <child name="timer"/> </service>
|
||||
<service name="Nitpicker"> <child name="nitpicker"/> </service>
|
||||
</route>
|
||||
</start>
|
||||
<start name="test-label-blade2">
|
||||
<binary name="testnit"/>
|
||||
<resource name="RAM" quantum="2M"/>
|
||||
<route>
|
||||
<service name="RM"> <parent/> </service>
|
||||
<service name="LOG"> <parent/> </service>
|
||||
<service name="SIGNAL"> <parent/> </service>
|
||||
<service name="CAP"> <parent/> </service>
|
||||
<service name="PD"> <parent/> </service>
|
||||
<service name="CPU"> <parent/> </service>
|
||||
<service name="RAM"> <parent/> </service>
|
||||
<service name="Timer"> <child name="timer"/> </service>
|
||||
<service name="Nitpicker"> <child name="nitpicker"/> </service>
|
||||
</route>
|
||||
</start>
|
||||
<start name="test-label-bladex">
|
||||
<binary name="testnit"/>
|
||||
<resource name="RAM" quantum="2M"/>
|
||||
<route>
|
||||
<service name="RM"> <parent/> </service>
|
||||
<service name="LOG"> <parent/> </service>
|
||||
<service name="SIGNAL"> <parent/> </service>
|
||||
<service name="CAP"> <parent/> </service>
|
||||
<service name="PD"> <parent/> </service>
|
||||
<service name="CPU"> <parent/> </service>
|
||||
<service name="RAM"> <parent/> </service>
|
||||
<service name="Timer"> <child name="timer"/> </service>
|
||||
<service name="Nitpicker"> <child name="nitpicker"/> </service>
|
||||
</route>
|
||||
</start>
|
||||
</config>}
|
||||
|
||||
install_config $config
|
||||
|
||||
#
|
||||
# Boot modules
|
||||
#
|
||||
|
||||
# generic modules
|
||||
set boot_modules {
|
||||
init timer
|
||||
fb_sdl
|
||||
report_rom dynamic_rom
|
||||
nitpicker
|
||||
vbox_pointer arrow.shape cross.shape smiley.shape
|
||||
test-vbox_pointer
|
||||
testnit
|
||||
}
|
||||
|
||||
# "lsort -unique" removes duplicates but core must be first
|
||||
build_boot_image "core [lsort -unique $boot_modules]"
|
||||
|
||||
run_genode_until forever
|
||||
|
||||
# vi: set ft=tcl :
|
26
repos/ports/src/app/vbox_pointer/README
Normal file
26
repos/ports/src/app/vbox_pointer/README
Normal file
@ -0,0 +1,26 @@
|
||||
Hover-sensitive pointer for Nitpicker with VirtualBox shape support
|
||||
|
||||
Per default the standard "big mouse" pointer is rendered on screen,
|
||||
which is the behavior known from the classical app/pointer.
|
||||
Additionally, VirtualBox pointer supports to render "pointer shapes"
|
||||
when hovering configured Nitpicker sessions. The policies can be
|
||||
defined for labels or domains of the sessions.
|
||||
|
||||
! <start name="vbox_pointer">
|
||||
! <resource name="RAM" quantum="1M"/>
|
||||
! <config>
|
||||
! <policy domain="smiley" rom="smiley"/>
|
||||
! <policy label="test-label-arrow" rom="arrow"/>
|
||||
! <policy label="test-label-blade" rom="blade"/>
|
||||
! </config>
|
||||
! </start>
|
||||
|
||||
In the example above, which is from vbox_pointer.run, the domain
|
||||
"smiley" gets the ROM "smiley" as pointer shape. The labels
|
||||
"test-label-blade" and "test-label-arrow" will render the ROMs "arrow"
|
||||
resp. "blade" as pointer shape. Note that label matching is done from
|
||||
the start of the actual label until the defined label ends. So,
|
||||
"test-label-blade2" will also match the policy defined above.
|
||||
|
||||
The most common use case for vbox_pointer is VirtualBox, which reports
|
||||
the guest-pointer shapes if Guest Additions are installed.
|
@ -14,29 +14,19 @@
|
||||
*/
|
||||
|
||||
/* Genode includes */
|
||||
#include <base/sleep.h>
|
||||
#include <os/attached_dataspace.h>
|
||||
#include <os/attached_ram_dataspace.h>
|
||||
#include <os/attached_rom_dataspace.h>
|
||||
#include <os/surface.h>
|
||||
#include <os/pixel_alpha8.h>
|
||||
#include <os/config.h>
|
||||
#include <os/pixel_rgb565.h>
|
||||
#include <os/pixel_rgb888.h>
|
||||
#include <os/texture_rgb888.h>
|
||||
#include <os/texture.h>
|
||||
#include <util/xml_node.h>
|
||||
#include <nitpicker_session/connection.h>
|
||||
#include <vbox_pointer/dither_painter.h>
|
||||
#include <vbox_pointer/shape_report.h>
|
||||
|
||||
/* local includes */
|
||||
#include "util.h"
|
||||
#include "policy.h"
|
||||
#include "big_mouse.h"
|
||||
|
||||
/* exception */
|
||||
struct Pointer_shape_too_large { };
|
||||
|
||||
template <typename PT>
|
||||
void convert_default_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());
|
||||
|
||||
@ -54,342 +44,232 @@ void convert_default_cursor_data_to_pixels(PT *pixel, Nitpicker::Area size)
|
||||
}
|
||||
}
|
||||
|
||||
template <typename PT>
|
||||
void convert_vbox_cursor_data_to_pixels(PT *pixel, unsigned char *shape,
|
||||
Nitpicker::Area size)
|
||||
|
||||
class Main : public Vbox_pointer::Pointer_updater
|
||||
{
|
||||
Genode::Attached_ram_dataspace texture_pixel_ds { Genode::env()->ram_session(),
|
||||
size.count() *
|
||||
sizeof(Genode::Pixel_rgb888) };
|
||||
|
||||
Genode::Attached_ram_dataspace texture_alpha_ds { Genode::env()->ram_session(),
|
||||
size.count() };
|
||||
|
||||
Genode::Texture<Genode::Pixel_rgb888>
|
||||
texture(texture_pixel_ds.local_addr<Genode::Pixel_rgb888>(),
|
||||
texture_alpha_ds.local_addr<unsigned char>(),
|
||||
size);
|
||||
|
||||
for (unsigned int y = 0; y < size.h(); y++) {
|
||||
|
||||
/* convert the shape data from BGRA encoding to RGBA encoding */
|
||||
unsigned char *bgra_line = &shape[y * size.w() * 4];
|
||||
unsigned char rgba_line[size.w() * 4];
|
||||
for (unsigned int i = 0; i < size.w() * 4; i += 4) {
|
||||
rgba_line[i + 0] = bgra_line[i + 2];
|
||||
rgba_line[i + 1] = bgra_line[i + 1];
|
||||
rgba_line[i + 2] = bgra_line[i + 0];
|
||||
rgba_line[i + 3] = bgra_line[i + 3];
|
||||
}
|
||||
|
||||
/* import the RGBA-encoded line into the texture */
|
||||
texture.rgba(rgba_line, size.w(), y);
|
||||
}
|
||||
|
||||
Genode::Pixel_alpha8 *alpha =
|
||||
reinterpret_cast<Genode::Pixel_alpha8*>(pixel + size.count());
|
||||
|
||||
Genode::Surface<PT> pixel_surface(pixel, size);
|
||||
Genode::Surface<Genode::Pixel_alpha8> alpha_surface(alpha, size);
|
||||
|
||||
Dither_painter::paint(pixel_surface, texture);
|
||||
Dither_painter::paint(alpha_surface, texture);
|
||||
}
|
||||
|
||||
//struct Log { Log(char const *msg) { PINF("Log: %s", msg); } };
|
||||
|
||||
|
||||
typedef Genode::String<64> Domain_name;
|
||||
|
||||
class Domain : public Genode::List<Domain>::Element
|
||||
{
|
||||
public:
|
||||
|
||||
struct Name_too_long { };
|
||||
|
||||
private:
|
||||
|
||||
Domain_name _name;
|
||||
typedef Vbox_pointer::String String;
|
||||
typedef Vbox_pointer::Policy Policy;
|
||||
typedef Vbox_pointer::Policy_registry Policy_registry;
|
||||
|
||||
Genode::Attached_rom_dataspace _hover_ds { "hover" };
|
||||
Genode::Attached_rom_dataspace _xray_ds { "xray" };
|
||||
|
||||
Genode::Signal_receiver _sig_rec;
|
||||
|
||||
Genode::Signal_dispatcher<Main> _hover_signal_dispatcher {
|
||||
_sig_rec, *this, &Main::_handle_hover };
|
||||
Genode::Signal_dispatcher<Main> _xray_signal_dispatcher {
|
||||
_sig_rec, *this, &Main::_handle_xray };
|
||||
|
||||
Nitpicker::Connection _nitpicker;
|
||||
|
||||
Nitpicker::Session::View_handle _view = _nitpicker.create_view();
|
||||
|
||||
Policy_registry _policy_registry { *this };
|
||||
|
||||
String _hovered_label;
|
||||
String _hovered_domain;
|
||||
|
||||
bool _xray = false;
|
||||
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 _show_shape_pointer(Policy *p);
|
||||
void _update_pointer();
|
||||
void _handle_hover(unsigned num = 0);
|
||||
void _handle_xray(unsigned num = 0);
|
||||
|
||||
public:
|
||||
|
||||
Domain(char const *name) : _name(name)
|
||||
{
|
||||
if (Genode::strlen(name) + 1 > _name.capacity())
|
||||
throw Name_too_long();
|
||||
}
|
||||
Main();
|
||||
|
||||
Domain_name const & name() { return _name; }
|
||||
/*******************************
|
||||
** Pointer_updater interface **
|
||||
*******************************/
|
||||
|
||||
void update_pointer(Policy *policy) override;
|
||||
|
||||
Genode::Signal_receiver & signal_receiver() override { return _sig_rec; }
|
||||
};
|
||||
|
||||
|
||||
struct Domain_list : private Genode::List<Domain>
|
||||
void Main::_resize_nitpicker_buffer_if_needed(Nitpicker::Area pointer_size)
|
||||
{
|
||||
void add(char const *name)
|
||||
{
|
||||
Domain *d = new (Genode::env()->heap()) Domain(name);
|
||||
insert(d);
|
||||
}
|
||||
if (pointer_size == _current_pointer_size)
|
||||
return;
|
||||
|
||||
bool contains(Domain_name const &name)
|
||||
{
|
||||
for (Domain *d = first(); d; d = d->next())
|
||||
if (d->name() == name)
|
||||
return true;
|
||||
Framebuffer::Mode const mode { (int)pointer_size.w(),
|
||||
(int)pointer_size.h(),
|
||||
Framebuffer::Mode::RGB565 };
|
||||
|
||||
return false;
|
||||
}
|
||||
};
|
||||
_nitpicker.buffer(mode, true /* use alpha */);
|
||||
|
||||
_pointer_ds = _nitpicker.framebuffer()->dataspace();
|
||||
|
||||
struct Main
|
||||
{
|
||||
Genode::Attached_rom_dataspace hover_ds { "hover" };
|
||||
Genode::Attached_rom_dataspace xray_ds { "xray" };
|
||||
Genode::Attached_rom_dataspace shape_ds { "shape" };
|
||||
|
||||
Genode::Signal_receiver sig_rec;
|
||||
|
||||
void handle_hover(unsigned num = 0);
|
||||
void handle_xray(unsigned num = 0);
|
||||
void handle_shape(unsigned num = 0);
|
||||
|
||||
Genode::Signal_dispatcher<Main> hover_signal_dispatcher {
|
||||
sig_rec, *this, &Main::handle_hover };
|
||||
Genode::Signal_dispatcher<Main> xray_signal_dispatcher {
|
||||
sig_rec, *this, &Main::handle_xray };
|
||||
Genode::Signal_dispatcher<Main> shape_signal_dispatcher {
|
||||
sig_rec, *this, &Main::handle_shape };
|
||||
|
||||
Nitpicker::Connection nitpicker;
|
||||
|
||||
Nitpicker::Session::View_handle view = nitpicker.create_view();
|
||||
|
||||
Domain_list vbox_domains;
|
||||
Domain_name current_domain;
|
||||
|
||||
bool xray = false;
|
||||
bool default_pointer_visible = false;
|
||||
bool vbox_pointer_visible = false;
|
||||
bool vbox_pointer_shape_changed = false;
|
||||
|
||||
Nitpicker::Area current_cursor_size;
|
||||
Genode::Dataspace_capability pointer_ds;
|
||||
|
||||
void resize_nitpicker_buffer_if_needed(Nitpicker::Area cursor_size)
|
||||
{
|
||||
if (cursor_size != current_cursor_size) {
|
||||
|
||||
Framebuffer::Mode const mode { (int)cursor_size.w(), (int)cursor_size.h(),
|
||||
Framebuffer::Mode::RGB565 };
|
||||
|
||||
nitpicker.buffer(mode, true /* use alpha */);
|
||||
|
||||
pointer_ds = nitpicker.framebuffer()->dataspace();
|
||||
|
||||
current_cursor_size = cursor_size;
|
||||
}
|
||||
}
|
||||
|
||||
void show_default_pointer()
|
||||
{
|
||||
if (!default_pointer_visible) {
|
||||
|
||||
Nitpicker::Area const cursor_size { big_mouse.w, big_mouse.h };
|
||||
|
||||
try {
|
||||
resize_nitpicker_buffer_if_needed(cursor_size);
|
||||
} catch (...) {
|
||||
PERR("%s: could not resize the pointer buffer for %u x %u pixels",
|
||||
__func__, cursor_size.w(), cursor_size.h());
|
||||
return;
|
||||
}
|
||||
|
||||
Genode::Attached_dataspace ds { pointer_ds };
|
||||
|
||||
convert_default_cursor_data_to_pixels(ds.local_addr<Genode::Pixel_rgb565>(),
|
||||
cursor_size);
|
||||
nitpicker.framebuffer()->refresh(0, 0, cursor_size.w(), cursor_size.h());
|
||||
|
||||
Nitpicker::Rect geometry(Nitpicker::Point(0, 0), cursor_size);
|
||||
nitpicker.enqueue<Nitpicker::Session::Command::Geometry>(view, geometry);
|
||||
nitpicker.execute();
|
||||
|
||||
default_pointer_visible = true;
|
||||
vbox_pointer_visible = false;
|
||||
}
|
||||
}
|
||||
|
||||
void show_vbox_pointer()
|
||||
{
|
||||
if (!vbox_pointer_visible || vbox_pointer_shape_changed) {
|
||||
|
||||
try {
|
||||
|
||||
Vbox_pointer::Shape_report *shape_report =
|
||||
shape_ds.local_addr<Vbox_pointer::Shape_report>();
|
||||
|
||||
if (shape_report->visible) {
|
||||
|
||||
if ((shape_report->width == 0) || (shape_report->height == 0))
|
||||
return;
|
||||
|
||||
if ((shape_report->width > Vbox_pointer::MAX_WIDTH) ||
|
||||
(shape_report->height > Vbox_pointer::MAX_HEIGHT))
|
||||
throw Pointer_shape_too_large();
|
||||
|
||||
Nitpicker::Area const cursor_size { shape_report->width,
|
||||
shape_report->height };
|
||||
|
||||
resize_nitpicker_buffer_if_needed(cursor_size);
|
||||
|
||||
Genode::Attached_dataspace ds { pointer_ds };
|
||||
|
||||
convert_vbox_cursor_data_to_pixels(ds.local_addr<Genode::Pixel_rgb565>(),
|
||||
shape_report->shape,
|
||||
cursor_size);
|
||||
nitpicker.framebuffer()->refresh(0, 0, cursor_size.w(), cursor_size.h());
|
||||
|
||||
Nitpicker::Rect geometry(Nitpicker::Point(-shape_report->x_hot, -shape_report->y_hot), cursor_size);
|
||||
nitpicker.enqueue<Nitpicker::Session::Command::Geometry>(view, geometry);
|
||||
|
||||
} else {
|
||||
|
||||
Nitpicker::Rect geometry(Nitpicker::Point(0, 0), Nitpicker::Area(0, 0));
|
||||
nitpicker.enqueue<Nitpicker::Session::Command::Geometry>(view, geometry);
|
||||
|
||||
}
|
||||
|
||||
} catch (Genode::Volatile_object<Genode::Attached_dataspace>::Deref_unconstructed_object) {
|
||||
/* no shape has been reported, yet */
|
||||
Nitpicker::Rect geometry(Nitpicker::Point(0, 0), Nitpicker::Area(0, 0));
|
||||
nitpicker.enqueue<Nitpicker::Session::Command::Geometry>(view, geometry);
|
||||
}
|
||||
|
||||
nitpicker.execute();
|
||||
|
||||
vbox_pointer_visible = true;
|
||||
vbox_pointer_shape_changed = false;
|
||||
default_pointer_visible = false;
|
||||
}
|
||||
}
|
||||
|
||||
void update_pointer()
|
||||
{
|
||||
if (xray || !vbox_domains.contains(current_domain))
|
||||
show_default_pointer();
|
||||
else
|
||||
try {
|
||||
show_vbox_pointer();
|
||||
} catch (Pointer_shape_too_large) {
|
||||
PERR("%s: the pointer shape is larger than the maximum supported size of %u x %u",
|
||||
__func__, Vbox_pointer::MAX_WIDTH, Vbox_pointer::MAX_HEIGHT);
|
||||
show_default_pointer();
|
||||
} catch (...) {
|
||||
PERR("%s: an unhandled exception occurred while trying to show \
|
||||
the VirtualBox pointer", __func__);
|
||||
show_default_pointer();
|
||||
}
|
||||
}
|
||||
|
||||
Main()
|
||||
{
|
||||
/*
|
||||
* 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 { Vbox_pointer::MAX_WIDTH, Vbox_pointer::MAX_HEIGHT,
|
||||
Framebuffer::Mode::RGB565 };
|
||||
|
||||
nitpicker.buffer(mode, true /* use alpha */);
|
||||
|
||||
/* TODO should be read from config */
|
||||
vbox_domains.add("vbox");
|
||||
|
||||
/* register signal handlers */
|
||||
hover_ds.sigh(hover_signal_dispatcher);
|
||||
xray_ds.sigh(xray_signal_dispatcher);
|
||||
shape_ds.sigh(shape_signal_dispatcher);
|
||||
|
||||
nitpicker.enqueue<Nitpicker::Session::Command::To_front>(view);
|
||||
nitpicker.execute();
|
||||
|
||||
/* import initial state */
|
||||
handle_hover();
|
||||
handle_xray();
|
||||
handle_shape();
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
static Domain_name read_string_attribute(Genode::Xml_node const &node,
|
||||
char const *attr,
|
||||
Domain_name const &default_value)
|
||||
{
|
||||
try {
|
||||
char buf[Domain_name::capacity()];
|
||||
node.attribute(attr).value(buf, sizeof(buf));
|
||||
return Domain_name(buf);
|
||||
}
|
||||
catch (...) {
|
||||
return default_value; }
|
||||
_current_pointer_size = pointer_size;
|
||||
}
|
||||
|
||||
|
||||
void Main::handle_hover(unsigned)
|
||||
void Main::_show_default_pointer()
|
||||
{
|
||||
hover_ds.update();
|
||||
if (!hover_ds.is_valid())
|
||||
/* 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 (...) {
|
||||
PERR("%s: could not resize the pointer buffer for %u x %u pixels",
|
||||
__func__, pointer_size.w(), pointer_size.h());
|
||||
return;
|
||||
}
|
||||
|
||||
Genode::Attached_dataspace ds { _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 Main::_show_shape_pointer(Policy *p)
|
||||
{
|
||||
try {
|
||||
_resize_nitpicker_buffer_if_needed(p->shape_size());
|
||||
} catch (...) {
|
||||
PERR("%s: could not resize the pointer buffer for %u x %u pixels",
|
||||
__func__, p->shape_size().w(), p->shape_size().h());
|
||||
throw;
|
||||
}
|
||||
|
||||
Genode::Attached_dataspace ds { _pointer_ds };
|
||||
|
||||
p->draw_shape(ds.local_addr<Genode::Pixel_rgb565>());
|
||||
|
||||
_nitpicker.framebuffer()->refresh(0, 0, p->shape_size().w(), p->shape_size().h());
|
||||
|
||||
Nitpicker::Rect geometry(p->shape_hot(), p->shape_size());
|
||||
_nitpicker.enqueue<Nitpicker::Session::Command::Geometry>(_view, geometry);
|
||||
_nitpicker.execute();
|
||||
|
||||
_default_pointer_visible = false;
|
||||
}
|
||||
|
||||
|
||||
void Main::_update_pointer()
|
||||
{
|
||||
Policy *policy = nullptr;
|
||||
|
||||
if (_xray
|
||||
|| !(policy = _policy_registry.lookup(_hovered_label, _hovered_domain))
|
||||
|| !policy->shape_valid())
|
||||
_show_default_pointer();
|
||||
else
|
||||
try {
|
||||
_show_shape_pointer(policy);
|
||||
} catch (...) { _show_default_pointer(); }
|
||||
}
|
||||
|
||||
|
||||
void Main::_handle_hover(unsigned)
|
||||
{
|
||||
using Vbox_pointer::read_string_attribute;
|
||||
|
||||
_hover_ds.update();
|
||||
if (!_hover_ds.is_valid())
|
||||
return;
|
||||
|
||||
/* read new hover information from nitpicker's hover report */
|
||||
try {
|
||||
Genode::Xml_node node(hover_ds.local_addr<char>());
|
||||
Genode::Xml_node node(_hover_ds.local_addr<char>());
|
||||
|
||||
current_domain = read_string_attribute(node, "domain", Domain_name());
|
||||
String hovered_label = read_string_attribute(node, "label", String());
|
||||
String hovered_domain = read_string_attribute(node, "domain", String());
|
||||
|
||||
/* update pointer if hovered domain or label changed */
|
||||
if (hovered_label != _hovered_label || hovered_domain != _hovered_domain) {
|
||||
_hovered_label = hovered_label;
|
||||
_hovered_domain = hovered_domain;
|
||||
_update_pointer();
|
||||
}
|
||||
}
|
||||
catch (...) {
|
||||
PWRN("could not parse hover report");
|
||||
}
|
||||
|
||||
update_pointer();
|
||||
}
|
||||
|
||||
|
||||
void Main::handle_xray(unsigned)
|
||||
void Main::_handle_xray(unsigned)
|
||||
{
|
||||
xray_ds.update();
|
||||
if (!xray_ds.is_valid())
|
||||
_xray_ds.update();
|
||||
if (!_xray_ds.is_valid())
|
||||
return;
|
||||
|
||||
try {
|
||||
Genode::Xml_node node(xray_ds.local_addr<char>());
|
||||
Genode::Xml_node node(_xray_ds.local_addr<char>());
|
||||
|
||||
xray = node.has_attribute("enabled")
|
||||
&& node.attribute("enabled").has_value("yes");
|
||||
bool xray = node.has_attribute("enabled")
|
||||
&& node.attribute("enabled").has_value("yes");
|
||||
|
||||
/* update pointer if xray status changed */
|
||||
if (xray != _xray) {
|
||||
_xray = xray;
|
||||
_update_pointer();
|
||||
}
|
||||
}
|
||||
catch (...) {
|
||||
PWRN("could not parse xray report");
|
||||
}
|
||||
|
||||
update_pointer();
|
||||
}
|
||||
|
||||
|
||||
void Main::handle_shape(unsigned)
|
||||
void Main::update_pointer(Policy *policy)
|
||||
{
|
||||
shape_ds.update();
|
||||
/* update pointer if shape-changing policy is hovered */
|
||||
if (policy == _policy_registry.lookup(_hovered_label, _hovered_domain))
|
||||
_update_pointer();
|
||||
}
|
||||
|
||||
if (!shape_ds.is_valid())
|
||||
return;
|
||||
|
||||
if (shape_ds.size() < sizeof(Vbox_pointer::Shape_report))
|
||||
return;
|
||||
Main::Main()
|
||||
{
|
||||
/*
|
||||
* 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 { Vbox_pointer::MAX_WIDTH, Vbox_pointer::MAX_HEIGHT,
|
||||
Framebuffer::Mode::RGB565 };
|
||||
|
||||
vbox_pointer_shape_changed = true;
|
||||
_nitpicker.buffer(mode, true /* use alpha */);
|
||||
|
||||
update_pointer();
|
||||
_policy_registry.update(Genode::config()->xml_node());
|
||||
|
||||
/* register signal handlers */
|
||||
_hover_ds.sigh(_hover_signal_dispatcher);
|
||||
_xray_ds.sigh(_xray_signal_dispatcher);
|
||||
|
||||
_nitpicker.enqueue<Nitpicker::Session::Command::To_front>(_view);
|
||||
_nitpicker.execute();
|
||||
|
||||
/* import initial state */
|
||||
_handle_hover();
|
||||
_handle_xray();
|
||||
_update_pointer();
|
||||
}
|
||||
|
||||
|
||||
@ -400,7 +280,7 @@ int main()
|
||||
/* dispatch signals */
|
||||
for (;;) {
|
||||
|
||||
Genode::Signal sig = main.sig_rec.wait_for_signal();
|
||||
Genode::Signal sig = main.signal_receiver().wait_for_signal();
|
||||
Genode::Signal_dispatcher_base *dispatcher =
|
||||
dynamic_cast<Genode::Signal_dispatcher_base *>(sig.context());
|
||||
|
||||
|
229
repos/ports/src/app/vbox_pointer/policy.cc
Normal file
229
repos/ports/src/app/vbox_pointer/policy.cc
Normal file
@ -0,0 +1,229 @@
|
||||
/*
|
||||
* \brief VirtualBox pointer policies implementation
|
||||
* \author Christian Prochaska
|
||||
* \author Christian Helmuth
|
||||
* \date 2015-06-08
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2015 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/attached_rom_dataspace.h>
|
||||
#include <os/attached_ram_dataspace.h>
|
||||
#include <os/pixel_alpha8.h>
|
||||
#include <os/pixel_rgb888.h>
|
||||
#include <os/surface.h>
|
||||
#include <os/texture_rgb888.h>
|
||||
#include <vbox_pointer/dither_painter.h>
|
||||
|
||||
/* local includes */
|
||||
#include "policy.h"
|
||||
|
||||
|
||||
/******************************
|
||||
** Entry in policy registry **
|
||||
******************************/
|
||||
|
||||
class Vbox_pointer::Policy_entry : public Vbox_pointer::Policy,
|
||||
public Genode::List<Policy_entry>::Element
|
||||
{
|
||||
private:
|
||||
|
||||
String _label;
|
||||
String _domain;
|
||||
|
||||
Pointer_updater &_updater;
|
||||
|
||||
Genode::Attached_ram_dataspace _texture_pixel_ds { Genode::env()->ram_session(),
|
||||
Vbox_pointer::MAX_WIDTH *
|
||||
Vbox_pointer::MAX_HEIGHT *
|
||||
sizeof(Genode::Pixel_rgb888) };
|
||||
|
||||
Genode::Attached_ram_dataspace _texture_alpha_ds { Genode::env()->ram_session(),
|
||||
Vbox_pointer::MAX_WIDTH *
|
||||
Vbox_pointer::MAX_HEIGHT };
|
||||
Genode::Attached_rom_dataspace _shape_ds;
|
||||
|
||||
Genode::Signal_dispatcher<Policy_entry> shape_signal_dispatcher {
|
||||
_updater.signal_receiver(), *this, &Policy_entry::_import_shape };
|
||||
|
||||
Nitpicker::Area _shape_size;
|
||||
Nitpicker::Point _shape_hot;
|
||||
|
||||
void _import_shape(unsigned = 0)
|
||||
{
|
||||
using namespace Genode;
|
||||
|
||||
_shape_ds.update();
|
||||
|
||||
if (!_shape_ds.is_valid())
|
||||
return;
|
||||
|
||||
if (_shape_ds.size() < sizeof(Vbox_pointer::Shape_report))
|
||||
return;
|
||||
|
||||
Vbox_pointer::Shape_report *shape_report =
|
||||
_shape_ds.local_addr<Vbox_pointer::Shape_report>();
|
||||
|
||||
if (!shape_report->visible
|
||||
|| shape_report->width == 0 || shape_report->height == 0
|
||||
|| shape_report->width > Vbox_pointer::MAX_WIDTH
|
||||
|| shape_report->height > Vbox_pointer::MAX_HEIGHT) {
|
||||
_shape_size = Nitpicker::Area();
|
||||
_shape_hot = Nitpicker::Point();
|
||||
_updater.update_pointer(this);
|
||||
}
|
||||
|
||||
_shape_size = Nitpicker::Area(shape_report->width, shape_report->height);
|
||||
_shape_hot = Nitpicker::Point(-shape_report->x_hot, -shape_report->y_hot);
|
||||
|
||||
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++) {
|
||||
|
||||
/* convert the shape data from BGRA encoding to RGBA encoding */
|
||||
unsigned char *shape = shape_report->shape;
|
||||
unsigned char *bgra_line = &shape[y * _shape_size.w() * 4];
|
||||
unsigned char rgba_line[_shape_size.w() * 4];
|
||||
for (unsigned int i = 0; i < _shape_size.w() * 4; i += 4) {
|
||||
rgba_line[i + 0] = bgra_line[i + 2];
|
||||
rgba_line[i + 1] = bgra_line[i + 1];
|
||||
rgba_line[i + 2] = bgra_line[i + 0];
|
||||
rgba_line[i + 3] = bgra_line[i + 3];
|
||||
}
|
||||
|
||||
/* import the RGBA-encoded line into the texture */
|
||||
texture.rgba(rgba_line, _shape_size.w(), y);
|
||||
}
|
||||
|
||||
_updater.update_pointer(this);
|
||||
}
|
||||
|
||||
public:
|
||||
|
||||
Policy_entry(String const &label, String const &domain, String const &rom,
|
||||
Pointer_updater &updater)
|
||||
:
|
||||
_label(label), _domain(domain), _updater(updater),
|
||||
_shape_ds(rom.string())
|
||||
{
|
||||
_import_shape();
|
||||
|
||||
_shape_ds.sigh(shape_signal_dispatcher);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return similarity of policy label and the passed label
|
||||
*/
|
||||
Genode::size_t match_label(String const &other) const
|
||||
{
|
||||
if (_label.length() > 1 && other.length() > 1) {
|
||||
/* length of string w/o null byte */
|
||||
Genode::size_t const len = _label.length() - 1;
|
||||
|
||||
if (Genode::strcmp(other.string(), _label.string(), len) == 0)
|
||||
return len;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return if policy domain and passed domain match exactly
|
||||
*/
|
||||
bool match_domain(String const &other) const
|
||||
{
|
||||
return _domain.length() > 1 && _domain == other;
|
||||
}
|
||||
|
||||
/**********************
|
||||
** Policy interface **
|
||||
**********************/
|
||||
|
||||
Nitpicker::Area shape_size() const override { return _shape_size; }
|
||||
Nitpicker::Point shape_hot() const override { return _shape_hot; }
|
||||
|
||||
bool shape_valid() const override { return _shape_size.valid(); }
|
||||
|
||||
void draw_shape(Genode::Pixel_rgb565 *pixel) override
|
||||
{
|
||||
using namespace Genode;
|
||||
|
||||
if (!_shape_size.valid())
|
||||
return;
|
||||
|
||||
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);
|
||||
|
||||
Texture<Pixel_rgb888>
|
||||
texture(_texture_pixel_ds.local_addr<Pixel_rgb888>(),
|
||||
_texture_alpha_ds.local_addr<unsigned char>(),
|
||||
_shape_size);
|
||||
|
||||
Dither_painter::paint(pixel_surface, texture);
|
||||
Dither_painter::paint(alpha_surface, texture);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**************
|
||||
** Registry **
|
||||
**************/
|
||||
|
||||
void Vbox_pointer::Policy_registry::update(Genode::Xml_node config)
|
||||
{
|
||||
/* TODO real update should flush at least */
|
||||
|
||||
try {
|
||||
for (Genode::Xml_node policy = config.sub_node("policy");
|
||||
true; policy = policy.next("policy")) {
|
||||
|
||||
String label = read_string_attribute(policy, "label", String());
|
||||
String domain = read_string_attribute(policy, "domain", String());
|
||||
String rom = read_string_attribute(policy, "rom", String());
|
||||
|
||||
if (!label.valid() && !domain.valid())
|
||||
PWRN("policy does not declare label/domain attribute");
|
||||
else if (!rom.valid())
|
||||
PWRN("policy does not declare shape rom");
|
||||
else
|
||||
insert(new (Genode::env()->heap())
|
||||
Policy_entry(label, domain, rom, _updater));
|
||||
}
|
||||
} catch (...) { }
|
||||
}
|
||||
|
||||
|
||||
Vbox_pointer::Policy * Vbox_pointer::Policy_registry::lookup(String const &label,
|
||||
String const &domain)
|
||||
{
|
||||
/* try label similarity matching first */
|
||||
unsigned similarity = 0;
|
||||
Policy_entry *match = nullptr;
|
||||
for (Policy_entry *p = first(); p; p = p->next()) {
|
||||
unsigned s = p->match_label(label);
|
||||
if (s > similarity) {
|
||||
similarity = s;
|
||||
match = p;
|
||||
}
|
||||
}
|
||||
if (match) return match;
|
||||
|
||||
/* then match domains */
|
||||
for (Policy_entry *p = first(); p; p = p->next())
|
||||
if (p->match_domain(domain))
|
||||
return p;
|
||||
|
||||
return nullptr;
|
||||
}
|
68
repos/ports/src/app/vbox_pointer/policy.h
Normal file
68
repos/ports/src/app/vbox_pointer/policy.h
Normal file
@ -0,0 +1,68 @@
|
||||
/*
|
||||
* \brief VirtualBox pointer policies
|
||||
* \author Christian Helmuth
|
||||
* \date 2015-06-08
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2015 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 _VBOX_POINTER_POLICY_H_
|
||||
#define _VBOX_POINTER_POLICY_H_
|
||||
|
||||
/* Genode includes */
|
||||
#include <os/pixel_rgb565.h>
|
||||
#include <nitpicker_session/nitpicker_session.h>
|
||||
#include <vbox_pointer/shape_report.h>
|
||||
#include <util/list.h>
|
||||
|
||||
/* local includes */
|
||||
#include "util.h"
|
||||
|
||||
|
||||
namespace Vbox_pointer {
|
||||
struct Pointer_updater;
|
||||
struct Policy;
|
||||
struct Policy_entry;
|
||||
struct Policy_registry;
|
||||
}
|
||||
|
||||
|
||||
struct Vbox_pointer::Pointer_updater
|
||||
{
|
||||
virtual void update_pointer(Policy *initiator) = 0;
|
||||
virtual Genode::Signal_receiver & signal_receiver() = 0;
|
||||
};
|
||||
|
||||
|
||||
struct Vbox_pointer::Policy
|
||||
{
|
||||
virtual Nitpicker::Area shape_size() const = 0;
|
||||
virtual Nitpicker::Point shape_hot() const = 0;
|
||||
virtual bool shape_valid() const = 0;
|
||||
|
||||
virtual void draw_shape(Genode::Pixel_rgb565 *pixel) = 0;
|
||||
};
|
||||
|
||||
|
||||
class Vbox_pointer::Policy_registry : private Genode::List<Policy_entry>
|
||||
{
|
||||
private:
|
||||
|
||||
Pointer_updater &_updater;
|
||||
|
||||
public:
|
||||
|
||||
Policy_registry(Pointer_updater &updater)
|
||||
: _updater(updater) { }
|
||||
|
||||
void update(Genode::Xml_node config);
|
||||
|
||||
Policy * lookup(String const &label, String const &domain);
|
||||
};
|
||||
|
||||
#endif /* _VBOX_POINTER_POLICY_H_ */
|
@ -1,3 +1,3 @@
|
||||
TARGET = vbox_pointer
|
||||
SRC_CC = main.cc
|
||||
LIBS += base
|
||||
SRC_CC = main.cc policy.cc
|
||||
LIBS += base config
|
||||
|
42
repos/ports/src/app/vbox_pointer/util.h
Normal file
42
repos/ports/src/app/vbox_pointer/util.h
Normal file
@ -0,0 +1,42 @@
|
||||
/*
|
||||
* \brief VirtualBox pointer utilities
|
||||
* \author Christian Helmuth
|
||||
* \date 2015-06-08
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2015 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 _VBOX_POINTER_UTIL_H_
|
||||
#define _VBOX_POINTER_UTIL_H_
|
||||
|
||||
/* Genode includes */
|
||||
#include <util/xml_node.h>
|
||||
#include <util/string.h>
|
||||
|
||||
|
||||
namespace Vbox_pointer {
|
||||
typedef Genode::String<64> String;
|
||||
|
||||
inline String read_string_attribute(Genode::Xml_node const &node,
|
||||
char const *attr,
|
||||
String const &default_value);
|
||||
}
|
||||
|
||||
|
||||
Vbox_pointer::String Vbox_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(buf);
|
||||
} catch (...) { return default_value; }
|
||||
}
|
||||
|
||||
#endif /* _VBOX_POINTER_UTIL_H_ */
|
210
repos/ports/src/test/vbox_pointer/main.cc
Normal file
210
repos/ports/src/test/vbox_pointer/main.cc
Normal file
@ -0,0 +1,210 @@
|
||||
/*
|
||||
* \brief Pointer shape reporter test
|
||||
* \author Christian Helmuth
|
||||
* \date 2015-06-03
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2015 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.
|
||||
*/
|
||||
|
||||
#include <base/printf.h>
|
||||
#include <util/string.h>
|
||||
#include <os/reporter.h>
|
||||
#include <os/config.h>
|
||||
#include <vbox_pointer/shape_report.h>
|
||||
|
||||
|
||||
static bool const verbose = false;
|
||||
|
||||
|
||||
typedef Genode::String<16> String;
|
||||
|
||||
static String 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(buf);
|
||||
}
|
||||
catch (...) {
|
||||
return default_value; }
|
||||
}
|
||||
|
||||
|
||||
struct Shape
|
||||
{
|
||||
enum { WIDTH = 16, HEIGHT = 16 };
|
||||
|
||||
String const id;
|
||||
unsigned const x_hot;
|
||||
unsigned const y_hot;
|
||||
unsigned char const map[WIDTH*HEIGHT];
|
||||
};
|
||||
|
||||
|
||||
struct Shape_report : Vbox_pointer::Shape_report
|
||||
{
|
||||
Genode::Reporter reporter { "shape", sizeof(Vbox_pointer::Shape_report) };
|
||||
|
||||
Shape_report()
|
||||
:
|
||||
Vbox_pointer::Shape_report{true, 0, 0, Shape::WIDTH, Shape::HEIGHT, { 0 }}
|
||||
{
|
||||
reporter.enabled(true);
|
||||
}
|
||||
|
||||
void report(Shape const &s)
|
||||
{
|
||||
x_hot = s.x_hot;
|
||||
y_hot = s.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[(y*w + x)*4 + 0] = 0xff;
|
||||
shape[(y*w + x)*4 + 1] = 0xff;
|
||||
shape[(y*w + x)*4 + 2] = 0xff;
|
||||
shape[(y*w + x)*4 + 3] = s.map[y*w +x] ? 0xe0 : 0;
|
||||
|
||||
if (verbose)
|
||||
Genode::printf("%c", s.map[y*w +x] ? 'X' : ' ');
|
||||
}
|
||||
if (verbose)
|
||||
Genode::printf("\n");
|
||||
}
|
||||
|
||||
if (verbose)
|
||||
Genode::printf(".%s.%u.%u.\n", s.id.string(), s.x_hot, s.y_hot);
|
||||
|
||||
reporter.report(static_cast<Vbox_pointer::Shape_report *>(this),
|
||||
sizeof(Vbox_pointer::Shape_report));
|
||||
}
|
||||
};
|
||||
|
||||
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()
|
||||
{
|
||||
String const id = read_string_attribute(Genode::config()->xml_node(),
|
||||
"shape", String("arrow"));
|
||||
|
||||
for (Shape const &s : shape)
|
||||
if (s.id == id)
|
||||
return s;
|
||||
|
||||
/* not found -> use first as default */
|
||||
return shape[0];
|
||||
}
|
||||
|
||||
|
||||
int main()
|
||||
{
|
||||
static Shape_report r;
|
||||
|
||||
/* register signal handler for config changes */
|
||||
Genode::Signal_receiver sig_rec;
|
||||
Genode::Signal_context sig_ctx;
|
||||
|
||||
Genode::config()->sigh(sig_rec.manage(&sig_ctx));
|
||||
|
||||
while (true) {
|
||||
r.report(select_shape());
|
||||
sig_rec.wait_for_signal();
|
||||
Genode::config()->reload();
|
||||
}
|
||||
}
|
3
repos/ports/src/test/vbox_pointer/target.mk
Normal file
3
repos/ports/src/test/vbox_pointer/target.mk
Normal file
@ -0,0 +1,3 @@
|
||||
TARGET = test-vbox_pointer
|
||||
SRC_CC = main.cc
|
||||
LIBS = base config
|
Loading…
x
Reference in New Issue
Block a user