diff --git a/include/components/bar.hpp b/include/components/bar.hpp index e6b249b2..72ca67a1 100644 --- a/include/components/bar.hpp +++ b/include/components/bar.hpp @@ -49,6 +49,7 @@ class bar : public xpp::event::sink; namespace randr_util { - monitor_t make_monitor(xcb_randr_output_t randr, string name, int w, int h, int x, int y); + monitor_t make_monitor(xcb_randr_output_t randr, string name, uint16_t w, uint16_t h, int16_t x, int16_t y); vector get_monitors(connection& conn, xcb_window_t root, bool connected_only = false); void get_backlight_range(connection& conn, const monitor_t& mon, backlight_values& dst); diff --git a/src/components/bar.cpp b/src/components/bar.cpp index 6898e17e..f93ee1f1 100644 --- a/src/components/bar.cpp +++ b/src/components/bar.cpp @@ -46,7 +46,8 @@ bar::~bar() { // {{{ m_connection.detach_sink(this, 1); } - m_window.destroy(); + m_connection.destroy_window(m_window); + m_connection.flush(); } // }}} /** @@ -140,12 +141,13 @@ void bar::bootstrap(bool nodraw) { // {{{ create_gcontexts(); create_rootpixmap(); restack_window(); + map_window(); set_wmhints(); // m_log.trace("bar: Listen to X RandR events"); // m_connection.select_input(m_window, XCB_RANDR_NOTIFY_MASK_SCREEN_CHANGE); - m_connection.map_window(m_window); + m_connection.flush(); // }}} // Connect signal handlers {{{ @@ -174,8 +176,6 @@ void bar::bootstrap(bool nodraw) { // {{{ m_sinkattached = true; load_fonts(); - - m_connection.flush(); } // }}} /** @@ -271,12 +271,12 @@ void bar::bootstrap_tray() { // {{{ auto offset_y = atoi(offset_y_def.c_str()); if (offset_x != 0 && offset_x_def.find("%") != string::npos) { - offset_x = math_util::percentage_to_value(offset_x, m_opts.monitor->w); + offset_x = math_util::percentage_to_value(offset_x, m_opts.monitor->w); offset_x -= settings.width / 2; } if (offset_y != 0 && offset_y_def.find("%") != string::npos) { - offset_y = math_util::percentage_to_value(offset_y, m_opts.monitor->h); + offset_y = math_util::percentage_to_value(offset_y, m_opts.monitor->h); offset_y -= settings.width / 2; } @@ -712,6 +712,18 @@ void bar::restack_window() { // {{{ } } // }}} +/** + * Map window and reconfigure its position + */ +void bar::map_window() { // {{{ + try { + m_window.map_checked(); + m_window.reconfigure_pos(m_opts.x, m_opts.y); + } catch (const exception& err) { + m_log.err("Failed to map bar window"); + } +} // }}} + /** * Set window atom values */ @@ -720,6 +732,12 @@ void bar::set_wmhints() { // {{{ xcb_icccm_set_wm_name(m_connection, m_window, XCB_ATOM_STRING, 8, m_opts.wmname.length(), m_opts.wmname.c_str()); xcb_icccm_set_wm_class(m_connection, m_window, 21, "lemonbuddy\0Lemonbuddy"); + m_log.trace("bar: Set WM_NORMAL_HINTS"); + xcb_size_hints_t hints; + xcb_icccm_size_hints_set_position(&hints, true, m_opts.x, m_opts.y); + xcb_icccm_size_hints_set_size(&hints, true, m_opts.width, m_opts.height); + xcb_icccm_set_wm_normal_hints(m_connection, m_window, &hints); + m_log.trace("bar: Set _NET_WM_WINDOW_TYPE"); wm_util::set_windowtype(m_connection, m_window, {_NET_WM_WINDOW_TYPE_DOCK}); @@ -732,28 +750,48 @@ void bar::set_wmhints() { // {{{ m_log.trace("bar: Set _NET_WM_PID"); wm_util::set_wmpid(m_connection, m_window, getpid()); - m_log.trace("bar: Set _NET_WM_STRUT_PARTIAL"); + m_log.trace("bar: Set _NET_WM_STRUT / _NET_WM_STRUT_PARTIAL"); { uint32_t none{0}; - uint32_t value_list[12]{none}; + uint32_t strut[12]{none}; auto mt = m_conf.get("global/wm", "margin-top", 0); auto mb = m_conf.get("global/wm", "margin-bottom", 0); auto ml = m_conf.get("global/wm", "margin-left", 0); auto mr = m_conf.get("global/wm", "margin-right", 0); + auto geom = m_connection.get_geometry(m_screen->root); + auto base_x = geom->x + m_opts.monitor->x; + auto max_x = base_x + m_opts.monitor->w; + auto height = m_opts.height + m_opts.offset_y; + auto width = m_opts.width + m_opts.offset_x; + auto start_x = base_x + m_opts.offset_x - ml; + auto end_x = base_x + width - m_opts.offset_x + mr; + + // clang-format off if (m_opts.bottom) { - value_list[3] = m_opts.monitor->y + m_opts.height + mt; - value_list[10] = m_opts.monitor->x + m_opts.x + ml; - value_list[11] = m_opts.monitor->x + m_opts.x + m_opts.width + mr; + auto base_y = geom->y + geom->height - m_opts.monitor->h - m_opts.monitor->y; + + strut[static_cast(strut::BOTTOM)] = + math_util::cap(base_y + height + mt, base_y, base_y + m_opts.monitor->h); + strut[static_cast(strut::BOTTOM_START_X)] = + math_util::cap(start_x, base_x, max_x); + strut[static_cast(strut::BOTTOM_END_X)] = + math_util::cap(end_x, base_x, max_x); } else { - value_list[2] = m_opts.monitor->y + m_opts.height + mb; - value_list[8] = m_opts.monitor->x + m_opts.x + ml; - value_list[9] = m_opts.monitor->x + m_opts.x + m_opts.width + mr; + auto base_y = geom->y + m_opts.monitor->y; + + strut[static_cast(strut::TOP)] = + math_util::cap(base_y + height + mb, base_y, base_y + m_opts.monitor->h); + strut[static_cast(strut::TOP_START_X)] = + math_util::cap(start_x, base_x, max_x); + strut[static_cast(strut::TOP_END_X)] = + math_util::cap(end_x, base_x, max_x); } - m_connection.change_property( - XCB_PROP_MODE_REPLACE, m_window, _NET_WM_STRUT_PARTIAL, XCB_ATOM_CARDINAL, 32, 12, value_list); + m_connection.change_property(XCB_PROP_MODE_REPLACE, m_window, _NET_WM_STRUT, XCB_ATOM_CARDINAL, 32, 4, strut); + m_connection.change_property(XCB_PROP_MODE_REPLACE, m_window, _NET_WM_STRUT_PARTIAL, XCB_ATOM_CARDINAL, 32, 12, strut); + // clang-format on } } // }}} diff --git a/src/x11/connection.cpp b/src/x11/connection.cpp index 7e91d7bf..292ea352 100644 --- a/src/x11/connection.cpp +++ b/src/x11/connection.cpp @@ -90,7 +90,7 @@ void connection::send_client_message(shared_ptr mess void connection::send_dummy_event(xcb_window_t target, uint32_t event) const { if (target == XCB_NONE) target = root(); - auto message = make_client_message(XCB_NONE, target); + auto message = make_client_message(XCB_VISIBILITY_NOTIFY, target); send_client_message(message, target, event); } diff --git a/src/x11/randr.cpp b/src/x11/randr.cpp index f91e7a85..38bc793e 100644 --- a/src/x11/randr.cpp +++ b/src/x11/randr.cpp @@ -6,7 +6,7 @@ namespace randr_util { /** * Define monitor */ - monitor_t make_monitor(xcb_randr_output_t randr, string name, int w, int h, int x, int y) { + monitor_t make_monitor(xcb_randr_output_t randr, string name, uint16_t w, uint16_t h, int16_t x, int16_t y) { monitor_t mon{new monitor_t::element_type{}}; mon->output = randr; mon->name = name; @@ -27,6 +27,8 @@ namespace randr_util { for (auto it = outputs.begin(); it != outputs.end(); it++) { try { auto info = conn.get_output_info(*it); + if (info->crtc == XCB_NONE) + continue; if (connected_only && info->connection != XCB_RANDR_CONNECTION_CONNECTED) continue; auto crtc = conn.get_crtc_info(info->crtc); @@ -37,7 +39,35 @@ namespace randr_util { } } - // use the same sort algo as lemonbar, to match the defaults + // clang-format off + const auto remove_monitor = [&](const monitor_t& monitor) { + monitors.erase(find(monitors.begin(), monitors.end(), monitor)); + }; + // clang-format on + + for (auto m = monitors.rbegin(); m != monitors.rend(); m++) { + if ((*m)->w == 0) { + remove_monitor(*m); + continue; + } + + // Test if there are any clones in the set + for (auto m2 = monitors.begin(); m2 != monitors.end(); m2++) { + if ((*m) == (*m2) || (*m2)->w == 0) { + continue; + } + + // clang-format off + if ((*m2)->x >= (*m)->x && (*m2)->x + (*m2)->w <= (*m)->x + (*m)->w && + (*m2)->y >= (*m)->y && (*m2)->y + (*m2)->h <= (*m)->y + (*m)->h) { + // Reset width so that the output gets + // removed in the base loop + (*m2)->w = 0; + } + // clang-format on + } + } + sort(monitors.begin(), monitors.end(), [](monitor_t& m1, monitor_t& m2) -> bool { if (m1->x < m2->x || m1->y + m1->h <= m2->y) return 1;