diff --git a/CHANGELOG.md b/CHANGELOG.md index fb548ffd..5a402df5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,6 +11,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] ### Fixed - `format-offset` being ignored ([`#2643`](https://github.com/polybar/polybar/pull/2643)) +- Negative struts (`margin-bottom`, `margin-top`) being ignored ([`#2642`](https://github.com/polybar/polybar/issues/2642), [`#2644`](https://github.com/polybar/polybar/pull/2644)) ## [3.6.1] - 2022-03-05 ### Build diff --git a/include/components/types.hpp b/include/components/types.hpp index 69fe0ace..9deb5322 100644 --- a/include/components/types.hpp +++ b/include/components/types.hpp @@ -59,6 +59,11 @@ static inline mousebtn mousebtn_get_double(mousebtn btn) { } } +/** + * Order of values for _NET_WM_STRUT_PARTIAL + * + * https://specifications.freedesktop.org/wm-spec/wm-spec-latest.html#idm45381391268672 + */ enum class strut { LEFT = 0, RIGHT, @@ -132,13 +137,6 @@ struct percentage_with_offset { extent_val offset{ZERO_PX_EXTENT}; }; -struct edge_values { - unsigned int left{0U}; - unsigned int right{0U}; - unsigned int top{0U}; - unsigned int bottom{0U}; -}; - struct radius { double top_left{0.0}; double top_right{0.0}; @@ -173,7 +171,7 @@ struct bar_settings { monitor_t monitor{}; bool monitor_strict{false}; bool monitor_exact{true}; - edge origin{edge::TOP}; + bool bottom{false}; struct size size { 1U, 1U }; @@ -185,7 +183,10 @@ struct bar_settings { position offset{0, 0}; side_values padding{ZERO_SPACE, ZERO_SPACE}; side_values module_margin{ZERO_SPACE, ZERO_SPACE}; - edge_values strut{0U, 0U, 0U, 0U}; + struct { + int top; + int bottom; + } strut{0, 0}; rgba background{0xFF000000}; rgba foreground{0xFFFFFFFF}; diff --git a/include/x11/window.hpp b/include/x11/window.hpp index 9ddfe9f4..e637d249 100644 --- a/include/x11/window.hpp +++ b/include/x11/window.hpp @@ -2,6 +2,7 @@ #include #include + #include #include "common.hpp" @@ -17,7 +18,7 @@ class window : public xpp::window { window reconfigure_geom(unsigned short int w, unsigned short int h, short int x = 0, short int y = 0); window reconfigure_pos(short int x, short int y); - window reconfigure_struts(unsigned short int w, unsigned short int h, short int x, bool bottom = false); + window reconfigure_struts(uint32_t w, uint32_t strut, uint32_t x, bool bottom = false); }; POLYBAR_NS_END diff --git a/src/components/bar.cpp b/src/components/bar.cpp index 187a6eeb..6a2ed49a 100644 --- a/src/components/bar.cpp +++ b/src/components/bar.cpp @@ -191,7 +191,7 @@ bar::bar(connection& conn, signal_emitter& emitter, const config& config, const // Load configuration values - m_opts.origin = m_conf.get(bs, "bottom", false) ? edge::BOTTOM : edge::TOP; + m_opts.bottom = m_conf.get(bs, "bottom", m_opts.bottom); m_opts.spacing = m_conf.get(bs, "spacing", m_opts.spacing); m_opts.separator = drawtypes::load_optional_label(m_conf, bs, "separator", ""); m_opts.locale = m_conf.get(bs, "locale", ""s); @@ -221,10 +221,8 @@ bar::bar(connection& conn, signal_emitter& emitter, const config& config, const // Load values used to adjust the struts atom auto margin_top = m_conf.get("global/wm", "margin-top", percentage_with_offset{}); auto margin_bottom = m_conf.get("global/wm", "margin-bottom", percentage_with_offset{}); - m_opts.strut.top = - units_utils::percentage_with_offset_to_pixel_nonnegative(margin_top, m_opts.monitor->h, m_opts.dpi_y); - m_opts.strut.bottom = - units_utils::percentage_with_offset_to_pixel_nonnegative(margin_bottom, m_opts.monitor->h, m_opts.dpi_y); + m_opts.strut.top = units_utils::percentage_with_offset_to_pixel(margin_top, m_opts.monitor->h, m_opts.dpi_y); + m_opts.strut.bottom = units_utils::percentage_with_offset_to_pixel(margin_bottom, m_opts.monitor->h, m_opts.dpi_y); // Load commands used for fallback click handlers vector actions; @@ -329,7 +327,7 @@ bar::bar(connection& conn, signal_emitter& emitter, const config& config, const m_opts.size.h += m_opts.borders[edge::TOP].size; m_opts.size.h += m_opts.borders[edge::BOTTOM].size; - if (m_opts.origin == edge::BOTTOM) { + if (m_opts.bottom) { m_opts.pos.y = m_opts.monitor->y + m_opts.monitor->h - m_opts.size.h - m_opts.offset.y; } @@ -556,23 +554,41 @@ void bar::reconfigure_pos() { */ void bar::reconfigure_struts() { auto geom = m_connection.get_geometry(m_screen->root()); - auto w = m_opts.size.w + m_opts.offset.x; - auto h = m_opts.size.h + m_opts.offset.y; + int h = m_opts.size.h + m_opts.offset.y; - if (m_opts.origin == edge::BOTTOM) { + // Apply user-defined margins + if (m_opts.bottom) { h += m_opts.strut.top; } else { h += m_opts.strut.bottom; } - if (m_opts.origin == edge::BOTTOM && m_opts.monitor->y + m_opts.monitor->h < geom->height) { - h += geom->height - (m_opts.monitor->y + m_opts.monitor->h); - } else if (m_opts.origin != edge::BOTTOM) { - h += m_opts.monitor->y; + h = std::max(h, 0); + + int correction = 0; + + // Only apply correction if any space is requested + if (h > 0) { + /* + * Strut coordinates have to be relative to root window and not any monitor. + * If any monitor is not aligned at the top or bottom + */ + if (m_opts.bottom) { + /* + * For bottom-algined bars, the correction is the number of pixels between + * the root window's bottom edge and the monitor's bottom edge + */ + correction = geom->height - (m_opts.monitor->y + m_opts.monitor->h); + } else { + // For top-aligned bars, we simply add the monitor's y-position + correction = m_opts.monitor->y; + } + + correction = std::max(correction, 0); } window win{m_connection, m_opts.window}; - win.reconfigure_struts(w, h, m_opts.pos.x, m_opts.origin == edge::BOTTOM); + win.reconfigure_struts(m_opts.size.w, h + correction, m_opts.pos.x, m_opts.bottom); } /** diff --git a/src/x11/window.cpp b/src/x11/window.cpp index 35393ddc..0c31505a 100644 --- a/src/x11/window.cpp +++ b/src/x11/window.cpp @@ -1,9 +1,10 @@ +#include "x11/window.hpp" + #include "components/types.hpp" #include "utils/memory.hpp" #include "x11/atoms.hpp" #include "x11/connection.hpp" #include "x11/extensions/randr.hpp" -#include "x11/window.hpp" POLYBAR_NS @@ -45,24 +46,31 @@ window window::reconfigure_pos(short int x, short int y) { /** * Reconfigure the windows ewmh strut + * + * Ref: https://specifications.freedesktop.org/wm-spec/wm-spec-latest.html#idm45381391268672 + * + * @param w Width of the bar window + * @param strut Size of the reserved space. Height of the window, corrected for unaligned monitors + * @param x The absolute x-position of the bar window (top-left corner) + * @param bottom Whether the bar is at the bottom of the screen */ -window window::reconfigure_struts(unsigned short int w, unsigned short int h, short int x, bool bottom) { - unsigned int none{0}; - unsigned int values[12]{none}; +window window::reconfigure_struts(uint32_t w, uint32_t strut, uint32_t x, bool bottom) { + std::array values{}; if (bottom) { - values[static_cast(strut::BOTTOM)] = h; - values[static_cast(strut::BOTTOM_START_X)] = x; - values[static_cast(strut::BOTTOM_END_X)] = x + w - 1; + values[to_integral(strut::BOTTOM)] = strut; + values[to_integral(strut::BOTTOM_START_X)] = x; + values[to_integral(strut::BOTTOM_END_X)] = x + w - 1; } else { - values[static_cast(strut::TOP)] = h; - values[static_cast(strut::TOP_START_X)] = x; - values[static_cast(strut::TOP_END_X)] = x + w - 1; + values[to_integral(strut::TOP)] = strut; + values[to_integral(strut::TOP_START_X)] = x; + values[to_integral(strut::TOP_END_X)] = x + w - 1; } - connection().change_property_checked(XCB_PROP_MODE_REPLACE, *this, _NET_WM_STRUT, XCB_ATOM_CARDINAL, 32, 4, values); connection().change_property_checked( - XCB_PROP_MODE_REPLACE, *this, _NET_WM_STRUT_PARTIAL, XCB_ATOM_CARDINAL, 32, 12, values); + XCB_PROP_MODE_REPLACE, *this, _NET_WM_STRUT, XCB_ATOM_CARDINAL, 32, 4, values.data()); + connection().change_property_checked( + XCB_PROP_MODE_REPLACE, *this, _NET_WM_STRUT_PARTIAL, XCB_ATOM_CARDINAL, 32, 12, values.data()); return *this; }