fix: Make the application work properly using i3wm

This commit is contained in:
Michael Carlberg 2016-10-11 23:36:11 +02:00
parent 0bf26642d2
commit eb38fb85ac
7 changed files with 165 additions and 26 deletions

View File

@ -423,6 +423,7 @@ The configuration syntax is based on the `ini` file format.
; ;
; Currently supported WM's: ; Currently supported WM's:
; bspwm ; bspwm
; i3
; Default: none ; Default: none
wm-restack = bspwm wm-restack = bspwm
~~~ ~~~

View File

@ -18,6 +18,7 @@
#include "components/x11/xlib.hpp" #include "components/x11/xlib.hpp"
#include "components/x11/xutils.hpp" #include "components/x11/xutils.hpp"
#include "utils/bspwm.hpp" #include "utils/bspwm.hpp"
#include "utils/i3.hpp"
#include "utils/math.hpp" #include "utils/math.hpp"
#include "utils/string.hpp" #include "utils/string.hpp"
#include "utils/threading.hpp" #include "utils/threading.hpp"
@ -28,7 +29,7 @@ namespace bar_signals {
delegate::Signal1<string> action_click; delegate::Signal1<string> action_click;
}; };
class bar : public xpp::event::sink<evt::button_press> { class bar : public xpp::event::sink<evt::button_press, evt::expose> {
public: public:
/** /**
* Construct bar * Construct bar
@ -244,23 +245,76 @@ class bar : public xpp::event::sink<evt::button_press> {
m_log.trace("bar: Set _NET_WM_WINDOW_TYPE"); m_log.trace("bar: Set _NET_WM_WINDOW_TYPE");
{ {
xcb_atom_t win_types[2] = {_NET_WM_WINDOW_TYPE_DOCK, _NET_WM_WINDOW_TYPE_NORMAL}; // const uint32_t win_types[2] = {_NET_WM_WINDOW_TYPE_DOCK, _NET_WM_WINDOW_TYPE_NORMAL};
const uint32_t win_types[1] = {_NET_WM_WINDOW_TYPE_DOCK};
m_connection.change_property_checked( m_connection.change_property_checked(
XCB_PROP_MODE_REPLACE, m_window, _NET_WM_WINDOW_TYPE, XCB_ATOM_ATOM, 32, 2, &win_types); XCB_PROP_MODE_REPLACE, m_window, _NET_WM_WINDOW_TYPE, XCB_ATOM_ATOM, 32, 1, win_types);
} }
m_log.trace("bar: Set _NET_WM_STATE"); m_log.trace("bar: Set _NET_WM_STATE");
{ {
xcb_atom_t win_states[2] = {_NET_WM_STATE_STICKY, _NET_WM_STATE_SKIP_TASKBAR}; if (m_bar.width == m_bar.monitor->w) {
const uint32_t win_states[3] = {
_NET_WM_STATE_STICKY, _NET_WM_STATE_SKIP_TASKBAR, _NET_WM_STATE_MAXIMIZED_VERT};
m_connection.change_property_checked( m_connection.change_property_checked(
XCB_PROP_MODE_REPLACE, m_window, _NET_WM_STATE, XCB_ATOM_ATOM, 32, 2, &win_states); XCB_PROP_MODE_REPLACE, m_window, _NET_WM_STATE, XCB_ATOM_ATOM, 32, 3, win_states);
} else {
const uint32_t win_states[2] = {_NET_WM_STATE_STICKY, _NET_WM_STATE_SKIP_TASKBAR};
m_connection.change_property_checked(
XCB_PROP_MODE_REPLACE, m_window, _NET_WM_STATE, XCB_ATOM_ATOM, 32, 2, win_states);
}
}
m_log.trace("bar: Set _NET_WM_STRUT");
{
// clang-format off
uint32_t none{0};
uint32_t value_list[4]{
static_cast<uint32_t>(m_bar.x), // left
none, // right
m_bar.bottom ? none : m_bar.height + m_bar.offset_y, // top
m_bar.bottom ? m_bar.height + m_bar.offset_y : none, // bottom
};
// clang-format on
m_connection.change_property_checked(
XCB_PROP_MODE_REPLACE, m_window, _NET_WM_STRUT, XCB_ATOM_CARDINAL, 32, 4, value_list);
}
m_log.trace("bar: Set _NET_WM_STRUT_PARTIAL");
{
// clang-format off
uint32_t none{0};
const uint32_t value_list[12]{
static_cast<uint32_t>(m_bar.x), // left
none, // right
m_bar.bottom ? none : m_bar.height + m_bar.offset_y, // top
m_bar.bottom ? m_bar.height + m_bar.offset_y : none, // bottom
none, // left_start_y
none, // left_end_y
none, // right_start_y
none, // right_end_y
m_bar.bottom ? none : m_bar.x, // top_start_x
m_bar.bottom ? none : static_cast<uint32_t>(m_bar.x + m_bar.width), // top_end_x
m_bar.bottom ? m_bar.x : none, // bottom_start_x
m_bar.bottom ? static_cast<uint32_t>(m_bar.x + m_bar.width) : none, // bottom_end_x
};
// clang-format on
m_connection.change_property_checked(XCB_PROP_MODE_REPLACE, m_window, _NET_WM_STRUT_PARTIAL,
XCB_ATOM_CARDINAL, 32, 12, value_list);
}
m_log.trace("bar: Set _NET_WM_DESKTOP");
{
const uint32_t value_list[1]{-1u};
m_connection.change_property_checked(
XCB_PROP_MODE_REPLACE, m_window, _NET_WM_DESKTOP, XCB_ATOM_CARDINAL, 32, 1, value_list);
} }
m_log.trace("bar: Set _NET_WM_PID"); m_log.trace("bar: Set _NET_WM_PID");
{ {
int pid = getpid(); const uint32_t value_list[1]{uint32_t(getpid())};
m_connection.change_property_checked( m_connection.change_property_checked(
XCB_PROP_MODE_REPLACE, m_window, _NET_WM_PID, XCB_ATOM_CARDINAL, 32, 1, &pid); XCB_PROP_MODE_REPLACE, m_window, _NET_WM_PID, XCB_ATOM_CARDINAL, 32, 1, value_list);
} }
m_log.trace("bar: Create pixmap"); m_log.trace("bar: Create pixmap");
@ -281,14 +335,27 @@ class bar : public xpp::event::sink<evt::button_press> {
try { try {
auto wm_restack = m_conf.get<string>(bs, "wm-restack"); auto wm_restack = m_conf.get<string>(bs, "wm-restack");
auto restacked = false;
if (wm_restack == "bspwm") { if (wm_restack == "bspwm") {
if (bspwm_util::restack_above_root(m_connection, m_bar.monitor, m_window)) restacked = bspwm_util::restack_above_root(m_connection, m_bar.monitor, m_window);
m_log.info("Successfully restacked window above Bspwm root");
else } else if (wm_restack == "i3" && m_bar.dock) {
m_log.err("Failed to restack bar window above Bspwm root"); restacked = i3_util::restack_above_root(m_connection, m_bar.monitor, m_window);
} else if (wm_restack == "i3" && !m_bar.dock) {
m_log.warn("Ignoring restack of i3 window (not needed when dock = false)");
wm_restack.clear();
} else { } else {
m_log.warn("Unsupported wm-restack option '%s'", wm_restack); m_log.warn("Ignoring unsupported wm-restack option '%s'", wm_restack);
wm_restack.clear();
}
if (restacked) {
m_log.info("Successfully restacked bar window");
} else if (!wm_restack.empty()) {
m_log.err("Failed to restack bar window");
} }
} catch (const key_error& err) { } catch (const key_error& err) {
} }
@ -296,13 +363,6 @@ class bar : public xpp::event::sink<evt::button_press> {
// }}} // }}}
// Create graphic contexts {{{ // Create graphic contexts {{{
// XCB_GC_LINE_WIDTH
// XCB_GC_LINE_STYLE
// -- XCB_LINE_STYLE_SOLID
// xcb_poly_line (connection, XCB_COORD_MODE_PREVIOUS, window, foreground, 4, polyline);
// xcb_poly_line(conn, XCB_COORD_MODE_ORIGIN, drawable, gc, 2, (xcb_point_t[]) { {10, 10}, {100,
// 10} });
m_log.trace("bar: Create graphic contexts"); m_log.trace("bar: Create graphic contexts");
{ {
// clang-format off // clang-format off
@ -598,6 +658,16 @@ class bar : public xpp::event::sink<evt::button_press> {
} }
} // }}} } // }}}
/**
* Event handler for XCB_EXPOSE events
*/
void handle(const evt::expose& evt) { // {{{
if (evt->window != m_window)
return;
m_log.trace("bar: Received expose event");
flush();
} // }}}
protected: protected:
/** /**
* Handle alignment update * Handle alignment update

View File

@ -10,6 +10,7 @@ struct cached_atom {
}; };
static xcb_atom_t _NET_WM_NAME; static xcb_atom_t _NET_WM_NAME;
static xcb_atom_t _NET_WM_DESKTOP;
static xcb_atom_t _NET_WM_WINDOW_TYPE; static xcb_atom_t _NET_WM_WINDOW_TYPE;
static xcb_atom_t _NET_WM_WINDOW_TYPE_DOCK; static xcb_atom_t _NET_WM_WINDOW_TYPE_DOCK;
static xcb_atom_t _NET_WM_WINDOW_TYPE_NORMAL; static xcb_atom_t _NET_WM_WINDOW_TYPE_NORMAL;
@ -18,6 +19,9 @@ static xcb_atom_t _NET_WM_STATE;
static xcb_atom_t _NET_WM_STATE_STICKY; static xcb_atom_t _NET_WM_STATE_STICKY;
static xcb_atom_t _NET_WM_STATE_SKIP_TASKBAR; static xcb_atom_t _NET_WM_STATE_SKIP_TASKBAR;
static xcb_atom_t _NET_WM_STATE_ABOVE; static xcb_atom_t _NET_WM_STATE_ABOVE;
static xcb_atom_t _NET_WM_STATE_MAXIMIZED_VERT;
static xcb_atom_t _NET_WM_STRUT;
static xcb_atom_t _NET_WM_STRUT_PARTIAL;
static xcb_atom_t WM_PROTOCOLS; static xcb_atom_t WM_PROTOCOLS;
static xcb_atom_t WM_DELETE_WINDOW; static xcb_atom_t WM_DELETE_WINDOW;
static xcb_atom_t _XEMBED; static xcb_atom_t _XEMBED;
@ -29,8 +33,9 @@ static xcb_atom_t _NET_SYSTEM_TRAY_ORIENTATION;
static xcb_atom_t WM_TAKE_FOCUS; static xcb_atom_t WM_TAKE_FOCUS;
// clang-format off // clang-format off
static cached_atom ATOMS[18] = { static cached_atom ATOMS[22] = {
{"_NET_WM_NAME", sizeof("_NET_WM_NAME") - 1, &_NET_WM_NAME}, {"_NET_WM_NAME", sizeof("_NET_WM_NAME") - 1, &_NET_WM_NAME},
{"_NET_WM_DESKTOP", sizeof("_NET_WM_DESKTOP") - 1, &_NET_WM_DESKTOP},
{"_NET_WM_WINDOW_TYPE", sizeof("_NET_WM_WINDOW_TYPE") - 1, &_NET_WM_WINDOW_TYPE}, {"_NET_WM_WINDOW_TYPE", sizeof("_NET_WM_WINDOW_TYPE") - 1, &_NET_WM_WINDOW_TYPE},
{"_NET_WM_WINDOW_TYPE_DOCK", sizeof("_NET_WM_WINDOW_TYPE_DOCK") - 1, &_NET_WM_WINDOW_TYPE_DOCK}, {"_NET_WM_WINDOW_TYPE_DOCK", sizeof("_NET_WM_WINDOW_TYPE_DOCK") - 1, &_NET_WM_WINDOW_TYPE_DOCK},
{"_NET_WM_WINDOW_TYPE_NORMAL", sizeof("_NET_WM_WINDOW_TYPE_NORMAL") - 1, &_NET_WM_WINDOW_TYPE_NORMAL}, {"_NET_WM_WINDOW_TYPE_NORMAL", sizeof("_NET_WM_WINDOW_TYPE_NORMAL") - 1, &_NET_WM_WINDOW_TYPE_NORMAL},
@ -39,6 +44,9 @@ static cached_atom ATOMS[18] = {
{"_NET_WM_STATE_STICKY", sizeof("_NET_WM_STATE_STICKY") - 1, &_NET_WM_STATE_STICKY}, {"_NET_WM_STATE_STICKY", sizeof("_NET_WM_STATE_STICKY") - 1, &_NET_WM_STATE_STICKY},
{"_NET_WM_STATE_SKIP_TASKBAR", sizeof("_NET_WM_STATE_SKIP_TASKBAR") - 1, &_NET_WM_STATE_SKIP_TASKBAR}, {"_NET_WM_STATE_SKIP_TASKBAR", sizeof("_NET_WM_STATE_SKIP_TASKBAR") - 1, &_NET_WM_STATE_SKIP_TASKBAR},
{"_NET_WM_STATE_ABOVE", sizeof("_NET_WM_STATE_ABOVE") - 1, &_NET_WM_STATE_ABOVE}, {"_NET_WM_STATE_ABOVE", sizeof("_NET_WM_STATE_ABOVE") - 1, &_NET_WM_STATE_ABOVE},
{"_NET_WM_STATE_MAXIMIZED_VERT", sizeof("_NET_WM_STATE_MAXIMIZED_VERT") - 1, &_NET_WM_STATE_MAXIMIZED_VERT},
{"_NET_WM_STRUT", sizeof("_NET_WM_STRUT") - 1, &_NET_WM_STRUT},
{"_NET_WM_STRUT_PARTIAL", sizeof("_NET_WM_STRUT_PARTIAL") - 1, &_NET_WM_STRUT_PARTIAL},
{"WM_PROTOCOLS", sizeof("WM_PROTOCOLS") - 1, &WM_PROTOCOLS}, {"WM_PROTOCOLS", sizeof("WM_PROTOCOLS") - 1, &WM_PROTOCOLS},
{"WM_DELETE_WINDOW", sizeof("WM_DELETE_WINDOW") - 1, &WM_DELETE_WINDOW}, {"WM_DELETE_WINDOW", sizeof("WM_DELETE_WINDOW") - 1, &WM_DELETE_WINDOW},
{"_XEMBED", sizeof("_XEMBED") - 1, &_XEMBED}, {"_XEMBED", sizeof("_XEMBED") - 1, &_XEMBED},

View File

@ -275,8 +275,8 @@ class traymanager
m_logger.trace("tray: Create tray window %s, (%ix%i+%i+%i)", m_connection.id(m_tray), m_logger.trace("tray: Create tray window %s, (%ix%i+%i+%i)", m_connection.id(m_tray),
m_settings.width, m_settings.height, x, y); m_settings.width, m_settings.height, x, y);
auto scr = m_connection.screen(); auto scr = m_connection.screen();
const uint32_t mask = XCB_CW_BACK_PIXEL | XCB_CW_EVENT_MASK; const uint32_t mask = XCB_CW_BACK_PIXEL | XCB_CW_OVERRIDE_REDIRECT | XCB_CW_EVENT_MASK;
const uint32_t values[2]{m_settings.background, const uint32_t values[3]{m_settings.background, true,
XCB_EVENT_MASK_SUBSTRUCTURE_REDIRECT | XCB_EVENT_MASK_STRUCTURE_NOTIFY}; XCB_EVENT_MASK_SUBSTRUCTURE_REDIRECT | XCB_EVENT_MASK_STRUCTURE_NOTIFY};
m_connection.create_window_checked(scr->root_depth, m_tray, scr->root, x, y, m_connection.create_window_checked(scr->root_depth, m_tray, scr->root, x, y,
m_settings.width + m_settings.spacing * 2, m_settings.height + m_settings.spacing * 2, 0, m_settings.width + m_settings.spacing * 2, m_settings.height + m_settings.spacing * 2, 0,

View File

@ -137,10 +137,12 @@ class window : public xpp::window<connection_t&> {
// //
// window operator<<(cw_flush f) { // window operator<<(cw_flush f) {
// if (f.checked) // if (f.checked)
// m_connection.create_window_checked(m_depth, m_window, m_parent, m_x, m_y, m_width, m_height, // m_connection.create_window_checked(m_depth, m_window, m_parent, m_x, m_y, m_width,
// m_height,
// m_border, m_class, m_visual, m_mask, m_params); // m_border, m_class, m_visual, m_mask, m_params);
// else // else
// m_connection.create_window(m_depth, m_window, m_parent, m_x, m_y, m_width, m_height, m_border, // m_connection.create_window(m_depth, m_window, m_parent, m_x, m_y, m_width, m_height,
// m_border,
// m_class, m_visual, m_mask, m_params); // m_class, m_visual, m_mask, m_params);
// return m_window; // return m_window;
// } // }

60
include/utils/i3.hpp Normal file
View File

@ -0,0 +1,60 @@
#pragma once
#include <xcb/xcb.h>
#include <xcb/xcb_icccm.h>
#include "common.hpp"
#include "components/x11/connection.hpp"
#include "components/x11/randr.hpp"
#include "config.hpp"
#include "utils/socket.hpp"
#include "utils/string.hpp"
LEMONBUDDY_NS
namespace i3_util {
/**
* Get all i3 root windows
*/
auto root_windows(connection& conn, string output_name = "") {
vector<xcb_window_t> roots;
auto children = conn.query_tree(conn.screen()->root).children();
for (auto it = children.begin(); it != children.end(); it++) {
auto cookie = xcb_icccm_get_wm_name(conn, *it);
xcb_icccm_get_text_property_reply_t reply;
if (xcb_icccm_get_wm_name_reply(conn, cookie, &reply, nullptr) == 0)
continue;
if (("[i3 con] output " + output_name).compare(0, 16 + output_name.length(), reply.name) != 0)
continue;
roots.emplace_back(*it);
}
return roots;
}
/**
* Restack given window above the i3 root window
* defined for the given monitor
*
* Fixes the issue with always-on-top window's
*/
bool restack_above_root(connection& conn, const monitor_t& mon, const xcb_window_t win) {
for (auto&& root : root_windows(conn, mon->name)) {
const uint32_t value_mask = XCB_CONFIG_WINDOW_SIBLING | XCB_CONFIG_WINDOW_STACK_MODE;
const uint32_t value_list[2]{root, XCB_STACK_MODE_ABOVE};
conn.configure_window_checked(win, value_mask, value_list);
conn.flush();
return true;
}
return false;
}
}
LEMONBUDDY_NS_END

View File

@ -8,8 +8,6 @@
#include "components/logger.hpp" #include "components/logger.hpp"
#include "components/x11/xutils.hpp" #include "components/x11/xutils.hpp"
#include "config.hpp" #include "config.hpp"
#include "utils/bspwm.hpp"
#include "utils/file.hpp"
#include "utils/inotify.hpp" #include "utils/inotify.hpp"
using namespace lemonbuddy; using namespace lemonbuddy;