diff --git a/README.md b/README.md index cd30fb20..79fff928 100644 --- a/README.md +++ b/README.md @@ -414,6 +414,17 @@ The configuration syntax is based on the `ini` file format. ; left ; right tray-position = right + + ; Restack the bar window and put it above the + ; selected window manager's root + ; + ; Fixes the issue where the bar is being drawn + ; on top of fullscreen window's + ; + ; Currently supported WM's: + ; bspwm + ; Default: none + wm-restack = bspwm ~~~ ### Modules diff --git a/examples/config.bspwm b/examples/config.bspwm index fa0b2303..a8e40bf2 100644 --- a/examples/config.bspwm +++ b/examples/config.bspwm @@ -30,6 +30,8 @@ modules-right = volume cpu ram clock tray-position = right +wm-restack = bspwm + [module/label] type = custom/text content = %{F#f90f59}Example%{F#ff} configuration diff --git a/include/components/bar.hpp b/include/components/bar.hpp index 9ac227ca..d6d22df3 100644 --- a/include/components/bar.hpp +++ b/include/components/bar.hpp @@ -17,6 +17,7 @@ #include "components/x11/window.hpp" #include "components/x11/xlib.hpp" #include "components/x11/xutils.hpp" +#include "utils/bspwm.hpp" #include "utils/math.hpp" #include "utils/string.hpp" #include "utils/threading.hpp" @@ -275,6 +276,23 @@ class bar : public xpp::event::sink { m_connection.map_window_checked(m_window); } + // }}} + // Restack window and put it above defined WM's root {{{ + + try { + auto wm_restack = m_conf.get(bs, "wm-restack"); + + if (wm_restack == "bspwm") { + if (bspwm_util::restack_above_root(m_connection, m_bar.monitor, m_window)) + m_log.info("Successfully restacked window above Bspwm root"); + else + m_log.err("Failed to restack bar window above Bspwm root"); + } else { + m_log.warn("Unsupported wm-restack option '%s'", wm_restack); + } + } catch (const key_error& err) { + } + // }}} // Create graphic contexts {{{ diff --git a/include/utils/bspwm.hpp b/include/utils/bspwm.hpp index b0c49ad5..94318a27 100644 --- a/include/utils/bspwm.hpp +++ b/include/utils/bspwm.hpp @@ -1,8 +1,12 @@ #pragma once #include +#include #include "common.hpp" +#include "components/x11/connection.hpp" +#include "components/x11/randr.hpp" +#include "components/x11/window.hpp" #include "config.hpp" #include "utils/socket.hpp" #include "utils/string.hpp" @@ -22,6 +26,57 @@ namespace bspwm_util { size_t len = 0; }; + /** + * Get all bspwm root windows + */ + auto root_windows(connection& conn) { + vector roots; + auto children = conn.query_tree(conn.screen()->root).children(); + + for (auto it = children.begin(); it != children.end(); it++) { + auto cookie = xcb_icccm_get_wm_class(conn, *it); + xcb_icccm_get_wm_class_reply_t reply; + + if (xcb_icccm_get_wm_class_reply(conn, cookie, &reply, nullptr) == 0) + continue; + + if (!string_util::compare("Bspwm", reply.class_name) || + !string_util::compare("root", reply.instance_name)) + continue; + + roots.emplace_back(*it); + } + + return roots; + } + + /** + * Restack given window above the bspwm root window + * for the given monitor. + * + * Fixes the issue with always-on-top window's + */ + bool restack_above_root(connection& conn, const monitor_t& mon, const xcb_window_t win) { + for (auto&& root : root_windows(conn)) { + auto geom = conn.get_geometry(root); + + if (mon->x != geom->x || mon->y != geom->y) + continue; + if (mon->w != geom->width || mon->h != geom->height) + continue; + + const uint32_t value_mask = XCB_CONFIG_WINDOW_SIBLING | XCB_CONFIG_WINDOW_STACK_MODE; + const uint32_t value_list[2]{root, XCB_STACK_MODE_ABOVE}; + + conn.configure_window_checked(win, value_mask, value_list); + conn.flush(); + + return true; + } + + return false; + } + /** * Get path to the bspwm socket by the following order *