Clean up restacking code

Restacking algorithms now only need to provide the sibling window and
stacking mode.
This commit is contained in:
patrick96 2023-05-15 13:22:38 +02:00 committed by Patrick Ziegler
parent 76c7ee3bf6
commit 59acb4150b
5 changed files with 130 additions and 139 deletions

View File

@ -25,7 +25,7 @@ namespace bspwm_util {
}; };
vector<xcb_window_t> root_windows(connection& conn); vector<xcb_window_t> root_windows(connection& conn);
bool restack_to_root(connection& conn, const monitor_t& mon, const xcb_window_t win); xcb_window_t get_restack_sibling(connection& conn, const monitor_t& mon);
string get_socket_path(); string get_socket_path();

View File

@ -19,7 +19,7 @@ namespace i3_util {
shared_ptr<workspace_t> focused_workspace(const connection_t&); shared_ptr<workspace_t> focused_workspace(const connection_t&);
vector<xcb_window_t> root_windows(connection& conn, const string& output_name = ""); vector<xcb_window_t> root_windows(connection& conn, const string& output_name = "");
bool restack_to_root(connection& conn, const xcb_window_t win); xcb_window_t get_restack_sibling(connection& conn);
} }
namespace { namespace {

View File

@ -11,9 +11,9 @@
#include "events/signal_emitter.hpp" #include "events/signal_emitter.hpp"
#include "tags/dispatch.hpp" #include "tags/dispatch.hpp"
#include "utils/bspwm.hpp" #include "utils/bspwm.hpp"
#include "utils/restack.hpp"
#include "utils/color.hpp" #include "utils/color.hpp"
#include "utils/math.hpp" #include "utils/math.hpp"
#include "utils/restack.hpp"
#include "utils/string.hpp" #include "utils/string.hpp"
#include "utils/units.hpp" #include "utils/units.hpp"
#include "x11/atoms.hpp" #include "x11/atoms.hpp"
@ -492,23 +492,20 @@ void bar::restack_window() {
return; return;
} }
auto restacked = false; xcb_window_t restack_sibling = XCB_NONE;
xcb_stack_mode_t stack_mode = XCB_STACK_MODE_ABOVE;
if (wm_restack == "generic") { if (wm_restack == "generic") {
try { auto children = m_connection.query_tree(m_connection.root()).children();
auto children = m_connection.query_tree(m_connection.root()).children(); if (children.begin() != children.end() && *children.begin() != m_opts.x_data.window) {
if (children.begin() != children.end() && *children.begin() != m_opts.x_data.window) { restack_sibling = *children.begin();
restack_util::restack_relative(m_connection, m_opts.x_data.window, *children.begin(), XCB_STACK_MODE_BELOW); stack_mode = XCB_STACK_MODE_BELOW;
}
restacked = true;
} catch (const exception& err) {
m_log.err("Failed to restack bar window (err=%s)", err.what());
} }
} else if (wm_restack == "bspwm") { } else if (wm_restack == "bspwm") {
restacked = bspwm_util::restack_to_root(m_connection, m_opts.monitor, m_opts.x_data.window); restack_sibling = bspwm_util::get_restack_sibling(m_connection, m_opts.monitor);
#if ENABLE_I3 #if ENABLE_I3
} else if (wm_restack == "i3" && m_opts.override_redirect) { } else if (wm_restack == "i3" && m_opts.override_redirect) {
restacked = i3_util::restack_to_root(m_connection, m_opts.x_data.window); restack_sibling = i3_util::get_restack_sibling(m_connection);
} else if (wm_restack == "i3" && !m_opts.override_redirect) { } else if (wm_restack == "i3" && !m_opts.override_redirect) {
m_log.warn("Ignoring restack of i3 window (not needed when `override-redirect = false`)"); m_log.warn("Ignoring restack of i3 window (not needed when `override-redirect = false`)");
wm_restack.clear(); wm_restack.clear();
@ -518,8 +515,13 @@ void bar::restack_window() {
wm_restack.clear(); wm_restack.clear();
} }
if (restacked) { if (restack_sibling != XCB_NONE) {
m_log.info("Successfully restacked bar window"); try {
restack_util::restack_relative(m_connection, m_opts.x_data.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()) { } else if (!wm_restack.empty()) {
m_log.err("Failed to restack bar window"); m_log.err("Failed to restack bar window");
} }

View File

@ -5,148 +5,143 @@
#include "errors.hpp" #include "errors.hpp"
#include "utils/env.hpp" #include "utils/env.hpp"
#include "x11/connection.hpp" #include "x11/connection.hpp"
#include "x11/ewmh.hpp"
POLYBAR_NS POLYBAR_NS
namespace bspwm_util { namespace bspwm_util {
/** /**
* Get all bspwm root windows * Get all bspwm root windows
*/ */
vector<xcb_window_t> root_windows(connection& conn) { vector<xcb_window_t> root_windows(connection& conn) {
vector<xcb_window_t> roots; vector<xcb_window_t> roots;
auto children = conn.query_tree(conn.root()).children(); auto children = conn.query_tree(conn.root()).children();
for (auto it = children.begin(); it != children.end(); it++) { for (auto it = children.begin(); it != children.end(); it++) {
xcb_icccm_get_wm_class_reply_t reply{}; xcb_icccm_get_wm_class_reply_t reply{};
reply.class_name = reply.instance_name = nullptr; reply.class_name = reply.instance_name = nullptr;
if (xcb_icccm_get_wm_class_reply(conn, xcb_icccm_get_wm_class(conn, *it), &reply, nullptr)) { if (xcb_icccm_get_wm_class_reply(conn, xcb_icccm_get_wm_class(conn, *it), &reply, nullptr)) {
if (string_util::compare("Bspwm", reply.class_name) && string_util::compare("root", reply.instance_name)) { if (string_util::compare("Bspwm", reply.class_name) && string_util::compare("root", reply.instance_name)) {
roots.emplace_back(*it); roots.emplace_back(*it);
}
}
if (reply.class_name != nullptr || reply.instance_name != nullptr) {
xcb_icccm_get_wm_class_reply_wipe(&reply);
} }
} }
return roots; if (reply.class_name != nullptr || reply.instance_name != nullptr) {
xcb_icccm_get_wm_class_reply_wipe(&reply);
}
} }
/** return roots;
* Restack given window relative to the bspwm root window }
* for the given monitor.
*
* Fixes the issue with always-on-top window's
*/
bool restack_to_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; * Restack given window relative to the bspwm root window
} * for the given monitor.
if (mon->w != geom->width || mon->h != geom->height) { *
continue; * Fixes the issue with always-on-top window's
} */
xcb_window_t get_restack_sibling(connection& conn, const monitor_t& mon) {
for (auto&& root : root_windows(conn)) {
auto geom = conn.get_geometry(root);
const unsigned int value_mask = XCB_CONFIG_WINDOW_SIBLING | XCB_CONFIG_WINDOW_STACK_MODE; if (mon->x != geom->x || mon->y != geom->y) {
const unsigned int value_list[2]{root, XCB_STACK_MODE_ABOVE}; continue;
}
conn.configure_window_checked(win, value_mask, value_list); if (mon->w != geom->width || mon->h != geom->height) {
conn.flush(); continue;
return true;
} }
return false; return root;
} }
/** return XCB_NONE;
* Get path to the bspwm socket by the following order }
*
* 1. Value of environment variable BSPWM_SOCKET
* 2. Value built from the bspwm socket path template
* 3. Value of the macro BSPWM_SOCKET_PATH
*/
string get_socket_path() {
string env_path;
if (!(env_path = env_util::get("BSPWM_SOCKET")).empty()) { /**
return env_path; * Get path to the bspwm socket by the following order
} *
* 1. Value of environment variable BSPWM_SOCKET
* 2. Value built from the bspwm socket path template
* 3. Value of the macro BSPWM_SOCKET_PATH
*/
string get_socket_path() {
string env_path;
struct sockaddr_un sa {}; if (!(env_path = env_util::get("BSPWM_SOCKET")).empty()) {
char* host = nullptr; return env_path;
int dsp = 0;
int scr = 0;
if (xcb_parse_display(nullptr, &host, &dsp, &scr) == 0) {
return BSPWM_SOCKET_PATH;
}
snprintf(sa.sun_path, sizeof(sa.sun_path), "/tmp/bspwm%s_%i_%i-socket", host, dsp, scr);
free(host);
return sa.sun_path;
} }
/** struct sockaddr_un sa {};
* Generate a payload object with properly formatted data char* host = nullptr;
* ready to be sent to the bspwm ipc controller int dsp = 0;
*/ int scr = 0;
payload_t make_payload(const string& cmd) {
payload_t payload{new payload_t::element_type{}};
auto size = sizeof(payload->data);
int offset = 0;
int chars = 0;
for (auto&& word : string_util::split(cmd, ' ')) { if (xcb_parse_display(nullptr, &host, &dsp, &scr) == 0) {
chars = snprintf(payload->data + offset, size - offset, "%s%c", word.c_str(), 0); return BSPWM_SOCKET_PATH;
payload->len += chars;
offset += chars;
}
return payload;
} }
/** snprintf(sa.sun_path, sizeof(sa.sun_path), "/tmp/bspwm%s_%i_%i-socket", host, dsp, scr);
* Create an ipc socket connection free(host);
*
* Example usage: return sa.sun_path;
* @code cpp }
* auto ipc = make_connection();
* ipc->send(make_payload("desktop -f eDP-1:^1")); /**
* @endcode * Generate a payload object with properly formatted data
*/ * ready to be sent to the bspwm ipc controller
connection_t make_connection() { */
return socket_util::make_unix_connection(get_socket_path()); payload_t make_payload(const string& cmd) {
payload_t payload{new payload_t::element_type{}};
auto size = sizeof(payload->data);
int offset = 0;
int chars = 0;
for (auto&& word : string_util::split(cmd, ' ')) {
chars = snprintf(payload->data + offset, size - offset, "%s%c", word.c_str(), 0);
payload->len += chars;
offset += chars;
} }
/** return payload;
* Create a connection and subscribe to events }
* on the bspwm socket
* /**
* Example usage: * Create an ipc socket connection
* @code cpp *
* auto ipc = make_subscriber(); * Example usage:
* * @code cpp
* while (!ipc->poll(POLLHUP, 0)) { * auto ipc = make_connection();
* ssize_t bytes_received = 0; * ipc->send(make_payload("desktop -f eDP-1:^1"));
* auto data = ipc->receive(BUFSIZ-1, bytes_received, 0); * @endcode
* std::cout << data << std::endl; */
* } connection_t make_connection() {
* @endcode return socket_util::make_unix_connection(get_socket_path());
*/ }
connection_t make_subscriber() {
auto conn = make_connection(); /**
auto payload = make_payload("subscribe report"); * Create a connection and subscribe to events
if (conn->send(payload->data, payload->len, 0) == 0) { * on the bspwm socket
throw system_error("Failed to initialize subscriber"); *
} * Example usage:
return conn; * @code cpp
* auto ipc = make_subscriber();
*
* while (!ipc->poll(POLLHUP, 0)) {
* ssize_t bytes_received = 0;
* auto data = ipc->receive(BUFSIZ-1, bytes_received, 0);
* std::cout << data << std::endl;
* }
* @endcode
*/
connection_t make_subscriber() {
auto conn = make_connection();
auto payload = make_payload("subscribe report");
if (conn->send(payload->data, payload->len, 0) == 0) {
throw system_error("Failed to initialize subscriber");
} }
return conn;
}
} // namespace bspwm_util } // namespace bspwm_util
POLYBAR_NS_END POLYBAR_NS_END

View File

@ -71,14 +71,8 @@ namespace i3_util {
* *
* Fixes the issue with always-on-top window's * Fixes the issue with always-on-top window's
*/ */
bool restack_to_root(connection& conn, const xcb_window_t win) { xcb_window_t get_restack_sibling(connection& conn) {
const unsigned int value_mask = XCB_CONFIG_WINDOW_SIBLING | XCB_CONFIG_WINDOW_STACK_MODE; return root_window(conn);
const unsigned int value_list[2]{root_window(conn), XCB_STACK_MODE_ABOVE};
if (value_list[0] != XCB_NONE) {
conn.configure_window_checked(win, value_mask, value_list);
return true;
}
return false;
} }
} // namespace i3_util } // namespace i3_util