From 51d58e7518ce31716bac70881165dfbaa9f07055 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Benno=20F=C3=BCnfst=C3=BCck?= Date: Thu, 31 Aug 2017 18:26:38 +0200 Subject: [PATCH] fix(render): support stacked bars We now take the bar position that the window manager gives us instead of trying to calculate it ourselves. This is more correct when multiple bars are attached to the same edge, as the window manager may move some of them in that case (assuming override redirect is not enabled) --- include/components/bar.hpp | 3 ++- include/events/signal.hpp | 3 +++ include/events/signal_fwd.hpp | 1 + include/x11/background_manager.hpp | 7 +++++- src/components/bar.cpp | 15 ++++++++++--- src/components/renderer.cpp | 2 +- src/x11/background_manager.cpp | 36 +++++++++++++++++++----------- 7 files changed, 48 insertions(+), 19 deletions(-) diff --git a/include/components/bar.hpp b/include/components/bar.hpp index 457fc9c1..9c83a039 100644 --- a/include/components/bar.hpp +++ b/include/components/bar.hpp @@ -51,7 +51,7 @@ inline double geom_format_to_pixels(std::string str, double max) { } class bar : public xpp::event::sink, + evt::leave_notify, evt::motion_notify, evt::destroy_notify, evt::client_message, evt::configure_notify>, public signal_receiver { using base_type::base_type; }; + struct update_geometry : public detail::base_signal { + using base_type::base_type; + }; } namespace ui_tray { diff --git a/include/events/signal_fwd.hpp b/include/events/signal_fwd.hpp index dac45782..78129ebe 100644 --- a/include/events/signal_fwd.hpp +++ b/include/events/signal_fwd.hpp @@ -39,6 +39,7 @@ namespace signals { struct unshade_window; struct request_snapshot; struct update_background; + struct update_geometry; } namespace ui_tray { struct mapped_clients; diff --git a/include/x11/background_manager.hpp b/include/x11/background_manager.hpp index 3ebea680..39f3096c 100644 --- a/include/x11/background_manager.hpp +++ b/include/x11/background_manager.hpp @@ -2,6 +2,8 @@ #include "common.hpp" #include "events/signal_fwd.hpp" +#include "events/signal_receiver.hpp" +#include "events/types.hpp" #include "x11/extensions/fwd.hpp" #include "x11/types.hpp" @@ -14,7 +16,9 @@ namespace cairo { class xcb_surface; } -class background_manager : public xpp::event::sink { +class background_manager : public signal_receiver, + public xpp::event::sink +{ public: using make_type = background_manager&; static make_type make(); @@ -28,6 +32,7 @@ class background_manager : public xpp::event::sink { cairo::surface* get_surface() const; void handle(const evt::property_notify& evt); + bool on(const signals::ui::update_geometry&); private: connection& m_connection; signal_emitter& m_sig; diff --git a/src/components/bar.cpp b/src/components/bar.cpp index cbd9ad13..cf525abd 100644 --- a/src/components/bar.cpp +++ b/src/components/bar.cpp @@ -761,9 +761,6 @@ void bar::handle(const evt::expose& evt) { * state of the tray container even though the tray * window restacking failed. Used as a fallback for * tedious WM's, like i3. - * - * - Track the root pixmap atom to update the - * pseudo-transparent background when it changes */ void bar::handle(const evt::property_notify& evt) { #ifdef DEBUG_LOGGER_VERBOSE @@ -776,6 +773,13 @@ void bar::handle(const evt::property_notify& evt) { } } +void bar::handle(const evt::configure_notify&) { + // The absolute position of the window in the root may be different after configuration is done + // (for example, because the parent is not positioned at 0/0 in the root window). + // Notify components that the geometry may have changed (used by the background manager for example). + m_sig.emit(signals::ui::update_geometry{}); +} + bool bar::on(const signals::eventqueue::start&) { m_log.trace("bar: Create renderer"); m_renderer = renderer::make(m_opts); @@ -789,6 +793,7 @@ bool bar::on(const signals::eventqueue::start&) { if (!m_opts.cursor_click.empty() || !m_opts.cursor_scroll.empty() ) { m_connection.ensure_event_mask(m_opts.window, XCB_EVENT_MASK_POINTER_MOTION); } + m_connection.ensure_event_mask(m_opts.window, XCB_EVENT_MASK_STRUCTURE_NOTIFY); m_log.info("Bar window: %s", m_connection.id(m_opts.window)); restack_window(); @@ -800,6 +805,10 @@ bool bar::on(const signals::eventqueue::start&) { m_log.trace("bar: Map window"); m_connection.map_window_checked(m_opts.window); + // With the mapping, the absolute position of our window may have changed (due to re-parenting for example). + // Notify all components that depend on the absolute bar position (such as the background manager). + m_sig.emit(signals::ui::update_geometry{}); + // Reconfigure window position after mapping (required by Openbox) // Required by Openbox reconfigure_pos(); diff --git a/src/components/renderer.cpp b/src/components/renderer.cpp index 5f3eebc7..2fb50148 100644 --- a/src/components/renderer.cpp +++ b/src/components/renderer.cpp @@ -166,7 +166,7 @@ renderer::renderer( } m_log.trace("Activate root background manager"); - m_background.activate(m_window, m_bar.outer_area(true)); + m_background.activate(m_window, m_bar.outer_area(false)); } m_comp_bg = m_conf.get("settings", "compositing-background", m_comp_bg); diff --git a/src/x11/background_manager.cpp b/src/x11/background_manager.cpp index 491b1a10..f5521f02 100644 --- a/src/x11/background_manager.cpp +++ b/src/x11/background_manager.cpp @@ -18,9 +18,11 @@ background_manager::background_manager( : m_connection(conn) , m_sig(sig) , m_log(log) { + m_sig.attach(this); } background_manager::~background_manager() { + m_sig.detach(this); free_resources(); } @@ -110,24 +112,26 @@ void background_manager::fetch_root_pixmap() { xcb_pixmap_t pixmap; xcb_rectangle_t pixmap_geom; - if (!m_connection.root_pixmap(&pixmap, &pixmap_depth, &pixmap_geom)) { - free_resources(); - return m_log.err("background_manager: Failed to get root pixmap for background (realloc=%i)", realloc); - }; - - auto src_x = math_util::cap(m_rect.x, pixmap_geom.x, int16_t(pixmap_geom.x + pixmap_geom.width)); - auto src_y = math_util::cap(m_rect.y, pixmap_geom.y, int16_t(pixmap_geom.y + pixmap_geom.height)); - auto h = math_util::min(m_rect.height, pixmap_geom.height); - auto w = math_util::min(m_rect.width, pixmap_geom.width); - - m_log.trace("background_manager: Copying from root pixmap (%d) %dx%d+%dx%d", pixmap, w, h, src_x, src_y); try { + auto translated = m_connection.translate_coordinates(m_window, m_connection.screen()->root, m_rect.x, m_rect.y); + if (!m_connection.root_pixmap(&pixmap, &pixmap_depth, &pixmap_geom)) { + free_resources(); + return m_log.err("background_manager: Failed to get root pixmap for background (realloc=%i)", realloc); + }; + + auto src_x = math_util::cap(translated->dst_x, pixmap_geom.x, int16_t(pixmap_geom.x + pixmap_geom.width)); + auto src_y = math_util::cap(translated->dst_y, pixmap_geom.y, int16_t(pixmap_geom.y + pixmap_geom.height)); + auto h = math_util::min(m_rect.height, pixmap_geom.height); + auto w = math_util::min(m_rect.width, pixmap_geom.width); + + m_log.trace("background_manager: Copying from root pixmap (%d) %dx%d+%dx%d", pixmap, w, h, src_x, src_y); m_connection.copy_area_checked(pixmap, m_pixmap, m_gcontext, src_x, src_y, 0, 0, w, h); - } catch (const exception& err) { + } catch(const exception& err) { m_log.err("background_manager: Failed to copy slice of root pixmap (%s)", err.what()); free_resources(); - return; + throw; } + } void background_manager::handle(const evt::property_notify& evt) { @@ -140,4 +144,10 @@ void background_manager::handle(const evt::property_notify& evt) { } } +bool background_manager::on(const signals::ui::update_geometry&) { + fetch_root_pixmap(); + m_sig.emit(signals::ui::update_background()); + return false; +} + POLYBAR_NS_END