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