mirror of
https://github.com/genodelabs/genode.git
synced 2025-04-14 22:47:12 +00:00
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
repos
gems/src/app
decorator
themed_decorator
os/include/decorator
@ -47,7 +47,7 @@ namespace Decorator {
|
||||
/**
|
||||
* Abstract interface of graphics back end
|
||||
*/
|
||||
struct Decorator::Canvas_base
|
||||
struct Decorator::Canvas_base : Interface
|
||||
{
|
||||
virtual Rect clip() const = 0;
|
||||
virtual void clip(Rect) = 0;
|
||||
|
@ -82,6 +82,12 @@ class Decorator::Config
|
||||
|
||||
private:
|
||||
|
||||
/**
|
||||
* Noncopyable
|
||||
*/
|
||||
Config(Config const &);
|
||||
Config & operator = (Config const &);
|
||||
|
||||
Genode::Allocator &_alloc;
|
||||
|
||||
Reconstructible<Genode::Buffered_xml> _buffered_config;
|
||||
|
@ -41,15 +41,40 @@ struct Decorator::Main : Window_factory_base
|
||||
|
||||
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(),
|
||||
(_nitpicker.buffer(_mode, false),
|
||||
_nitpicker.framebuffer()->dataspace()) };
|
||||
Canvas(Env &env, Nitpicker::Connection &nitpicker)
|
||||
:
|
||||
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>(),
|
||||
Area(_mode.width(), _mode.height()),
|
||||
_env.ram(), _env.rm() };
|
||||
Reconstructible<Canvas> _canvas { _env, _nitpicker };
|
||||
|
||||
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 };
|
||||
|
||||
@ -73,7 +98,7 @@ struct Decorator::Main : Window_factory_base
|
||||
|
||||
Attached_rom_dataspace _pointer { _env, "pointer" };
|
||||
|
||||
Window_base::Hover _hover;
|
||||
Window_base::Hover _hover { };
|
||||
|
||||
Reporter _hover_reporter = { _env, "hover" };
|
||||
|
||||
@ -81,7 +106,7 @@ struct Decorator::Main : Window_factory_base
|
||||
|
||||
Reporter _decorator_margins_reporter = { _env, "decorator_margins" };
|
||||
|
||||
Animator _animator;
|
||||
Animator _animator { };
|
||||
|
||||
/**
|
||||
* Process the update every 'frame_period' nitpicker sync signals. The
|
||||
@ -124,6 +149,8 @@ struct Decorator::Main : Window_factory_base
|
||||
_config.sigh(_config_handler);
|
||||
_handle_config();
|
||||
|
||||
_nitpicker.mode_sigh(_mode_handler);
|
||||
|
||||
_window_layout.sigh(_window_layout_handler);
|
||||
_pointer.sigh(_pointer_handler);
|
||||
|
||||
@ -264,14 +291,14 @@ void Decorator::Main::_handle_nitpicker_sync()
|
||||
|
||||
bool model_updated = false;
|
||||
|
||||
auto flush_window_stack_changes = [&] () { };
|
||||
|
||||
if (_window_layout_update_needed && _window_layout.valid()) {
|
||||
|
||||
try {
|
||||
Xml_node xml(_window_layout.local_addr<char>(),
|
||||
_window_layout.size());
|
||||
|
||||
auto flush_window_stack_changes = [&] () { };
|
||||
|
||||
_window_stack.update_model(xml, flush_window_stack_changes);
|
||||
|
||||
model_updated = true;
|
||||
@ -288,9 +315,10 @@ void Decorator::Main::_handle_nitpicker_sync()
|
||||
|
||||
/*
|
||||
* 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;
|
||||
@ -309,7 +337,7 @@ void Decorator::Main::_handle_nitpicker_sync()
|
||||
if (!model_updated && !windows_animated)
|
||||
return;
|
||||
|
||||
Dirty_rect dirty = _window_stack.draw(_canvas);
|
||||
Dirty_rect dirty = _window_stack.draw(_canvas->canvas);
|
||||
|
||||
_window_stack.update_nitpicker_views();
|
||||
|
||||
|
@ -8,5 +8,3 @@ INC_DIR += $(PRG_DIR)
|
||||
|
||||
vpath %.tff $(TFF_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);
|
||||
|
||||
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);
|
||||
|
||||
@ -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;
|
||||
|
||||
/*
|
||||
* 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
|
||||
*/
|
||||
@ -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");
|
||||
|
||||
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()));
|
||||
} catch (...) {
|
||||
|
||||
/* window node has no "highlight" sub node, reset highlighting */
|
||||
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;
|
||||
@ -354,7 +341,7 @@ Decorator::Window_base::Hover Decorator::Window::hover(Point abs_pos) const
|
||||
Point pos = titlbar_pos +
|
||||
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 */
|
||||
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;
|
||||
|
||||
Nitpicker::Session::View_handle _neighbor;
|
||||
|
||||
struct Nitpicker_view
|
||||
{
|
||||
Nitpicker::Session_client &_nitpicker;
|
||||
Nitpicker::Session::View_handle _handle { _nitpicker.create_view() };
|
||||
Nitpicker::Session_client &_nitpicker;
|
||||
|
||||
View_handle _handle { _nitpicker.create_view() };
|
||||
|
||||
typedef Nitpicker::Session::Command Command;
|
||||
|
||||
@ -66,13 +65,18 @@ class Decorator::Window : public Window_base
|
||||
_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);
|
||||
}
|
||||
|
||||
void stack_back_most()
|
||||
{
|
||||
_nitpicker.enqueue<Command::To_back>(_handle, View_handle());
|
||||
}
|
||||
|
||||
void place(Rect rect)
|
||||
{
|
||||
_nitpicker.enqueue<Command::Geometry>(_handle, rect);
|
||||
@ -96,7 +100,7 @@ class Decorator::Window : public Window_base
|
||||
|
||||
unsigned _topped_cnt = 0;
|
||||
|
||||
Window_title _title;
|
||||
Window_title _title { };
|
||||
|
||||
bool _focused = false;
|
||||
|
||||
@ -157,7 +161,7 @@ class Decorator::Window : public Window_base
|
||||
|
||||
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);
|
||||
}
|
||||
@ -172,7 +176,7 @@ class Decorator::Window : public Window_base
|
||||
|
||||
private:
|
||||
|
||||
Control _controls[MAX_CONTROLS];
|
||||
Control _controls[MAX_CONTROLS] { };
|
||||
|
||||
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));
|
||||
}
|
||||
|
||||
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:
|
||||
|
||||
Window(unsigned id, Nitpicker::Session_client &nitpicker,
|
||||
@ -404,21 +416,27 @@ class Decorator::Window : public Window_base
|
||||
{
|
||||
return Border(_border_size + _title_height,
|
||||
_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);
|
||||
_top_view.stack(_content_view.handle());
|
||||
_left_view.stack(_top_view.handle());
|
||||
_right_view.stack(_left_view.handle());
|
||||
_bottom_view.stack(_right_view.handle());
|
||||
_stack_decoration_views();
|
||||
}
|
||||
|
||||
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();
|
||||
}
|
||||
@ -434,11 +452,6 @@ class Decorator::Window : public Window_base
|
||||
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
|
||||
{
|
||||
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;
|
||||
|
||||
bool update(Xml_node, bool) override;
|
||||
bool update(Xml_node) override;
|
||||
|
||||
Hover hover(Point) const override;
|
||||
|
||||
|
@ -44,19 +44,19 @@ class Decorator::Window_element : public Animator::Item
|
||||
Genode::min(c1.b + c2.b, 255));
|
||||
}
|
||||
|
||||
Type _type;
|
||||
Type const _type;
|
||||
|
||||
/*
|
||||
* 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
|
||||
* represent the fractional part to enable smooth
|
||||
* interpolation between the color values.
|
||||
*/
|
||||
Lazy_value<int> _r, _g, _b;
|
||||
Lazy_value<int> _r { }, _g { }, _b { };
|
||||
|
||||
bool _focused = false;
|
||||
bool _highlighted = false;
|
||||
|
@ -56,9 +56,9 @@ struct Decorator::Main : Window_factory_base
|
||||
Signal_handler<Main> _pointer_handler = {
|
||||
_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" };
|
||||
|
||||
@ -69,7 +69,7 @@ struct Decorator::Main : Window_factory_base
|
||||
|
||||
bool _window_layout_update_needed = false;
|
||||
|
||||
Animator _animator;
|
||||
Animator _animator { };
|
||||
|
||||
Heap _heap { _env.ram(), _env.rm() };
|
||||
|
||||
@ -258,15 +258,15 @@ void Decorator::Main::_handle_nitpicker_sync()
|
||||
|
||||
bool model_updated = false;
|
||||
|
||||
auto flush_window_stack_changes = [&] () {
|
||||
_window_stack.update_nitpicker_views(); };
|
||||
|
||||
if (_window_layout_update_needed && _window_layout.valid()) {
|
||||
|
||||
try {
|
||||
Xml_node xml(_window_layout.local_addr<char>(),
|
||||
_window_layout.size());
|
||||
|
||||
auto flush_window_stack_changes = [&] () {
|
||||
_window_stack.update_nitpicker_views(); };
|
||||
|
||||
_window_stack.update_model(xml, flush_window_stack_changes);
|
||||
|
||||
model_updated = true;
|
||||
@ -285,7 +285,8 @@ void Decorator::Main::_handle_nitpicker_sync()
|
||||
* An error occured with processing the XML model. Flush the
|
||||
* internal representation.
|
||||
*/
|
||||
_window_stack.flush();
|
||||
_window_stack.update_model(Xml_node("<window_layout/>"),
|
||||
flush_window_stack_changes);
|
||||
}
|
||||
|
||||
_window_layout_update_needed = false;
|
||||
|
@ -8,5 +8,3 @@ INC_DIR += $(PRG_DIR)
|
||||
$(TARGET): plain_decorator_theme.tar
|
||||
plain_decorator_theme.tar:
|
||||
$(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
|
||||
{
|
||||
Margins_from_metadata(char const *sub_node, Genode::Allocator &alloc)
|
||||
:
|
||||
Decorator::Theme::Margins()
|
||||
{
|
||||
Genode::Xml_node aura = metadata(alloc).sub_node(sub_node);
|
||||
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,
|
||||
Decorator::Alpha_surface &alpha_surface,
|
||||
Decorator::Alpha_surface &,
|
||||
char const *title) const
|
||||
{
|
||||
/* 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;
|
||||
|
||||
Nitpicker::Session::View_handle _neighbor;
|
||||
|
||||
unsigned _topped_cnt = 0;
|
||||
|
||||
Window_title _title;
|
||||
Window_title _title { };
|
||||
|
||||
bool _focused = false;
|
||||
|
||||
@ -67,63 +65,73 @@ class Decorator::Window : public Window_base, public Animator::Item
|
||||
|
||||
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 _present = false;
|
||||
bool _highlighted = false;
|
||||
bool _present = false;
|
||||
|
||||
Lazy_value<int> alpha = 0;
|
||||
int _alpha_dst() const
|
||||
{
|
||||
if (!_present)
|
||||
return 0;
|
||||
|
||||
int _alpha_dst() const
|
||||
{
|
||||
if (!_present)
|
||||
return 0;
|
||||
return _highlighted ? 255 : 150;
|
||||
}
|
||||
|
||||
return _highlighted ? 255 : 150;
|
||||
}
|
||||
void _update_alpha_dst()
|
||||
{
|
||||
if ((int)alpha == _alpha_dst())
|
||||
return;
|
||||
|
||||
void _update_alpha_dst()
|
||||
{
|
||||
if ((int)alpha == _alpha_dst())
|
||||
return;
|
||||
alpha.dst(_alpha_dst(), 20);
|
||||
animate();
|
||||
}
|
||||
|
||||
alpha.dst(_alpha_dst(), 20);
|
||||
animate();
|
||||
}
|
||||
public:
|
||||
|
||||
void highlighted(bool highlighted)
|
||||
{
|
||||
_highlighted = highlighted;
|
||||
_update_alpha_dst();
|
||||
}
|
||||
Theme::Element_type const type;
|
||||
|
||||
bool highlighted() const { return _highlighted; }
|
||||
char const * const attr;
|
||||
|
||||
void present(bool present)
|
||||
{
|
||||
_present = present;
|
||||
_update_alpha_dst();
|
||||
}
|
||||
Lazy_value<int> alpha = 0;
|
||||
|
||||
bool present() const { return _present; }
|
||||
void highlighted(bool highlighted)
|
||||
{
|
||||
_highlighted = highlighted;
|
||||
_update_alpha_dst();
|
||||
}
|
||||
|
||||
void animate() override
|
||||
{
|
||||
alpha.animate();
|
||||
animated((int)alpha != alpha.dst());
|
||||
}
|
||||
bool highlighted() const { return _highlighted; }
|
||||
|
||||
Element(Animator &animator, Theme::Element_type type, char const *attr)
|
||||
:
|
||||
Animator::Item(animator),
|
||||
type(type), attr(attr)
|
||||
{
|
||||
_update_alpha_dst();
|
||||
}
|
||||
void present(bool present)
|
||||
{
|
||||
_present = present;
|
||||
_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" };
|
||||
@ -139,7 +147,6 @@ class Decorator::Window : public Window_base, public Animator::Item
|
||||
struct Nitpicker_view
|
||||
{
|
||||
typedef Nitpicker::Session::Command Command;
|
||||
typedef Nitpicker::Session::View_handle View_handle;
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
void stack_back_most()
|
||||
{
|
||||
_nitpicker.enqueue<Command::To_back>(_handle, View_handle());
|
||||
}
|
||||
|
||||
void place(Rect rect, Point offset)
|
||||
{
|
||||
_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
|
||||
* 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); }
|
||||
|
||||
@ -232,14 +244,14 @@ class Decorator::Window : public Window_base, public Animator::Item
|
||||
* decorations.
|
||||
*/
|
||||
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
|
||||
* decorations.
|
||||
*/
|
||||
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 },
|
||||
_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);
|
||||
}
|
||||
|
||||
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:
|
||||
|
||||
Window(Genode::Env &env, unsigned id, Nitpicker::Session_client &nitpicker,
|
||||
@ -328,20 +348,27 @@ class Decorator::Window : public Window_base, public Animator::Item
|
||||
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());
|
||||
_right_view.stack(_left_view.handle());
|
||||
_bottom_view.stack(_right_view.handle());
|
||||
_content_view.stack(_bottom_view.handle());
|
||||
}
|
||||
void stack_front_most() override
|
||||
{
|
||||
_content_view.stack(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
|
||||
@ -371,11 +398,6 @@ class Decorator::Window : public Window_base, public Animator::Item
|
||||
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
|
||||
{
|
||||
if (!_nitpicker_views_up_to_date) {
|
||||
@ -405,24 +427,10 @@ class Decorator::Window : public Window_base, public Animator::Item
|
||||
animate();
|
||||
}
|
||||
|
||||
bool update(Xml_node window_node, bool new_top_most) override
|
||||
bool update(Xml_node window_node) override
|
||||
{
|
||||
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;
|
||||
|
||||
Rect const old_geometry = geometry();
|
||||
|
@ -21,6 +21,8 @@
|
||||
#include <util/geometry.h>
|
||||
#include <util/color.h>
|
||||
#include <util/dirty_rect.h>
|
||||
#include <util/list_model.h>
|
||||
#include <util/interface.h>
|
||||
#include <os/surface.h>
|
||||
|
||||
namespace Decorator {
|
||||
@ -34,6 +36,8 @@ namespace Decorator {
|
||||
using Genode::size_t;
|
||||
using Genode::Color;
|
||||
using Genode::Xml_node;
|
||||
using Genode::List_model;
|
||||
using Genode::Interface;
|
||||
}
|
||||
|
||||
#endif /* _INCLUDE__DECORATOR__TYPES_H_ */
|
||||
|
@ -15,9 +15,9 @@
|
||||
#define _INCLUDE__DECORATOR__WINDOW_H_
|
||||
|
||||
/* Genode includes */
|
||||
#include <util/list.h>
|
||||
#include <util/string.h>
|
||||
#include <util/xml_generator.h>
|
||||
#include <util/list_model.h>
|
||||
#include <nitpicker_session/client.h>
|
||||
#include <base/snprintf.h>
|
||||
|
||||
@ -29,14 +29,18 @@
|
||||
namespace Decorator {
|
||||
class Canvas_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:
|
||||
|
||||
typedef Nitpicker::Session::View_handle View_handle;
|
||||
|
||||
struct Border
|
||||
{
|
||||
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
|
||||
* 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;
|
||||
};
|
||||
|
||||
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
|
||||
*/
|
||||
Rect _geometry;
|
||||
Rect _geometry { };
|
||||
|
||||
/*
|
||||
* Unique window 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:
|
||||
|
||||
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; }
|
||||
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; }
|
||||
|
||||
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
|
||||
@ -125,10 +173,6 @@ class Decorator::Window_base : public Window_list::Element
|
||||
/**
|
||||
* 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
|
||||
*
|
||||
* 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
|
||||
* 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() { }
|
||||
|
||||
|
@ -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 void destroy (Window_base *) = 0;
|
||||
|
@ -31,24 +31,15 @@ class Decorator::Window_stack : public Window_base::Draw_behind_fn
|
||||
{
|
||||
private:
|
||||
|
||||
Window_list _windows;
|
||||
Window_factory_base &_window_factory;
|
||||
Dirty_rect mutable _dirty_rect;
|
||||
List_model<Window_base> _windows { };
|
||||
Window_factory_base &_window_factory;
|
||||
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,
|
||||
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
|
||||
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();
|
||||
}
|
||||
|
||||
void _destroy(Window_base &window)
|
||||
{
|
||||
_windows.remove(&window);
|
||||
_window_factory.destroy(&window);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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;
|
||||
while (Window_base *w = _windows.first()) {
|
||||
_windows.remove(w);
|
||||
reversed.insert(w);
|
||||
}
|
||||
Reversed_windows reversed { };
|
||||
_windows.for_each([&] (Window_base &window) {
|
||||
window.prepend_to_reverse_list(reversed); });
|
||||
return reversed;
|
||||
}
|
||||
|
||||
@ -91,12 +72,15 @@ class Decorator::Window_stack : public Window_base::Draw_behind_fn
|
||||
_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 result = _dirty_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;
|
||||
}
|
||||
@ -108,12 +92,13 @@ class Decorator::Window_stack : public Window_base::Draw_behind_fn
|
||||
{
|
||||
bool redraw_needed = false;
|
||||
|
||||
for (Window_base *win = _windows.first(); win; win = win->next()) {
|
||||
if (win->animated()) {
|
||||
_dirty_rect.mark_as_dirty(win->outer_geometry());
|
||||
_windows.for_each([&] (Window_base const &win) {
|
||||
|
||||
if (win.animated()) {
|
||||
_dirty_rect.mark_as_dirty(win.outer_geometry());
|
||||
redraw_needed = true;
|
||||
}
|
||||
}
|
||||
});
|
||||
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.
|
||||
*/
|
||||
template <typename FUNC>
|
||||
void for_each_window(FUNC const &func)
|
||||
{
|
||||
for (Window_base *win = _windows.first(); win; win = win->next())
|
||||
func(*win);
|
||||
}
|
||||
void for_each_window(FUNC const &func) { _windows.for_each(func); }
|
||||
|
||||
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
|
||||
* specified as neighbor of another view.
|
||||
*/
|
||||
Window_list reversed = _reversed_window_list();
|
||||
Reversed_windows reversed = _reversed_window_list();
|
||||
|
||||
while (Window_base *win = reversed.first()) {
|
||||
win->update_nitpicker_views();
|
||||
while (Genode::List_element<Window_base> *win = reversed.first()) {
|
||||
win->object()->update_nitpicker_views();
|
||||
reversed.remove(win);
|
||||
_windows.insert(win);
|
||||
}
|
||||
}
|
||||
|
||||
void flush()
|
||||
{
|
||||
while (Window_base *window = _windows.first())
|
||||
_destroy(*window);
|
||||
}
|
||||
|
||||
Window_base::Hover hover(Point pos) const
|
||||
{
|
||||
for (Window_base const *win = _windows.first(); win; win = win->next())
|
||||
if (win->outer_geometry().contains(pos)) {
|
||||
Window_base::Hover result { };
|
||||
|
||||
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)
|
||||
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 */
|
||||
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 */
|
||||
if (!win) return;
|
||||
@ -212,116 +190,58 @@ template <typename FN>
|
||||
void Decorator::Window_stack::update_model(Genode::Xml_node root_node,
|
||||
FN const &flush_window_stack_changes)
|
||||
{
|
||||
Window_list _destroyed_windows { };
|
||||
Abandoned_windows _abandoned_windows { };
|
||||
|
||||
unsigned long new_top_most_id = ~0UL;
|
||||
if (root_node.has_sub_node("window"))
|
||||
new_top_most_id = root_node.sub_node("window").attribute_value("id", ~0UL);
|
||||
struct Update_policy : List_model<Window_base>::Update_policy
|
||||
{
|
||||
Abandoned_windows &_abandoned_windows;
|
||||
Window_factory_base &_window_factory;
|
||||
Dirty_rect &_dirty_rect;
|
||||
|
||||
/*
|
||||
* Step 1: Remove windows that are no longer present.
|
||||
*/
|
||||
for (Window_base *window = _windows.first(), *next = nullptr; window; window = next) {
|
||||
next = window->next();
|
||||
try {
|
||||
_xml_node_by_window_id(root_node, window->id());
|
||||
Update_policy(Abandoned_windows &abandoned_windows,
|
||||
Window_factory_base &window_factory,
|
||||
Dirty_rect &dirty_rect)
|
||||
:
|
||||
_abandoned_windows(abandoned_windows),
|
||||
_window_factory(window_factory),
|
||||
_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);
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if window has came to front
|
||||
*/
|
||||
auto window_is_new_top_most = [&] (Window_base const &window) {
|
||||
return (_top_most_id != new_top_most_id) && (window.id() == new_top_most_id); };
|
||||
Window_base &create_element(Xml_node node)
|
||||
{
|
||||
return *_window_factory.create(node);
|
||||
}
|
||||
|
||||
/*
|
||||
* Step 2: Update window properties of already present windows.
|
||||
*/
|
||||
for (Window_base *window = _windows.first(); window; window = window->next()) {
|
||||
void update_element(Window_base &window, Xml_node node)
|
||||
{
|
||||
Rect const orig_geometry = window.outer_geometry();
|
||||
|
||||
/*
|
||||
* 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))) {
|
||||
if (window.update(node)) {
|
||||
_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"); }
|
||||
}
|
||||
|
||||
/*
|
||||
* Step 3: Add new appearing windows to the window stack.
|
||||
*/
|
||||
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;
|
||||
static bool element_matches_xml_node(Window_base const &elem, Xml_node node)
|
||||
{
|
||||
return elem.id() == node.attribute_value("id", ~0UL);
|
||||
}
|
||||
|
||||
unsigned long const id = attribute(window_node, "id", 0UL);
|
||||
static bool node_is_element(Xml_node) { return true; }
|
||||
};
|
||||
|
||||
if (window->id() != id) {
|
||||
window = _lookup_by_id(id);
|
||||
if (!window) {
|
||||
Genode::error("window lookup unexpectedly failed during re-ordering");
|
||||
return;
|
||||
}
|
||||
Update_policy policy { _abandoned_windows, _window_factory, _dirty_rect };
|
||||
|
||||
_windows.remove(window);
|
||||
_windows.insert(window, previous_window);
|
||||
_windows.update_from_xml(policy, root_node);
|
||||
|
||||
_dirty_rect.mark_as_dirty(window->outer_geometry());
|
||||
}
|
||||
|
||||
previous_window = window;
|
||||
window = window->next();
|
||||
});
|
||||
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);
|
||||
|
||||
/*
|
||||
* 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
|
||||
* 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);
|
||||
_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 */
|
||||
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);
|
||||
_windows.insert(w);
|
||||
|
||||
/* propagate change stacking order to nitpicker */
|
||||
if (w->in_front_of(*neighbor))
|
||||
continue;
|
||||
|
||||
w->stack(neighbor->frontmost_view());
|
||||
Window_base &window = *elem->object();
|
||||
stack_window(window, *neighbor);
|
||||
window.stacking_neighbor(neighbor->frontmost_view());
|
||||
neighbor = &window;
|
||||
}
|
||||
}
|
||||
|
||||
@ -362,7 +312,7 @@ void Decorator::Window_stack::update_model(Genode::Xml_node root_node,
|
||||
flush_window_stack_changes();
|
||||
|
||||
/*
|
||||
* Destroy window objects.
|
||||
* Destroy abandoned window objects
|
||||
*
|
||||
* This is done after all other operations to avoid flickering whenever one
|
||||
* 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
|
||||
* all times.
|
||||
*/
|
||||
for (Window_base *window = _destroyed_windows.first(), *next = nullptr; window; window = next) {
|
||||
next = window->next();
|
||||
_destroy(*window);
|
||||
Genode::List_element<Window_base> *elem = _abandoned_windows.first(), *next = nullptr;
|
||||
for (; elem; elem = next) {
|
||||
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_ */
|
||||
|
Loading…
x
Reference in New Issue
Block a user