mirror of
https://github.com/genodelabs/genode.git
synced 2025-03-04 05:21:19 +00:00
wm/decorator/layouter: window clipping
This patch changes the window-layout format to support the rectangular clipping of windows at screen boundaries. The new <boundary> node defines the clipping boundary for the windows listed within the node. Boundaries are expected to be disjoint. In the example below, the "vbox" window is placed partially outside the screen area of "screen_2". <window_layout> <boundary name="screen_1" xpos="0" ypos="0" width="640" height="480"> <window id="1" title="launchpad" xpos="10" ypos="140" width="400" height="> </boundary> <boundary name="screen_2" xpos="640" ypos="0" width="800" height="600"> <window id="2" title="vbox" xpos="520" ypos="52" width="800" height="600"> <window id="3" title="terminal" xpos="650" ypos="72" width="500" height="400"> </boundary> </window_layout> The layouter uses boundaries to restrict the visiblilty of windows to their respective target areas. Until now, Sculpt relied on the fact that the window-layout ROM had the same structure as the resize-request ROM. With the addition of the <boundary> nodes, this is no longer the case. Therefore, the Sculpt manager generates a dedicated resize-request ROM now. Issue #5390
This commit is contained in:
parent
b3d99960e7
commit
1638ee00c3
@ -77,24 +77,29 @@ install_config {
|
|||||||
<sleep milliseconds="500" />
|
<sleep milliseconds="500" />
|
||||||
<inline description="open window 1">
|
<inline description="open window 1">
|
||||||
<window_layout>
|
<window_layout>
|
||||||
|
<boundary width="1024" height="768">
|
||||||
<window id="1" title="Genode Toolchain"
|
<window id="1" title="Genode Toolchain"
|
||||||
xpos="100" ypos="50" width="200" height="200"
|
xpos="100" ypos="50" width="200" height="200"
|
||||||
focused="yes" />
|
focused="yes" />
|
||||||
|
</boundary>
|
||||||
</window_layout>
|
</window_layout>
|
||||||
</inline>
|
</inline>
|
||||||
<sleep milliseconds="1000" />
|
<sleep milliseconds="1000" />
|
||||||
<inline description="open window 2 behind window 1">
|
<inline description="open window 2 behind window 1">
|
||||||
<window_layout>
|
<window_layout>
|
||||||
|
<boundary width="1024" height="768">
|
||||||
<window id="1" title="Genode Toolchain"
|
<window id="1" title="Genode Toolchain"
|
||||||
xpos="100" ypos="50" width="200" height="200"
|
xpos="100" ypos="50" width="200" height="200"
|
||||||
focused="yes" />
|
focused="yes" />
|
||||||
<window id="2" title="Arora (2)"
|
<window id="2" title="Arora (2)"
|
||||||
xpos="170" ypos="150" width="300" height="200" />
|
xpos="170" ypos="150" width="300" height="200" />
|
||||||
|
</boundary>
|
||||||
</window_layout>
|
</window_layout>
|
||||||
</inline>
|
</inline>
|
||||||
<sleep milliseconds="1000" />
|
<sleep milliseconds="1000" />
|
||||||
<inline description="open window 3 in front">
|
<inline description="open window 3 in front">
|
||||||
<window_layout>
|
<window_layout>
|
||||||
|
<boundary width="1024" height="768">
|
||||||
<window id="3" title="Launchpad"
|
<window id="3" title="Launchpad"
|
||||||
xpos="210" ypos="250" width="400" height="200" />
|
xpos="210" ypos="250" width="400" height="200" />
|
||||||
<window id="1" title="Genode Toolchain"
|
<window id="1" title="Genode Toolchain"
|
||||||
@ -102,11 +107,13 @@ install_config {
|
|||||||
focused="yes" />
|
focused="yes" />
|
||||||
<window id="2" title="Arora (2)"
|
<window id="2" title="Arora (2)"
|
||||||
xpos="170" ypos="150" width="300" height="200" />
|
xpos="170" ypos="150" width="300" height="200" />
|
||||||
|
</boundary>
|
||||||
</window_layout>
|
</window_layout>
|
||||||
</inline>
|
</inline>
|
||||||
<sleep milliseconds="1000" />
|
<sleep milliseconds="1000" />
|
||||||
<inline description="bring window 1 to front">
|
<inline description="bring window 1 to front">
|
||||||
<window_layout>
|
<window_layout>
|
||||||
|
<boundary width="1024" height="768">
|
||||||
<window id="1" title="Genode Toolchain"
|
<window id="1" title="Genode Toolchain"
|
||||||
xpos="100" ypos="50" width="200" height="200"
|
xpos="100" ypos="50" width="200" height="200"
|
||||||
focused="yes" />
|
focused="yes" />
|
||||||
@ -114,11 +121,13 @@ install_config {
|
|||||||
xpos="210" ypos="250" width="400" height="200" />
|
xpos="210" ypos="250" width="400" height="200" />
|
||||||
<window id="2" title="Arora (2)"
|
<window id="2" title="Arora (2)"
|
||||||
xpos="170" ypos="150" width="300" height="200" />
|
xpos="170" ypos="150" width="300" height="200" />
|
||||||
|
</boundary>
|
||||||
</window_layout>
|
</window_layout>
|
||||||
</inline>
|
</inline>
|
||||||
<sleep milliseconds="1000" />
|
<sleep milliseconds="1000" />
|
||||||
<inline description="change title of window 1">
|
<inline description="change title of window 1">
|
||||||
<window_layout>
|
<window_layout>
|
||||||
|
<boundary width="1024" height="768">
|
||||||
<window id="1" title="Genode Toolchain (running)"
|
<window id="1" title="Genode Toolchain (running)"
|
||||||
xpos="100" ypos="50" width="200" height="200"
|
xpos="100" ypos="50" width="200" height="200"
|
||||||
focused="yes" />
|
focused="yes" />
|
||||||
@ -126,11 +135,13 @@ install_config {
|
|||||||
xpos="210" ypos="250" width="400" height="200" />
|
xpos="210" ypos="250" width="400" height="200" />
|
||||||
<window id="2" title="Arora (2)"
|
<window id="2" title="Arora (2)"
|
||||||
xpos="170" ypos="150" width="300" height="200" />
|
xpos="170" ypos="150" width="300" height="200" />
|
||||||
|
</boundary>
|
||||||
</window_layout>
|
</window_layout>
|
||||||
</inline>
|
</inline>
|
||||||
<sleep milliseconds="1000" />
|
<sleep milliseconds="1000" />
|
||||||
<inline description="change focus to window 3">
|
<inline description="change focus to window 3">
|
||||||
<window_layout>
|
<window_layout>
|
||||||
|
<boundary width="1024" height="768">
|
||||||
<window id="1" title="Genode Toolchain (running)"
|
<window id="1" title="Genode Toolchain (running)"
|
||||||
xpos="100" ypos="50" width="200" height="200" />
|
xpos="100" ypos="50" width="200" height="200" />
|
||||||
<window id="3" title="Launchpad"
|
<window id="3" title="Launchpad"
|
||||||
@ -138,11 +149,13 @@ install_config {
|
|||||||
focused="yes" />
|
focused="yes" />
|
||||||
<window id="2" title="Arora (2)"
|
<window id="2" title="Arora (2)"
|
||||||
xpos="170" ypos="150" width="300" height="200" />
|
xpos="170" ypos="150" width="300" height="200" />
|
||||||
|
</boundary>
|
||||||
</window_layout>
|
</window_layout>
|
||||||
</inline>
|
</inline>
|
||||||
<sleep milliseconds="1000" />
|
<sleep milliseconds="1000" />
|
||||||
<inline description="move window 3">
|
<inline description="move window 3">
|
||||||
<window_layout>
|
<window_layout>
|
||||||
|
<boundary width="1024" height="768">
|
||||||
<window id="1" title="Genode Toolchain"
|
<window id="1" title="Genode Toolchain"
|
||||||
xpos="100" ypos="50" width="200" height="200" />
|
xpos="100" ypos="50" width="200" height="200" />
|
||||||
<window id="3" title="Launchpad"
|
<window id="3" title="Launchpad"
|
||||||
@ -150,6 +163,7 @@ install_config {
|
|||||||
focused="yes" />
|
focused="yes" />
|
||||||
<window id="2" title="Arora (2)"
|
<window id="2" title="Arora (2)"
|
||||||
xpos="170" ypos="150" width="300" height="200" />
|
xpos="170" ypos="150" width="300" height="200" />
|
||||||
|
</boundary>
|
||||||
</window_layout>
|
</window_layout>
|
||||||
</inline>
|
</inline>
|
||||||
<sleep milliseconds="1000" />
|
<sleep milliseconds="1000" />
|
||||||
@ -160,7 +174,7 @@ install_config {
|
|||||||
</start>
|
</start>
|
||||||
|
|
||||||
<start name="decorator">
|
<start name="decorator">
|
||||||
<resource name="RAM" quantum="4M"/>
|
<resource name="RAM" quantum="8M"/>
|
||||||
<route>
|
<route>
|
||||||
<service name="ROM" label="pointer">
|
<service name="ROM" label="pointer">
|
||||||
<child name="report_rom" />
|
<child name="report_rom" />
|
||||||
|
@ -114,7 +114,7 @@
|
|||||||
</provides>
|
</provides>
|
||||||
<config verbose="no">
|
<config verbose="no">
|
||||||
<policy label="decorator -> window_layout" report="manager -> window_layout"/>
|
<policy label="decorator -> window_layout" report="manager -> window_layout"/>
|
||||||
<policy label="wm -> resize_request" report="manager -> window_layout"/>
|
<policy label="wm -> resize_request" report="manager -> resize_request"/>
|
||||||
<policy label="wm -> focus" report="manager -> wm_focus"/>
|
<policy label="wm -> focus" report="manager -> wm_focus"/>
|
||||||
<policy label="decorator -> pointer" report="wm -> pointer"/>
|
<policy label="decorator -> pointer" report="wm -> pointer"/>
|
||||||
<policy label="manager -> window_list" report="wm -> window_list"/>
|
<policy label="manager -> window_list" report="wm -> window_list"/>
|
||||||
|
@ -40,6 +40,8 @@ struct Decorator::Main : Window_factory_base
|
|||||||
{
|
{
|
||||||
Env &_env;
|
Env &_env;
|
||||||
|
|
||||||
|
Heap _heap { _env.ram(), _env.rm() };
|
||||||
|
|
||||||
Timer::Connection _timer { _env };
|
Timer::Connection _timer { _env };
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -120,7 +122,9 @@ struct Decorator::Main : Window_factory_base
|
|||||||
_back_to_front(dirty);
|
_back_to_front(dirty);
|
||||||
}
|
}
|
||||||
|
|
||||||
Window_stack _window_stack = { *this };
|
Window_stack _window_stack { *this, _heap };
|
||||||
|
|
||||||
|
Windows _windows { };
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Handler for responding to window-layout changes
|
* Handler for responding to window-layout changes
|
||||||
@ -172,8 +176,6 @@ struct Decorator::Main : Window_factory_base
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Heap _heap { _env.ram(), _env.rm() };
|
|
||||||
|
|
||||||
Attached_rom_dataspace _config { _env, "config" };
|
Attached_rom_dataspace _config { _env, "config" };
|
||||||
|
|
||||||
void _handle_config();
|
void _handle_config();
|
||||||
@ -222,19 +224,34 @@ struct Decorator::Main : Window_factory_base
|
|||||||
/**
|
/**
|
||||||
* Window_factory_base interface
|
* Window_factory_base interface
|
||||||
*/
|
*/
|
||||||
Window_base *create(Xml_node window_node) override
|
Window_base::Ref &create_ref(Xml_node const &window_node) override
|
||||||
{
|
{
|
||||||
return new (_heap)
|
Windows::Id const id { window_node.attribute_value("id", 0U) };
|
||||||
Window(window_node.attribute_value("id", 0U),
|
|
||||||
_gui, _animator, _decorator_config);
|
Window_base *window_ptr = nullptr;
|
||||||
|
_windows.apply<Window_base>(id,
|
||||||
|
[&] (Window_base &window) { window_ptr = &window; },
|
||||||
|
[&] /* missing */ {
|
||||||
|
window_ptr = new (_heap)
|
||||||
|
Window(_windows, id, _gui, _animator, _decorator_config); });
|
||||||
|
|
||||||
|
return *new (_heap) Window_base::Ref(*window_ptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Window_factory_base interface
|
* Window_factory_base interface
|
||||||
*/
|
*/
|
||||||
void destroy(Window_base *window) override
|
void destroy_ref(Window_base::Ref &ref) override
|
||||||
{
|
{
|
||||||
Genode::destroy(_heap, static_cast<Window *>(window));
|
destroy(_heap, &ref);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Window_factory_base interface
|
||||||
|
*/
|
||||||
|
void destroy_window(Window_base &window) override
|
||||||
|
{
|
||||||
|
destroy(_heap, &window);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -280,11 +297,11 @@ static void update_hover_report(Genode::Xml_node pointer_node,
|
|||||||
|
|
||||||
Genode::Reporter::Xml_generator xml(hover_reporter, [&] ()
|
Genode::Reporter::Xml_generator xml(hover_reporter, [&] ()
|
||||||
{
|
{
|
||||||
if (hover.window_id > 0) {
|
if (hover.window_id.value > 0) {
|
||||||
|
|
||||||
xml.node("window", [&] () {
|
xml.node("window", [&] () {
|
||||||
|
|
||||||
xml.attribute("id", hover.window_id);
|
xml.attribute("id", hover.window_id.value);
|
||||||
|
|
||||||
if (hover.left_sizer) xml.node("left_sizer");
|
if (hover.left_sizer) xml.node("left_sizer");
|
||||||
if (hover.right_sizer) xml.node("right_sizer");
|
if (hover.right_sizer) xml.node("right_sizer");
|
||||||
|
@ -15,9 +15,8 @@
|
|||||||
#include "window.h"
|
#include "window.h"
|
||||||
|
|
||||||
|
|
||||||
void Decorator::Window::draw(Decorator::Canvas_base &canvas,
|
void Decorator::Window::draw(Decorator::Canvas_base &canvas, Ref const &win_ref,
|
||||||
Decorator::Rect clip,
|
Decorator::Rect clip, Draw_behind_fn const &draw_behind_fn) const
|
||||||
Draw_behind_fn const &draw_behind_fn) const
|
|
||||||
{
|
{
|
||||||
Clip_guard clip_guard(canvas, clip);
|
Clip_guard clip_guard(canvas, clip);
|
||||||
|
|
||||||
@ -28,7 +27,7 @@ void Decorator::Window::draw(Decorator::Canvas_base &canvas,
|
|||||||
Point p2 = rect.p2();
|
Point p2 = rect.p2();
|
||||||
|
|
||||||
if (_has_alpha)
|
if (_has_alpha)
|
||||||
draw_behind_fn.draw_behind(canvas, *this, canvas.clip());
|
draw_behind_fn.draw_behind(canvas, win_ref, canvas.clip());
|
||||||
|
|
||||||
_draw_corner(canvas, Rect(p1, corner), _border_size, true, true,
|
_draw_corner(canvas, Rect(p1, corner), _border_size, true, true,
|
||||||
_window_elem_attr(Element::TOP_LEFT));
|
_window_elem_attr(Element::TOP_LEFT));
|
||||||
|
@ -38,6 +38,8 @@ class Decorator::Window : public Window_base
|
|||||||
*/
|
*/
|
||||||
bool _gui_views_up_to_date = false;
|
bool _gui_views_up_to_date = false;
|
||||||
|
|
||||||
|
Rect _clip { }; /* most recently used clipping rectangle */
|
||||||
|
|
||||||
struct Gui_view : Genode::Noncopyable
|
struct Gui_view : Genode::Noncopyable
|
||||||
{
|
{
|
||||||
Gui::Connection &_gui;
|
Gui::Connection &_gui;
|
||||||
@ -74,11 +76,18 @@ class Decorator::Window : public Window_base
|
|||||||
|
|
||||||
void stack_back_most() { _gui.enqueue<Command::Back>(id()); }
|
void stack_back_most() { _gui.enqueue<Command::Back>(id()); }
|
||||||
|
|
||||||
void place(Rect rect)
|
void place_as_decor(Clip const &clip, Rect rect)
|
||||||
{
|
{
|
||||||
_gui.enqueue<Command::Geometry>(id(), rect);
|
Rect const intersection = Rect::intersect(clip, rect);
|
||||||
Point offset = Point(0, 0) - rect.at;
|
_gui.enqueue<Command::Geometry>(id(), intersection);
|
||||||
_gui.enqueue<Command::Offset>(id(), offset);
|
_gui.enqueue<Command::Offset>(id(), Point() - intersection.at);
|
||||||
|
}
|
||||||
|
|
||||||
|
void place_as_content(Clip const &clip, Rect rect)
|
||||||
|
{
|
||||||
|
Rect const intersection = Rect::intersect(clip, rect);
|
||||||
|
_gui.enqueue<Command::Geometry>(id(), intersection);
|
||||||
|
_gui.enqueue<Command::Offset>(id(), rect.at - intersection.at);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -87,7 +96,7 @@ class Decorator::Window : public Window_base
|
|||||||
_left_view { _gui },
|
_left_view { _gui },
|
||||||
_top_view { _gui };
|
_top_view { _gui };
|
||||||
|
|
||||||
Gui_view _content_view { _gui, (unsigned)id() };
|
Gui_view _content_view { _gui, unsigned(id().value) };
|
||||||
|
|
||||||
static Border _init_border() {
|
static Border _init_border() {
|
||||||
return Border(_border_size + _title_height,
|
return Border(_border_size + _title_height,
|
||||||
@ -419,10 +428,10 @@ class Decorator::Window : public Window_base
|
|||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
Window(unsigned id, Gui::Connection &gui,
|
Window(Windows &windows, Windows::Id id, Gui::Connection &gui,
|
||||||
Animator &animator, Config const &config)
|
Animator &animator, Config const &config)
|
||||||
:
|
:
|
||||||
Window_base(id),
|
Window_base(windows, id),
|
||||||
_gui(gui),
|
_gui(gui),
|
||||||
_animator(animator), _config(config)
|
_animator(animator), _config(config)
|
||||||
{ }
|
{ }
|
||||||
@ -465,18 +474,18 @@ class Decorator::Window : public Window_base
|
|||||||
geometry().p2() + Point(_border.right, _border.bottom));
|
geometry().p2() + Point(_border.right, _border.bottom));
|
||||||
}
|
}
|
||||||
|
|
||||||
void update_gui_views() override
|
void update_gui_views(Clip const &clip) override
|
||||||
{
|
{
|
||||||
if (!_gui_views_up_to_date) {
|
if (!_gui_views_up_to_date || (clip != _clip)) {
|
||||||
|
|
||||||
/* update view positions */
|
/* update view positions */
|
||||||
auto const border = outer_geometry().cut(geometry());
|
auto const border = outer_geometry().cut(geometry());
|
||||||
|
|
||||||
_content_view.place(geometry());
|
_content_view.place_as_content(clip, geometry());
|
||||||
_top_view .place(border.top);
|
_top_view .place_as_decor (clip, border.top);
|
||||||
_left_view .place(border.left);
|
_left_view .place_as_decor (clip, border.left);
|
||||||
_right_view .place(border.right);
|
_right_view .place_as_decor (clip, border.right);
|
||||||
_bottom_view .place(border.bottom);
|
_bottom_view .place_as_decor (clip, border.bottom);
|
||||||
|
|
||||||
_gui_views_up_to_date = true;
|
_gui_views_up_to_date = true;
|
||||||
}
|
}
|
||||||
@ -487,7 +496,7 @@ class Decorator::Window : public Window_base
|
|||||||
_base_color = _config.base_color(_title);
|
_base_color = _config.base_color(_title);
|
||||||
}
|
}
|
||||||
|
|
||||||
void draw(Canvas_base &canvas, Rect clip, Draw_behind_fn const &) const override;
|
void draw(Canvas_base &canvas, Ref const &, Rect clip, Draw_behind_fn const &) const override;
|
||||||
|
|
||||||
bool update(Xml_node) override;
|
bool update(Xml_node) override;
|
||||||
|
|
||||||
|
@ -1623,6 +1623,7 @@ struct Sculpt::Main : Input_event_handler,
|
|||||||
|
|
||||||
Expanding_reporter _wm_focus { _env, "focus", "wm_focus" };
|
Expanding_reporter _wm_focus { _env, "focus", "wm_focus" };
|
||||||
Expanding_reporter _window_layout { _env, "window_layout", "window_layout" };
|
Expanding_reporter _window_layout { _env, "window_layout", "window_layout" };
|
||||||
|
Expanding_reporter _resize_request { _env, "resize_request", "resize_request" };
|
||||||
|
|
||||||
template <size_t N>
|
template <size_t N>
|
||||||
void _with_window(Xml_node window_list, String<N> const &match, auto const &fn)
|
void _with_window(Xml_node window_list, String<N> const &match, auto const &fn)
|
||||||
@ -1906,10 +1907,20 @@ void Sculpt::Main::_update_window_layout(Xml_node const &decorator_margins,
|
|||||||
Point const inspect_p2(avail.x2() - margins.right - 1,
|
Point const inspect_p2(avail.x2() - margins.right - 1,
|
||||||
avail.y2() - margins.bottom - 1);
|
avail.y2() - margins.bottom - 1);
|
||||||
|
|
||||||
|
auto generate_within_screen_boundary = [&] (auto const &fn)
|
||||||
|
{
|
||||||
|
_resize_request.generate([&] (Xml_generator &resize_xml) {
|
||||||
_window_layout.generate([&] (Xml_generator &xml) {
|
_window_layout.generate([&] (Xml_generator &xml) {
|
||||||
|
xml.node("boundary", [&] {
|
||||||
|
xml.attribute("width", _screen_size.w);
|
||||||
|
xml.attribute("height", _screen_size.h);
|
||||||
|
fn(xml, resize_xml); }); }); });
|
||||||
|
};
|
||||||
|
|
||||||
|
generate_within_screen_boundary([&] (Xml_generator &xml, Xml_generator &resize_xml) {
|
||||||
|
|
||||||
auto gen_window = [&] (Xml_node const &win, Rect rect) {
|
auto gen_window = [&] (Xml_node const &win, Rect rect) {
|
||||||
if (rect.valid()) {
|
if (rect.valid())
|
||||||
xml.node("window", [&] {
|
xml.node("window", [&] {
|
||||||
xml.attribute("id", win.attribute_value("id", 0UL));
|
xml.attribute("id", win.attribute_value("id", 0UL));
|
||||||
xml.attribute("xpos", rect.x1());
|
xml.attribute("xpos", rect.x1());
|
||||||
@ -1918,7 +1929,15 @@ void Sculpt::Main::_update_window_layout(Xml_node const &decorator_margins,
|
|||||||
xml.attribute("height", rect.h());
|
xml.attribute("height", rect.h());
|
||||||
xml.attribute("title", win.attribute_value("label", Label()));
|
xml.attribute("title", win.attribute_value("label", Label()));
|
||||||
});
|
});
|
||||||
}
|
};
|
||||||
|
|
||||||
|
auto gen_resize = [&] (Xml_node const &win, Area area) {
|
||||||
|
if (area.valid())
|
||||||
|
resize_xml.node("window", [&] {
|
||||||
|
resize_xml.attribute("id", win.attribute_value("id", 0UL));
|
||||||
|
resize_xml.attribute("width", area.w);
|
||||||
|
resize_xml.attribute("height", area.h);
|
||||||
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
/* window size limited to space unobstructed by the menu and log */
|
/* window size limited to space unobstructed by the menu and log */
|
||||||
@ -1935,7 +1954,10 @@ void Sculpt::Main::_update_window_layout(Xml_node const &decorator_margins,
|
|||||||
gen_window(win, panel); });
|
gen_window(win, panel); });
|
||||||
|
|
||||||
_with_window(window_list, Label("log"), [&] (Xml_node const &win) {
|
_with_window(window_list, Label("log"), [&] (Xml_node const &win) {
|
||||||
gen_window(win, Rect::compound(log_p1, log_p2)); });
|
Rect const rect = Rect::compound(log_p1, log_p2);
|
||||||
|
gen_window(win, rect);
|
||||||
|
gen_resize(win, rect.area);
|
||||||
|
});
|
||||||
|
|
||||||
int system_right_xpos = 0;
|
int system_right_xpos = 0;
|
||||||
if (system_available()) {
|
if (system_available()) {
|
||||||
@ -2058,8 +2080,12 @@ void Sculpt::Main::_update_window_layout(Xml_node const &decorator_margins,
|
|||||||
}
|
}
|
||||||
|
|
||||||
_with_window(window_list, inspect_label, [&] (Xml_node const &win) {
|
_with_window(window_list, inspect_label, [&] (Xml_node const &win) {
|
||||||
if (_selected_tab == Panel_dialog::Tab::INSPECT)
|
if (_selected_tab == Panel_dialog::Tab::INSPECT) {
|
||||||
gen_window(win, Rect::compound(inspect_p1, inspect_p2)); });
|
Rect const rect = Rect::compound(inspect_p1, inspect_p2);
|
||||||
|
gen_window(win, rect);
|
||||||
|
gen_resize(win, rect.area);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Position runtime view centered within the inspect area, but allow
|
* Position runtime view centered within the inspect area, but allow
|
||||||
|
@ -37,6 +37,8 @@ struct Decorator::Main : Window_factory_base
|
|||||||
{
|
{
|
||||||
Env &_env;
|
Env &_env;
|
||||||
|
|
||||||
|
Heap _heap { _env.ram(), _env.rm() };
|
||||||
|
|
||||||
Timer::Connection _timer { _env };
|
Timer::Connection _timer { _env };
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -49,7 +51,9 @@ struct Decorator::Main : Window_factory_base
|
|||||||
return { .cs = _timer.curr_time().trunc_to_plain_ms().value / 10 };
|
return { .cs = _timer.curr_time().trunc_to_plain_ms().value / 10 };
|
||||||
}
|
}
|
||||||
|
|
||||||
Window_stack _window_stack = { *this };
|
Window_stack _window_stack = { *this, _heap };
|
||||||
|
|
||||||
|
Windows _windows { };
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Handler for responding to window-layout changes
|
* Handler for responding to window-layout changes
|
||||||
@ -84,8 +88,6 @@ struct Decorator::Main : Window_factory_base
|
|||||||
|
|
||||||
Animator _animator { };
|
Animator _animator { };
|
||||||
|
|
||||||
Heap _heap { _env.ram(), _env.rm() };
|
|
||||||
|
|
||||||
Theme _theme { _env.ram(), _env.rm(), _heap };
|
Theme _theme { _env.ram(), _env.rm(), _heap };
|
||||||
|
|
||||||
Reporter _decorator_margins_reporter = { _env, "decorator_margins" };
|
Reporter _decorator_margins_reporter = { _env, "decorator_margins" };
|
||||||
@ -177,19 +179,35 @@ struct Decorator::Main : Window_factory_base
|
|||||||
/**
|
/**
|
||||||
* Window_factory_base interface
|
* Window_factory_base interface
|
||||||
*/
|
*/
|
||||||
Window_base *create(Xml_node window_node) override
|
Window_base::Ref &create_ref(Xml_node const &window_node) override
|
||||||
{
|
{
|
||||||
return new (_heap)
|
Windows::Id const id { window_node.attribute_value("id", 0U) };
|
||||||
Window(_env, window_node.attribute_value("id", 0U),
|
|
||||||
_gui, _animator, _theme, _decorator_config);
|
Window_base *window_ptr = nullptr;
|
||||||
|
_windows.apply<Window_base>(id,
|
||||||
|
[&] (Window_base &window) { window_ptr = &window; },
|
||||||
|
[&] /* missing */ {
|
||||||
|
window_ptr = new (_heap)
|
||||||
|
Window(_env, _windows, id, _gui, _animator, _theme,
|
||||||
|
_decorator_config); });
|
||||||
|
|
||||||
|
return *new (_heap) Window_base::Ref(*window_ptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Window_factory_base interface
|
* Window_factory_base interface
|
||||||
*/
|
*/
|
||||||
void destroy(Window_base *window) override
|
void destroy_ref(Window_base::Ref &ref) override
|
||||||
{
|
{
|
||||||
Genode::destroy(_heap, static_cast<Window *>(window));
|
destroy(_heap, &ref);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Window_factory_base interface
|
||||||
|
*/
|
||||||
|
void destroy_window(Window_base &window) override
|
||||||
|
{
|
||||||
|
destroy(_heap, &window);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -233,11 +251,11 @@ static void update_hover_report(Genode::Xml_node pointer_node,
|
|||||||
|
|
||||||
Genode::Reporter::Xml_generator xml(hover_reporter, [&] ()
|
Genode::Reporter::Xml_generator xml(hover_reporter, [&] ()
|
||||||
{
|
{
|
||||||
if (hover.window_id > 0) {
|
if (hover.window_id.value > 0) {
|
||||||
|
|
||||||
xml.node("window", [&] () {
|
xml.node("window", [&] () {
|
||||||
|
|
||||||
xml.attribute("id", hover.window_id);
|
xml.attribute("id", hover.window_id.value);
|
||||||
|
|
||||||
if (hover.left_sizer) xml.node("left_sizer");
|
if (hover.left_sizer) xml.node("left_sizer");
|
||||||
if (hover.right_sizer) xml.node("right_sizer");
|
if (hover.right_sizer) xml.node("right_sizer");
|
||||||
|
@ -161,7 +161,9 @@ element_geometry(Genode::Ram_allocator &ram, Genode::Region_map &rm,
|
|||||||
Genode::Allocator &alloc, char const *sub_node_type,
|
Genode::Allocator &alloc, char const *sub_node_type,
|
||||||
Texture_id texture_id)
|
Texture_id texture_id)
|
||||||
{
|
{
|
||||||
using namespace Decorator;
|
using Rect = Decorator::Rect;
|
||||||
|
using Point = Decorator::Point;
|
||||||
|
using Area = Decorator::Area;
|
||||||
|
|
||||||
static Genode::Xml_node const node = metadata(alloc);
|
static Genode::Xml_node const node = metadata(alloc);
|
||||||
|
|
||||||
|
@ -19,6 +19,7 @@
|
|||||||
#include <os/texture.h>
|
#include <os/texture.h>
|
||||||
#include <os/pixel_alpha8.h>
|
#include <os/pixel_alpha8.h>
|
||||||
#include <os/pixel_rgb888.h>
|
#include <os/pixel_rgb888.h>
|
||||||
|
#include <decorator/types.h>
|
||||||
|
|
||||||
namespace Decorator {
|
namespace Decorator {
|
||||||
|
|
||||||
@ -29,10 +30,6 @@ namespace Decorator {
|
|||||||
|
|
||||||
using Pixel_surface = Genode::Surface<Pixel_rgb888>;
|
using Pixel_surface = Genode::Surface<Pixel_rgb888>;
|
||||||
using Alpha_surface = Genode::Surface<Pixel_alpha8>;
|
using Alpha_surface = Genode::Surface<Pixel_alpha8>;
|
||||||
|
|
||||||
using Area = Genode::Surface_base::Area;
|
|
||||||
using Point = Genode::Surface_base::Point;
|
|
||||||
using Rect = Genode::Surface_base::Rect;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -52,6 +52,8 @@ class Decorator::Window : public Window_base, public Animator::Item
|
|||||||
*/
|
*/
|
||||||
bool _gui_views_up_to_date = false;
|
bool _gui_views_up_to_date = false;
|
||||||
|
|
||||||
|
Rect _clip { }; /* most recently used clipping rectangle */
|
||||||
|
|
||||||
unsigned _topped_cnt = 0;
|
unsigned _topped_cnt = 0;
|
||||||
|
|
||||||
Window_title _title { };
|
Window_title _title { };
|
||||||
@ -162,10 +164,11 @@ class Decorator::Window : public Window_base, public Animator::Item
|
|||||||
|
|
||||||
void stack_back_most() { _gui.enqueue<Command::Back>(id()); }
|
void stack_back_most() { _gui.enqueue<Command::Back>(id()); }
|
||||||
|
|
||||||
void place(Rect rect, Point offset)
|
void place(Clip const &clip, Rect rect, Point offset)
|
||||||
{
|
{
|
||||||
_gui.enqueue<Command::Geometry>(id(), rect);
|
Rect const intersection = Rect::intersect(clip, rect);
|
||||||
_gui.enqueue<Command::Offset>(id(), offset);
|
_gui.enqueue<Command::Geometry>(id(), intersection);
|
||||||
|
_gui.enqueue<Command::Offset>(id(), offset + rect.at - intersection.at);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -263,7 +266,7 @@ class Decorator::Window : public Window_base, public Animator::Item
|
|||||||
_left_view { _gui, _gui_left_right },
|
_left_view { _gui, _gui_left_right },
|
||||||
_top_view { _gui, _gui_top_bottom };
|
_top_view { _gui, _gui_top_bottom };
|
||||||
|
|
||||||
Content_view _content_view { _gui, (unsigned)id() };
|
Content_view _content_view { _gui, unsigned(id().value) };
|
||||||
|
|
||||||
void _repaint_decorations(Gui_buffer &buffer, Area area)
|
void _repaint_decorations(Gui_buffer &buffer, Area area)
|
||||||
{
|
{
|
||||||
@ -352,10 +355,11 @@ class Decorator::Window : public Window_base, public Animator::Item
|
|||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
Window(Genode::Env &env, unsigned id, Gui::Connection &gui,
|
Window(Genode::Env &env, Windows &windows, Windows::Id id,
|
||||||
Animator &animator, Theme const &theme, Config const &config)
|
Gui::Connection &gui, Animator &animator, Theme const &theme,
|
||||||
|
Config const &config)
|
||||||
:
|
:
|
||||||
Window_base(id),
|
Window_base(windows, id),
|
||||||
Animator::Item(animator),
|
Animator::Item(animator),
|
||||||
_env(env), _theme(theme), _animator(animator),
|
_env(env), _theme(theme), _animator(animator),
|
||||||
_gui(gui), _config(config)
|
_gui(gui), _config(config)
|
||||||
@ -433,11 +437,10 @@ class Decorator::Window : public Window_base, public Animator::Item
|
|||||||
return _outer_from_inner_geometry(geometry());
|
return _outer_from_inner_geometry(geometry());
|
||||||
}
|
}
|
||||||
|
|
||||||
void update_gui_views() override
|
void update_gui_views(Clip const &clip) override
|
||||||
{
|
{
|
||||||
bool const gui_view_rect_up_to_date =
|
bool const gui_view_rect_up_to_date = (_gui_view_rect == geometry())
|
||||||
_gui_view_rect.p1() == geometry().p1() &&
|
&& (_clip == clip);
|
||||||
_gui_view_rect.p2() == geometry().p2();
|
|
||||||
|
|
||||||
if (!_gui_views_up_to_date || !gui_view_rect_up_to_date) {
|
if (!_gui_views_up_to_date || !gui_view_rect_up_to_date) {
|
||||||
|
|
||||||
@ -448,20 +451,21 @@ class Decorator::Window : public Window_base, public Animator::Item
|
|||||||
/* update view positions */
|
/* update view positions */
|
||||||
Rect::Cut_remainder const r = outer.cut(inner);
|
Rect::Cut_remainder const r = outer.cut(inner);
|
||||||
|
|
||||||
_content_view.place(inner, Point(0, 0));
|
_content_view.place(clip, inner, Point(0, 0));
|
||||||
_top_view .place(r.top, Point(0, 0));
|
_top_view .place(clip, r.top, Point(0, 0));
|
||||||
_left_view .place(r.left, Point(0, -r.top.h()));
|
_left_view .place(clip, r.left, Point(0, -r.top.h()));
|
||||||
_right_view .place(r.right, Point(-r.right.w(), -r.top.h()));
|
_right_view .place(clip, r.right, Point(-r.right.w(), -r.top.h()));
|
||||||
_bottom_view .place(r.bottom, Point(0, -theme_size.h + r.bottom.h()));
|
_bottom_view .place(clip, r.bottom, Point(0, -theme_size.h + r.bottom.h()));
|
||||||
|
|
||||||
_gui.execute();
|
_gui.execute();
|
||||||
|
|
||||||
_gui_view_rect = inner;
|
_gui_view_rect = inner;
|
||||||
_gui_views_up_to_date = true;
|
_gui_views_up_to_date = true;
|
||||||
|
_clip = clip;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void draw(Canvas_base &, Rect, Draw_behind_fn const &) const override { }
|
void draw(Canvas_base &, Ref const &, Rect, Draw_behind_fn const &) const override { }
|
||||||
|
|
||||||
void adapt_to_changed_config()
|
void adapt_to_changed_config()
|
||||||
{
|
{
|
||||||
|
@ -90,11 +90,24 @@ class Window_layouter::Assign_list : Noncopyable
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename FN>
|
void for_each(auto const &fn) { _assignments.for_each(fn); }
|
||||||
void for_each(FN const &fn) { _assignments.for_each(fn); }
|
void for_each(auto const &fn) const { _assignments.for_each(fn); }
|
||||||
|
|
||||||
template <typename FN>
|
void for_each_visible(auto const &target_name, auto const &fn) const
|
||||||
void for_each(FN const &fn) const { _assignments.for_each(fn); }
|
{
|
||||||
|
for_each([&] (Assign const &assign) {
|
||||||
|
if (assign.visible() && target_name == assign.target_name())
|
||||||
|
fn(assign); });
|
||||||
|
}
|
||||||
|
|
||||||
|
bool target_empty(auto const &target_name) const
|
||||||
|
{
|
||||||
|
bool result = true;
|
||||||
|
for_each_visible(target_name, [&] (Assign const &assign) {
|
||||||
|
assign.for_each_member([&] (Assign::Member const &) {
|
||||||
|
result = false; }); });
|
||||||
|
return result;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif /* _ASSIGN_LIST_H_ */
|
#endif /* _ASSIGN_LIST_H_ */
|
||||||
|
@ -146,29 +146,28 @@ class Window_layouter::Target_list
|
|||||||
if (target.layer() >= min_layer && target.layer() <= layer)
|
if (target.layer() >= min_layer && target.layer() <= layer)
|
||||||
layer = target.layer(); });
|
layer = target.layer(); });
|
||||||
|
|
||||||
/* visit all windows on the layer */
|
|
||||||
assignments.for_each([&] (Assign const &assign) {
|
|
||||||
|
|
||||||
if (!assign.visible())
|
|
||||||
return;
|
|
||||||
|
|
||||||
Target::Name const target_name = assign.target_name();
|
|
||||||
|
|
||||||
/* search target by name */
|
/* search target by name */
|
||||||
_targets.for_each([&] (Target const &target) {
|
_targets.for_each([&] (Target const &target) {
|
||||||
|
|
||||||
if (target.name() != target_name)
|
|
||||||
return;
|
|
||||||
|
|
||||||
if (target.layer() != layer)
|
if (target.layer() != layer)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (!target.visible())
|
if (!target.visible())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
/* found target area, iterate though all assigned windows */
|
if (assignments.target_empty(target.name()))
|
||||||
|
return;
|
||||||
|
|
||||||
|
Rect const boundary = target.geometry();
|
||||||
|
xml.node("boundary", [&] {
|
||||||
|
xml.attribute("name", target.name());
|
||||||
|
generate(xml, boundary);
|
||||||
|
|
||||||
|
/* visit all windows on the layer */
|
||||||
|
assignments.for_each_visible(target.name(), [&] (Assign const &assign) {
|
||||||
assign.for_each_member([&] (Assign::Member const &member) {
|
assign.for_each_member([&] (Assign::Member const &member) {
|
||||||
member.window.generate(xml, target.geometry()); });
|
member.window.generate(xml, boundary); });
|
||||||
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -78,6 +78,14 @@ namespace Window_layouter {
|
|||||||
from.for_each_sub_node([&] (Xml_node const &sub_node) {
|
from.for_each_sub_node([&] (Xml_node const &sub_node) {
|
||||||
copy_node(xml, sub_node, { max_depth.value - 1 }); }); });
|
copy_node(xml, sub_node, { max_depth.value - 1 }); }); });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void generate(Xml_generator &xml, Rect const &rect)
|
||||||
|
{
|
||||||
|
xml.attribute("xpos", rect.x1());
|
||||||
|
xml.attribute("ypos", rect.y1());
|
||||||
|
xml.attribute("width", rect.w());
|
||||||
|
xml.attribute("height", rect.h());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif /* _TYPES_H_ */
|
#endif /* _TYPES_H_ */
|
||||||
|
@ -64,6 +64,11 @@ struct Wm::Decorator_gui_session : Session_object<Gui::Session>,
|
|||||||
|
|
||||||
Window_registry::Id win_id;
|
Window_registry::Id win_id;
|
||||||
|
|
||||||
|
Rect geometry { };
|
||||||
|
Point offset { };
|
||||||
|
|
||||||
|
Rect content_geometry() const { return { geometry.p1() + offset, geometry.area }; }
|
||||||
|
|
||||||
Content_view_ref(Window_registry::Id win_id, Gui::View_ids &ids, View_id id)
|
Content_view_ref(Window_registry::Id win_id, Gui::View_ids &ids, View_id id)
|
||||||
: id(*this, ids, id), win_id(win_id) { }
|
: id(*this, ids, id), win_id(win_id) { }
|
||||||
};
|
};
|
||||||
@ -152,35 +157,33 @@ struct Wm::Decorator_gui_session : Session_object<Gui::Session>,
|
|||||||
|
|
||||||
void _execute_command(Command const &cmd)
|
void _execute_command(Command const &cmd)
|
||||||
{
|
{
|
||||||
|
/*
|
||||||
|
* If the content view changes position, propagate the new position to
|
||||||
|
* the GUI service to properly transform absolute input coordinates.
|
||||||
|
*/
|
||||||
|
auto with_content_view_ref = [&] (View_id id, auto const &fn)
|
||||||
|
{
|
||||||
|
_content_view_ids.apply<Content_view_ref>(id,
|
||||||
|
[&] (Content_view_ref &ref) {
|
||||||
|
Rect const orig = ref.content_geometry();
|
||||||
|
fn(ref);
|
||||||
|
if (orig != ref.content_geometry())
|
||||||
|
_content_callback.content_geometry(ref.win_id,
|
||||||
|
ref.content_geometry()); },
|
||||||
|
[&] { });
|
||||||
|
};
|
||||||
|
|
||||||
switch (cmd.opcode) {
|
switch (cmd.opcode) {
|
||||||
|
|
||||||
case Command::GEOMETRY:
|
case Command::GEOMETRY:
|
||||||
|
|
||||||
/*
|
with_content_view_ref(cmd.geometry.view, [&] (Content_view_ref &view_ref) {
|
||||||
* If the content view changes position, propagate the new position
|
view_ref.geometry = cmd.geometry.rect; });
|
||||||
* to the GUI service to properly transform absolute input
|
|
||||||
* coordinates.
|
|
||||||
*/
|
|
||||||
_content_view_ids.apply<Content_view_ref const>(cmd.geometry.view,
|
|
||||||
[&] (Content_view_ref const &view_ref) {
|
|
||||||
_content_callback.content_geometry(view_ref.win_id, cmd.geometry.rect); },
|
|
||||||
[&] { });
|
|
||||||
|
|
||||||
/* forward command */
|
/* forward command */
|
||||||
_real_gui.enqueue(cmd);
|
_real_gui.enqueue(cmd);
|
||||||
return;
|
return;
|
||||||
|
|
||||||
case Command::OFFSET:
|
|
||||||
|
|
||||||
/*
|
|
||||||
* If non-content views change their offset (if the lookup
|
|
||||||
* fails), propagate the event
|
|
||||||
*/
|
|
||||||
_content_view_ids.apply<Content_view_ref const>(cmd.geometry.view,
|
|
||||||
[&] (Content_view_ref const &) { },
|
|
||||||
[&] { _real_gui.enqueue(cmd); });
|
|
||||||
return;
|
|
||||||
|
|
||||||
case Command::FRONT:
|
case Command::FRONT:
|
||||||
case Command::BACK:
|
case Command::BACK:
|
||||||
case Command::FRONT_OF:
|
case Command::FRONT_OF:
|
||||||
@ -192,7 +195,14 @@ struct Wm::Decorator_gui_session : Session_object<Gui::Session>,
|
|||||||
_real_gui.execute();
|
_real_gui.execute();
|
||||||
_content_callback.update_content_child_views(view_ref.win_id); },
|
_content_callback.update_content_child_views(view_ref.win_id); },
|
||||||
[&] { });
|
[&] { });
|
||||||
|
return;
|
||||||
|
|
||||||
|
case Command::OFFSET:
|
||||||
|
|
||||||
|
with_content_view_ref(cmd.offset.view, [&] (Content_view_ref &view_ref) {
|
||||||
|
view_ref.offset = cmd.offset.offset; });
|
||||||
|
|
||||||
|
_real_gui.enqueue(cmd);
|
||||||
return;
|
return;
|
||||||
|
|
||||||
case Command::TITLE:
|
case Command::TITLE:
|
||||||
|
@ -45,18 +45,21 @@ struct Param
|
|||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
void report_window_layout(Param param, Genode::Reporter &reporter)
|
void report_window_layout(Param param, Genode::Expanding_reporter &reporter)
|
||||||
{
|
{
|
||||||
|
|
||||||
float w = 1024;
|
float w = 1024;
|
||||||
float h = 768;
|
float h = 768;
|
||||||
|
|
||||||
Genode::Reporter::Xml_generator xml(reporter, [&] ()
|
reporter.generate([&] (Genode::Xml_generator &xml) {
|
||||||
{
|
|
||||||
|
xml.node("boundary", [&] {
|
||||||
|
xml.attribute("width", unsigned(w));
|
||||||
|
xml.attribute("height", unsigned(h));
|
||||||
|
|
||||||
for (unsigned i = 1; i <= 10; i++) {
|
for (unsigned i = 1; i <= 10; i++) {
|
||||||
|
|
||||||
xml.node("window", [&] ()
|
xml.node("window", [&] {
|
||||||
{
|
|
||||||
xml.attribute("id", i);
|
xml.attribute("id", i);
|
||||||
xml.attribute("xpos", (long)(w * (0.25 + sin(param.angle[0])/5)));
|
xml.attribute("xpos", (long)(w * (0.25 + sin(param.angle[0])/5)));
|
||||||
xml.attribute("ypos", (long)(h * (0.25 + sin(param.angle[1])/5)));
|
xml.attribute("ypos", (long)(h * (0.25 + sin(param.angle[1])/5)));
|
||||||
@ -70,6 +73,7 @@ void report_window_layout(Param param, Genode::Reporter &reporter)
|
|||||||
param = param + Param(2.2, 3.3, 4.4, 5.5);
|
param = param + Param(2.2, 3.3, 4.4, 5.5);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -79,7 +83,8 @@ struct Main
|
|||||||
|
|
||||||
Param _param { 0, 1, 2, 3 };
|
Param _param { 0, 1, 2, 3 };
|
||||||
|
|
||||||
Genode::Reporter _window_layout_reporter { _env, "window_layout", "window_layout", 10*4096 };
|
Genode::Expanding_reporter _window_layout_reporter {
|
||||||
|
_env, "window_layout", "window_layout" };
|
||||||
|
|
||||||
Timer::Connection _timer { _env };
|
Timer::Connection _timer { _env };
|
||||||
|
|
||||||
@ -95,7 +100,6 @@ struct Main
|
|||||||
|
|
||||||
Main(Genode::Env &env) : _env(env)
|
Main(Genode::Env &env) : _env(env)
|
||||||
{
|
{
|
||||||
_window_layout_reporter.enabled(true);
|
|
||||||
_timer.sigh(_timer_handler);
|
_timer.sigh(_timer_handler);
|
||||||
_timer.trigger_periodic(10*1000);
|
_timer.trigger_periodic(10*1000);
|
||||||
}
|
}
|
||||||
|
@ -27,16 +27,12 @@
|
|||||||
|
|
||||||
namespace Decorator {
|
namespace Decorator {
|
||||||
|
|
||||||
using Point = Genode::Surface_base::Point;
|
using namespace Genode;
|
||||||
using Area = Genode::Surface_base::Area;
|
|
||||||
using Rect = Genode::Surface_base::Rect;
|
|
||||||
using Dirty_rect = Genode::Dirty_rect<Rect, 3>;
|
|
||||||
|
|
||||||
using Genode::size_t;
|
using Point = Surface_base::Point;
|
||||||
using Genode::Color;
|
using Area = Surface_base::Area;
|
||||||
using Genode::Xml_node;
|
using Rect = Surface_base::Rect;
|
||||||
using Genode::List_model;
|
using Dirty_rect = Genode::Dirty_rect<Rect, 3>;
|
||||||
using Genode::Interface;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif /* _INCLUDE__DECORATOR__TYPES_H_ */
|
#endif /* _INCLUDE__DECORATOR__TYPES_H_ */
|
||||||
|
@ -20,6 +20,8 @@
|
|||||||
#include <util/list_model.h>
|
#include <util/list_model.h>
|
||||||
#include <util/reconstructible.h>
|
#include <util/reconstructible.h>
|
||||||
#include <gui_session/client.h>
|
#include <gui_session/client.h>
|
||||||
|
#include <base/registry.h>
|
||||||
|
#include <base/id_space.h>
|
||||||
|
|
||||||
/* decorator includes */
|
/* decorator includes */
|
||||||
#include <decorator/types.h>
|
#include <decorator/types.h>
|
||||||
@ -30,15 +32,49 @@ namespace Decorator {
|
|||||||
class Canvas_base;
|
class Canvas_base;
|
||||||
class Window_base;
|
class Window_base;
|
||||||
|
|
||||||
using Abandoned_windows = Genode::List<Genode::List_element<Window_base> >;
|
using Windows = Id_space<Window_base>;
|
||||||
|
using Abandoned_windows = Registry<Window_base>;
|
||||||
using Reversed_windows = Genode::List<Genode::List_element<Window_base> >;
|
using Reversed_windows = Genode::List<Genode::List_element<Window_base> >;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
class Decorator::Window_base : private Genode::List_model<Window_base>::Element
|
class Decorator::Window_base : private Windows::Element
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
|
||||||
|
using Windows::Element::id;
|
||||||
|
|
||||||
|
struct Ref;
|
||||||
|
|
||||||
|
using Refs = List_model<Ref>;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reference to a window
|
||||||
|
*
|
||||||
|
* The 'Ref' type decouples the lifetime of window objects from
|
||||||
|
* the lifetimes of their surrounding boundaries. If a window
|
||||||
|
* moves from one boundary to another, the old 'Ref' vanishes and
|
||||||
|
* a new 'Ref' is created but the window object stays intact.
|
||||||
|
*/
|
||||||
|
struct Ref : Refs::Element
|
||||||
|
{
|
||||||
|
Window_base &window;
|
||||||
|
|
||||||
|
Registry<Ref>::Element _registered;
|
||||||
|
|
||||||
|
inline Ref(Window_base &);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* List_model::Element
|
||||||
|
*/
|
||||||
|
inline bool matches(Xml_node const &) const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* List_model::Element
|
||||||
|
*/
|
||||||
|
static bool type_matches(Xml_node const &) { return true; }
|
||||||
|
};
|
||||||
|
|
||||||
struct Border
|
struct Border
|
||||||
{
|
{
|
||||||
unsigned top, left, right, bottom;
|
unsigned top, left, right, bottom;
|
||||||
@ -59,7 +95,7 @@ class Decorator::Window_base : private Genode::List_model<Window_base>::Element
|
|||||||
maximizer = false,
|
maximizer = false,
|
||||||
unmaximizer = false;
|
unmaximizer = false;
|
||||||
|
|
||||||
unsigned window_id = 0;
|
Windows::Id window_id { };
|
||||||
|
|
||||||
bool operator != (Hover const &other) const
|
bool operator != (Hover const &other) const
|
||||||
{
|
{
|
||||||
@ -84,7 +120,7 @@ class Decorator::Window_base : private Genode::List_model<Window_base>::Element
|
|||||||
*/
|
*/
|
||||||
struct Draw_behind_fn : Interface
|
struct Draw_behind_fn : Interface
|
||||||
{
|
{
|
||||||
virtual void draw_behind(Canvas_base &, Window_base const &, Rect) const = 0;
|
virtual void draw_behind(Canvas_base &, Ref const &, Rect) const = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
private:
|
private:
|
||||||
@ -93,16 +129,13 @@ class Decorator::Window_base : private Genode::List_model<Window_base>::Element
|
|||||||
friend class Genode::List_model<Window_base>;
|
friend class Genode::List_model<Window_base>;
|
||||||
friend class Genode::List<Window_base>;
|
friend class Genode::List<Window_base>;
|
||||||
|
|
||||||
|
Registry<Ref> _refs { };
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Geometry of content
|
* Geometry of content
|
||||||
*/
|
*/
|
||||||
Rect _geometry { };
|
Rect _geometry { };
|
||||||
|
|
||||||
/*
|
|
||||||
* Unique window ID
|
|
||||||
*/
|
|
||||||
unsigned const _id;
|
|
||||||
|
|
||||||
bool _stacked = false;
|
bool _stacked = false;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -110,29 +143,41 @@ class Decorator::Window_base : private Genode::List_model<Window_base>::Element
|
|||||||
*/
|
*/
|
||||||
Genode::Constructible<Gui::View_id> _neighbor { };
|
Genode::Constructible<Gui::View_id> _neighbor { };
|
||||||
|
|
||||||
Genode::List_element<Window_base> _abandoned { this };
|
Constructible<Abandoned_windows::Element> _abandoned { };
|
||||||
|
|
||||||
Genode::List_element<Window_base> _reversed { this };
|
Genode::List_element<Window_base> _reversed { this };
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
Window_base(unsigned id) : _id(id) { }
|
Window_base(Windows &windows, Windows::Id id)
|
||||||
|
:
|
||||||
|
Windows::Element(*this, windows, id)
|
||||||
|
{ }
|
||||||
|
|
||||||
virtual ~Window_base() { }
|
virtual ~Window_base() { }
|
||||||
|
|
||||||
void abandon(Abandoned_windows &abandoned_windows)
|
bool referenced() const
|
||||||
{
|
{
|
||||||
abandoned_windows.insert(&_abandoned);
|
bool result = false;
|
||||||
|
_refs.for_each([&] (Ref const &) { result = true; });
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void consider_as_abandoned(Abandoned_windows ®istry)
|
||||||
|
{
|
||||||
|
_abandoned.construct(registry, *this);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Revert 'consider_as_abandoned' after window was temporarily not referenced
|
||||||
|
*/
|
||||||
|
void dont_abandon() { _abandoned.destruct(); }
|
||||||
|
|
||||||
void prepend_to_reverse_list(Reversed_windows &window_list)
|
void prepend_to_reverse_list(Reversed_windows &window_list)
|
||||||
{
|
{
|
||||||
window_list.insert(&_reversed);
|
window_list.insert(&_reversed);
|
||||||
}
|
}
|
||||||
|
|
||||||
using List_model<Window_base>::Element::next;
|
|
||||||
|
|
||||||
unsigned id() const { return _id; }
|
|
||||||
Rect geometry() const { return _geometry; }
|
Rect geometry() const { return _geometry; }
|
||||||
|
|
||||||
void stacking_neighbor(Gui::View_id neighbor)
|
void stacking_neighbor(Gui::View_id neighbor)
|
||||||
@ -169,11 +214,8 @@ class Decorator::Window_base : private Genode::List_model<Window_base>::Element
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Draw window elements
|
* Draw window elements
|
||||||
*
|
|
||||||
* \param canvas graphics back end
|
|
||||||
* \param clip clipping area to apply
|
|
||||||
*/
|
*/
|
||||||
virtual void draw(Canvas_base &canvas, Rect clip, Draw_behind_fn const &) const = 0;
|
virtual void draw(Canvas_base &, Ref const &, Rect clip, Draw_behind_fn const &) const = 0;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Update internal window representation from XML model
|
* Update internal window representation from XML model
|
||||||
@ -187,7 +229,9 @@ class Decorator::Window_base : private Genode::List_model<Window_base>::Element
|
|||||||
*/
|
*/
|
||||||
virtual bool update(Xml_node window_node) = 0;
|
virtual bool update(Xml_node window_node) = 0;
|
||||||
|
|
||||||
virtual void update_gui_views() { }
|
struct Clip : Rect { };
|
||||||
|
|
||||||
|
virtual void update_gui_views(Clip const &) { }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Report information about element at specified position
|
* Report information about element at specified position
|
||||||
@ -207,7 +251,7 @@ class Decorator::Window_base : private Genode::List_model<Window_base>::Element
|
|||||||
*/
|
*/
|
||||||
bool matches(Xml_node const &node) const
|
bool matches(Xml_node const &node) const
|
||||||
{
|
{
|
||||||
return _id == node.attribute_value("id", ~0UL);
|
return id() == Windows::Id { node.attribute_value("id", ~0UL) };
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -216,4 +260,16 @@ class Decorator::Window_base : private Genode::List_model<Window_base>::Element
|
|||||||
static bool type_matches(Xml_node const &) { return true; }
|
static bool type_matches(Xml_node const &) { return true; }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
Decorator::Window_base::Ref::Ref(Window_base &window)
|
||||||
|
:
|
||||||
|
window(window), _registered(window._refs, *this)
|
||||||
|
{ }
|
||||||
|
|
||||||
|
|
||||||
|
bool Decorator::Window_base::Ref::matches(Xml_node const &node) const
|
||||||
|
{
|
||||||
|
return window.id() == Windows::Id { node.attribute_value("id", ~0UL) };
|
||||||
|
}
|
||||||
|
|
||||||
#endif /* _INCLUDE__DECORATOR__WINDOW_H_ */
|
#endif /* _INCLUDE__DECORATOR__WINDOW_H_ */
|
||||||
|
@ -24,8 +24,13 @@ namespace Decorator {
|
|||||||
|
|
||||||
struct Decorator::Window_factory_base : Interface
|
struct Decorator::Window_factory_base : Interface
|
||||||
{
|
{
|
||||||
virtual Window_base *create (Xml_node) = 0;
|
using Win_ref = Window_base::Ref;
|
||||||
virtual void destroy (Window_base *) = 0;
|
|
||||||
|
virtual Win_ref &create_ref(Xml_node const &) = 0;
|
||||||
|
|
||||||
|
virtual void destroy_ref(Win_ref &) = 0;
|
||||||
|
|
||||||
|
virtual void destroy_window(Window_base &) = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif /* _INCLUDE__DECORATOR__WINDOW_FACTORY_H_ */
|
#endif /* _INCLUDE__DECORATOR__WINDOW_FACTORY_H_ */
|
||||||
|
@ -17,6 +17,7 @@
|
|||||||
/* Genode includes */
|
/* Genode includes */
|
||||||
#include <gui_session/gui_session.h>
|
#include <gui_session/gui_session.h>
|
||||||
#include <base/log.h>
|
#include <base/log.h>
|
||||||
|
#include <base/allocator.h>
|
||||||
|
|
||||||
/* local includes */
|
/* local includes */
|
||||||
#include <decorator/types.h>
|
#include <decorator/types.h>
|
||||||
@ -31,13 +32,102 @@ class Decorator::Window_stack : public Window_base::Draw_behind_fn
|
|||||||
{
|
{
|
||||||
private:
|
private:
|
||||||
|
|
||||||
List_model<Window_base> _windows { };
|
struct Boundary;
|
||||||
|
using Boundaries = List_model<Boundary>;
|
||||||
|
|
||||||
|
using Abandoned_boundaries = Registry<Boundary>;
|
||||||
|
|
||||||
|
using Win_ref = Window_base::Ref;
|
||||||
|
|
||||||
|
struct Boundary : Boundaries::Element
|
||||||
|
{
|
||||||
|
using Name = Genode::String<64>;
|
||||||
|
|
||||||
|
Name const _name;
|
||||||
|
|
||||||
|
Constructible<Registry<Boundary>::Element> _abandoned { };
|
||||||
|
|
||||||
|
Rect rect { };
|
||||||
|
|
||||||
|
List_model<Win_ref> win_refs { };
|
||||||
|
|
||||||
|
Boundary(Name const &name) : _name(name) { }
|
||||||
|
|
||||||
|
void update(Window_factory_base &factory,
|
||||||
|
Abandoned_windows &abandoned_windows,
|
||||||
|
Dirty_rect &dirty_rect,
|
||||||
|
Xml_node const &boundary)
|
||||||
|
{
|
||||||
|
rect = Rect::from_xml(boundary);
|
||||||
|
|
||||||
|
win_refs.update_from_xml(boundary,
|
||||||
|
|
||||||
|
[&] (Xml_node const &node) -> Win_ref & {
|
||||||
|
return factory.create_ref(node); },
|
||||||
|
|
||||||
|
[&] (Win_ref &ref) {
|
||||||
|
Window_base &window = ref.window;
|
||||||
|
factory.destroy_ref(ref);
|
||||||
|
if (!window.referenced())
|
||||||
|
window.consider_as_abandoned(abandoned_windows);
|
||||||
|
},
|
||||||
|
|
||||||
|
[&] (Win_ref &ref, Xml_node const &node) {
|
||||||
|
Rect const orig_geometry = ref.window.outer_geometry();
|
||||||
|
if (ref.window.update(node)) {
|
||||||
|
dirty_rect.mark_as_dirty(orig_geometry);
|
||||||
|
dirty_rect.mark_as_dirty(ref.window.outer_geometry());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
void abandon(Registry<Boundary> ®istry)
|
||||||
|
{
|
||||||
|
_abandoned.construct(registry, *this);
|
||||||
|
}
|
||||||
|
|
||||||
|
static Name name(Xml_node const &node)
|
||||||
|
{
|
||||||
|
return node.attribute_value("name", Name());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* List_model::Element
|
||||||
|
*/
|
||||||
|
bool matches(Xml_node const &node) const
|
||||||
|
{
|
||||||
|
return _name == name(node);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* List_model::Element
|
||||||
|
*/
|
||||||
|
static bool type_matches(Xml_node const &node)
|
||||||
|
{
|
||||||
|
return node.has_type("boundary");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Generate window list in reverse order
|
||||||
|
*/
|
||||||
|
Reversed_windows reversed_window_list()
|
||||||
|
{
|
||||||
|
Reversed_windows reversed { };
|
||||||
|
win_refs.for_each([&] (Win_ref &ref) {
|
||||||
|
ref.window.prepend_to_reverse_list(reversed); });
|
||||||
|
return reversed;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
Boundaries _boundaries { };
|
||||||
Window_factory_base &_window_factory;
|
Window_factory_base &_window_factory;
|
||||||
|
Allocator &_alloc;
|
||||||
Dirty_rect mutable _dirty_rect { };
|
Dirty_rect mutable _dirty_rect { };
|
||||||
|
|
||||||
unsigned long _front_most_id = ~0UL;
|
Windows::Id _front_most_id { ~0UL };
|
||||||
|
|
||||||
inline void _draw_rec(Canvas_base &canvas, Window_base const *win,
|
inline void _draw_rec(Canvas_base &canvas, Win_ref const *,
|
||||||
Rect rect) const;
|
Rect rect) const;
|
||||||
|
|
||||||
static inline
|
static inline
|
||||||
@ -54,33 +144,38 @@ class Decorator::Window_stack : public Window_base::Draw_behind_fn
|
|||||||
throw Xml_node::Nonexistent_sub_node();
|
throw Xml_node::Nonexistent_sub_node();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
void _for_each_window_const(auto const &fn) const
|
||||||
* Generate window list in reverse order
|
|
||||||
*/
|
|
||||||
Reversed_windows _reversed_window_list()
|
|
||||||
{
|
{
|
||||||
Reversed_windows reversed { };
|
_boundaries.for_each([&] (Boundary const &boundary) {
|
||||||
_windows.for_each([&] (Window_base &window) {
|
boundary.win_refs.for_each([&] (Win_ref const &ref) {
|
||||||
window.prepend_to_reverse_list(reversed); });
|
fn(ref.window); }); });
|
||||||
return reversed;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
Window_stack(Window_factory_base &window_factory)
|
Window_stack(Window_factory_base &window_factory, Allocator &alloc)
|
||||||
:
|
:
|
||||||
_window_factory(window_factory)
|
_window_factory(window_factory), _alloc(alloc)
|
||||||
{ }
|
{ }
|
||||||
|
|
||||||
void mark_as_dirty(Rect rect) { _dirty_rect.mark_as_dirty(rect); }
|
void mark_as_dirty(Rect rect) { _dirty_rect.mark_as_dirty(rect); }
|
||||||
|
|
||||||
|
void for_each_window(auto const &fn)
|
||||||
|
{
|
||||||
|
_boundaries.for_each([&] (Boundary &boundary) {
|
||||||
|
boundary.win_refs.for_each([&] (Win_ref &ref) {
|
||||||
|
fn(ref.window); }); });
|
||||||
|
}
|
||||||
|
|
||||||
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) {
|
||||||
_windows.with_first([&] (Window_base const &first) {
|
_boundaries.for_each([&] (Boundary const &boundary) {
|
||||||
_draw_rec(canvas, &first, rect); }); });
|
Rect const clipped = Rect::intersect(rect, boundary.rect);
|
||||||
|
boundary.win_refs.with_first([&] (Win_ref const &first) {
|
||||||
|
_draw_rec(canvas, &first, clipped); }); }); });
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
@ -91,8 +186,7 @@ class Decorator::Window_stack : public Window_base::Draw_behind_fn
|
|||||||
{
|
{
|
||||||
bool redraw_needed = false;
|
bool redraw_needed = false;
|
||||||
|
|
||||||
_windows.for_each([&] (Window_base const &win) {
|
_for_each_window_const([&] (Window_base const &win) {
|
||||||
|
|
||||||
if (win.animated()) {
|
if (win.animated()) {
|
||||||
_dirty_rect.mark_as_dirty(win.outer_geometry());
|
_dirty_rect.mark_as_dirty(win.outer_geometry());
|
||||||
redraw_needed = true;
|
redraw_needed = true;
|
||||||
@ -101,41 +195,37 @@ class Decorator::Window_stack : public Window_base::Draw_behind_fn
|
|||||||
return redraw_needed;
|
return redraw_needed;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Apply functor to each window
|
|
||||||
*
|
|
||||||
* The functor is called with 'Window_base &' as argument.
|
|
||||||
*/
|
|
||||||
void for_each_window(auto const &fn) { _windows.for_each(fn); }
|
|
||||||
|
|
||||||
void update_gui_views()
|
void update_gui_views()
|
||||||
{
|
{
|
||||||
|
_boundaries.for_each([&] (Boundary &boundary) {
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Update GUI views in reverse order (back-most first). The
|
* Update GUI views in reverse order (back-most first). The
|
||||||
* reverse order is important because the stacking position of a
|
* reverse order is important because the stacking position of
|
||||||
* view is propagated by referring to the neighbor the view is in
|
* a view is propagated by referring to the neighbor the view
|
||||||
* front of. By starting with the back-most view, we make sure that
|
* is in front of. By starting with the back-most view, we make
|
||||||
* each view is always at its final stacking position when
|
* sure that each view is always at its final stacking position
|
||||||
* specified as neighbor of another view.
|
* when specified as neighbor of another view.
|
||||||
*/
|
*/
|
||||||
Reversed_windows reversed = _reversed_window_list();
|
Reversed_windows reversed = boundary.reversed_window_list();
|
||||||
|
|
||||||
while (Genode::List_element<Window_base> *win = reversed.first()) {
|
while (Genode::List_element<Window_base> *win = reversed.first()) {
|
||||||
win->object()->update_gui_views();
|
win->object()->update_gui_views({ boundary.rect });
|
||||||
reversed.remove(win);
|
reversed.remove(win);
|
||||||
}
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
Window_base::Hover hover(Point pos) const
|
Window_base::Hover hover(Point pos) const
|
||||||
{
|
{
|
||||||
Window_base::Hover result { };
|
Window_base::Hover result { };
|
||||||
|
|
||||||
_windows.for_each([&] (Window_base const &win) {
|
_for_each_window_const([&] (Window_base const &win) {
|
||||||
|
|
||||||
if (!result.window_id && win.outer_geometry().contains(pos)) {
|
if (!result.window_id.value && win.outer_geometry().contains(pos)) {
|
||||||
|
|
||||||
Window_base::Hover const hover = win.hover(pos);
|
Window_base::Hover const hover = win.hover(pos);
|
||||||
if (hover.window_id != 0)
|
if (hover.window_id.value != 0)
|
||||||
result = hover;
|
result = hover;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@ -148,28 +238,27 @@ class Decorator::Window_stack : public Window_base::Draw_behind_fn
|
|||||||
** Window::Draw_behind_fn interface **
|
** Window::Draw_behind_fn interface **
|
||||||
**************************************/
|
**************************************/
|
||||||
|
|
||||||
void draw_behind(Canvas_base &canvas, Window_base const &window, Rect clip) const override
|
void draw_behind(Canvas_base &canvas, Win_ref const &ref, Rect clip) const override
|
||||||
{
|
{
|
||||||
_draw_rec(canvas, window.next(), clip);
|
_draw_rec(canvas, ref.next(), clip);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
void Decorator::Window_stack::_draw_rec(Decorator::Canvas_base &canvas,
|
void Decorator::Window_stack::_draw_rec(Canvas_base &canvas,
|
||||||
Decorator::Window_base const *win,
|
Win_ref const *ref, Rect rect) const
|
||||||
Decorator::Rect rect) const
|
|
||||||
{
|
{
|
||||||
Rect clipped;
|
Rect clipped;
|
||||||
|
|
||||||
/* 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 ( ; ref && !(clipped = Rect::intersect(ref->window.outer_geometry(), rect)).valid(); )
|
||||||
win = win->next();
|
ref = ref->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 (!ref) return;
|
||||||
|
|
||||||
/* draw areas around the current window */
|
/* draw areas around the current window */
|
||||||
if (Window_base const * const next = win->next()) {
|
if (Window_base::Ref const * const next = ref->next()) {
|
||||||
|
|
||||||
Rect::Cut_remainder const r = rect.cut(clipped);
|
Rect::Cut_remainder const r = rect.cut(clipped);
|
||||||
|
|
||||||
@ -180,50 +269,41 @@ void Decorator::Window_stack::_draw_rec(Decorator::Canvas_base &canvas,
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* draw current window */
|
/* draw current window */
|
||||||
win->draw(canvas, clipped, *this);
|
ref->window.draw(canvas, *ref, clipped, *this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void Decorator::Window_stack::update_model(Genode::Xml_node root_node,
|
void Decorator::Window_stack::update_model(Genode::Xml_node root_node,
|
||||||
auto const &flush_window_stack_changes_fn)
|
auto const &flush_window_stack_changes_fn)
|
||||||
{
|
{
|
||||||
Abandoned_windows _abandoned_windows { };
|
Abandoned_boundaries abandoned_boundaries { };
|
||||||
|
Abandoned_windows abandoned_windows { };
|
||||||
|
|
||||||
_windows.update_from_xml(root_node,
|
_boundaries.update_from_xml(root_node,
|
||||||
|
|
||||||
[&] (Xml_node const &node) -> Window_base & {
|
[&] (Xml_node const &node) -> Boundary & {
|
||||||
return *_window_factory.create(node); },
|
return *new (_alloc) Boundary(Boundary::name(node)); },
|
||||||
|
|
||||||
[&] (Window_base &window) { window.abandon(_abandoned_windows); },
|
[&] (Boundary &boundary) {
|
||||||
|
boundary.update(_window_factory, abandoned_windows, _dirty_rect,
|
||||||
|
Xml_node("<empty/>"));
|
||||||
|
boundary.abandon(abandoned_boundaries);
|
||||||
|
},
|
||||||
|
|
||||||
[&] (Window_base &window, Xml_node const &node)
|
[&] (Boundary &boundary, Xml_node const &node) {
|
||||||
{
|
boundary.update(_window_factory, abandoned_windows, _dirty_rect, node); }
|
||||||
Rect const orig_geometry = window.outer_geometry();
|
|
||||||
|
|
||||||
if (window.update(node)) {
|
|
||||||
_dirty_rect.mark_as_dirty(orig_geometry);
|
|
||||||
_dirty_rect.mark_as_dirty(window.outer_geometry());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
);
|
);
|
||||||
|
|
||||||
unsigned long new_front_most_id = ~0UL;
|
Windows::Id 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);
|
|
||||||
|
|
||||||
/*
|
_boundaries.with_first([&] (Boundary const &boundary) {
|
||||||
* Propagate changed stacking order to the GUI server
|
boundary.win_refs.with_first([&] (Window_base::Ref const &ref) {
|
||||||
*
|
new_front_most_id = ref.window.id(); }); });
|
||||||
* First, we reverse the window list. The 'reversed' list starts with
|
|
||||||
* the back-most window. We then go throuh each window back to front
|
|
||||||
* and check if its neighbor is consistent with its position in the
|
|
||||||
* window list.
|
|
||||||
*/
|
|
||||||
Reversed_windows reversed = _reversed_window_list();
|
|
||||||
|
|
||||||
/* return true if window just came to front */
|
/* return true if window just came to front */
|
||||||
auto new_front_most_window = [&] (Window_base const &win) {
|
auto new_front_most_window = [&] (Window_base const &win) {
|
||||||
return (new_front_most_id != _front_most_id) && (win.id() == new_front_most_id); };
|
return (new_front_most_id.value != _front_most_id.value)
|
||||||
|
&& (win.id() == new_front_most_id); };
|
||||||
|
|
||||||
auto stack_back_most_window = [&] (Window_base &window) {
|
auto stack_back_most_window = [&] (Window_base &window) {
|
||||||
|
|
||||||
@ -251,6 +331,18 @@ void Decorator::Window_stack::update_model(Genode::Xml_node root_node,
|
|||||||
_dirty_rect.mark_as_dirty(window.outer_geometry());
|
_dirty_rect.mark_as_dirty(window.outer_geometry());
|
||||||
};
|
};
|
||||||
|
|
||||||
|
_boundaries.for_each([&] (Boundary &boundary) {
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Propagate changed stacking order to the GUI server
|
||||||
|
*
|
||||||
|
* First, we reverse the window list. The 'reversed' list starts with
|
||||||
|
* the back-most window. We then go throuh each window back to front
|
||||||
|
* and check if its neighbor is consistent with its position in the
|
||||||
|
* window list.
|
||||||
|
*/
|
||||||
|
Reversed_windows reversed = boundary.reversed_window_list();
|
||||||
|
|
||||||
if (Genode::List_element<Window_base> *back_most = reversed.first()) {
|
if (Genode::List_element<Window_base> *back_most = reversed.first()) {
|
||||||
|
|
||||||
/* handle back-most window */
|
/* handle back-most window */
|
||||||
@ -272,6 +364,7 @@ void Decorator::Window_stack::update_model(Genode::Xml_node root_node,
|
|||||||
neighbor = &window;
|
neighbor = &window;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
});
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Apply window-creation operations before destroying windows to prevent
|
* Apply window-creation operations before destroying windows to prevent
|
||||||
@ -280,7 +373,7 @@ void Decorator::Window_stack::update_model(Genode::Xml_node root_node,
|
|||||||
flush_window_stack_changes_fn();
|
flush_window_stack_changes_fn();
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Destroy abandoned window objects
|
* Destroy abandoned window and boundary 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
|
||||||
@ -289,12 +382,19 @@ 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.
|
||||||
*/
|
*/
|
||||||
Genode::List_element<Window_base> *elem = _abandoned_windows.first(), *next = nullptr;
|
|
||||||
for (; elem; elem = next) {
|
abandoned_boundaries.for_each([&] (Boundary &boundary) {
|
||||||
next = elem->next();
|
destroy(_alloc, &boundary); });
|
||||||
_dirty_rect.mark_as_dirty(elem->object()->outer_geometry());
|
|
||||||
_window_factory.destroy(elem->object());
|
abandoned_windows.for_each([&] (Window_base &window) {
|
||||||
|
if (window.referenced()) {
|
||||||
|
window.dont_abandon();
|
||||||
|
} else {
|
||||||
|
Rect const rect = window.outer_geometry();
|
||||||
|
_window_factory.destroy_window(window);
|
||||||
|
mark_as_dirty(rect);
|
||||||
}
|
}
|
||||||
|
});
|
||||||
|
|
||||||
_front_most_id = new_front_most_id;
|
_front_most_id = new_front_most_id;
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user