Window-resize support for liquid_fb

Related to #740.
This commit is contained in:
Norman Feske 2013-05-22 19:24:20 +02:00
parent fbbd2018bb
commit cf9eedca47
6 changed files with 221 additions and 71 deletions

View File

@ -86,9 +86,10 @@ class Texture_rgb565 : public Canvas::Texture
{
private:
int _w, _h; /* size of texture */
unsigned char *_alpha; /* alpha channel */
Pixel_rgb565 *_pixel; /* pixel data */
int _w, _h; /* size of texture */
unsigned char *_alpha; /* alpha channel */
Pixel_rgb565 *_pixel; /* pixel data */
bool _preallocated;
public:
@ -96,23 +97,25 @@ class Texture_rgb565 : public Canvas::Texture
* Constructor
*/
Texture_rgb565(int w, int h)
{
_w = w;
_h = h;
_alpha = (unsigned char *)scout_malloc(w*h);
_pixel = (Pixel_rgb565 *)scout_malloc(w*h*sizeof(Pixel_rgb565));
}
:
_w(w), _h(h),
_alpha((unsigned char *)scout_malloc(w*h)),
_pixel((Pixel_rgb565 *)scout_malloc(w*h*sizeof(Pixel_rgb565))),
_preallocated(false)
{ }
Texture_rgb565(Pixel_rgb565 *pixel, unsigned char *alpha, int w, int h):
_w(w), _h(h), _alpha(alpha), _pixel(pixel) { }
_w(w), _h(h), _alpha(alpha), _pixel(pixel), _preallocated(true) { }
/**
* Destructor
*/
~Texture_rgb565()
{
scout_free(_alpha);
scout_free(_pixel);
if (!_preallocated) {
scout_free(_alpha);
scout_free(_pixel);
}
_w = _h = 0;
}

View File

@ -164,6 +164,11 @@ class Element
*/
virtual void format_fixed_width(int w) { }
/**
* Format element and all child elements to specified width and height
*/
virtual void format_fixed_size(int w, int h) { }
/**
* Draw function
*

View File

@ -17,10 +17,13 @@
#include "window.h"
#include "titlebar.h"
#include "sky_texture.h"
#include "fade_icon.h"
#define TITLEBAR_RGBA _binary_titlebar_rgba_start
#define SIZER_RGBA _binary_sizer_rgba_start
extern unsigned char TITLEBAR_RGBA[];
extern unsigned char SIZER_RGBA[];
template <typename PT>
@ -39,7 +42,9 @@ class Framebuffer_window : public Window
Titlebar<PT> _titlebar;
Sky_texture<PT, 512, 512> _bg_texture;
int _bg_offset;
Fade_icon<PT, 32, 32> _sizer;
Element *_content;
bool _config_alpha;
public:
@ -49,7 +54,8 @@ class Framebuffer_window : public Window
Framebuffer_window(Platform *pf,
Redraw_manager *redraw,
Element *content,
const char *name)
const char *name,
bool config_alpha)
:
Window(pf, redraw, content->min_w() + 2, content->min_h() + 1 + _TH),
_bg_offset(0), _content(content)
@ -59,8 +65,14 @@ class Framebuffer_window : public Window
_titlebar.text(name);
_titlebar.event_handler(new Mover_event_handler(this));
/* resize handle */
_sizer.rgba(SIZER_RGBA);
_sizer.event_handler(new Sizer_event_handler(this));
_sizer.alpha(100);
append(&_titlebar);
append(_content);
append(&_sizer);
_min_w = max_w();
_min_h = max_h();
@ -71,10 +83,23 @@ class Framebuffer_window : public Window
*/
void format(int w, int h)
{
w = (w > max_w()) ? max_w() : w;
h = (h > max_h()) ? max_h() : h;
_w = w;
_h = h;
Parent_element::_format_children(1, w);
int y = 0;
_titlebar.format_fixed_width(w);
_titlebar.geometry(1, y, _titlebar.min_w(), _titlebar.min_h());
y += _titlebar.min_h();
int const content_h = (h > y + 1) ? (h - y - 1) : 0;
int const content_w = w - 2;
_content->format_fixed_size(content_w, content_h);
_content->geometry(1, y, content_w, content_h);
_sizer.geometry(_w - 32, _h - 32, 32, 32);
pf()->view_geometry(pf()->vx(), pf()->vy(), _w, _h);
redraw()->size(_w, _h);
@ -91,7 +116,8 @@ class Framebuffer_window : public Window
*/
void draw(Canvas *c, int x, int y)
{
_bg_texture.draw(c, 0, - _bg_offset);
if (_config_alpha)
_bg_texture.draw(c, 0, - _bg_offset);
::Parent_element::draw(c, x, y);

View File

@ -162,7 +162,7 @@ int main(int argc, char **argv)
/* create instance of browser window */
static Framebuffer_window<Pixel_rgb565>
fb_win(&pf, &redraw, window_content(), config_title);
fb_win(&pf, &redraw, window_content(), config_title, config_alpha);
if (config_animate) {
static Background_animator fb_win_bg_anim(&fb_win);
@ -181,8 +181,11 @@ int main(int argc, char **argv)
Event ev;
unsigned long curr_time, old_time;
curr_time = old_time = pf.timer_ticks();
lock_window_content();
do {
unlock_window_content();
pf.get_event(&ev);
lock_window_content();
if (ev.type != Event::WHEEL) {
ev.mx -= user_state.vx();

View File

@ -90,15 +90,21 @@ class Window_content : public Element
{
private:
Event_queue *_ev_queue;
int _omx, _omy;
Element *_element;
Genode::Lock &_lock;
Event_queue *_ev_queue;
int _omx, _omy;
Element *_element;
public:
Content_event_handler(Event_queue *ev_queue, Element *element):
_ev_queue(ev_queue), _element(element) { }
Content_event_handler(Event_queue *ev_queue, Element *element,
Genode::Lock &lock)
:
_lock(lock), _ev_queue(ev_queue), _element(element) { }
/*
* Called from main program with taken lock for window content
*/
void handle(Event &ev)
{
int mx = ev.mx - _element->abs_x();
@ -124,60 +130,143 @@ class Window_content : public Element
}
};
unsigned _fb_w, _fb_h;
Genode::Attached_ram_dataspace _fb_ds;
Pixel_rgb565 *_pixel;
unsigned char *_alpha;
Texture_rgb565 _fb_texture;
Content_event_handler _ev_handler;
struct Fb_texture
{
unsigned w, h;
Genode::Attached_ram_dataspace ds;
Pixel_rgb565 *pixel;
unsigned char *alpha;
Texture_rgb565 texture;
Fb_texture(unsigned w, unsigned h, bool config_alpha)
:
w(w), h(h),
ds(Genode::env()->ram_session(), w*h*sizeof(Pixel_rgb565)),
pixel(ds.local_addr<Pixel_rgb565>()),
alpha((unsigned char *)Genode::env()->heap()->alloc(w*h)),
texture(pixel, alpha, w, h)
{
int alpha_min = config_alpha ? 0 : 255;
/* init alpha channel */
for (unsigned y = 0; y < h; y++)
for (unsigned x = 0; x < w; x++) {
int v = (x * y + (w*h)/4) / w;
v = v + (x + y)/2;
int a = v & 0xff;
if (v & 0x100)
a = 255 - a;
a += (dither_matrix[y % dither_size][x % dither_size] - 127) >> 4;
alpha[y*w + x] = Genode::max(alpha_min, Genode::min(a, 255));
}
}
~Fb_texture()
{
Genode::env()->heap()->free(alpha, w*h);
}
};
Genode::Lock _lock;
bool _config_alpha;
Content_event_handler _ev_handler;
Fb_texture *_fb;
unsigned _new_w, _new_h;
Genode::Signal_context_capability _mode_sigh;
bool _wait_for_refresh;
public:
Window_content(unsigned fb_w, unsigned fb_h, Event_queue *ev_queue,
bool config_alpha)
:
_fb_w(fb_w), _fb_h(fb_h),
_fb_ds(Genode::env()->ram_session(), _fb_w*_fb_h*sizeof(Pixel_rgb565)),
_pixel(_fb_ds.local_addr<Pixel_rgb565>()),
_alpha((unsigned char *)Genode::env()->heap()->alloc(_fb_w*_fb_h)),
_fb_texture(_pixel, _alpha, _fb_w, _fb_h),
_ev_handler(ev_queue, this)
_config_alpha(config_alpha),
_ev_handler(ev_queue, this, _lock),
_fb(new (Genode::env()->heap()) Fb_texture(fb_w, fb_h, _config_alpha)),
_new_w(fb_w), _new_h(fb_h),
_wait_for_refresh(false)
{
_min_w = _fb_w;
_min_h = _fb_h;
int alpha_min = config_alpha ? 0 : 255;
/* init alpha channel */
for (unsigned y = 0; y < _fb_h; y++)
for (unsigned x = 0; x < _fb_w; x++) {
int v = (x * y + (_fb_w*_fb_h)/4) / _fb_w;
v = v + (x + y)/2;
int a = v & 0xff;
if (v & 0x100)
a = 255 - a;
a += (dither_matrix[y % dither_size][x % dither_size] - 127) >> 4;
_alpha[y*_fb_w + x] = Genode::max(alpha_min, Genode::min(a, 255));
}
_min_w = _fb->w;
_min_h = _fb->h;
event_handler(&_ev_handler);
}
/**
* Accessors
/*
* Accessors, called by the RPC entrypoint. Hence, the need for
* locking.
*/
Genode::Dataspace_capability fb_ds_cap() { return _fb_ds.cap(); }
unsigned fb_w() { return _fb_w; }
unsigned fb_h() { return _fb_h; }
Genode::Dataspace_capability fb_ds_cap() {
Genode::Lock::Guard guard(_lock);
return _fb->ds.cap();
}
unsigned fb_w() {
Genode::Lock::Guard guard(_lock);
return _fb->w;
}
unsigned fb_h() {
Genode::Lock::Guard guard(_lock);
return _fb->h;
}
void mode_sigh(Genode::Signal_context_capability sigh)
{
Genode::Lock::Guard guard(_lock);
_mode_sigh = sigh;
}
void realloc_framebuffer()
{
Genode::Lock::Guard guard(_lock);
/* skip reallocation if size has not changed */
if (_new_w == _fb->w && _new_h == _fb->h)
return;
Genode::destroy(Genode::env()->heap(), _fb);
_fb = new (Genode::env()->heap())
Fb_texture(_new_w, _new_h, _config_alpha);
/*
* Suppress drawing of the texture until we received the next
* refresh call from the client. This way, we avoid flickering
* artifacts while continuously resizing the window.
*/
_wait_for_refresh = true;
}
void client_called_refresh() { _wait_for_refresh = false; }
/**
* Element interface
*
* Called indirectly by the Content_event_handler thread, which has
* already taken the lock.
*/
void draw(Canvas *c, int x, int y) {
c->draw_texture(&_fb_texture, _x + x, _y + y); }
void draw(Canvas *c, int x, int y)
{
if (!_wait_for_refresh)
c->draw_texture(&_fb->texture, _x + x, _y + y);
}
void format_fixed_size(int w, int h)
{
_new_w = w, _new_h = h;
/* notify framebuffer client about mode change */
if (_mode_sigh.valid())
Genode::Signal_transmitter(_mode_sigh).submit();
}
void lock() { _lock.lock(); }
void unlock() { _lock.unlock(); }
};
@ -185,6 +274,9 @@ static Window_content *_window_content;
Element *window_content() { return _window_content; }
void lock_window_content() { _window_content->lock(); }
void unlock_window_content() { _window_content->unlock(); }
/***********************************************
** Implementation of the framebuffer service **
@ -194,39 +286,58 @@ namespace Framebuffer
{
class Session_component : public Genode::Rpc_object<Session>
{
private:
Window_content &_window_content;
public:
Genode::Dataspace_capability dataspace() {
return _window_content->fb_ds_cap(); }
Session_component(Window_content &window_content)
: _window_content(window_content) { }
void release() { }
Genode::Dataspace_capability dataspace() {
return _window_content.fb_ds_cap(); }
void release() {
_window_content.realloc_framebuffer(); }
Mode mode() const
{
return Mode(_window_content->fb_w(), _window_content->fb_h(),
return Mode(_window_content.fb_w(), _window_content.fb_h(),
Mode::RGB565);
}
void mode_sigh(Genode::Signal_context_capability) { }
void mode_sigh(Genode::Signal_context_capability sigh) {
_window_content.mode_sigh(sigh); }
void refresh(int x, int y, int w, int h) {
window_content()->redraw_area(x, y, w, h); }
void refresh(int x, int y, int w, int h)
{
_window_content.client_called_refresh();
_window_content.redraw_area(x, y, w, h);
}
};
class Root : public Genode::Root_component<Session_component>
{
private:
Window_content &_window_content;
protected:
Session_component *_create_session(const char *args) {
PDBG("creating framebuffer session");
return new (md_alloc()) Session_component(); }
return new (md_alloc()) Session_component(_window_content); }
public:
Root(Genode::Rpc_entrypoint *session_ep,
Genode::Allocator *md_alloc)
: Genode::Root_component<Session_component>(session_ep, md_alloc) { }
Genode::Allocator *md_alloc,
Window_content &window_content)
:
Genode::Root_component<Session_component>(session_ep, md_alloc),
_window_content(window_content)
{ }
};
}
@ -248,7 +359,7 @@ void init_services(unsigned fb_w, unsigned fb_h, bool config_alpha)
/*
* Let the entry point serve the framebuffer and input root interfaces
*/
static Framebuffer::Root fb_root(&ep, env()->heap());
static Framebuffer::Root fb_root(&ep, env()->heap(), content);
static Input::Root input_root(&ep, env()->heap());
/*

View File

@ -19,5 +19,7 @@
extern Element *window_content();
extern void init_services(unsigned fb_w, unsigned fb_h, bool config_alpha);
extern void lock_window_content();
extern void unlock_window_content();
#endif