From 785cac716832677f6cbfa4c4b2ef92f56bc905db Mon Sep 17 00:00:00 2001 From: Norman Feske Date: Wed, 1 Jul 2015 21:03:12 +0200 Subject: [PATCH] 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. --- repos/gems/src/app/decorator/window.h | 16 +++++++----- .../src/app/floating_window_layouter/main.cc | 12 +++++++++ repos/gems/src/server/wm/nitpicker.h | 26 +++++++++++++------ repos/gems/src/server/wm/window_registry.h | 17 ++++++++++-- repos/os/include/decorator/window.h | 14 +++++++++- repos/os/include/decorator/window_stack.h | 14 ++++++++-- 6 files changed, 80 insertions(+), 19 deletions(-) diff --git a/repos/gems/src/app/decorator/window.h b/repos/gems/src/app/decorator/window.h index bd0a446200..e07b33da30 100644 --- a/repos/gems/src/app/decorator/window.h +++ b/repos/gems/src/app/decorator/window.h @@ -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"); diff --git a/repos/gems/src/app/floating_window_layouter/main.cc b/repos/gems/src/app/floating_window_layouter/main.cc index c0e6a0953b..20b64b9fb5 100644 --- a/repos/gems/src/app/floating_window_layouter/main.cc +++ b/repos/gems/src/app/floating_window_layouter/main.cc @@ -117,6 +117,11 @@ class Floating_window_layouter::Window : public List::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::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::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 (...) { } } diff --git a/repos/gems/src/server/wm/nitpicker.h b/repos/gems/src/server/wm/nitpicker.h index c92c4d35d9..2769bcabce 100644 --- a/repos/gems/src/server/wm/nitpicker.h +++ b/repos/gems/src/server/wm/nitpicker.h @@ -108,11 +108,14 @@ class Wm::Nitpicker::View : public Genode::Weak_object, Point _buffer_offset; Weak_ptr _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, _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 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, 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, Weak_ptr 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, */ 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, _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) { } diff --git a/repos/gems/src/server/wm/window_registry.h b/repos/gems/src/server/wm/window_registry.h index c25fc70b38..22f81d95e5 100644 --- a/repos/gems/src/server/wm/window_registry.h +++ b/repos/gems/src/server/wm/window_registry.h @@ -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_ */ diff --git a/repos/os/include/decorator/window.h b/repos/os/include/decorator/window.h index ae166856f7..50e3e55aa3 100644 --- a/repos/os/include/decorator/window.h +++ b/repos/os/include/decorator/window.h @@ -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 diff --git a/repos/os/include/decorator/window_stack.h b/repos/os/include/decorator/window_stack.h index 95717e0354..b9cdcb9e43 100644 --- a/repos/os/include/decorator/window_stack.h +++ b/repos/os/include/decorator/window_stack.h @@ -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); }