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

View File

@ -164,6 +164,11 @@ class Element
*/ */
virtual void format_fixed_width(int w) { } 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 * Draw function
* *

View File

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

View File

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

View File

@ -90,15 +90,21 @@ class Window_content : public Element
{ {
private: private:
Event_queue *_ev_queue; Genode::Lock &_lock;
int _omx, _omy; Event_queue *_ev_queue;
Element *_element; int _omx, _omy;
Element *_element;
public: public:
Content_event_handler(Event_queue *ev_queue, Element *element): Content_event_handler(Event_queue *ev_queue, Element *element,
_ev_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) void handle(Event &ev)
{ {
int mx = ev.mx - _element->abs_x(); int mx = ev.mx - _element->abs_x();
@ -124,60 +130,143 @@ class Window_content : public Element
} }
}; };
unsigned _fb_w, _fb_h; struct Fb_texture
Genode::Attached_ram_dataspace _fb_ds; {
Pixel_rgb565 *_pixel; unsigned w, h;
unsigned char *_alpha; Genode::Attached_ram_dataspace ds;
Texture_rgb565 _fb_texture; Pixel_rgb565 *pixel;
Content_event_handler _ev_handler; 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: public:
Window_content(unsigned fb_w, unsigned fb_h, Event_queue *ev_queue, Window_content(unsigned fb_w, unsigned fb_h, Event_queue *ev_queue,
bool config_alpha) bool config_alpha)
: :
_fb_w(fb_w), _fb_h(fb_h), _config_alpha(config_alpha),
_fb_ds(Genode::env()->ram_session(), _fb_w*_fb_h*sizeof(Pixel_rgb565)), _ev_handler(ev_queue, this, _lock),
_pixel(_fb_ds.local_addr<Pixel_rgb565>()), _fb(new (Genode::env()->heap()) Fb_texture(fb_w, fb_h, _config_alpha)),
_alpha((unsigned char *)Genode::env()->heap()->alloc(_fb_w*_fb_h)), _new_w(fb_w), _new_h(fb_h),
_fb_texture(_pixel, _alpha, _fb_w, _fb_h), _wait_for_refresh(false)
_ev_handler(ev_queue, this)
{ {
_min_w = _fb_w; _min_w = _fb->w;
_min_h = _fb_h; _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));
}
event_handler(&_ev_handler); 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; } Genode::Dataspace_capability fb_ds_cap() {
unsigned fb_h() { return _fb_h; } 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 * Element interface
*
* Called indirectly by the Content_event_handler thread, which has
* already taken the lock.
*/ */
void draw(Canvas *c, int x, int y) { void draw(Canvas *c, int x, int y)
c->draw_texture(&_fb_texture, _x + x, _y + 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; } 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 ** ** Implementation of the framebuffer service **
@ -194,39 +286,58 @@ namespace Framebuffer
{ {
class Session_component : public Genode::Rpc_object<Session> class Session_component : public Genode::Rpc_object<Session>
{ {
private:
Window_content &_window_content;
public: public:
Genode::Dataspace_capability dataspace() { Session_component(Window_content &window_content)
return _window_content->fb_ds_cap(); } : _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 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); 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) { void refresh(int x, int y, int w, int h)
window_content()->redraw_area(x, y, w, h); } {
_window_content.client_called_refresh();
_window_content.redraw_area(x, y, w, h);
}
}; };
class Root : public Genode::Root_component<Session_component> class Root : public Genode::Root_component<Session_component>
{ {
private:
Window_content &_window_content;
protected: protected:
Session_component *_create_session(const char *args) { Session_component *_create_session(const char *args) {
PDBG("creating framebuffer session"); return new (md_alloc()) Session_component(_window_content); }
return new (md_alloc()) Session_component(); }
public: public:
Root(Genode::Rpc_entrypoint *session_ep, Root(Genode::Rpc_entrypoint *session_ep,
Genode::Allocator *md_alloc) Genode::Allocator *md_alloc,
: Genode::Root_component<Session_component>(session_ep, 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 * 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()); static Input::Root input_root(&ep, env()->heap());
/* /*

View File

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