diff --git a/include/utils/restack.hpp b/include/utils/restack.hpp index bf3eaca8..7fdb98a8 100644 --- a/include/utils/restack.hpp +++ b/include/utils/restack.hpp @@ -8,7 +8,12 @@ POLYBAR_NS namespace restack_util { + using params = std::pair; + void restack_relative(connection& conn, xcb_window_t win, xcb_window_t sibling, xcb_stack_mode_t stack_mode); + bool are_siblings(connection& conn, xcb_window_t win, xcb_window_t sibling); + params get_bottom_params(connection& conn, xcb_window_t bar_window); + params get_generic_params(connection& conn, xcb_window_t bar_window); } POLYBAR_NS_END diff --git a/src/components/bar.cpp b/src/components/bar.cpp index fb02b158..22c730ba 100644 --- a/src/components/bar.cpp +++ b/src/components/bar.cpp @@ -480,8 +480,11 @@ void bar::toggle() { } /** - * Move the bar window above defined sibling - * in the X window stack + * Move the bar window above/below defined sibling in the X window stack. + * + * How the sibling is determined depends on the wm-restack setting. + * + * This is meant to resolve polybar appearing above other windows (especially in fullscreen). */ void bar::restack_window() { string wm_restack; @@ -492,15 +495,15 @@ void bar::restack_window() { return; } + xcb_window_t bar_window = m_opts.x_data.window; + xcb_window_t restack_sibling = XCB_NONE; xcb_stack_mode_t stack_mode = XCB_STACK_MODE_ABOVE; if (wm_restack == "generic") { - auto children = m_connection.query_tree(m_connection.root()).children(); - if (children.begin() != children.end() && *children.begin() != m_opts.x_data.window) { - restack_sibling = *children.begin(); - stack_mode = XCB_STACK_MODE_BELOW; - } + std::tie(restack_sibling, stack_mode) = restack_util::get_bottom_params(m_connection, bar_window); + } else if (wm_restack == "bottom") { + std::tie(restack_sibling, stack_mode) = restack_util::get_bottom_params(m_connection, bar_window); } else if (wm_restack == "bspwm") { restack_sibling = bspwm_util::get_restack_sibling(m_connection, m_opts.monitor); #if ENABLE_I3 @@ -517,13 +520,13 @@ void bar::restack_window() { if (restack_sibling != XCB_NONE) { try { - restack_util::restack_relative(m_connection, m_opts.x_data.window, restack_sibling, stack_mode); + restack_util::restack_relative(m_connection, bar_window, restack_sibling, stack_mode); m_log.info("Successfully restacked bar window"); } catch (const exception& err) { m_log.err("Failed to restack bar window (err=%s)", err.what()); } } else if (!wm_restack.empty()) { - m_log.err("Failed to restack bar window"); + m_log.err("Failed to restack bar window: No suitable sibling window for restacking was found"); } } diff --git a/src/utils/bspwm.cpp b/src/utils/bspwm.cpp index 310e8cce..9a3a9885 100644 --- a/src/utils/bspwm.cpp +++ b/src/utils/bspwm.cpp @@ -36,10 +36,7 @@ vector root_windows(connection& conn) { } /** - * Restack given window relative to the bspwm root window - * for the given monitor. - * - * Fixes the issue with always-on-top window's + * Returns window against which to restack. */ xcb_window_t get_restack_sibling(connection& conn, const monitor_t& mon) { for (auto&& root : root_windows(conn)) { diff --git a/src/utils/i3.cpp b/src/utils/i3.cpp index 6c2c7b1f..b532edf7 100644 --- a/src/utils/i3.cpp +++ b/src/utils/i3.cpp @@ -66,10 +66,7 @@ namespace i3_util { } /** - * Restack given window relative to the i3 root window - * defined for the given monitor - * - * Fixes the issue with always-on-top window's + * Returns window against which to restack. */ xcb_window_t get_restack_sibling(connection& conn) { return root_window(conn); diff --git a/src/utils/restack.cpp b/src/utils/restack.cpp index af3cb7e3..7f4962a4 100644 --- a/src/utils/restack.cpp +++ b/src/utils/restack.cpp @@ -3,21 +3,69 @@ POLYBAR_NS namespace restack_util { - /** - * Restacks the given window relative to a given sibling with some stack order (above, below) - * - * Both windows need to be siblings (have the same parent window). - * - * @param win The window to restack - * @param sibling The window relative to which restacking happens - * @param stack_mode The restacking mode (above, below) - * @throw Some xpp error if restacking fails - */ - void restack_relative(connection& conn, xcb_window_t win, xcb_window_t sibling, xcb_stack_mode_t stack_mode) { - const unsigned int value_mask = XCB_CONFIG_WINDOW_SIBLING | XCB_CONFIG_WINDOW_STACK_MODE; - const std::array value_list = {sibling, stack_mode}; - conn.configure_window_checked(win, value_mask, value_list.data()); - } + +static constexpr params NONE_PARAMS = {XCB_NONE, XCB_STACK_MODE_ABOVE}; + +/** + * Restacks the given window relative to a given sibling with some stack order (above, below) + * + * Both windows need to be siblings (have the same parent window). + * + * @param win The window to restack + * @param sibling The window relative to which restacking happens + * @param stack_mode The restacking mode (above, below) + * @throw Some xpp error if restacking fails + */ +void restack_relative(connection& conn, xcb_window_t win, xcb_window_t sibling, xcb_stack_mode_t stack_mode) { + const unsigned int value_mask = XCB_CONFIG_WINDOW_SIBLING | XCB_CONFIG_WINDOW_STACK_MODE; + const std::array value_list = {sibling, stack_mode}; + conn.configure_window_checked(win, value_mask, value_list.data()); } +/** + * @return true iff the two given windows are sibings (are different windows and have same parent). + */ +bool are_siblings(connection& conn, xcb_window_t win, xcb_window_t sibling) { + if (win == XCB_NONE || sibling == XCB_NONE || win == sibling) { + return false; + } + + auto win_tree = conn.query_tree(win); + auto sibling_tree = conn.query_tree(sibling); + return win_tree->parent == sibling_tree->parent; +} + +/** + * "bottom" restack strategy. + * + * Moves the bar window to the bottom of the window stack + */ +std::pair get_bottom_params(connection& conn, xcb_window_t bar_window) { + auto children = conn.query_tree(conn.root()).children(); + if (children.begin() != children.end() && *children.begin() != bar_window) { + return {*children.begin(), XCB_STACK_MODE_BELOW}; + } + + return NONE_PARAMS; +} + +/** + * Generic restack stratgey. + * + * Tries to provide the best WM-agnostic restacking. + * + * Currently tries to the following stratgies in order: + * * bottom + */ +std::pair get_generic_params(connection& conn, xcb_window_t bar_window) { + auto [sibling, mode] = get_bottom_params(conn, bar_window); + + if (are_siblings(conn, bar_window, sibling)) { + return {sibling, mode}; + } + + return NONE_PARAMS; +} +} // namespace restack_util + POLYBAR_NS_END