decorator: make window-layout updates more robust
This patch improves the window decorators in the following respects: * Strict warnings are enabled now. * The use of the 'List_model' makes the application of window- layout changes more robust. This is particularly the case for the restacking of windows. * Display-mode changes are now supported by both decorators. Issue #3094
This commit is contained in:
parent
f7d33010e5
commit
56cb1885bb
|
@ -47,7 +47,7 @@ namespace Decorator {
|
||||||
/**
|
/**
|
||||||
* Abstract interface of graphics back end
|
* Abstract interface of graphics back end
|
||||||
*/
|
*/
|
||||||
struct Decorator::Canvas_base
|
struct Decorator::Canvas_base : Interface
|
||||||
{
|
{
|
||||||
virtual Rect clip() const = 0;
|
virtual Rect clip() const = 0;
|
||||||
virtual void clip(Rect) = 0;
|
virtual void clip(Rect) = 0;
|
||||||
|
|
|
@ -82,6 +82,12 @@ class Decorator::Config
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Noncopyable
|
||||||
|
*/
|
||||||
|
Config(Config const &);
|
||||||
|
Config & operator = (Config const &);
|
||||||
|
|
||||||
Genode::Allocator &_alloc;
|
Genode::Allocator &_alloc;
|
||||||
|
|
||||||
Reconstructible<Genode::Buffered_xml> _buffered_config;
|
Reconstructible<Genode::Buffered_xml> _buffered_config;
|
||||||
|
|
|
@ -41,15 +41,40 @@ struct Decorator::Main : Window_factory_base
|
||||||
|
|
||||||
Nitpicker::Connection _nitpicker { _env };
|
Nitpicker::Connection _nitpicker { _env };
|
||||||
|
|
||||||
Framebuffer::Mode _mode = { _nitpicker.mode() };
|
struct Canvas
|
||||||
|
{
|
||||||
|
Framebuffer::Mode const mode;
|
||||||
|
Attached_dataspace fb_ds;
|
||||||
|
Decorator::Canvas<Pixel_rgb565> canvas;
|
||||||
|
|
||||||
Attached_dataspace _fb_ds = { _env.rm(),
|
Canvas(Env &env, Nitpicker::Connection &nitpicker)
|
||||||
(_nitpicker.buffer(_mode, false),
|
:
|
||||||
_nitpicker.framebuffer()->dataspace()) };
|
mode(nitpicker.mode()),
|
||||||
|
fb_ds(env.rm(),
|
||||||
|
(nitpicker.buffer(mode, false), nitpicker.framebuffer()->dataspace())),
|
||||||
|
canvas(fb_ds.local_addr<Pixel_rgb565>(),
|
||||||
|
Area(mode.width(), mode.height()),
|
||||||
|
env.ram(), env.rm())
|
||||||
|
{ }
|
||||||
|
};
|
||||||
|
|
||||||
Canvas<Pixel_rgb565> _canvas = { _fb_ds.local_addr<Pixel_rgb565>(),
|
Reconstructible<Canvas> _canvas { _env, _nitpicker };
|
||||||
Area(_mode.width(), _mode.height()),
|
|
||||||
_env.ram(), _env.rm() };
|
Signal_handler<Main> _mode_handler { _env.ep(), *this, &Main::_handle_mode };
|
||||||
|
|
||||||
|
void _handle_mode()
|
||||||
|
{
|
||||||
|
_canvas.construct(_env, _nitpicker);
|
||||||
|
|
||||||
|
_window_stack.mark_as_dirty(Rect(Point(0, 0),
|
||||||
|
Area(_canvas->mode.width(),
|
||||||
|
_canvas->mode.height())));
|
||||||
|
|
||||||
|
Dirty_rect dirty = _window_stack.draw(_canvas->canvas);
|
||||||
|
|
||||||
|
dirty.flush([&] (Rect const &r) {
|
||||||
|
_nitpicker.framebuffer()->refresh(r.x1(), r.y1(), r.w(), r.h()); });
|
||||||
|
}
|
||||||
|
|
||||||
Window_stack _window_stack = { *this };
|
Window_stack _window_stack = { *this };
|
||||||
|
|
||||||
|
@ -73,7 +98,7 @@ struct Decorator::Main : Window_factory_base
|
||||||
|
|
||||||
Attached_rom_dataspace _pointer { _env, "pointer" };
|
Attached_rom_dataspace _pointer { _env, "pointer" };
|
||||||
|
|
||||||
Window_base::Hover _hover;
|
Window_base::Hover _hover { };
|
||||||
|
|
||||||
Reporter _hover_reporter = { _env, "hover" };
|
Reporter _hover_reporter = { _env, "hover" };
|
||||||
|
|
||||||
|
@ -81,7 +106,7 @@ struct Decorator::Main : Window_factory_base
|
||||||
|
|
||||||
Reporter _decorator_margins_reporter = { _env, "decorator_margins" };
|
Reporter _decorator_margins_reporter = { _env, "decorator_margins" };
|
||||||
|
|
||||||
Animator _animator;
|
Animator _animator { };
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Process the update every 'frame_period' nitpicker sync signals. The
|
* Process the update every 'frame_period' nitpicker sync signals. The
|
||||||
|
@ -124,6 +149,8 @@ struct Decorator::Main : Window_factory_base
|
||||||
_config.sigh(_config_handler);
|
_config.sigh(_config_handler);
|
||||||
_handle_config();
|
_handle_config();
|
||||||
|
|
||||||
|
_nitpicker.mode_sigh(_mode_handler);
|
||||||
|
|
||||||
_window_layout.sigh(_window_layout_handler);
|
_window_layout.sigh(_window_layout_handler);
|
||||||
_pointer.sigh(_pointer_handler);
|
_pointer.sigh(_pointer_handler);
|
||||||
|
|
||||||
|
@ -264,14 +291,14 @@ void Decorator::Main::_handle_nitpicker_sync()
|
||||||
|
|
||||||
bool model_updated = false;
|
bool model_updated = false;
|
||||||
|
|
||||||
|
auto flush_window_stack_changes = [&] () { };
|
||||||
|
|
||||||
if (_window_layout_update_needed && _window_layout.valid()) {
|
if (_window_layout_update_needed && _window_layout.valid()) {
|
||||||
|
|
||||||
try {
|
try {
|
||||||
Xml_node xml(_window_layout.local_addr<char>(),
|
Xml_node xml(_window_layout.local_addr<char>(),
|
||||||
_window_layout.size());
|
_window_layout.size());
|
||||||
|
|
||||||
auto flush_window_stack_changes = [&] () { };
|
|
||||||
|
|
||||||
_window_stack.update_model(xml, flush_window_stack_changes);
|
_window_stack.update_model(xml, flush_window_stack_changes);
|
||||||
|
|
||||||
model_updated = true;
|
model_updated = true;
|
||||||
|
@ -288,9 +315,10 @@ void Decorator::Main::_handle_nitpicker_sync()
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* An error occured with processing the XML model. Flush the
|
* An error occured with processing the XML model. Flush the
|
||||||
* internal representation.
|
* internal representation with an empty window layout.
|
||||||
*/
|
*/
|
||||||
_window_stack.flush();
|
_window_stack.update_model(Xml_node("<window_layout/>"),
|
||||||
|
flush_window_stack_changes);
|
||||||
}
|
}
|
||||||
|
|
||||||
_window_layout_update_needed = false;
|
_window_layout_update_needed = false;
|
||||||
|
@ -309,7 +337,7 @@ void Decorator::Main::_handle_nitpicker_sync()
|
||||||
if (!model_updated && !windows_animated)
|
if (!model_updated && !windows_animated)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
Dirty_rect dirty = _window_stack.draw(_canvas);
|
Dirty_rect dirty = _window_stack.draw(_canvas->canvas);
|
||||||
|
|
||||||
_window_stack.update_nitpicker_views();
|
_window_stack.update_nitpicker_views();
|
||||||
|
|
||||||
|
|
|
@ -8,5 +8,3 @@ INC_DIR += $(PRG_DIR)
|
||||||
|
|
||||||
vpath %.tff $(TFF_DIR)
|
vpath %.tff $(TFF_DIR)
|
||||||
vpath %.rgba $(PRG_DIR)
|
vpath %.rgba $(PRG_DIR)
|
||||||
|
|
||||||
CC_CXX_WARN_STRICT =
|
|
||||||
|
|
|
@ -94,7 +94,7 @@ void Decorator::Window::draw(Decorator::Canvas_base &canvas,
|
||||||
Point right_pos = controls_rect.p1() + Point(controls_rect.w() - _icon_size.w(), 0);
|
Point right_pos = controls_rect.p1() + Point(controls_rect.w() - _icon_size.w(), 0);
|
||||||
|
|
||||||
if (_controls.num() > 0) {
|
if (_controls.num() > 0) {
|
||||||
for (unsigned i = _controls.num() - 1; i >= 0; i--) {
|
for (int i = _controls.num() - 1; i >= 0; i--) {
|
||||||
|
|
||||||
Control control = _controls.control(i);
|
Control control = _controls.control(i);
|
||||||
|
|
||||||
|
@ -193,23 +193,10 @@ void Decorator::Window::draw(Decorator::Canvas_base &canvas,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
bool Decorator::Window::update(Genode::Xml_node window_node, bool new_top_most)
|
bool Decorator::Window::update(Genode::Xml_node window_node)
|
||||||
{
|
{
|
||||||
bool updated = false;
|
bool updated = false;
|
||||||
|
|
||||||
/*
|
|
||||||
* Detect the need to bring the window to the top of the global
|
|
||||||
* view stack.
|
|
||||||
*/
|
|
||||||
unsigned const topped_cnt = attribute(window_node, "topped", 0UL);
|
|
||||||
if (topped_cnt != _topped_cnt || new_top_most) {
|
|
||||||
|
|
||||||
_topped_cnt = topped_cnt;
|
|
||||||
|
|
||||||
stack(Nitpicker::Session::View_handle());
|
|
||||||
updated |= true;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Detect geometry changes
|
* Detect geometry changes
|
||||||
*/
|
*/
|
||||||
|
@ -276,13 +263,13 @@ bool Decorator::Window::update(Genode::Xml_node window_node, bool new_top_most)
|
||||||
Xml_node highlight = window_node.sub_node("highlight");
|
Xml_node highlight = window_node.sub_node("highlight");
|
||||||
|
|
||||||
for (unsigned i = 0; i < num_elements(); i++)
|
for (unsigned i = 0; i < num_elements(); i++)
|
||||||
updated |= _apply_state(_elements[i].type(), _focused,
|
updated |= _apply_state(_elements[i].type(),
|
||||||
highlight.has_sub_node(_elements[i].type_name()));
|
highlight.has_sub_node(_elements[i].type_name()));
|
||||||
} catch (...) {
|
} catch (...) {
|
||||||
|
|
||||||
/* window node has no "highlight" sub node, reset highlighting */
|
/* window node has no "highlight" sub node, reset highlighting */
|
||||||
for (unsigned i = 0; i < num_elements(); i++)
|
for (unsigned i = 0; i < num_elements(); i++)
|
||||||
updated |= _apply_state(_elements[i].type(), _focused, false);
|
updated |= _apply_state(_elements[i].type(), false);
|
||||||
}
|
}
|
||||||
|
|
||||||
return updated;
|
return updated;
|
||||||
|
@ -354,7 +341,7 @@ Decorator::Window_base::Hover Decorator::Window::hover(Point abs_pos) const
|
||||||
Point pos = titlbar_pos +
|
Point pos = titlbar_pos +
|
||||||
Point(area.w() - _border_size - _icon_size.w(), 0);
|
Point(area.w() - _border_size - _icon_size.w(), 0);
|
||||||
|
|
||||||
for (unsigned i = _controls.num() - 1; i >= 0; i--) {
|
for (int i = _controls.num() - 1; i >= 0; i--) {
|
||||||
|
|
||||||
/* controls end when we reach the title */
|
/* controls end when we reach the title */
|
||||||
if (_controls.control(i).type() == Control::TYPE_TITLE)
|
if (_controls.control(i).type() == Control::TYPE_TITLE)
|
||||||
|
|
|
@ -37,12 +37,11 @@ class Decorator::Window : public Window_base
|
||||||
*/
|
*/
|
||||||
bool _nitpicker_views_up_to_date = false;
|
bool _nitpicker_views_up_to_date = false;
|
||||||
|
|
||||||
Nitpicker::Session::View_handle _neighbor;
|
|
||||||
|
|
||||||
struct Nitpicker_view
|
struct Nitpicker_view
|
||||||
{
|
{
|
||||||
Nitpicker::Session_client &_nitpicker;
|
Nitpicker::Session_client &_nitpicker;
|
||||||
Nitpicker::Session::View_handle _handle { _nitpicker.create_view() };
|
|
||||||
|
View_handle _handle { _nitpicker.create_view() };
|
||||||
|
|
||||||
typedef Nitpicker::Session::Command Command;
|
typedef Nitpicker::Session::Command Command;
|
||||||
|
|
||||||
|
@ -66,13 +65,18 @@ class Decorator::Window : public Window_base
|
||||||
_nitpicker.destroy_view(_handle);
|
_nitpicker.destroy_view(_handle);
|
||||||
}
|
}
|
||||||
|
|
||||||
Nitpicker::Session::View_handle handle() const { return _handle; }
|
View_handle handle() const { return _handle; }
|
||||||
|
|
||||||
void stack(Nitpicker::Session::View_handle neighbor)
|
void stack(View_handle neighbor)
|
||||||
{
|
{
|
||||||
_nitpicker.enqueue<Command::To_front>(_handle, neighbor);
|
_nitpicker.enqueue<Command::To_front>(_handle, neighbor);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void stack_back_most()
|
||||||
|
{
|
||||||
|
_nitpicker.enqueue<Command::To_back>(_handle, View_handle());
|
||||||
|
}
|
||||||
|
|
||||||
void place(Rect rect)
|
void place(Rect rect)
|
||||||
{
|
{
|
||||||
_nitpicker.enqueue<Command::Geometry>(_handle, rect);
|
_nitpicker.enqueue<Command::Geometry>(_handle, rect);
|
||||||
|
@ -96,7 +100,7 @@ class Decorator::Window : public Window_base
|
||||||
|
|
||||||
unsigned _topped_cnt = 0;
|
unsigned _topped_cnt = 0;
|
||||||
|
|
||||||
Window_title _title;
|
Window_title _title { };
|
||||||
|
|
||||||
bool _focused = false;
|
bool _focused = false;
|
||||||
|
|
||||||
|
@ -157,7 +161,7 @@ class Decorator::Window : public Window_base
|
||||||
|
|
||||||
unsigned num_elements() const { return sizeof(_elements)/sizeof(Element); }
|
unsigned num_elements() const { return sizeof(_elements)/sizeof(Element); }
|
||||||
|
|
||||||
bool _apply_state(Window::Element::Type type, bool focused, bool highlighted)
|
bool _apply_state(Window::Element::Type type, bool highlighted)
|
||||||
{
|
{
|
||||||
return element(type).apply_state(_focused, highlighted, _base_color);
|
return element(type).apply_state(_focused, highlighted, _base_color);
|
||||||
}
|
}
|
||||||
|
@ -172,7 +176,7 @@ class Decorator::Window : public Window_base
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
Control _controls[MAX_CONTROLS];
|
Control _controls[MAX_CONTROLS] { };
|
||||||
|
|
||||||
unsigned _num = 0;
|
unsigned _num = 0;
|
||||||
|
|
||||||
|
@ -214,7 +218,7 @@ class Decorator::Window : public Window_base
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
Controls _controls;
|
Controls _controls { };
|
||||||
|
|
||||||
|
|
||||||
/***********************
|
/***********************
|
||||||
|
@ -387,6 +391,14 @@ class Decorator::Window : public Window_base
|
||||||
_window_control_texture(control));
|
_window_control_texture(control));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void _stack_decoration_views()
|
||||||
|
{
|
||||||
|
_top_view.stack(_content_view.handle());
|
||||||
|
_left_view.stack(_top_view.handle());
|
||||||
|
_right_view.stack(_left_view.handle());
|
||||||
|
_bottom_view.stack(_right_view.handle());
|
||||||
|
}
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
Window(unsigned id, Nitpicker::Session_client &nitpicker,
|
Window(unsigned id, Nitpicker::Session_client &nitpicker,
|
||||||
|
@ -404,21 +416,27 @@ class Decorator::Window : public Window_base
|
||||||
{
|
{
|
||||||
return Border(_border_size + _title_height,
|
return Border(_border_size + _title_height,
|
||||||
_border_size, _border_size, _border_size);
|
_border_size, _border_size, _border_size);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void stack(Nitpicker::Session::View_handle neighbor) override
|
void stack(View_handle neighbor) override
|
||||||
{
|
{
|
||||||
_neighbor = neighbor;
|
|
||||||
|
|
||||||
_content_view.stack(neighbor);
|
_content_view.stack(neighbor);
|
||||||
_top_view.stack(_content_view.handle());
|
_stack_decoration_views();
|
||||||
_left_view.stack(_top_view.handle());
|
|
||||||
_right_view.stack(_left_view.handle());
|
|
||||||
_bottom_view.stack(_right_view.handle());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Nitpicker::Session::View_handle frontmost_view() const override
|
void stack_front_most() override
|
||||||
|
{
|
||||||
|
_content_view.stack(View_handle());
|
||||||
|
_stack_decoration_views();
|
||||||
|
}
|
||||||
|
|
||||||
|
void stack_back_most() override
|
||||||
|
{
|
||||||
|
_content_view.stack_back_most();
|
||||||
|
_stack_decoration_views();
|
||||||
|
}
|
||||||
|
|
||||||
|
View_handle frontmost_view() const override
|
||||||
{
|
{
|
||||||
return _bottom_view.handle();
|
return _bottom_view.handle();
|
||||||
}
|
}
|
||||||
|
@ -434,11 +452,6 @@ class Decorator::Window : public Window_base
|
||||||
outer_geometry().cut(geometry(), top, left, right, bottom);
|
outer_geometry().cut(geometry(), top, left, right, bottom);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool in_front_of(Window_base const &neighbor) const override
|
|
||||||
{
|
|
||||||
return _neighbor == neighbor.frontmost_view();
|
|
||||||
}
|
|
||||||
|
|
||||||
void update_nitpicker_views() override
|
void update_nitpicker_views() override
|
||||||
{
|
{
|
||||||
if (!_nitpicker_views_up_to_date) {
|
if (!_nitpicker_views_up_to_date) {
|
||||||
|
@ -464,7 +477,7 @@ class Decorator::Window : public Window_base
|
||||||
|
|
||||||
void draw(Canvas_base &canvas, Rect clip, Draw_behind_fn const &) const override;
|
void draw(Canvas_base &canvas, Rect clip, Draw_behind_fn const &) const override;
|
||||||
|
|
||||||
bool update(Xml_node, bool) override;
|
bool update(Xml_node) override;
|
||||||
|
|
||||||
Hover hover(Point) const override;
|
Hover hover(Point) const override;
|
||||||
|
|
||||||
|
|
|
@ -44,19 +44,19 @@ class Decorator::Window_element : public Animator::Item
|
||||||
Genode::min(c1.b + c2.b, 255));
|
Genode::min(c1.b + c2.b, 255));
|
||||||
}
|
}
|
||||||
|
|
||||||
Type _type;
|
Type const _type;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Rememeber base color to detect when it changes
|
* Rememeber base color to detect when it changes
|
||||||
*/
|
*/
|
||||||
Color _base_color;
|
Color _base_color { };
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Color value in 8.4 fixpoint format. We use four bits to
|
* Color value in 8.4 fixpoint format. We use four bits to
|
||||||
* represent the fractional part to enable smooth
|
* represent the fractional part to enable smooth
|
||||||
* interpolation between the color values.
|
* interpolation between the color values.
|
||||||
*/
|
*/
|
||||||
Lazy_value<int> _r, _g, _b;
|
Lazy_value<int> _r { }, _g { }, _b { };
|
||||||
|
|
||||||
bool _focused = false;
|
bool _focused = false;
|
||||||
bool _highlighted = false;
|
bool _highlighted = false;
|
||||||
|
|
|
@ -56,9 +56,9 @@ struct Decorator::Main : Window_factory_base
|
||||||
Signal_handler<Main> _pointer_handler = {
|
Signal_handler<Main> _pointer_handler = {
|
||||||
_env.ep(), *this, &Main::_handle_pointer_update };
|
_env.ep(), *this, &Main::_handle_pointer_update };
|
||||||
|
|
||||||
Constructible<Attached_rom_dataspace> _pointer;
|
Constructible<Attached_rom_dataspace> _pointer { };
|
||||||
|
|
||||||
Window_base::Hover _hover;
|
Window_base::Hover _hover { };
|
||||||
|
|
||||||
Reporter _hover_reporter = { _env, "hover" };
|
Reporter _hover_reporter = { _env, "hover" };
|
||||||
|
|
||||||
|
@ -69,7 +69,7 @@ struct Decorator::Main : Window_factory_base
|
||||||
|
|
||||||
bool _window_layout_update_needed = false;
|
bool _window_layout_update_needed = false;
|
||||||
|
|
||||||
Animator _animator;
|
Animator _animator { };
|
||||||
|
|
||||||
Heap _heap { _env.ram(), _env.rm() };
|
Heap _heap { _env.ram(), _env.rm() };
|
||||||
|
|
||||||
|
@ -258,15 +258,15 @@ void Decorator::Main::_handle_nitpicker_sync()
|
||||||
|
|
||||||
bool model_updated = false;
|
bool model_updated = false;
|
||||||
|
|
||||||
|
auto flush_window_stack_changes = [&] () {
|
||||||
|
_window_stack.update_nitpicker_views(); };
|
||||||
|
|
||||||
if (_window_layout_update_needed && _window_layout.valid()) {
|
if (_window_layout_update_needed && _window_layout.valid()) {
|
||||||
|
|
||||||
try {
|
try {
|
||||||
Xml_node xml(_window_layout.local_addr<char>(),
|
Xml_node xml(_window_layout.local_addr<char>(),
|
||||||
_window_layout.size());
|
_window_layout.size());
|
||||||
|
|
||||||
auto flush_window_stack_changes = [&] () {
|
|
||||||
_window_stack.update_nitpicker_views(); };
|
|
||||||
|
|
||||||
_window_stack.update_model(xml, flush_window_stack_changes);
|
_window_stack.update_model(xml, flush_window_stack_changes);
|
||||||
|
|
||||||
model_updated = true;
|
model_updated = true;
|
||||||
|
@ -285,7 +285,8 @@ void Decorator::Main::_handle_nitpicker_sync()
|
||||||
* An error occured with processing the XML model. Flush the
|
* An error occured with processing the XML model. Flush the
|
||||||
* internal representation.
|
* internal representation.
|
||||||
*/
|
*/
|
||||||
_window_stack.flush();
|
_window_stack.update_model(Xml_node("<window_layout/>"),
|
||||||
|
flush_window_stack_changes);
|
||||||
}
|
}
|
||||||
|
|
||||||
_window_layout_update_needed = false;
|
_window_layout_update_needed = false;
|
||||||
|
|
|
@ -8,5 +8,3 @@ INC_DIR += $(PRG_DIR)
|
||||||
$(TARGET): plain_decorator_theme.tar
|
$(TARGET): plain_decorator_theme.tar
|
||||||
plain_decorator_theme.tar:
|
plain_decorator_theme.tar:
|
||||||
$(VERBOSE)cd $(PRG_DIR); tar cf $(PWD)/bin/$@ theme
|
$(VERBOSE)cd $(PRG_DIR); tar cf $(PWD)/bin/$@ theme
|
||||||
|
|
||||||
CC_CXX_WARN_STRICT =
|
|
||||||
|
|
|
@ -120,6 +120,8 @@ Decorator::Area Decorator::Theme::background_size() const
|
||||||
struct Margins_from_metadata : Decorator::Theme::Margins
|
struct Margins_from_metadata : Decorator::Theme::Margins
|
||||||
{
|
{
|
||||||
Margins_from_metadata(char const *sub_node, Genode::Allocator &alloc)
|
Margins_from_metadata(char const *sub_node, Genode::Allocator &alloc)
|
||||||
|
:
|
||||||
|
Decorator::Theme::Margins()
|
||||||
{
|
{
|
||||||
Genode::Xml_node aura = metadata(alloc).sub_node(sub_node);
|
Genode::Xml_node aura = metadata(alloc).sub_node(sub_node);
|
||||||
top = aura.attribute_value("top", 0UL);
|
top = aura.attribute_value("top", 0UL);
|
||||||
|
@ -259,7 +261,7 @@ void Decorator::Theme::draw_background(Decorator::Pixel_surface &pixel_surface,
|
||||||
|
|
||||||
|
|
||||||
void Decorator::Theme::draw_title(Decorator::Pixel_surface &pixel_surface,
|
void Decorator::Theme::draw_title(Decorator::Pixel_surface &pixel_surface,
|
||||||
Decorator::Alpha_surface &alpha_surface,
|
Decorator::Alpha_surface &,
|
||||||
char const *title) const
|
char const *title) const
|
||||||
{
|
{
|
||||||
/* skip title drawing if the metadata lacks a title declaration */
|
/* skip title drawing if the metadata lacks a title declaration */
|
||||||
|
|
|
@ -55,11 +55,9 @@ class Decorator::Window : public Window_base, public Animator::Item
|
||||||
*/
|
*/
|
||||||
bool _nitpicker_views_up_to_date = false;
|
bool _nitpicker_views_up_to_date = false;
|
||||||
|
|
||||||
Nitpicker::Session::View_handle _neighbor;
|
|
||||||
|
|
||||||
unsigned _topped_cnt = 0;
|
unsigned _topped_cnt = 0;
|
||||||
|
|
||||||
Window_title _title;
|
Window_title _title { };
|
||||||
|
|
||||||
bool _focused = false;
|
bool _focused = false;
|
||||||
|
|
||||||
|
@ -67,63 +65,73 @@ class Decorator::Window : public Window_base, public Animator::Item
|
||||||
|
|
||||||
Animator &_animator;
|
Animator &_animator;
|
||||||
|
|
||||||
struct Element : Animator::Item
|
class Element : public Animator::Item
|
||||||
{
|
{
|
||||||
Theme::Element_type const type;
|
private:
|
||||||
|
|
||||||
char const * const attr;
|
/*
|
||||||
|
* Noncopyable
|
||||||
|
*/
|
||||||
|
Element(Element const &);
|
||||||
|
Element & operator = (Element const &);
|
||||||
|
|
||||||
bool _highlighted = false;
|
bool _highlighted = false;
|
||||||
bool _present = false;
|
bool _present = false;
|
||||||
|
|
||||||
Lazy_value<int> alpha = 0;
|
int _alpha_dst() const
|
||||||
|
{
|
||||||
|
if (!_present)
|
||||||
|
return 0;
|
||||||
|
|
||||||
int _alpha_dst() const
|
return _highlighted ? 255 : 150;
|
||||||
{
|
}
|
||||||
if (!_present)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
return _highlighted ? 255 : 150;
|
void _update_alpha_dst()
|
||||||
}
|
{
|
||||||
|
if ((int)alpha == _alpha_dst())
|
||||||
|
return;
|
||||||
|
|
||||||
void _update_alpha_dst()
|
alpha.dst(_alpha_dst(), 20);
|
||||||
{
|
animate();
|
||||||
if ((int)alpha == _alpha_dst())
|
}
|
||||||
return;
|
|
||||||
|
|
||||||
alpha.dst(_alpha_dst(), 20);
|
public:
|
||||||
animate();
|
|
||||||
}
|
|
||||||
|
|
||||||
void highlighted(bool highlighted)
|
Theme::Element_type const type;
|
||||||
{
|
|
||||||
_highlighted = highlighted;
|
|
||||||
_update_alpha_dst();
|
|
||||||
}
|
|
||||||
|
|
||||||
bool highlighted() const { return _highlighted; }
|
char const * const attr;
|
||||||
|
|
||||||
void present(bool present)
|
Lazy_value<int> alpha = 0;
|
||||||
{
|
|
||||||
_present = present;
|
|
||||||
_update_alpha_dst();
|
|
||||||
}
|
|
||||||
|
|
||||||
bool present() const { return _present; }
|
void highlighted(bool highlighted)
|
||||||
|
{
|
||||||
|
_highlighted = highlighted;
|
||||||
|
_update_alpha_dst();
|
||||||
|
}
|
||||||
|
|
||||||
void animate() override
|
bool highlighted() const { return _highlighted; }
|
||||||
{
|
|
||||||
alpha.animate();
|
|
||||||
animated((int)alpha != alpha.dst());
|
|
||||||
}
|
|
||||||
|
|
||||||
Element(Animator &animator, Theme::Element_type type, char const *attr)
|
void present(bool present)
|
||||||
:
|
{
|
||||||
Animator::Item(animator),
|
_present = present;
|
||||||
type(type), attr(attr)
|
_update_alpha_dst();
|
||||||
{
|
}
|
||||||
_update_alpha_dst();
|
|
||||||
}
|
bool present() const { return _present; }
|
||||||
|
|
||||||
|
void animate() override
|
||||||
|
{
|
||||||
|
alpha.animate();
|
||||||
|
animated((int)alpha != alpha.dst());
|
||||||
|
}
|
||||||
|
|
||||||
|
Element(Animator &animator, Theme::Element_type type, char const *attr)
|
||||||
|
:
|
||||||
|
Animator::Item(animator),
|
||||||
|
type(type), attr(attr)
|
||||||
|
{
|
||||||
|
_update_alpha_dst();
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
Element _closer { _animator, Theme::ELEMENT_TYPE_CLOSER, "closer" };
|
Element _closer { _animator, Theme::ELEMENT_TYPE_CLOSER, "closer" };
|
||||||
|
@ -139,7 +147,6 @@ class Decorator::Window : public Window_base, public Animator::Item
|
||||||
struct Nitpicker_view
|
struct Nitpicker_view
|
||||||
{
|
{
|
||||||
typedef Nitpicker::Session::Command Command;
|
typedef Nitpicker::Session::Command Command;
|
||||||
typedef Nitpicker::Session::View_handle View_handle;
|
|
||||||
|
|
||||||
bool const _view_is_remote;
|
bool const _view_is_remote;
|
||||||
|
|
||||||
|
@ -202,6 +209,11 @@ class Decorator::Window : public Window_base, public Animator::Item
|
||||||
_nitpicker.enqueue<Command::To_front>(_handle, neighbor);
|
_nitpicker.enqueue<Command::To_front>(_handle, neighbor);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void stack_back_most()
|
||||||
|
{
|
||||||
|
_nitpicker.enqueue<Command::To_back>(_handle, View_handle());
|
||||||
|
}
|
||||||
|
|
||||||
void place(Rect rect, Point offset)
|
void place(Rect rect, Point offset)
|
||||||
{
|
{
|
||||||
_nitpicker.enqueue<Command::Geometry>(_handle, rect);
|
_nitpicker.enqueue<Command::Geometry>(_handle, rect);
|
||||||
|
@ -223,7 +235,7 @@ class Decorator::Window : public Window_base, public Animator::Item
|
||||||
* represent the fractional part to enable smooth
|
* represent the fractional part to enable smooth
|
||||||
* interpolation between the color values.
|
* interpolation between the color values.
|
||||||
*/
|
*/
|
||||||
Lazy_value<int> _r, _g, _b;
|
Lazy_value<int> _r { }, _g { }, _b { };
|
||||||
|
|
||||||
Color _color() const { return Color(_r >> 4, _g >> 4, _b >> 4); }
|
Color _color() const { return Color(_r >> 4, _g >> 4, _b >> 4); }
|
||||||
|
|
||||||
|
@ -232,14 +244,14 @@ class Decorator::Window : public Window_base, public Animator::Item
|
||||||
* decorations.
|
* decorations.
|
||||||
*/
|
*/
|
||||||
Nitpicker::Connection _nitpicker_top_bottom { _env };
|
Nitpicker::Connection _nitpicker_top_bottom { _env };
|
||||||
Genode::Constructible<Nitpicker_buffer> _buffer_top_bottom;
|
Genode::Constructible<Nitpicker_buffer> _buffer_top_bottom { };
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Nitpicker session that contains the left and right window
|
* Nitpicker session that contains the left and right window
|
||||||
* decorations.
|
* decorations.
|
||||||
*/
|
*/
|
||||||
Nitpicker::Connection _nitpicker_left_right { _env };
|
Nitpicker::Connection _nitpicker_left_right { _env };
|
||||||
Genode::Constructible<Nitpicker_buffer> _buffer_left_right;
|
Genode::Constructible<Nitpicker_buffer> _buffer_left_right { };
|
||||||
|
|
||||||
Nitpicker_view _bottom_view { _nitpicker, _nitpicker_top_bottom },
|
Nitpicker_view _bottom_view { _nitpicker, _nitpicker_top_bottom },
|
||||||
_right_view { _nitpicker, _nitpicker_left_right },
|
_right_view { _nitpicker, _nitpicker_left_right },
|
||||||
|
@ -313,6 +325,14 @@ class Decorator::Window : public Window_base, public Animator::Item
|
||||||
_b.dst(_base_color.b << 4, 20);
|
_b.dst(_base_color.b << 4, 20);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void _stack_decoration_views()
|
||||||
|
{
|
||||||
|
_top_view.stack(_content_view.handle());
|
||||||
|
_left_view.stack(_top_view.handle());
|
||||||
|
_right_view.stack(_left_view.handle());
|
||||||
|
_bottom_view.stack(_right_view.handle());
|
||||||
|
}
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
Window(Genode::Env &env, unsigned id, Nitpicker::Session_client &nitpicker,
|
Window(Genode::Env &env, unsigned id, Nitpicker::Session_client &nitpicker,
|
||||||
|
@ -328,20 +348,27 @@ class Decorator::Window : public Window_base, public Animator::Item
|
||||||
animate();
|
animate();
|
||||||
}
|
}
|
||||||
|
|
||||||
void stack(Nitpicker::Session::View_handle neighbor) override
|
void stack(View_handle neighbor) override
|
||||||
{
|
{
|
||||||
_neighbor = neighbor;
|
_content_view.stack(neighbor);
|
||||||
|
_stack_decoration_views();
|
||||||
|
|
||||||
_top_view.stack(neighbor);
|
}
|
||||||
_left_view.stack(_top_view.handle());
|
void stack_front_most() override
|
||||||
_right_view.stack(_left_view.handle());
|
{
|
||||||
_bottom_view.stack(_right_view.handle());
|
_content_view.stack(View_handle());
|
||||||
_content_view.stack(_bottom_view.handle());
|
_stack_decoration_views();
|
||||||
}
|
}
|
||||||
|
|
||||||
Nitpicker::Session::View_handle frontmost_view() const override
|
void stack_back_most() override
|
||||||
{
|
{
|
||||||
return _content_view.handle();
|
_content_view.stack_back_most();
|
||||||
|
_stack_decoration_views();
|
||||||
|
}
|
||||||
|
|
||||||
|
View_handle frontmost_view() const override
|
||||||
|
{
|
||||||
|
return _bottom_view.handle();
|
||||||
}
|
}
|
||||||
|
|
||||||
Rect _decor_geometry() const
|
Rect _decor_geometry() const
|
||||||
|
@ -371,11 +398,6 @@ class Decorator::Window : public Window_base, public Animator::Item
|
||||||
outer_geometry().cut(geometry(), top, left, right, bottom);
|
outer_geometry().cut(geometry(), top, left, right, bottom);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool in_front_of(Window_base const &neighbor) const override
|
|
||||||
{
|
|
||||||
return _neighbor == neighbor.frontmost_view();
|
|
||||||
}
|
|
||||||
|
|
||||||
void update_nitpicker_views() override
|
void update_nitpicker_views() override
|
||||||
{
|
{
|
||||||
if (!_nitpicker_views_up_to_date) {
|
if (!_nitpicker_views_up_to_date) {
|
||||||
|
@ -405,24 +427,10 @@ class Decorator::Window : public Window_base, public Animator::Item
|
||||||
animate();
|
animate();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool update(Xml_node window_node, bool new_top_most) override
|
bool update(Xml_node window_node) override
|
||||||
{
|
{
|
||||||
bool updated = false;
|
bool updated = false;
|
||||||
|
|
||||||
/*
|
|
||||||
* Detect the need to bring the window to the top of the global
|
|
||||||
* view stack.
|
|
||||||
*/
|
|
||||||
unsigned const topped_cnt = attribute(window_node, "topped", 0UL);
|
|
||||||
if (topped_cnt != _topped_cnt || new_top_most) {
|
|
||||||
|
|
||||||
_topped_cnt = topped_cnt;
|
|
||||||
|
|
||||||
stack(Nitpicker::Session::View_handle());
|
|
||||||
|
|
||||||
updated = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool trigger_animation = false;
|
bool trigger_animation = false;
|
||||||
|
|
||||||
Rect const old_geometry = geometry();
|
Rect const old_geometry = geometry();
|
||||||
|
|
|
@ -21,6 +21,8 @@
|
||||||
#include <util/geometry.h>
|
#include <util/geometry.h>
|
||||||
#include <util/color.h>
|
#include <util/color.h>
|
||||||
#include <util/dirty_rect.h>
|
#include <util/dirty_rect.h>
|
||||||
|
#include <util/list_model.h>
|
||||||
|
#include <util/interface.h>
|
||||||
#include <os/surface.h>
|
#include <os/surface.h>
|
||||||
|
|
||||||
namespace Decorator {
|
namespace Decorator {
|
||||||
|
@ -34,6 +36,8 @@ namespace Decorator {
|
||||||
using Genode::size_t;
|
using Genode::size_t;
|
||||||
using Genode::Color;
|
using Genode::Color;
|
||||||
using Genode::Xml_node;
|
using Genode::Xml_node;
|
||||||
|
using Genode::List_model;
|
||||||
|
using Genode::Interface;
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif /* _INCLUDE__DECORATOR__TYPES_H_ */
|
#endif /* _INCLUDE__DECORATOR__TYPES_H_ */
|
||||||
|
|
|
@ -15,9 +15,9 @@
|
||||||
#define _INCLUDE__DECORATOR__WINDOW_H_
|
#define _INCLUDE__DECORATOR__WINDOW_H_
|
||||||
|
|
||||||
/* Genode includes */
|
/* Genode includes */
|
||||||
#include <util/list.h>
|
|
||||||
#include <util/string.h>
|
#include <util/string.h>
|
||||||
#include <util/xml_generator.h>
|
#include <util/xml_generator.h>
|
||||||
|
#include <util/list_model.h>
|
||||||
#include <nitpicker_session/client.h>
|
#include <nitpicker_session/client.h>
|
||||||
#include <base/snprintf.h>
|
#include <base/snprintf.h>
|
||||||
|
|
||||||
|
@ -29,14 +29,18 @@
|
||||||
namespace Decorator {
|
namespace Decorator {
|
||||||
class Canvas_base;
|
class Canvas_base;
|
||||||
class Window_base;
|
class Window_base;
|
||||||
typedef Genode::List<Window_base> Window_list;
|
|
||||||
|
typedef Genode::List<Genode::List_element<Window_base> > Abandoned_windows;
|
||||||
|
typedef Genode::List<Genode::List_element<Window_base> > Reversed_windows;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
class Decorator::Window_base : public Window_list::Element
|
class Decorator::Window_base : private Genode::List_model<Window_base>::Element
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
|
||||||
|
typedef Nitpicker::Session::View_handle View_handle;
|
||||||
|
|
||||||
struct Border
|
struct Border
|
||||||
{
|
{
|
||||||
unsigned top, left, right, bottom;
|
unsigned top, left, right, bottom;
|
||||||
|
@ -80,39 +84,83 @@ class Decorator::Window_base : public Window_list::Element
|
||||||
* This functor is used for drawing the decorations of partially
|
* This functor is used for drawing the decorations of partially
|
||||||
* transparent windows. It is implemented by the window stack.
|
* transparent windows. It is implemented by the window stack.
|
||||||
*/
|
*/
|
||||||
struct Draw_behind_fn
|
struct Draw_behind_fn : Interface
|
||||||
{
|
{
|
||||||
virtual void draw_behind(Canvas_base &, Window_base const &, Rect) const = 0;
|
virtual void draw_behind(Canvas_base &, Window_base const &, Rect) const = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
|
/* allow 'List_model' to access 'List_model::Element' */
|
||||||
|
friend class Genode::List_model<Window_base>;
|
||||||
|
friend class Genode::List<Window_base>;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Geometry of content
|
* Geometry of content
|
||||||
*/
|
*/
|
||||||
Rect _geometry;
|
Rect _geometry { };
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Unique window ID
|
* Unique window ID
|
||||||
*/
|
*/
|
||||||
unsigned const _id;
|
unsigned const _id;
|
||||||
|
|
||||||
|
bool _stacked = false;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* View immediately behind the window
|
||||||
|
*/
|
||||||
|
View_handle _neighbor { };
|
||||||
|
|
||||||
|
Genode::List_element<Window_base> _abandoned { this };
|
||||||
|
|
||||||
|
Genode::List_element<Window_base> _reversed { this };
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
Window_base(unsigned id) : _id(id) { }
|
Window_base(unsigned id) : _id(id) { }
|
||||||
|
|
||||||
|
virtual ~Window_base() { }
|
||||||
|
|
||||||
|
void abandon(Abandoned_windows &abandoned_windows)
|
||||||
|
{
|
||||||
|
abandoned_windows.insert(&_abandoned);
|
||||||
|
}
|
||||||
|
|
||||||
|
void prepend_to_reverse_list(Reversed_windows &window_list)
|
||||||
|
{
|
||||||
|
window_list.insert(&_reversed);
|
||||||
|
}
|
||||||
|
|
||||||
|
using List_model<Window_base>::Element::next;
|
||||||
|
|
||||||
unsigned long id() const { return _id; }
|
unsigned long id() const { return _id; }
|
||||||
Rect geometry() const { return _geometry; }
|
Rect geometry() const { return _geometry; }
|
||||||
|
|
||||||
|
void stacking_neighbor(View_handle neighbor)
|
||||||
|
{
|
||||||
|
_neighbor = neighbor;
|
||||||
|
_stacked = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool stacked() const { return _stacked; }
|
||||||
|
|
||||||
|
bool in_front_of(Window_base const &neighbor) const
|
||||||
|
{
|
||||||
|
return _neighbor == neighbor.frontmost_view();
|
||||||
|
}
|
||||||
|
|
||||||
void geometry(Rect geometry) { _geometry = geometry; }
|
void geometry(Rect geometry) { _geometry = geometry; }
|
||||||
|
|
||||||
virtual Rect outer_geometry() const = 0;
|
virtual Rect outer_geometry() const = 0;
|
||||||
|
|
||||||
virtual void stack(Nitpicker::Session::View_handle neighbor) = 0;
|
virtual void stack(View_handle neighbor) = 0;
|
||||||
|
|
||||||
virtual Nitpicker::Session::View_handle frontmost_view() const = 0;
|
virtual void stack_front_most() = 0;
|
||||||
|
|
||||||
virtual bool in_front_of(Window_base const &neighbor) const = 0;
|
virtual void stack_back_most() = 0;
|
||||||
|
|
||||||
|
virtual View_handle frontmost_view() const = 0;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Draw window elements
|
* Draw window elements
|
||||||
|
@ -125,10 +173,6 @@ class Decorator::Window_base : public Window_list::Element
|
||||||
/**
|
/**
|
||||||
* Update internal window representation from XML model
|
* Update internal window representation from XML model
|
||||||
*
|
*
|
||||||
* \param new_top_most true if window became the new top-most
|
|
||||||
* window, which should prompt a corresponding
|
|
||||||
* nitpicker stacking operation.
|
|
||||||
*
|
|
||||||
* \return true if window changed
|
* \return true if window changed
|
||||||
*
|
*
|
||||||
* We do not immediately update the views as part of the update
|
* We do not immediately update the views as part of the update
|
||||||
|
@ -136,7 +180,7 @@ class Decorator::Window_base : public Window_list::Element
|
||||||
* decorations haven't been redrawn already. If we updated the
|
* decorations haven't been redrawn already. If we updated the
|
||||||
* nitpicker views at this point, we would reveal not-yet-drawn pixels.
|
* nitpicker views at this point, we would reveal not-yet-drawn pixels.
|
||||||
*/
|
*/
|
||||||
virtual bool update(Xml_node window_node, bool new_top_most) = 0;
|
virtual bool update(Xml_node window_node) = 0;
|
||||||
|
|
||||||
virtual void update_nitpicker_views() { }
|
virtual void update_nitpicker_views() { }
|
||||||
|
|
||||||
|
|
|
@ -22,7 +22,7 @@ namespace Decorator {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
struct Decorator::Window_factory_base
|
struct Decorator::Window_factory_base : Interface
|
||||||
{
|
{
|
||||||
virtual Window_base *create (Xml_node) = 0;
|
virtual Window_base *create (Xml_node) = 0;
|
||||||
virtual void destroy (Window_base *) = 0;
|
virtual void destroy (Window_base *) = 0;
|
||||||
|
|
|
@ -31,24 +31,15 @@ class Decorator::Window_stack : public Window_base::Draw_behind_fn
|
||||||
{
|
{
|
||||||
private:
|
private:
|
||||||
|
|
||||||
Window_list _windows;
|
List_model<Window_base> _windows { };
|
||||||
Window_factory_base &_window_factory;
|
Window_factory_base &_window_factory;
|
||||||
Dirty_rect mutable _dirty_rect;
|
Dirty_rect mutable _dirty_rect { };
|
||||||
|
|
||||||
unsigned long _top_most_id = ~0UL;
|
unsigned long _front_most_id = ~0UL;
|
||||||
|
|
||||||
inline void _draw_rec(Canvas_base &canvas, Window_base const *win,
|
inline void _draw_rec(Canvas_base &canvas, Window_base const *win,
|
||||||
Rect rect) const;
|
Rect rect) const;
|
||||||
|
|
||||||
Window_base *_lookup_by_id(unsigned const id)
|
|
||||||
{
|
|
||||||
for (Window_base *win = _windows.first(); win; win = win->next())
|
|
||||||
if (win->id() == id)
|
|
||||||
return win;
|
|
||||||
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline
|
static inline
|
||||||
Xml_node _xml_node_by_window_id(Genode::Xml_node node, unsigned id)
|
Xml_node _xml_node_by_window_id(Genode::Xml_node node, unsigned id)
|
||||||
{
|
{
|
||||||
|
@ -63,24 +54,14 @@ class Decorator::Window_stack : public Window_base::Draw_behind_fn
|
||||||
throw Xml_node::Nonexistent_sub_node();
|
throw Xml_node::Nonexistent_sub_node();
|
||||||
}
|
}
|
||||||
|
|
||||||
void _destroy(Window_base &window)
|
|
||||||
{
|
|
||||||
_windows.remove(&window);
|
|
||||||
_window_factory.destroy(&window);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Generate window list in reverse order
|
* Generate window list in reverse order
|
||||||
*
|
|
||||||
* After calling this method, the '_windows' list is empty.
|
|
||||||
*/
|
*/
|
||||||
Window_list _reversed_window_list()
|
Reversed_windows _reversed_window_list()
|
||||||
{
|
{
|
||||||
Window_list reversed;
|
Reversed_windows reversed { };
|
||||||
while (Window_base *w = _windows.first()) {
|
_windows.for_each([&] (Window_base &window) {
|
||||||
_windows.remove(w);
|
window.prepend_to_reverse_list(reversed); });
|
||||||
reversed.insert(w);
|
|
||||||
}
|
|
||||||
return reversed;
|
return reversed;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -91,12 +72,15 @@ class Decorator::Window_stack : public Window_base::Draw_behind_fn
|
||||||
_window_factory(window_factory)
|
_window_factory(window_factory)
|
||||||
{ }
|
{ }
|
||||||
|
|
||||||
|
void mark_as_dirty(Rect rect) { _dirty_rect.mark_as_dirty(rect); }
|
||||||
|
|
||||||
Dirty_rect draw(Canvas_base &canvas) const
|
Dirty_rect draw(Canvas_base &canvas) const
|
||||||
{
|
{
|
||||||
Dirty_rect result = _dirty_rect;
|
Dirty_rect result = _dirty_rect;
|
||||||
|
|
||||||
_dirty_rect.flush([&] (Rect const &rect) {
|
_dirty_rect.flush([&] (Rect const &rect) {
|
||||||
_draw_rec(canvas, _windows.first(), rect); });
|
_windows.apply_first([&] (Window_base const &first) {
|
||||||
|
_draw_rec(canvas, &first, rect); }); });
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
@ -108,12 +92,13 @@ class Decorator::Window_stack : public Window_base::Draw_behind_fn
|
||||||
{
|
{
|
||||||
bool redraw_needed = false;
|
bool redraw_needed = false;
|
||||||
|
|
||||||
for (Window_base *win = _windows.first(); win; win = win->next()) {
|
_windows.for_each([&] (Window_base const &win) {
|
||||||
if (win->animated()) {
|
|
||||||
_dirty_rect.mark_as_dirty(win->outer_geometry());
|
if (win.animated()) {
|
||||||
|
_dirty_rect.mark_as_dirty(win.outer_geometry());
|
||||||
redraw_needed = true;
|
redraw_needed = true;
|
||||||
}
|
}
|
||||||
}
|
});
|
||||||
return redraw_needed;
|
return redraw_needed;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -123,11 +108,7 @@ class Decorator::Window_stack : public Window_base::Draw_behind_fn
|
||||||
* The functor is called with 'Window_base &' as argument.
|
* The functor is called with 'Window_base &' as argument.
|
||||||
*/
|
*/
|
||||||
template <typename FUNC>
|
template <typename FUNC>
|
||||||
void for_each_window(FUNC const &func)
|
void for_each_window(FUNC const &func) { _windows.for_each(func); }
|
||||||
{
|
|
||||||
for (Window_base *win = _windows.first(); win; win = win->next())
|
|
||||||
func(*win);
|
|
||||||
}
|
|
||||||
|
|
||||||
void update_nitpicker_views()
|
void update_nitpicker_views()
|
||||||
{
|
{
|
||||||
|
@ -139,32 +120,29 @@ class Decorator::Window_stack : public Window_base::Draw_behind_fn
|
||||||
* each view is always at its final stacking position when
|
* each view is always at its final stacking position when
|
||||||
* specified as neighbor of another view.
|
* specified as neighbor of another view.
|
||||||
*/
|
*/
|
||||||
Window_list reversed = _reversed_window_list();
|
Reversed_windows reversed = _reversed_window_list();
|
||||||
|
|
||||||
while (Window_base *win = reversed.first()) {
|
while (Genode::List_element<Window_base> *win = reversed.first()) {
|
||||||
win->update_nitpicker_views();
|
win->object()->update_nitpicker_views();
|
||||||
reversed.remove(win);
|
reversed.remove(win);
|
||||||
_windows.insert(win);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void flush()
|
|
||||||
{
|
|
||||||
while (Window_base *window = _windows.first())
|
|
||||||
_destroy(*window);
|
|
||||||
}
|
|
||||||
|
|
||||||
Window_base::Hover hover(Point pos) const
|
Window_base::Hover hover(Point pos) const
|
||||||
{
|
{
|
||||||
for (Window_base const *win = _windows.first(); win; win = win->next())
|
Window_base::Hover result { };
|
||||||
if (win->outer_geometry().contains(pos)) {
|
|
||||||
|
|
||||||
Window_base::Hover const hover = win->hover(pos);
|
_windows.for_each([&] (Window_base const &win) {
|
||||||
|
|
||||||
|
if (!result.window_id && win.outer_geometry().contains(pos)) {
|
||||||
|
|
||||||
|
Window_base::Hover const hover = win.hover(pos);
|
||||||
if (hover.window_id != 0)
|
if (hover.window_id != 0)
|
||||||
return hover;
|
result = hover;
|
||||||
}
|
}
|
||||||
|
});
|
||||||
|
|
||||||
return Window_base::Hover();
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -187,7 +165,7 @@ void Decorator::Window_stack::_draw_rec(Decorator::Canvas_base &canvas,
|
||||||
|
|
||||||
/* find next window that intersects with the rectangle */
|
/* find next window that intersects with the rectangle */
|
||||||
for ( ; win && !(clipped = Rect::intersect(win->outer_geometry(), rect)).valid(); )
|
for ( ; win && !(clipped = Rect::intersect(win->outer_geometry(), rect)).valid(); )
|
||||||
win = win->next();;
|
win = win->next();
|
||||||
|
|
||||||
/* check if we hit the bottom of the window stack */
|
/* check if we hit the bottom of the window stack */
|
||||||
if (!win) return;
|
if (!win) return;
|
||||||
|
@ -212,116 +190,58 @@ template <typename FN>
|
||||||
void Decorator::Window_stack::update_model(Genode::Xml_node root_node,
|
void Decorator::Window_stack::update_model(Genode::Xml_node root_node,
|
||||||
FN const &flush_window_stack_changes)
|
FN const &flush_window_stack_changes)
|
||||||
{
|
{
|
||||||
Window_list _destroyed_windows { };
|
Abandoned_windows _abandoned_windows { };
|
||||||
|
|
||||||
unsigned long new_top_most_id = ~0UL;
|
struct Update_policy : List_model<Window_base>::Update_policy
|
||||||
if (root_node.has_sub_node("window"))
|
{
|
||||||
new_top_most_id = root_node.sub_node("window").attribute_value("id", ~0UL);
|
Abandoned_windows &_abandoned_windows;
|
||||||
|
Window_factory_base &_window_factory;
|
||||||
|
Dirty_rect &_dirty_rect;
|
||||||
|
|
||||||
/*
|
Update_policy(Abandoned_windows &abandoned_windows,
|
||||||
* Step 1: Remove windows that are no longer present.
|
Window_factory_base &window_factory,
|
||||||
*/
|
Dirty_rect &dirty_rect)
|
||||||
for (Window_base *window = _windows.first(), *next = nullptr; window; window = next) {
|
:
|
||||||
next = window->next();
|
_abandoned_windows(abandoned_windows),
|
||||||
try {
|
_window_factory(window_factory),
|
||||||
_xml_node_by_window_id(root_node, window->id());
|
_dirty_rect(dirty_rect)
|
||||||
|
{ }
|
||||||
|
|
||||||
|
void destroy_element(Window_base &window)
|
||||||
|
{
|
||||||
|
window.abandon(_abandoned_windows);
|
||||||
}
|
}
|
||||||
catch (Xml_node::Nonexistent_sub_node) {
|
|
||||||
_dirty_rect.mark_as_dirty(window->outer_geometry());
|
|
||||||
_windows.remove(window);
|
|
||||||
_destroyed_windows.insert(window);
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
Window_base &create_element(Xml_node node)
|
||||||
* Return true if window has came to front
|
{
|
||||||
*/
|
return *_window_factory.create(node);
|
||||||
auto window_is_new_top_most = [&] (Window_base const &window) {
|
}
|
||||||
return (_top_most_id != new_top_most_id) && (window.id() == new_top_most_id); };
|
|
||||||
|
|
||||||
/*
|
void update_element(Window_base &window, Xml_node node)
|
||||||
* Step 2: Update window properties of already present windows.
|
{
|
||||||
*/
|
Rect const orig_geometry = window.outer_geometry();
|
||||||
for (Window_base *window = _windows.first(); window; window = window->next()) {
|
|
||||||
|
|
||||||
/*
|
if (window.update(node)) {
|
||||||
* After step 1, a Xml_node::Nonexistent_sub_node exception can no
|
|
||||||
* longer occur. All windows remaining in the window stack are present
|
|
||||||
* in the XML model.
|
|
||||||
*/
|
|
||||||
try {
|
|
||||||
Rect const orig_geometry = window->outer_geometry();
|
|
||||||
if (window->update(_xml_node_by_window_id(root_node, window->id()),
|
|
||||||
window_is_new_top_most(*window))) {
|
|
||||||
_dirty_rect.mark_as_dirty(orig_geometry);
|
_dirty_rect.mark_as_dirty(orig_geometry);
|
||||||
_dirty_rect.mark_as_dirty(window->outer_geometry());
|
_dirty_rect.mark_as_dirty(window.outer_geometry());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch (Xml_node::Nonexistent_sub_node) {
|
|
||||||
Genode::error("could not look up window ", window->id(), " in XML model"); }
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
static bool element_matches_xml_node(Window_base const &elem, Xml_node node)
|
||||||
* Step 3: Add new appearing windows to the window stack.
|
{
|
||||||
*/
|
return elem.id() == node.attribute_value("id", ~0UL);
|
||||||
for_each_sub_node(root_node, "window", [&] (Xml_node window_node) {
|
|
||||||
|
|
||||||
unsigned long const id = attribute(window_node, "id", 0UL);
|
|
||||||
|
|
||||||
if (!_lookup_by_id(id)) {
|
|
||||||
|
|
||||||
Window_base *new_window = _window_factory.create(window_node);
|
|
||||||
|
|
||||||
if (new_window) {
|
|
||||||
|
|
||||||
new_window->update(window_node, window_is_new_top_most(*new_window));
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Insert new window in front of all other windows.
|
|
||||||
*
|
|
||||||
* Immediately propagate the new stacking position of the new
|
|
||||||
* window to nitpicker ('update_nitpicker_views'). Otherwise,
|
|
||||||
*/
|
|
||||||
new_window->stack(Nitpicker::Session::View_handle());
|
|
||||||
|
|
||||||
_windows.insert(new_window);
|
|
||||||
|
|
||||||
_dirty_rect.mark_as_dirty(new_window->outer_geometry());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Step 4: Adjust window order.
|
|
||||||
*/
|
|
||||||
Window_base *previous_window = nullptr;
|
|
||||||
Window_base *window = _windows.first();
|
|
||||||
|
|
||||||
for_each_sub_node(root_node, "window", [&] (Xml_node window_node) {
|
|
||||||
|
|
||||||
if (!window) {
|
|
||||||
Genode::error("unexpected end of window list during re-ordering");
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned long const id = attribute(window_node, "id", 0UL);
|
static bool node_is_element(Xml_node) { return true; }
|
||||||
|
};
|
||||||
|
|
||||||
if (window->id() != id) {
|
Update_policy policy { _abandoned_windows, _window_factory, _dirty_rect };
|
||||||
window = _lookup_by_id(id);
|
|
||||||
if (!window) {
|
|
||||||
Genode::error("window lookup unexpectedly failed during re-ordering");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
_windows.remove(window);
|
_windows.update_from_xml(policy, root_node);
|
||||||
_windows.insert(window, previous_window);
|
|
||||||
|
|
||||||
_dirty_rect.mark_as_dirty(window->outer_geometry());
|
unsigned long new_front_most_id = ~0UL;
|
||||||
}
|
if (root_node.has_sub_node("window"))
|
||||||
|
new_front_most_id = root_node.sub_node("window").attribute_value("id", ~0UL);
|
||||||
previous_window = window;
|
|
||||||
window = window->next();
|
|
||||||
});
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Propagate changed stacking order to nitpicker
|
* Propagate changed stacking order to nitpicker
|
||||||
|
@ -331,27 +251,57 @@ void Decorator::Window_stack::update_model(Genode::Xml_node root_node,
|
||||||
* and check if its neighbor is consistent with its position in the
|
* and check if its neighbor is consistent with its position in the
|
||||||
* window list.
|
* window list.
|
||||||
*/
|
*/
|
||||||
Window_list reversed = _reversed_window_list();
|
Reversed_windows reversed = _reversed_window_list();
|
||||||
|
|
||||||
if (Window_base * const back_most = reversed.first()) {
|
/* return true if window just came to front */
|
||||||
|
auto new_front_most_window = [&] (Window_base const &win) {
|
||||||
|
return (new_front_most_id != _front_most_id) && (win.id() == new_front_most_id); };
|
||||||
|
|
||||||
/* keep back-most window as is */
|
auto stack_back_most_window = [&] (Window_base &window) {
|
||||||
|
|
||||||
|
if (window.stacked())
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (new_front_most_window(window))
|
||||||
|
window.stack_front_most();
|
||||||
|
else
|
||||||
|
window.stack_back_most();
|
||||||
|
|
||||||
|
_dirty_rect.mark_as_dirty(window.outer_geometry());
|
||||||
|
};
|
||||||
|
|
||||||
|
auto stack_window = [&] (Window_base &window, Window_base &neighbor) {
|
||||||
|
|
||||||
|
if (window.stacked() && window.in_front_of(neighbor))
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (new_front_most_window(window))
|
||||||
|
window.stack_front_most();
|
||||||
|
else
|
||||||
|
window.stack(neighbor.frontmost_view());
|
||||||
|
|
||||||
|
_dirty_rect.mark_as_dirty(window.outer_geometry());
|
||||||
|
};
|
||||||
|
|
||||||
|
if (Genode::List_element<Window_base> *back_most = reversed.first()) {
|
||||||
|
|
||||||
|
/* handle back-most window */
|
||||||
reversed.remove(back_most);
|
reversed.remove(back_most);
|
||||||
_windows.insert(back_most);
|
Window_base &window = *back_most->object();
|
||||||
|
stack_back_most_window(window);
|
||||||
|
window.stacking_neighbor(Window_base::View_handle());
|
||||||
|
|
||||||
|
Window_base *neighbor = &window;
|
||||||
|
|
||||||
/* check consistency between window list order and view stacking */
|
/* check consistency between window list order and view stacking */
|
||||||
while (Window_base *w = reversed.first()) {
|
while (Genode::List_element<Window_base> *elem = reversed.first()) {
|
||||||
|
|
||||||
Window_base * const neighbor = _windows.first();
|
reversed.remove(elem);
|
||||||
|
|
||||||
reversed.remove(w);
|
Window_base &window = *elem->object();
|
||||||
_windows.insert(w);
|
stack_window(window, *neighbor);
|
||||||
|
window.stacking_neighbor(neighbor->frontmost_view());
|
||||||
/* propagate change stacking order to nitpicker */
|
neighbor = &window;
|
||||||
if (w->in_front_of(*neighbor))
|
|
||||||
continue;
|
|
||||||
|
|
||||||
w->stack(neighbor->frontmost_view());
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -362,7 +312,7 @@ void Decorator::Window_stack::update_model(Genode::Xml_node root_node,
|
||||||
flush_window_stack_changes();
|
flush_window_stack_changes();
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Destroy window objects.
|
* Destroy abandoned window objects
|
||||||
*
|
*
|
||||||
* This is done after all other operations to avoid flickering whenever one
|
* This is done after all other operations to avoid flickering whenever one
|
||||||
* window is replaced by another one. If we first destroyed the original
|
* window is replaced by another one. If we first destroyed the original
|
||||||
|
@ -371,12 +321,14 @@ void Decorator::Window_stack::update_model(Genode::Xml_node root_node,
|
||||||
* point when the new one already exists, one of both windows is visible at
|
* point when the new one already exists, one of both windows is visible at
|
||||||
* all times.
|
* all times.
|
||||||
*/
|
*/
|
||||||
for (Window_base *window = _destroyed_windows.first(), *next = nullptr; window; window = next) {
|
Genode::List_element<Window_base> *elem = _abandoned_windows.first(), *next = nullptr;
|
||||||
next = window->next();
|
for (; elem; elem = next) {
|
||||||
_destroy(*window);
|
next = elem->next();
|
||||||
|
_dirty_rect.mark_as_dirty(elem->object()->outer_geometry());
|
||||||
|
_window_factory.destroy(elem->object());
|
||||||
}
|
}
|
||||||
|
|
||||||
_top_most_id = new_top_most_id;
|
_front_most_id = new_front_most_id;
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif /* _INCLUDE__DECORATOR__WINDOW_STACK_H_ */
|
#endif /* _INCLUDE__DECORATOR__WINDOW_STACK_H_ */
|
||||||
|
|
Loading…
Reference in New Issue