refactor(bar): Strut values based on EMWH spec

This commit is contained in:
Michael Carlberg 2016-11-13 11:30:27 +01:00
parent c8f2a934b1
commit 4224d838a8
6 changed files with 109 additions and 25 deletions

View File

@ -49,6 +49,7 @@ class bar : public xpp::event::sink<evt::button_press, evt::expose, evt::propert
void create_gcontexts(); void create_gcontexts();
void create_rootpixmap(); void create_rootpixmap();
void restack_window(); void restack_window();
void map_window();
void set_wmhints(); void set_wmhints();
int get_centerx(); int get_centerx();
@ -89,7 +90,7 @@ class bar : public xpp::event::sink<evt::button_press, evt::expose, evt::propert
xcb_screen_t* m_screen; xcb_screen_t* m_screen;
xcb_visualtype_t* m_visual; xcb_visualtype_t* m_visual;
window m_window{m_connection}; window m_window{m_connection, m_connection.generate_id()};
colormap m_colormap{m_connection, m_connection.generate_id()}; colormap m_colormap{m_connection, m_connection.generate_id()};
pixmap m_pixmap{m_connection, m_connection.generate_id()}; pixmap m_pixmap{m_connection, m_connection.generate_id()};

View File

@ -13,6 +13,21 @@ enum class attribute { NONE = 0, o = 2, u = 4 };
enum class mousebtn { NONE = 0, LEFT, MIDDLE, RIGHT, SCROLL_UP, SCROLL_DOWN }; enum class mousebtn { NONE = 0, LEFT, MIDDLE, RIGHT, SCROLL_UP, SCROLL_DOWN };
enum class gc { NONE = 0, BG, FG, OL, UL, BT, BB, BL, BR }; enum class gc { NONE = 0, BG, FG, OL, UL, BT, BB, BL, BR };
enum class strut {
LEFT = 0,
RIGHT,
TOP,
BOTTOM,
LEFT_START_Y,
LEFT_END_Y,
RIGHT_START_Y,
RIGHT_END_Y,
TOP_START_X,
TOP_END_X,
BOTTOM_START_X,
BOTTOM_END_X,
};
struct bar_settings { struct bar_settings {
bar_settings() = default; bar_settings() = default;

View File

@ -21,10 +21,10 @@ struct backlight_values {
struct randr_output { struct randr_output {
string name; string name;
int w = 0; uint16_t w = 0;
int h = 0; uint16_t h = 0;
int x = 0; int16_t x = 0;
int y = 0; int16_t y = 0;
xcb_randr_output_t output; xcb_randr_output_t output;
backlight_values backlight; backlight_values backlight;
@ -43,7 +43,7 @@ struct randr_output {
using monitor_t = shared_ptr<randr_output>; using monitor_t = shared_ptr<randr_output>;
namespace randr_util { namespace randr_util {
monitor_t make_monitor(xcb_randr_output_t randr, string name, int w, int h, int x, int y); monitor_t make_monitor(xcb_randr_output_t randr, string name, uint16_t w, uint16_t h, int16_t x, int16_t y);
vector<monitor_t> get_monitors(connection& conn, xcb_window_t root, bool connected_only = false); vector<monitor_t> get_monitors(connection& conn, xcb_window_t root, bool connected_only = false);
void get_backlight_range(connection& conn, const monitor_t& mon, backlight_values& dst); void get_backlight_range(connection& conn, const monitor_t& mon, backlight_values& dst);

View File

@ -46,7 +46,8 @@ bar::~bar() { // {{{
m_connection.detach_sink(this, 1); m_connection.detach_sink(this, 1);
} }
m_window.destroy(); m_connection.destroy_window(m_window);
m_connection.flush();
} // }}} } // }}}
/** /**
@ -140,12 +141,13 @@ void bar::bootstrap(bool nodraw) { // {{{
create_gcontexts(); create_gcontexts();
create_rootpixmap(); create_rootpixmap();
restack_window(); restack_window();
map_window();
set_wmhints(); set_wmhints();
// m_log.trace("bar: Listen to X RandR events"); // m_log.trace("bar: Listen to X RandR events");
// m_connection.select_input(m_window, XCB_RANDR_NOTIFY_MASK_SCREEN_CHANGE); // m_connection.select_input(m_window, XCB_RANDR_NOTIFY_MASK_SCREEN_CHANGE);
m_connection.map_window(m_window); m_connection.flush();
// }}} // }}}
// Connect signal handlers {{{ // Connect signal handlers {{{
@ -174,8 +176,6 @@ void bar::bootstrap(bool nodraw) { // {{{
m_sinkattached = true; m_sinkattached = true;
load_fonts(); load_fonts();
m_connection.flush();
} // }}} } // }}}
/** /**
@ -271,12 +271,12 @@ void bar::bootstrap_tray() { // {{{
auto offset_y = atoi(offset_y_def.c_str()); auto offset_y = atoi(offset_y_def.c_str());
if (offset_x != 0 && offset_x_def.find("%") != string::npos) { if (offset_x != 0 && offset_x_def.find("%") != string::npos) {
offset_x = math_util::percentage_to_value(offset_x, m_opts.monitor->w); offset_x = math_util::percentage_to_value<int>(offset_x, m_opts.monitor->w);
offset_x -= settings.width / 2; offset_x -= settings.width / 2;
} }
if (offset_y != 0 && offset_y_def.find("%") != string::npos) { if (offset_y != 0 && offset_y_def.find("%") != string::npos) {
offset_y = math_util::percentage_to_value(offset_y, m_opts.monitor->h); offset_y = math_util::percentage_to_value<int>(offset_y, m_opts.monitor->h);
offset_y -= settings.width / 2; offset_y -= settings.width / 2;
} }
@ -712,6 +712,18 @@ void bar::restack_window() { // {{{
} }
} // }}} } // }}}
/**
* Map window and reconfigure its position
*/
void bar::map_window() { // {{{
try {
m_window.map_checked();
m_window.reconfigure_pos(m_opts.x, m_opts.y);
} catch (const exception& err) {
m_log.err("Failed to map bar window");
}
} // }}}
/** /**
* Set window atom values * Set window atom values
*/ */
@ -720,6 +732,12 @@ void bar::set_wmhints() { // {{{
xcb_icccm_set_wm_name(m_connection, m_window, XCB_ATOM_STRING, 8, m_opts.wmname.length(), m_opts.wmname.c_str()); xcb_icccm_set_wm_name(m_connection, m_window, XCB_ATOM_STRING, 8, m_opts.wmname.length(), m_opts.wmname.c_str());
xcb_icccm_set_wm_class(m_connection, m_window, 21, "lemonbuddy\0Lemonbuddy"); xcb_icccm_set_wm_class(m_connection, m_window, 21, "lemonbuddy\0Lemonbuddy");
m_log.trace("bar: Set WM_NORMAL_HINTS");
xcb_size_hints_t hints;
xcb_icccm_size_hints_set_position(&hints, true, m_opts.x, m_opts.y);
xcb_icccm_size_hints_set_size(&hints, true, m_opts.width, m_opts.height);
xcb_icccm_set_wm_normal_hints(m_connection, m_window, &hints);
m_log.trace("bar: Set _NET_WM_WINDOW_TYPE"); m_log.trace("bar: Set _NET_WM_WINDOW_TYPE");
wm_util::set_windowtype(m_connection, m_window, {_NET_WM_WINDOW_TYPE_DOCK}); wm_util::set_windowtype(m_connection, m_window, {_NET_WM_WINDOW_TYPE_DOCK});
@ -732,28 +750,48 @@ void bar::set_wmhints() { // {{{
m_log.trace("bar: Set _NET_WM_PID"); m_log.trace("bar: Set _NET_WM_PID");
wm_util::set_wmpid(m_connection, m_window, getpid()); wm_util::set_wmpid(m_connection, m_window, getpid());
m_log.trace("bar: Set _NET_WM_STRUT_PARTIAL"); m_log.trace("bar: Set _NET_WM_STRUT / _NET_WM_STRUT_PARTIAL");
{ {
uint32_t none{0}; uint32_t none{0};
uint32_t value_list[12]{none}; uint32_t strut[12]{none};
auto mt = m_conf.get<int>("global/wm", "margin-top", 0); auto mt = m_conf.get<int>("global/wm", "margin-top", 0);
auto mb = m_conf.get<int>("global/wm", "margin-bottom", 0); auto mb = m_conf.get<int>("global/wm", "margin-bottom", 0);
auto ml = m_conf.get<int>("global/wm", "margin-left", 0); auto ml = m_conf.get<int>("global/wm", "margin-left", 0);
auto mr = m_conf.get<int>("global/wm", "margin-right", 0); auto mr = m_conf.get<int>("global/wm", "margin-right", 0);
auto geom = m_connection.get_geometry(m_screen->root);
auto base_x = geom->x + m_opts.monitor->x;
auto max_x = base_x + m_opts.monitor->w;
auto height = m_opts.height + m_opts.offset_y;
auto width = m_opts.width + m_opts.offset_x;
auto start_x = base_x + m_opts.offset_x - ml;
auto end_x = base_x + width - m_opts.offset_x + mr;
// clang-format off
if (m_opts.bottom) { if (m_opts.bottom) {
value_list[3] = m_opts.monitor->y + m_opts.height + mt; auto base_y = geom->y + geom->height - m_opts.monitor->h - m_opts.monitor->y;
value_list[10] = m_opts.monitor->x + m_opts.x + ml;
value_list[11] = m_opts.monitor->x + m_opts.x + m_opts.width + mr; strut[static_cast<int>(strut::BOTTOM)] =
math_util::cap<int>(base_y + height + mt, base_y, base_y + m_opts.monitor->h);
strut[static_cast<int>(strut::BOTTOM_START_X)] =
math_util::cap<int>(start_x, base_x, max_x);
strut[static_cast<int>(strut::BOTTOM_END_X)] =
math_util::cap<int>(end_x, base_x, max_x);
} else { } else {
value_list[2] = m_opts.monitor->y + m_opts.height + mb; auto base_y = geom->y + m_opts.monitor->y;
value_list[8] = m_opts.monitor->x + m_opts.x + ml;
value_list[9] = m_opts.monitor->x + m_opts.x + m_opts.width + mr; strut[static_cast<int>(strut::TOP)] =
math_util::cap<int>(base_y + height + mb, base_y, base_y + m_opts.monitor->h);
strut[static_cast<int>(strut::TOP_START_X)] =
math_util::cap<int>(start_x, base_x, max_x);
strut[static_cast<int>(strut::TOP_END_X)] =
math_util::cap<int>(end_x, base_x, max_x);
} }
m_connection.change_property( m_connection.change_property(XCB_PROP_MODE_REPLACE, m_window, _NET_WM_STRUT, XCB_ATOM_CARDINAL, 32, 4, strut);
XCB_PROP_MODE_REPLACE, m_window, _NET_WM_STRUT_PARTIAL, XCB_ATOM_CARDINAL, 32, 12, value_list); m_connection.change_property(XCB_PROP_MODE_REPLACE, m_window, _NET_WM_STRUT_PARTIAL, XCB_ATOM_CARDINAL, 32, 12, strut);
// clang-format on
} }
} // }}} } // }}}

View File

@ -90,7 +90,7 @@ void connection::send_client_message(shared_ptr<xcb_client_message_event_t> mess
void connection::send_dummy_event(xcb_window_t target, uint32_t event) const { void connection::send_dummy_event(xcb_window_t target, uint32_t event) const {
if (target == XCB_NONE) if (target == XCB_NONE)
target = root(); target = root();
auto message = make_client_message(XCB_NONE, target); auto message = make_client_message(XCB_VISIBILITY_NOTIFY, target);
send_client_message(message, target, event); send_client_message(message, target, event);
} }

View File

@ -6,7 +6,7 @@ namespace randr_util {
/** /**
* Define monitor * Define monitor
*/ */
monitor_t make_monitor(xcb_randr_output_t randr, string name, int w, int h, int x, int y) { monitor_t make_monitor(xcb_randr_output_t randr, string name, uint16_t w, uint16_t h, int16_t x, int16_t y) {
monitor_t mon{new monitor_t::element_type{}}; monitor_t mon{new monitor_t::element_type{}};
mon->output = randr; mon->output = randr;
mon->name = name; mon->name = name;
@ -27,6 +27,8 @@ namespace randr_util {
for (auto it = outputs.begin(); it != outputs.end(); it++) { for (auto it = outputs.begin(); it != outputs.end(); it++) {
try { try {
auto info = conn.get_output_info(*it); auto info = conn.get_output_info(*it);
if (info->crtc == XCB_NONE)
continue;
if (connected_only && info->connection != XCB_RANDR_CONNECTION_CONNECTED) if (connected_only && info->connection != XCB_RANDR_CONNECTION_CONNECTED)
continue; continue;
auto crtc = conn.get_crtc_info(info->crtc); auto crtc = conn.get_crtc_info(info->crtc);
@ -37,7 +39,35 @@ namespace randr_util {
} }
} }
// use the same sort algo as lemonbar, to match the defaults // clang-format off
const auto remove_monitor = [&](const monitor_t& monitor) {
monitors.erase(find(monitors.begin(), monitors.end(), monitor));
};
// clang-format on
for (auto m = monitors.rbegin(); m != monitors.rend(); m++) {
if ((*m)->w == 0) {
remove_monitor(*m);
continue;
}
// Test if there are any clones in the set
for (auto m2 = monitors.begin(); m2 != monitors.end(); m2++) {
if ((*m) == (*m2) || (*m2)->w == 0) {
continue;
}
// clang-format off
if ((*m2)->x >= (*m)->x && (*m2)->x + (*m2)->w <= (*m)->x + (*m)->w &&
(*m2)->y >= (*m)->y && (*m2)->y + (*m2)->h <= (*m)->y + (*m)->h) {
// Reset width so that the output gets
// removed in the base loop
(*m2)->w = 0;
}
// clang-format on
}
}
sort(monitors.begin(), monitors.end(), [](monitor_t& m1, monitor_t& m2) -> bool { sort(monitors.begin(), monitors.end(), [](monitor_t& m1, monitor_t& m2) -> bool {
if (m1->x < m2->x || m1->y + m1->h <= m2->y) if (m1->x < m2->x || m1->y + m1->h <= m2->y)
return 1; return 1;