decorator: generalize include/decorator/window.h

This change makes it possible to reuse the generic window decorator
classes in include/decorator/ for decorators of a different structure.
E.g., instead of painting decorations on a single nitpicker session,
each window may paint its decorations into additional window-specific
nitpicker sessions.
This commit is contained in:
Norman Feske 2015-11-09 15:09:27 +01:00 committed by Christian Helmuth
parent 493386ed27
commit acb0ddd9ef
4 changed files with 187 additions and 184 deletions

View File

@ -1,5 +1,5 @@
/*
* \brief Accessor for the default font
* \brief Accessor for textures
* \author Norman Feske
* \date 2015-09-16
*/

View File

@ -205,7 +205,35 @@ static bool attribute_has_value(Genode::Xml_node node,
bool Decorator::Window::update(Genode::Xml_node window_node)
{
bool updated = Window_base::update(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) {
_global_to_front = true;
_topped_cnt = topped_cnt;
_nitpicker_stacking_up_to_date = false;
updated |= true;
}
/*
* Detect geometry changes
*/
Rect new_geometry = rect_attribute(window_node);
if (new_geometry.p1() != geometry().p1()
|| new_geometry.p2() != geometry().p2()) {
geometry(new_geometry);
_nitpicker_views_up_to_date = false;
updated |= true;
}
_focused = attribute_has_value(window_node, "focused", "yes");
_has_alpha = attribute_has_value(window_node, "has_alpha", "yes");

View File

@ -29,6 +29,82 @@ class Decorator::Window : public Window_base
{
private:
Nitpicker::Session_client &_nitpicker;
/*
* Flag indicating that the current window position has been propagated
* to the window's corresponding nitpicker views.
*/
bool _nitpicker_views_up_to_date = false;
/*
* Flag indicating that the stacking position of the window within the
* window stack has changed. The new stacking position must be
* propagated to nitpicker.
*/
bool _nitpicker_stacking_up_to_date = false;
Nitpicker::Session::View_handle _neighbor;
struct Nitpicker_view
{
Nitpicker::Session_client &_nitpicker;
Nitpicker::Session::View_handle _handle { _nitpicker.create_view() };
typedef Nitpicker::Session::Command Command;
Nitpicker_view(Nitpicker::Session_client &nitpicker, unsigned id = 0)
:
_nitpicker(nitpicker)
{
/*
* We supply the window ID as label for the anchor view.
*/
if (id) {
char buf[128];
Genode::snprintf(buf, sizeof(buf), "%d", id);
_nitpicker.enqueue<Command::Title>(_handle, buf);
}
}
~Nitpicker_view()
{
_nitpicker.destroy_view(_handle);
}
Nitpicker::Session::View_handle handle() const { return _handle; }
void stack(Nitpicker::Session::View_handle neighbor)
{
_nitpicker.enqueue<Command::To_front>(_handle, neighbor);
}
void place(Rect rect)
{
_nitpicker.enqueue<Command::Geometry>(_handle, rect);
Point offset = Point(0, 0) - rect.p1();
_nitpicker.enqueue<Command::Offset>(_handle, offset);
}
};
Nitpicker_view _bottom_view { _nitpicker },
_right_view { _nitpicker },
_left_view { _nitpicker },
_top_view { _nitpicker };
Nitpicker_view _content_view { _nitpicker, id() };
static Border _init_border() {
return Border(_border_size + _title_height,
_border_size, _border_size, _border_size); }
Border const _border { _init_border() };
bool _global_to_front = false;
unsigned _topped_cnt = 0;
Window_title _title;
bool _focused = false;
@ -41,9 +117,6 @@ class Decorator::Window : public Window_base
static unsigned const _border_size = 4;
static unsigned const _title_height = 16;
static Border _border() {
return Border(_border_size + _title_height,
_border_size, _border_size, _border_size); }
Color _bright = { 255, 255, 255, 64 };
Color _dark = { 0, 0, 0, 127 };
@ -54,7 +127,6 @@ class Decorator::Window : public Window_base
Area const _icon_size { 16, 16 };
/*
* Intensity of the title-bar radient in percent. A value of 0 produces
* no gradient. A value of 100 creates a gradient from white over
@ -329,10 +401,78 @@ class Decorator::Window : public Window_base
Window(unsigned id, Nitpicker::Session_client &nitpicker,
Animator &animator, Config const &config)
:
Window_base(id, nitpicker, _border()),
Window_base(id),
_nitpicker(nitpicker),
_animator(animator), _config(config)
{ }
void stack(Nitpicker::Session::View_handle neighbor) override
{
_neighbor = neighbor;
_nitpicker_stacking_up_to_date = false;
}
Nitpicker::Session::View_handle frontmost_view() const override
{
return _bottom_view.handle();
}
Rect outer_geometry() const override
{
return Rect(geometry().p1() - Point(_border.left, _border.top),
geometry().p2() + Point(_border.right, _border.bottom));
}
void border_rects(Rect *top, Rect *left, Rect *right, Rect *bottom) const
{
outer_geometry().cut(geometry(), top, left, right, bottom);
}
bool is_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) {
/* update view positions */
Rect top, left, right, bottom;
border_rects(&top, &left, &right, &bottom);
_content_view.place(geometry());
_top_view .place(top);
_left_view .place(left);
_right_view .place(right);
_bottom_view .place(bottom);
_nitpicker_views_up_to_date = true;
}
if (!_nitpicker_stacking_up_to_date) {
/*
* Bring the view to the global top of the view stack if the
* 'topped' counter changed. Otherwise, we refer to a
* session-local neighbor for the restacking operation.
*/
Nitpicker::Session::View_handle neighbor = _neighbor;
if (_global_to_front) {
neighbor = Nitpicker::Session::View_handle();
_global_to_front = false;
}
_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());
_nitpicker_stacking_up_to_date = true;
}
}
void adapt_to_changed_config()
{
_base_color = _config.base_color(_title);

View File

@ -85,11 +85,8 @@ class Decorator::Window_base : public Window_list::Element
virtual void draw_behind(Canvas_base &, Window_base const &, Rect) const = 0;
};
private:
Nitpicker::Session_client &_nitpicker;
/*
* Geometry of content
*/
@ -100,114 +97,22 @@ class Decorator::Window_base : public Window_list::Element
*/
unsigned const _id;
/*
* Flag indicating that the current window position has been propagated
* to the window's corresponding nitpicker views.
*/
bool _nitpicker_views_up_to_date = false;
/*
* Flag indicating that the stacking position of the window within the
* window stack has changed. The new stacking position must be
* propagated to nitpicker.
*/
bool _nitpicker_stacking_up_to_date = false;
unsigned _topped_cnt = 0;
bool _global_to_front = false;
Nitpicker::Session::View_handle _neighbor;
Border const _border;
struct Nitpicker_view
{
Nitpicker::Session_client &_nitpicker;
Nitpicker::Session::View_handle _handle { _nitpicker.create_view() };
typedef Nitpicker::Session::Command Command;
Nitpicker_view(Nitpicker::Session_client &nitpicker, unsigned id = 0)
:
_nitpicker(nitpicker)
{
/*
* We supply the window ID as label for the anchor view.
*/
if (id) {
char buf[128];
Genode::snprintf(buf, sizeof(buf), "%d", id);
_nitpicker.enqueue<Command::Title>(_handle, buf);
}
}
~Nitpicker_view()
{
_nitpicker.destroy_view(_handle);
}
Nitpicker::Session::View_handle handle() const { return _handle; }
void stack(Nitpicker::Session::View_handle neighbor)
{
_nitpicker.enqueue<Command::To_front>(_handle, neighbor);
}
void place(Rect rect)
{
_nitpicker.enqueue<Command::Geometry>(_handle, rect);
Point offset = Point(0, 0) - rect.p1();
_nitpicker.enqueue<Command::Offset>(_handle, offset);
}
};
Nitpicker_view _bottom_view, _right_view, _left_view, _top_view;
Nitpicker_view _content_view;
public:
Window_base(unsigned id, Nitpicker::Session_client &nitpicker,
Border border)
:
_nitpicker(nitpicker), _id(id), _border(border),
_bottom_view(nitpicker),
_right_view(nitpicker),
_left_view(nitpicker),
_top_view(nitpicker),
_content_view(nitpicker, _id)
{ }
void stack(Nitpicker::Session::View_handle neighbor)
{
_neighbor = neighbor;
_nitpicker_stacking_up_to_date = false;
}
Nitpicker::Session::View_handle frontmost_view() const
{
return _bottom_view.handle();
}
Rect outer_geometry() const
{
return Rect(_geometry.p1() - Point(_border.left, _border.top),
_geometry.p2() + Point(_border.right, _border.bottom));
}
void border_rects(Rect *top, Rect *left, Rect *right, Rect *bottom) const
{
outer_geometry().cut(_geometry, top, left, right, bottom);
}
Window_base(unsigned id) : _id(id) { }
unsigned long id() const { return _id; }
Rect geometry() const { return _geometry; }
bool is_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 Nitpicker::Session::View_handle frontmost_view() const = 0;
virtual bool is_in_front_of(Window_base const &neighbor) const = 0;
/**
* Draw window elements
@ -227,79 +132,9 @@ 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 result = false;
virtual bool update(Xml_node window_node) = 0;
/*
* 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) {
_global_to_front = true;
_topped_cnt = topped_cnt;
_nitpicker_stacking_up_to_date = false;
result = true;
}
/*
* Detect geometry changes
*/
Rect new_geometry = rect_attribute(window_node);
if (new_geometry.p1() != _geometry.p1()
|| new_geometry.p2() != _geometry.p2()) {
_geometry = new_geometry;
_nitpicker_views_up_to_date = false;
result = true;
}
return result;
}
virtual void update_nitpicker_views()
{
if (!_nitpicker_views_up_to_date) {
/* update view positions */
Rect top, left, right, bottom;
border_rects(&top, &left, &right, &bottom);
_content_view.place(_geometry);
_top_view .place(top);
_left_view .place(left);
_right_view .place(right);
_bottom_view .place(bottom);
_nitpicker_views_up_to_date = true;
}
if (!_nitpicker_stacking_up_to_date) {
/*
* Bring the view to the global top of the view stack if the
* 'topped' counter changed. Otherwise, we refer to a
* session-local neighbor for the restacking operation.
*/
Nitpicker::Session::View_handle neighbor = _neighbor;
if (_global_to_front) {
neighbor = Nitpicker::Session::View_handle();
_global_to_front = false;
}
_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());
_nitpicker_stacking_up_to_date = true;
}
}
virtual void update_nitpicker_views() { }
/**
* Report information about element at specified position