Clean up restacking code
Restacking algorithms now only need to provide the sibling window and stacking mode.
This commit is contained in:
parent
76c7ee3bf6
commit
59acb4150b
@ -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();
|
||||||
|
|
||||||
|
@ -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 {
|
||||||
|
@ -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");
|
||||||
}
|
}
|
||||||
|
@ -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
|
||||||
|
@ -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
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user