restack: Add ewmh restacking strategy

Positions the bar window above the _NET_SUPPORTING_WM_CHECK window

The generic restacking strategy now first tries the ewmh strategy, the
the bottom strategy.
This commit is contained in:
patrick96 2023-05-15 14:00:00 +02:00 committed by Patrick Ziegler
parent b11a2ff653
commit 4f9f07eefd
5 changed files with 258 additions and 176 deletions

View File

@ -11,8 +11,10 @@ namespace restack_util {
using params = std::pair<xcb_window_t, xcb_stack_mode_t>;
void restack_relative(connection& conn, xcb_window_t win, xcb_window_t sibling, xcb_stack_mode_t stack_mode);
string stack_mode_to_string(xcb_stack_mode_t 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_ewmh_params(connection& conn);
params get_generic_params(connection& conn, xcb_window_t bar_window);
}

View File

@ -53,6 +53,9 @@ namespace ewmh_util {
void set_wm_window_opacity(xcb_window_t win, unsigned long int values);
vector<xcb_window_t> get_client_list(int screen = 0);
xcb_window_t get_supporting_wm_check(xcb_window_t win);
xcb_window_t get_ewmh_meta_window(xcb_window_t root);
} // namespace ewmh_util
POLYBAR_NS_END

View File

@ -501,7 +501,9 @@ void bar::restack_window() {
xcb_stack_mode_t stack_mode = XCB_STACK_MODE_ABOVE;
if (wm_restack == "generic") {
std::tie(restack_sibling, stack_mode) = restack_util::get_bottom_params(m_connection, bar_window);
std::tie(restack_sibling, stack_mode) = restack_util::get_generic_params(m_connection, bar_window);
} else if (wm_restack == "ewmh") {
std::tie(restack_sibling, stack_mode) = restack_util::get_ewmh_params(m_connection);
} 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") {
@ -520,6 +522,8 @@ void bar::restack_window() {
if (restack_sibling != XCB_NONE) {
try {
m_log.info("bar: Restacking bar window relative to %s with stacking mode %s", m_connection.id(restack_sibling),
restack_util::stack_mode_to_string(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) {

View File

@ -22,6 +22,23 @@ void restack_relative(connection& conn, xcb_window_t win, xcb_window_t sibling,
conn.configure_window_checked(win, value_mask, value_list.data());
}
string stack_mode_to_string(xcb_stack_mode_t mode) {
switch (mode) {
case XCB_STACK_MODE_ABOVE:
return "ABOVE";
case XCB_STACK_MODE_BELOW:
return "BELOW";
case XCB_STACK_MODE_TOP_IF:
return "TOP_IF";
case XCB_STACK_MODE_BOTTOM_IF:
return "BOTTOM_IF";
case XCB_STACK_MODE_OPPOSITE:
return "OPPOSITE";
}
return "UNKNOWN";
}
/**
* @return true iff the two given windows are sibings (are different windows and have same parent).
*/
@ -40,7 +57,7 @@ bool are_siblings(connection& conn, xcb_window_t win, xcb_window_t sibling) {
*
* Moves the bar window to the bottom of the window stack
*/
std::pair<xcb_window_t, xcb_stack_mode_t> get_bottom_params(connection& conn, xcb_window_t bar_window) {
params 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};
@ -49,19 +66,42 @@ std::pair<xcb_window_t, xcb_stack_mode_t> get_bottom_params(connection& conn, xc
return NONE_PARAMS;
}
/**
* EWMH restack strategy.
*
* Moves the bar window above the WM meta window (_NET_SUPPORTING_WM_CHECK).
* This window is generally towards the bottom of the window stack, but still above other windows that could interfere.
*
* @see ewmh_util::get_ewmh_meta_window
*/
params get_ewmh_params(connection& conn) {
if (auto meta_window = ewmh_util::get_ewmh_meta_window(conn.root())) {
return {meta_window, XCB_STACK_MODE_ABOVE};
}
return NONE_PARAMS;
}
/**
* Generic restack stratgey.
*
* Tries to provide the best WM-agnostic restacking.
*
* Currently tries to the following stratgies in order:
* * ewmh
* * bottom
*/
std::pair<xcb_window_t, xcb_stack_mode_t> get_generic_params(connection& conn, xcb_window_t bar_window) {
auto [sibling, mode] = get_bottom_params(conn, bar_window);
params get_generic_params(connection& conn, xcb_window_t bar_window) {
auto ewmh_params = get_ewmh_params(conn);
if (are_siblings(conn, bar_window, sibling)) {
return {sibling, mode};
if (are_siblings(conn, bar_window, ewmh_params.first)) {
return ewmh_params;
}
auto bottom_params = get_bottom_params(conn, bar_window);
if (are_siblings(conn, bar_window, bottom_params.first)) {
return bottom_params;
}
return NONE_PARAMS;

View File

@ -193,6 +193,39 @@ namespace ewmh_util {
}
return {};
}
/**
* Retrieves the _NET_SUPPORTING_WM_CHECK atom on the given window
*
* @return The _NET_SUPPORTING_WM_CHECK window id or XCB_NONE in case of an error
*/
xcb_window_t get_supporting_wm_check(xcb_window_t win) {
auto& conn = initialize();
xcb_window_t result{};
if (xcb_ewmh_get_supporting_wm_check_reply(conn, xcb_ewmh_get_supporting_wm_check(conn, win), &result, nullptr)) {
return result;
}
return XCB_NONE;
}
/**
* Searches for the meta window spawned by the WM to indicate a compliant WM is active.
*
* The window has the following properties:
* * It's pointed to by the root window's _NET_SUPPORTING_WM_CHECK atom
* * Its own _NET_SUPPORTING_WM_CHECK atom is set and points to itself
*
* @return The meta window id or XCB_NONE if it wasn't found
*/
xcb_window_t get_ewmh_meta_window(xcb_window_t root) {
xcb_window_t wm_meta_window = ewmh_util::get_supporting_wm_check(root);
if (wm_meta_window != XCB_NONE && ewmh_util::get_supporting_wm_check(wm_meta_window) == wm_meta_window) {
return wm_meta_window;
}
return XCB_NONE;
}
} // namespace ewmh_util
POLYBAR_NS_END