275 lines
6.8 KiB
C++
275 lines
6.8 KiB
C++
/*
|
|
* \brief Nitpicker-based virtual framebuffer
|
|
* \author Norman Feske
|
|
* \date 2006-09-21
|
|
*/
|
|
|
|
/*
|
|
* Copyright (C) 2006-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/heap.h>
|
|
#include <base/rpc_server.h>
|
|
#include <base/attached_rom_dataspace.h>
|
|
#include <input/component.h>
|
|
#include <scout/user_state.h>
|
|
#include <scout/nitpicker_graphics_backend.h>
|
|
|
|
#include "framebuffer_window.h"
|
|
#include "services.h"
|
|
|
|
|
|
static Genode::Allocator *_alloc_ptr;
|
|
|
|
void *operator new (__SIZE_TYPE__ n) { return _alloc_ptr->alloc(n); }
|
|
|
|
|
|
void Scout::Launcher::launch() { }
|
|
|
|
|
|
class Background_animator : public Scout::Tick
|
|
{
|
|
private:
|
|
|
|
Framebuffer_window<Scout::Pixel_rgb565> &_fb_win;
|
|
|
|
int _bg_offset = 0;
|
|
|
|
public:
|
|
|
|
/**
|
|
* Constructor
|
|
*/
|
|
Background_animator(Framebuffer_window<Scout::Pixel_rgb565> &fb_win)
|
|
: _fb_win(fb_win) { schedule(20); }
|
|
|
|
/**
|
|
* Tick interface
|
|
*/
|
|
int on_tick() override
|
|
{
|
|
_fb_win.bg_offset(_bg_offset);
|
|
_bg_offset += 2;
|
|
_fb_win.refresh();
|
|
|
|
/* schedule next tick */
|
|
return 1;
|
|
}
|
|
};
|
|
|
|
|
|
/**
|
|
* Animated background
|
|
*/
|
|
static bool config_animate = true;
|
|
static bool config_alpha = true;
|
|
|
|
/**
|
|
* Size and position of virtual frame buffer
|
|
*/
|
|
static unsigned config_fb_width = 500;
|
|
static unsigned config_fb_height = 400;
|
|
static long config_fb_x = 400;
|
|
static long config_fb_y = 260;
|
|
|
|
/**
|
|
* Window title
|
|
*/
|
|
typedef Genode::String<128> Title;
|
|
static Title config_title { "Liquid Framebuffer" };
|
|
|
|
/**
|
|
* Resize handle
|
|
*/
|
|
static bool config_resize_handle = false;
|
|
|
|
/**
|
|
* Window decoration
|
|
*/
|
|
static bool config_decoration = true;
|
|
|
|
/**
|
|
* Parse configuration
|
|
*/
|
|
static void read_config(Genode::Xml_node node)
|
|
{
|
|
config_fb_x = node.attribute_value("xpos", config_fb_x);
|
|
config_fb_y = node.attribute_value("ypos", config_fb_y);
|
|
config_fb_width = node.attribute_value("width", config_fb_width);
|
|
config_fb_height = node.attribute_value("height", config_fb_height);
|
|
config_title = node.attribute_value("title", config_title);
|
|
config_animate = node.attribute_value("animate", true);
|
|
config_decoration = node.attribute_value("decoration", true);
|
|
config_resize_handle = node.attribute_value("resize_handle", true);
|
|
}
|
|
|
|
|
|
/*******************
|
|
** Input handler **
|
|
*******************/
|
|
|
|
struct Input_handler
|
|
{
|
|
GENODE_RPC(Rpc_handle_input, void, handle_input, Scout::Event const &);
|
|
GENODE_RPC_INTERFACE(Rpc_handle_input);
|
|
};
|
|
|
|
|
|
namespace Liquid_fb {
|
|
class Main;
|
|
using namespace Scout;
|
|
using namespace Genode;
|
|
}
|
|
|
|
|
|
class Liquid_fb::Main : public Scout::Event_handler
|
|
{
|
|
private:
|
|
|
|
Env &_env;
|
|
|
|
Heap _heap { _env.ram(), _env.rm() };
|
|
|
|
bool const _global_new_initialized = (_alloc_ptr = &_heap, true);
|
|
|
|
Attached_rom_dataspace _config { _env, "config" };
|
|
|
|
void _process_config()
|
|
{
|
|
try { read_config(_config.xml()); } catch (...) { }
|
|
}
|
|
|
|
bool const _config_processed = (_process_config(), true);
|
|
|
|
/* heuristic for allocating the double-buffer backing store */
|
|
enum { WINBORDER_WIDTH = 10, WINBORDER_HEIGHT = 40 };
|
|
|
|
Nitpicker::Connection _nitpicker { _env };
|
|
|
|
Platform _platform { _env, *_nitpicker.input() };
|
|
|
|
bool const _event_handler_registered = (_platform.event_handler(*this), true);
|
|
|
|
Scout::Area const _max_size { config_fb_width + WINBORDER_WIDTH,
|
|
config_fb_height + WINBORDER_HEIGHT };
|
|
Scout::Point const _initial_position { (int)config_fb_x, (int)config_fb_y };
|
|
Scout::Area const _initial_size = _max_size;
|
|
|
|
Nitpicker_graphics_backend
|
|
_graphics_backend { _env.rm(), _nitpicker, _heap, _max_size,
|
|
_initial_position, _initial_size };
|
|
|
|
Input::Session_component _input_session_component { _env, _env.ram() };
|
|
|
|
bool const _window_content_initialized =
|
|
(init_window_content(_env.ram(), _env.rm(), _heap, _input_session_component,
|
|
config_fb_width, config_fb_height, config_alpha), true);
|
|
|
|
Framebuffer_window<Pixel_rgb565>
|
|
_fb_win { _graphics_backend, window_content(),
|
|
_initial_position, _initial_size, _max_size,
|
|
config_title.string(), config_alpha,
|
|
config_resize_handle, config_decoration };
|
|
|
|
/* create background animator if configured */
|
|
Constructible<Background_animator> _fb_win_bg_anim { };
|
|
void _init_background_animator()
|
|
{
|
|
if (config_animate) {
|
|
_fb_win_bg_anim.construct(_fb_win);
|
|
}
|
|
}
|
|
bool _background_animator_initialized = (_init_background_animator(), true);
|
|
|
|
User_state _user_state { &_fb_win, &_fb_win,
|
|
_initial_position.x(), _initial_position.y() };
|
|
|
|
void _init_fb_win()
|
|
{
|
|
_fb_win.parent(&_user_state);
|
|
_fb_win.content_geometry(config_fb_x, config_fb_y,
|
|
config_fb_width, config_fb_height);
|
|
}
|
|
|
|
bool _fb_win_initialized = (_init_fb_win(), true);
|
|
|
|
bool _services_initialized = (init_services(_env, _input_session_component), true);
|
|
|
|
Genode::uint64_t _curr_time = _platform.timer_ticks();
|
|
Genode::uint64_t _old_time = _curr_time;
|
|
|
|
void _handle_config()
|
|
{
|
|
_config.update();
|
|
|
|
/* keep the current values by default */
|
|
config_fb_x = _fb_win.view_x();
|
|
config_fb_y = _fb_win.view_y();
|
|
config_fb_width = _fb_win.view_w();
|
|
config_fb_height = _fb_win.view_h();
|
|
|
|
try { read_config(_config.xml()); } catch (...) { }
|
|
|
|
_fb_win.name(config_title.string());
|
|
_fb_win.config_alpha(config_alpha);
|
|
_fb_win.config_resize_handle(config_resize_handle);
|
|
_fb_win.config_decoration(config_decoration);
|
|
|
|
/* must get called after 'config_decoration()' */
|
|
_fb_win.content_geometry(config_fb_x, config_fb_y,
|
|
config_fb_width, config_fb_height);
|
|
_user_state.update_view_offset();
|
|
}
|
|
|
|
Signal_handler<Main> _config_handler {
|
|
_env.ep(), *this, &Main::_handle_config };
|
|
|
|
public:
|
|
|
|
void handle_event(Scout::Event const &event) override
|
|
{
|
|
using Scout::Event;
|
|
|
|
Event ev = event;
|
|
|
|
if (ev.type != Event::WHEEL)
|
|
ev.mouse_position = ev.mouse_position - _user_state.view_position();
|
|
|
|
/* direct all keyboard events to the window content */
|
|
if ((ev.type == Event::PRESS || ev.type == Event::RELEASE)
|
|
&& (ev.code != Event::BTN_LEFT))
|
|
window_content()->handle_event(ev);
|
|
else
|
|
_user_state.handle_event(ev);
|
|
|
|
if (ev.type == Event::TIMER) {
|
|
Scout::Tick::handle(_platform.timer_ticks());
|
|
}
|
|
|
|
/* perform periodic redraw */
|
|
_curr_time = _platform.timer_ticks();
|
|
if ((_curr_time - _old_time > 20) || (_curr_time < _old_time)) {
|
|
_old_time = _curr_time;
|
|
_fb_win.process_redraw();
|
|
}
|
|
}
|
|
|
|
Main(Env &env) : _env(env)
|
|
{
|
|
_config.sigh(_config_handler);
|
|
}
|
|
};
|
|
|
|
|
|
void Component::construct(Genode::Env &env)
|
|
{
|
|
/* XXX execute constructors of global statics */
|
|
env.exec_static_constructors();
|
|
|
|
static Liquid_fb::Main main(env);
|
|
}
|