From 4556a4a7a8cbf3fe8e80c10ce31e889a65d3afba Mon Sep 17 00:00:00 2001
From: patrick96
Date: Mon, 14 Mar 2022 23:47:05 +0100
Subject: [PATCH] fix: Support negative struts
Fixed #2642
---
CHANGELOG.md | 1 +
include/components/types.hpp | 19 ++++++++--------
include/x11/window.hpp | 3 ++-
src/components/bar.cpp | 44 ++++++++++++++++++++++++------------
src/x11/window.cpp | 32 ++++++++++++++++----------
5 files changed, 63 insertions(+), 36 deletions(-)
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;
}