diff --git a/include/events/signal.hpp b/include/events/signal.hpp index f54f0684..3299f075 100644 --- a/include/events/signal.hpp +++ b/include/events/signal.hpp @@ -101,9 +101,6 @@ namespace signals { } // namespace ui namespace ui_tray { - struct mapped_clients : public detail::value_signal { - using base_type::base_type; - }; struct tray_width_change : public detail::value_signal { using base_type::base_type; }; diff --git a/include/events/signal_fwd.hpp b/include/events/signal_fwd.hpp index 0e422b21..7895a99b 100644 --- a/include/events/signal_fwd.hpp +++ b/include/events/signal_fwd.hpp @@ -35,7 +35,6 @@ namespace signals { struct update_geometry; } // namespace ui namespace ui_tray { - struct mapped_clients; struct tray_width_change; struct tray_pos_change; } diff --git a/include/x11/tray_client.hpp b/include/x11/tray_client.hpp index eb2593fa..3a4fcaee 100644 --- a/include/x11/tray_client.hpp +++ b/include/x11/tray_client.hpp @@ -13,7 +13,7 @@ class connection; class tray_client { public: - explicit tray_client(connection& conn, xcb_window_t win, unsigned int w, unsigned int h); + explicit tray_client(connection& conn, xcb_window_t win, size s); tray_client(const tray_client& c) = delete; tray_client& operator=(tray_client& c) = delete; @@ -55,8 +55,7 @@ class tray_client { bool m_mapped{false}; - unsigned int m_width; - unsigned int m_height; + size m_size; }; POLYBAR_NS_END diff --git a/include/x11/tray_manager.hpp b/include/x11/tray_manager.hpp index cf60488a..6c093e2d 100644 --- a/include/x11/tray_manager.hpp +++ b/include/x11/tray_manager.hpp @@ -43,14 +43,41 @@ struct tray_settings { alignment align{alignment::NONE}; bool running{false}; - int orig_x{0}; - int orig_y{0}; - unsigned int configured_w{0U}; - unsigned int configured_slots{0U}; - unsigned int width{0U}; + /** + * Tray window position. + * + * Relative to the bar window + * TODO make relative to inner area + */ + position pos{0, 0}; + + /** + * Tray offset in pixels. + */ + position offset{0, 0}; + + /** + * Current dimensions of the tray window. + */ + size win_size{0, 0}; + + /** + * Dimensions for client windows. + */ + size client_size{0, 0}; + + /** + * Number of clients currently mapped. + */ + int num_clients{0}; + + // This is the width of the bar window + // TODO directly read from bar_settings unsigned int width_max{0U}; - unsigned int height{0U}; - unsigned int height_fill{0U}; + + /** + * Number of pixels added between tray icons + */ unsigned int spacing{0U}; rgba background{}; rgba foreground{}; @@ -116,7 +143,8 @@ class tray_manager : public xpp::event::sink find_client(const xcb_window_t& win) const; void remove_client(shared_ptr& client, bool reconfigure = true); void remove_client(xcb_window_t win, bool reconfigure = true); - unsigned int mapped_clients() const; + int mapped_clients() const; + bool has_mapped_clients() const; void handle(const evt::expose& evt) override; void handle(const evt::visibility_notify& evt) override; diff --git a/src/components/bar.cpp b/src/components/bar.cpp index 2c06674f..fada7501 100644 --- a/src/components/bar.cpp +++ b/src/components/bar.cpp @@ -393,9 +393,9 @@ void bar::parse(string&& data, bool force) { auto rect = m_opts.inner_area(); - if (m_tray && !m_tray->settings().detached && m_tray->settings().configured_slots && !m_tray->settings().adaptive) { + if (m_tray && !m_tray->settings().detached && m_tray->settings().num_clients > 0 && !m_tray->settings().adaptive) { auto trayalign = m_tray->settings().align; - auto traywidth = m_tray->settings().configured_w; + auto traywidth = m_tray->settings().win_size.w; if (trayalign == alignment::LEFT) { rect.x += traywidth; rect.width -= traywidth; diff --git a/src/x11/tray_client.cpp b/src/x11/tray_client.cpp index e9fee279..89fdf638 100644 --- a/src/x11/tray_client.cpp +++ b/src/x11/tray_client.cpp @@ -8,19 +8,18 @@ POLYBAR_NS -tray_client::tray_client(connection& conn, xcb_window_t win, unsigned int w, unsigned int h) - : m_connection(conn), m_window(win), m_width(w), m_height(h) {} +tray_client::tray_client(connection& conn, xcb_window_t win, size s) : m_connection(conn), m_window(win), m_size(s) {} tray_client::~tray_client() { xembed::unembed(m_connection, window(), m_connection.root()); } unsigned int tray_client::width() const { - return m_width; + return m_size.w; } unsigned int tray_client::height() const { - return m_height; + return m_size.h; } void tray_client::clear_window() const { @@ -92,8 +91,8 @@ void tray_client::reconfigure(int x, int y) const { unsigned int configure_values[7]; xcb_params_configure_window_t configure_params{}; - XCB_AUX_ADD_PARAM(&configure_mask, &configure_params, width, m_width); - XCB_AUX_ADD_PARAM(&configure_mask, &configure_params, height, m_height); + XCB_AUX_ADD_PARAM(&configure_mask, &configure_params, width, m_size.w); + XCB_AUX_ADD_PARAM(&configure_mask, &configure_params, height, m_size.h); XCB_AUX_ADD_PARAM(&configure_mask, &configure_params, x, x); XCB_AUX_ADD_PARAM(&configure_mask, &configure_params, y, y); @@ -113,8 +112,8 @@ void tray_client::configure_notify(int x, int y) const { notify.above_sibling = 0; notify.x = x; notify.y = y; - notify.width = m_width; - notify.height = m_height; + notify.width = m_size.w; + notify.height = m_size.h; notify.border_width = 0; unsigned int mask{XCB_EVENT_MASK_STRUCTURE_NOTIFY}; diff --git a/src/x11/tray_manager.cpp b/src/x11/tray_manager.cpp index c23ae7ba..e181daae 100644 --- a/src/x11/tray_manager.cpp +++ b/src/x11/tray_manager.cpp @@ -92,46 +92,40 @@ void tray_manager::setup() { return; } - m_opts.detached = conf.get(bs, "tray-detached", false); - m_opts.height = m_bar_opts.size.h; - m_opts.height -= m_bar_opts.borders.at(edge::BOTTOM).size; - m_opts.height -= m_bar_opts.borders.at(edge::TOP).size; - m_opts.height_fill = m_opts.height; + auto inner_area = m_bar_opts.inner_area(); + m_opts.win_size.w = 0; + m_opts.win_size.h = inner_area.height; - if (m_opts.height % 2 != 0) { - m_opts.height--; - } + m_opts.detached = conf.get(bs, "tray-detached", false); + unsigned int client_height = inner_area.height; auto maxsize = conf.get(bs, "tray-maxsize", 16); - if (m_opts.height > maxsize) { - m_opts.spacing += (m_opts.height - maxsize) / 2; - m_opts.height = maxsize; + if (client_height > maxsize) { + m_opts.spacing += (client_height - maxsize) / 2; + client_height = maxsize; } m_opts.width_max = m_bar_opts.size.w; - m_opts.width = m_opts.height; - m_opts.orig_y = m_bar_opts.borders.at(edge::TOP).size; + m_opts.client_size = {client_height, client_height}; // Apply user-defined scaling auto scale = conf.get(bs, "tray-scale", 1.0); - m_opts.width *= scale; - m_opts.height_fill *= scale; + m_opts.client_size.w *= scale; + m_opts.win_size.h *= scale; - auto inner_area = m_bar_opts.inner_area(); - - switch (m_opts.align) { - case alignment::NONE: - break; - case alignment::LEFT: - m_opts.orig_x = inner_area.x; - break; - case alignment::CENTER: - m_opts.orig_x = inner_area.x + inner_area.width / 2 - m_opts.width / 2; - break; - case alignment::RIGHT: - m_opts.orig_x = inner_area.x + inner_area.width; - break; - } + m_opts.pos.x = inner_area.x + [&]() -> int { + switch (m_opts.align) { + case alignment::LEFT: + return 0; + case alignment::CENTER: + return inner_area.width / 2 - m_opts.client_size.w / 2; + case alignment::RIGHT: + return inner_area.width; + default: + return 0; + } + }(); + m_opts.pos.y = inner_area.y; if (conf.has(bs, "tray-transparent")) { m_log.warn("tray-transparent is deprecated, the tray always uses pseudo-transparency. Please remove it."); @@ -164,10 +158,13 @@ void tray_manager::setup() { max_y = inner_area.height; } - m_opts.orig_x += units_utils::percentage_with_offset_to_pixel(offset_x, max_x, m_bar_opts.dpi_x); - m_opts.orig_y += units_utils::percentage_with_offset_to_pixel(offset_y, max_y, m_bar_opts.dpi_y); + m_opts.offset.x = units_utils::percentage_with_offset_to_pixel(offset_x, max_x, m_bar_opts.dpi_x); + m_opts.offset.y = units_utils::percentage_with_offset_to_pixel(offset_y, max_y, m_bar_opts.dpi_y); - m_opts.bar_window = bar_opts.window; + m_opts.pos.x += m_opts.offset.x; + m_opts.pos.y += m_opts.offset.y; + + m_opts.bar_window = m_bar_opts.window; // Activate the tray manager query_atom(); @@ -264,8 +261,8 @@ void tray_manager::deactivate(bool clear_selection) { m_tray = 0; m_pixmap = 0; m_gc = 0; - m_opts.configured_w = 0; - m_opts.configured_slots = 0; + m_opts.win_size.w = 0; + m_opts.num_clients = 0; m_acquired_selection = false; m_mapped = false; @@ -299,7 +296,7 @@ void tray_manager::reconfigure() { m_log.err("Failed to reconfigure tray background (%s)", err.what()); } - m_opts.configured_slots = mapped_clients(); + m_opts.num_clients = mapped_clients(); guard.unlock(); refresh_window(); m_connection.flush(); @@ -318,17 +315,17 @@ void tray_manager::reconfigure_window() { return; } - auto clients = mapped_clients(); - if (!clients && m_mapped) { + bool has_clients = has_mapped_clients(); + if (!has_clients && m_mapped) { m_log.trace("tray: Reconfigure window / unmap"); m_connection.unmap_window_checked(m_tray); - } else if (clients && !m_mapped && !m_hidden) { + } else if (has_clients && !m_mapped && !m_hidden) { m_log.trace("tray: Reconfigure window / map"); m_connection.map_window_checked(m_tray); } auto width = calculate_w(); - auto x = calculate_x(width); + m_opts.win_size.w = width; if (m_opts.transparent) { xcb_rectangle_t rect{0, 0, calculate_w(), calculate_h()}; @@ -336,6 +333,7 @@ void tray_manager::reconfigure_window() { } if (width > 0) { + auto x = calculate_x(width); m_log.trace("tray: New window values, width=%d, x=%d", width, x); unsigned int mask = 0; @@ -347,8 +345,6 @@ void tray_manager::reconfigure_window() { connection::pack_values(mask, ¶ms, values); m_connection.configure_window_checked(m_tray, mask, values); } - - m_opts.configured_w = width; } /** @@ -366,7 +362,7 @@ void tray_manager::reconfigure_clients() { client->ensure_state(); client->reconfigure(x, calculate_client_y()); - x += m_opts.width + m_opts.spacing; + x += m_opts.client_size.w + m_opts.spacing; } catch (const xpp::x::error::window& err) { remove_client(client, false); } @@ -441,10 +437,10 @@ void tray_manager::refresh_window() { m_connection.flush(); - if (!mapped_clients()) { - m_opts.configured_w = 0; + if (has_mapped_clients()) { + m_opts.win_size.w = width; } else { - m_opts.configured_w = width; + m_opts.win_size.w = 0; } } @@ -696,7 +692,7 @@ void tray_manager::track_selection_owner(xcb_window_t owner) { void tray_manager::process_docking_request(xcb_window_t win) { m_log.info("Processing docking request from '%s' (%s)", ewmh_util::get_wm_name(win), m_connection.id(win)); - m_clients.emplace_back(std::make_shared(m_connection, win, m_opts.width, m_opts.height)); + m_clients.emplace_back(std::make_shared(m_connection, win, m_opts.client_size)); auto& client = m_clients.back(); try { @@ -753,11 +749,11 @@ void tray_manager::process_docking_request(xcb_window_t win) { * Calculate x position of tray window */ int tray_manager::calculate_x(unsigned int width) const { - auto x = m_opts.orig_x; + auto x = m_opts.pos.x; if (m_opts.align == alignment::RIGHT) { - x -= ((m_opts.width + m_opts.spacing) * m_clients.size() + m_opts.spacing); + x -= ((m_opts.client_size.w + m_opts.spacing) * m_clients.size() + m_opts.spacing); } else if (m_opts.align == alignment::CENTER) { - x -= (width / 2) - (m_opts.width / 2); + x -= (width / 2) - (m_opts.client_size.w / 2); } return x; } @@ -766,7 +762,7 @@ int tray_manager::calculate_x(unsigned int width) const { * Calculate y position of tray window */ int tray_manager::calculate_y() const { - return m_opts.orig_y; + return m_opts.pos.y; } /** @@ -778,7 +774,7 @@ unsigned short int tray_manager::calculate_w() const { for (auto&& client : m_clients) { if (client->mapped()) { count++; - width += m_opts.spacing + m_opts.width; + width += m_opts.spacing + m_opts.client_size.w; } } return count ? width : 0; @@ -788,7 +784,7 @@ unsigned short int tray_manager::calculate_w() const { * Calculate height of tray window */ unsigned short int tray_manager::calculate_h() const { - return m_opts.height_fill; + return m_opts.win_size.h; } /** @@ -797,7 +793,7 @@ unsigned short int tray_manager::calculate_h() const { int tray_manager::calculate_client_x(const xcb_window_t& win) { for (unsigned int i = 0; i < m_clients.size(); i++) { if (m_clients[i]->match(win)) { - return m_opts.spacing + m_opts.width * i; + return m_opts.spacing + m_opts.client_size.w * i; } } return m_opts.spacing; @@ -807,7 +803,7 @@ int tray_manager::calculate_client_x(const xcb_window_t& win) { * Calculate y position of client window */ int tray_manager::calculate_client_y() { - return (m_opts.height_fill - m_opts.height) / 2; + return (m_opts.win_size.h - m_opts.client_size.h) / 2; } /** @@ -852,8 +848,8 @@ void tray_manager::remove_client(xcb_window_t win, bool reconfigure) { /** * Get number of mapped clients */ -unsigned int tray_manager::mapped_clients() const { - unsigned int mapped_clients = 0; +int tray_manager::mapped_clients() const { + int mapped_clients = 0; for (auto&& client : m_clients) { if (client->mapped()) { @@ -864,6 +860,16 @@ unsigned int tray_manager::mapped_clients() const { return mapped_clients; } +bool tray_manager::has_mapped_clients() const { + for (auto&& client : m_clients) { + if (client->mapped()) { + return true; + } + } + + return false; +} + /** * Event callback : XCB_EXPOSE */ @@ -1052,11 +1058,9 @@ void tray_manager::handle(const evt::map_notify& evt) { m_log.trace("tray: Received map_notify"); m_log.trace("tray: Set client mapped"); find_client(evt->window)->mapped(true); - unsigned int clientcount{mapped_clients()}; - if (clientcount > m_opts.configured_slots) { + if (mapped_clients() > m_opts.num_clients) { reconfigure(); } - m_sig.emit(signals::ui_tray::mapped_clients{move(clientcount)}); } } @@ -1072,7 +1076,6 @@ void tray_manager::handle(const evt::unmap_notify& evt) { m_log.trace("tray: Received unmap_notify"); m_log.trace("tray: Set client unmapped"); find_client(evt->window)->mapped(false); - m_sig.emit(signals::ui_tray::mapped_clients{mapped_clients()}); } } @@ -1083,7 +1086,7 @@ void tray_manager::handle(const evt::unmap_notify& evt) { */ bool tray_manager::on(const signals::ui::visibility_change& evt) { bool visible{evt.cast()}; - unsigned int clients{mapped_clients()}; + bool has_clients = has_mapped_clients(); m_log.trace("tray: visibility_change (state=%i, activated=%i, mapped=%i, hidden=%i)", visible, static_cast(m_activated), static_cast(m_mapped), static_cast(m_hidden)); @@ -1092,11 +1095,11 @@ bool tray_manager::on(const signals::ui::visibility_change& evt) { if (!m_activated) { return false; - } else if (!m_hidden && !m_mapped && clients) { + } else if (!m_hidden && !m_mapped && has_clients) { m_connection.map_window(m_tray); - } else if ((!clients || m_hidden) && m_mapped) { + } else if ((!has_clients || m_hidden) && m_mapped) { m_connection.unmap_window(m_tray); - } else if (m_mapped && !m_hidden && clients) { + } else if (m_mapped && !m_hidden && has_clients) { redraw_window(); } @@ -1120,7 +1123,7 @@ bool tray_manager::on(const signals::ui::update_background&) { } bool tray_manager::on(const signals::ui_tray::tray_pos_change& evt) { - m_opts.orig_x = m_bar_opts.inner_area(true).x + evt.cast(); + m_opts.pos.x = m_bar_opts.inner_area(true).x + evt.cast(); reconfigure_window(); return true;