polybar-dwm/src/utils/bspwm.cpp

152 lines
3.9 KiB
C++
Raw Normal View History

2016-11-02 19:22:45 +00:00
#include <sys/un.h>
2016-11-25 12:55:15 +00:00
#include "errors.hpp"
2016-11-02 19:22:45 +00:00
#include "utils/bspwm.hpp"
2016-11-20 22:04:31 +00:00
#include "utils/env.hpp"
2016-11-26 05:13:20 +00:00
#include "x11/connection.hpp"
2016-11-02 19:22:45 +00:00
2016-11-19 05:22:44 +00:00
POLYBAR_NS
2016-11-02 19:22:45 +00:00
namespace bspwm_util {
/**
* Get all bspwm root windows
*/
vector<xcb_window_t> root_windows(connection& conn) {
vector<xcb_window_t> roots;
auto children = conn.query_tree(conn.screen()->root).children();
for (auto it = children.begin(); it != children.end(); it++) {
2016-12-15 08:29:14 +00:00
xcb_icccm_get_wm_class_reply_t reply{};
2016-11-19 03:06:05 +00:00
reply.class_name = reply.instance_name = nullptr;
2016-11-02 19:22:45 +00:00
2016-11-19 03:06:05 +00:00
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)) {
roots.emplace_back(*it);
}
}
2016-11-02 19:22:45 +00:00
2016-11-19 03:06:05 +00:00
if (reply.class_name != nullptr || reply.instance_name != nullptr) {
xcb_icccm_get_wm_class_reply_wipe(&reply);
}
2016-11-02 19:22:45 +00:00
}
return roots;
}
/**
2017-01-01 14:45:18 +00:00
* Restack given window relative to the bspwm root window
2016-11-02 19:22:45 +00:00
* for the given monitor.
*
* Fixes the issue with always-on-top window's
*/
2017-01-01 14:45:18 +00:00
bool restack_to_root(connection& conn, const monitor_t& mon, const xcb_window_t win) {
2016-11-02 19:22:45 +00:00
for (auto&& root : root_windows(conn)) {
auto geom = conn.get_geometry(root);
2016-11-25 12:55:15 +00:00
if (mon->x != geom->x || mon->y != geom->y) {
2016-11-02 19:22:45 +00:00
continue;
2016-11-25 12:55:15 +00:00
}
if (mon->w != geom->width || mon->h != geom->height) {
2016-11-02 19:22:45 +00:00
continue;
2016-11-25 12:55:15 +00:00
}
2016-11-02 19:22:45 +00:00
2017-01-19 10:11:28 +00:00
const unsigned int value_mask = XCB_CONFIG_WINDOW_SIBLING | XCB_CONFIG_WINDOW_STACK_MODE;
const unsigned int value_list[2]{root, XCB_STACK_MODE_ABOVE};
2016-11-02 19:22:45 +00:00
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
*
* 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;
2016-11-25 12:55:15 +00:00
if (!(env_path = env_util::get("BSPWM_SOCKET")).empty()) {
2016-11-02 19:22:45 +00:00
return env_path;
2016-11-25 12:55:15 +00:00
}
2016-11-02 19:22:45 +00:00
2016-12-15 08:29:14 +00:00
struct sockaddr_un sa {};
2016-11-02 19:22:45 +00:00
char* host = nullptr;
int dsp = 0;
int scr = 0;
2016-11-25 12:55:15 +00:00
if (xcb_parse_display(nullptr, &host, &dsp, &scr) == 0) {
2016-11-02 19:22:45 +00:00
return BSPWM_SOCKET_PATH;
2016-11-25 12:55:15 +00:00
}
2016-11-02 19:22:45 +00:00
snprintf(sa.sun_path, sizeof(sa.sun_path), "/tmp/bspwm%s_%i_%i-socket", host, dsp, scr);
2016-11-25 10:41:57 +00:00
free(host);
2016-11-02 19:22:45 +00:00
return sa.sun_path;
}
/**
* Generate a payload object with properly formatted data
* ready to be sent to the bspwm ipc controller
*/
2016-11-25 12:55:15 +00:00
payload_t make_payload(const string& cmd) {
2016-11-02 19:22:45 +00:00
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 an ipc socket connection
*
* Example usage:
* \code cpp
2016-11-02 19:22:45 +00:00
* auto ipc = make_connection();
* ipc->send(make_payload("desktop -f eDP-1:^1"));
* \endcode
2016-11-02 19:22:45 +00:00
*/
connection_t make_connection() {
return socket_util::make_unix_connection(get_socket_path());
}
/**
* Create a connection and subscribe to events
* on the bspwm socket
*
* Example usage:
* \code cpp
2016-11-02 19:22:45 +00:00
* 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
2016-11-02 19:22:45 +00:00
*/
connection_t make_subscriber() {
auto conn = make_connection();
auto payload = make_payload("subscribe report");
2016-11-25 12:55:15 +00:00
if (conn->send(payload->data, payload->len, 0) == 0) {
2016-11-02 19:22:45 +00:00
throw system_error("Failed to initialize subscriber");
2016-11-25 12:55:15 +00:00
}
2016-11-02 19:22:45 +00:00
return conn;
}
}
2016-11-19 05:22:44 +00:00
POLYBAR_NS_END