decorator: consider partially transparent windows

This patch changes the window manager, the decorator, and the
floating window layouter to propagate the usage of an alpha channel from
the client application to the decorator. This way, the decorator can
paint the decoration elements behind the affected windows, which would
otherwise be skipped.
This commit is contained in:
Norman Feske 2015-07-01 21:03:12 +02:00 committed by Christian Helmuth
parent ea16c19516
commit 785cac7168
6 changed files with 80 additions and 19 deletions

View File

@ -51,6 +51,8 @@ class Decorator::Window : public Window_base
Color _base_color() const { return Color(45, 49, 65); }
bool _has_alpha = false;
class Element : public Animator::Item
{
public:
@ -306,7 +308,7 @@ class Decorator::Window : public Window_base
_animator(animator)
{ }
void draw(Canvas_base &canvas, Rect clip) const override;
void draw(Canvas_base &canvas, Rect clip, Draw_behind_fn const &) const override;
bool update(Xml_node window_node) override;
@ -324,7 +326,8 @@ class Decorator::Window : public Window_base
void Decorator::Window::draw(Decorator::Canvas_base &canvas,
Decorator::Rect clip) const
Decorator::Rect clip,
Draw_behind_fn const &draw_behind_fn) const
{
Clip_guard clip_guard(canvas, clip);
@ -334,10 +337,8 @@ void Decorator::Window::draw(Decorator::Canvas_base &canvas,
Point p1 = rect.p1();
Point p2 = rect.p2();
bool const draw_content = false;
if (draw_content)
canvas.draw_box(geometry(), Color(10, 20, 40));
if (_has_alpha)
draw_behind_fn.draw_behind(canvas, *this, canvas.clip());
_draw_corner(canvas, Rect(p1, corner), _border_size, true, true,
element(Element::TOP_LEFT).color());
@ -403,6 +404,9 @@ bool Decorator::Window::update(Genode::Xml_node window_node)
_focused = window_node.has_attribute("focused")
&& window_node.attribute("focused").has_value("yes");
_has_alpha = window_node.has_attribute("has_alpha")
&& window_node.attribute("has_alpha").has_value("yes");
try {
Xml_node highlight = window_node.sub_node("highlight");

View File

@ -117,6 +117,11 @@ class Floating_window_layouter::Window : public List<Window>::Element
*/
Area _requested_size;
/**
* Window may be partially transparent
*/
bool _has_alpha = false;
/*
* Number of times the window has been topped. This value is used by
* the decorator to detect the need for bringing the window to the
@ -147,6 +152,8 @@ class Floating_window_layouter::Window : public List<Window>::Element
void position(Point pos) { _geometry = Rect(pos, _geometry.area()); }
void has_alpha(bool has_alpha) { _has_alpha = has_alpha; }
/**
* Return true if user drags a window border
*/
@ -208,6 +215,9 @@ class Floating_window_layouter::Window : public List<Window>::Element
xml.node(highlight.name());
});
}
if (_has_alpha)
xml.attribute("has_alpha", "yes");
});
}
@ -393,6 +403,8 @@ void Floating_window_layouter::Main::import_window_list(Xml_node window_list_xml
win->size(area_attribute(node));
win->title(string_attribute(node, "title", Window::Title("untitled")));
win->has_alpha(node.has_attribute("has_alpha")
&& node.attribute("has_alpha").has_value("yes"));
}
} catch (...) { }
}

View File

@ -108,11 +108,14 @@ class Wm::Nitpicker::View : public Genode::Weak_object<View>,
Point _buffer_offset;
Weak_ptr<View> _neighbor_ptr;
bool _neighbor_behind;
bool _has_alpha;
View(Nitpicker::Session_client &real_nitpicker,
Session_label const &session_label)
Session_label const &session_label,
bool has_alpha)
:
_session_label(session_label), _real_nitpicker(real_nitpicker)
_session_label(session_label), _real_nitpicker(real_nitpicker),
_has_alpha(has_alpha)
{ }
/**
@ -204,6 +207,8 @@ class Wm::Nitpicker::View : public Genode::Weak_object<View>,
_real_nitpicker.execute();
}
}
bool has_alpha() const { return _has_alpha; }
};
@ -246,9 +251,10 @@ class Wm::Nitpicker::Top_level_view : public View,
Top_level_view(Nitpicker::Session_client &real_nitpicker,
Session_label const &session_label,
bool has_alpha,
Window_registry &window_registry)
:
View(real_nitpicker, session_label),
View(real_nitpicker, session_label, has_alpha),
_window_registry(window_registry),
_window_title(session_label, "")
{ }
@ -271,6 +277,7 @@ class Wm::Nitpicker::Top_level_view : public View,
if (!_win_id.valid()) {
_win_id = _window_registry.create();
_window_registry.title(_win_id, _window_title.string());
_window_registry.has_alpha(_win_id, View::has_alpha());
}
_window_registry.size(_win_id, geometry.area());
@ -334,9 +341,10 @@ class Wm::Nitpicker::Child_view : public View,
Child_view(Nitpicker::Session_client &real_nitpicker,
Session_label const &session_label,
bool has_alpha,
Weak_ptr<View> parent)
:
View(real_nitpicker, session_label), _parent(parent)
View(real_nitpicker, session_label, has_alpha), _parent(parent)
{
try_to_init_real_view();
}
@ -418,6 +426,7 @@ class Wm::Nitpicker::Session_component : public Rpc_object<Nitpicker::Session>,
Click_handler &_click_handler;
Signal_context_capability _mode_sigh;
Area _requested_size;
bool _has_alpha = false;
/*
* Command buffer
@ -553,7 +562,7 @@ class Wm::Nitpicker::Session_component : public Rpc_object<Nitpicker::Session>,
Weak_ptr<View> parent_ptr = _view_handle_registry.lookup(parent_handle);
Child_view *view = new (_child_view_alloc)
Child_view(_session, _session_label, parent_ptr);
Child_view(_session, _session_label, _has_alpha, parent_ptr);
_child_views.insert(view);
return *view;
@ -564,7 +573,7 @@ class Wm::Nitpicker::Session_component : public Rpc_object<Nitpicker::Session>,
*/
else {
Top_level_view *view = new (_top_level_view_alloc)
Top_level_view(_session, _session_label, _window_registry);
Top_level_view(_session, _session_label, _has_alpha, _window_registry);
_top_level_views.insert(view);
return *view;
@ -873,9 +882,10 @@ class Wm::Nitpicker::Session_component : public Rpc_object<Nitpicker::Session>,
_mode_sigh = sigh;
}
void buffer(Framebuffer::Mode mode, bool use_alpha) override
void buffer(Framebuffer::Mode mode, bool has_alpha) override
{
_session.buffer(mode, use_alpha);
_session.buffer(mode, has_alpha);
_has_alpha = has_alpha;
}
void focus(Genode::Capability<Nitpicker::Session>) { }

View File

@ -62,6 +62,8 @@ class Wm::Window_registry
typedef Genode::String<200> Title;
enum Has_alpha { HAS_ALPHA, HAS_NO_ALPHA };
private:
Id const _id;
@ -70,6 +72,8 @@ class Wm::Window_registry
Area _size;
Has_alpha _has_alpha;
friend class Window_registry;
Window(Id id) : _id(id) { }
@ -81,8 +85,9 @@ class Wm::Window_registry
/*
* Accessors for setting attributes
*/
void attr(Title const &title) { _title = title; }
void attr(Area size) { _size = size; }
void attr(Title const &title) { _title = title; }
void attr(Area size) { _size = size; }
void attr(Has_alpha has_alpha) { _has_alpha = has_alpha; }
void generate_window_list_entry_xml(Xml_generator &xml) const
{
@ -91,6 +96,9 @@ class Wm::Window_registry
xml.attribute("title", _title.string());
xml.attribute("width", _size.w());
xml.attribute("height", _size.h());
if (_has_alpha == HAS_ALPHA)
xml.attribute("has_alpha", "yes");
});
}
};
@ -183,6 +191,11 @@ class Wm::Window_registry
void size(Id id, Area size) { _set_attr(id, size); }
void title(Id id, Window::Title title) { _set_attr(id, title); }
void has_alpha(Id id, bool has_alpha)
{
_set_attr(id, has_alpha ? Window::HAS_ALPHA : Window::HAS_NO_ALPHA);
}
};
#endif /* _WINDOW_REGISTRY_H_ */

View File

@ -66,6 +66,18 @@ class Decorator::Window_base : public Window_list::Element
}
};
/**
* Functor for drawing the elements behind a window
*
* This functor is used for drawing the decorations of partially
* transparent windows. It is implemented by the window stack.
*/
struct Draw_behind_fn
{
virtual void draw_behind(Canvas_base &, Window_base const &, Rect) const = 0;
};
private:
Nitpicker::Session_client &_nitpicker;
@ -195,7 +207,7 @@ class Decorator::Window_base : public Window_list::Element
* \param canvas graphics back end
* \param clip clipping area to apply
*/
virtual void draw(Canvas_base &canvas, Rect clip) const = 0;
virtual void draw(Canvas_base &canvas, Rect clip, Draw_behind_fn const &) const = 0;
/**
* Update internal window representation from XML model

View File

@ -27,7 +27,7 @@
namespace Decorator { class Window_stack; }
class Decorator::Window_stack
class Decorator::Window_stack : public Window_base::Draw_behind_fn
{
private:
@ -147,6 +147,16 @@ class Decorator::Window_stack
return Window_base::Hover();
}
/**************************************
** Window::Draw_behind_fn interface **
**************************************/
void draw_behind(Canvas_base &canvas, Window_base const &window, Rect clip) const override
{
_draw_rec(canvas, window.next(), clip);
}
};
@ -175,7 +185,7 @@ void Decorator::Window_stack::_draw_rec(Decorator::Canvas_base &canvas,
}
/* draw current window */
win->draw(canvas, clipped);
win->draw(canvas, clipped, *this);
}