refactor(bar): Strut values based on EMWH spec
This commit is contained in:
parent
c8f2a934b1
commit
4224d838a8
@ -49,6 +49,7 @@ class bar : public xpp::event::sink<evt::button_press, evt::expose, evt::propert
|
||||
void create_gcontexts();
|
||||
void create_rootpixmap();
|
||||
void restack_window();
|
||||
void map_window();
|
||||
void set_wmhints();
|
||||
|
||||
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_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()};
|
||||
pixmap m_pixmap{m_connection, m_connection.generate_id()};
|
||||
|
||||
|
@ -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 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 {
|
||||
bar_settings() = default;
|
||||
|
||||
|
@ -21,10 +21,10 @@ struct backlight_values {
|
||||
|
||||
struct randr_output {
|
||||
string name;
|
||||
int w = 0;
|
||||
int h = 0;
|
||||
int x = 0;
|
||||
int y = 0;
|
||||
uint16_t w = 0;
|
||||
uint16_t h = 0;
|
||||
int16_t x = 0;
|
||||
int16_t y = 0;
|
||||
xcb_randr_output_t output;
|
||||
backlight_values backlight;
|
||||
|
||||
@ -43,7 +43,7 @@ struct randr_output {
|
||||
using monitor_t = shared_ptr<randr_output>;
|
||||
|
||||
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);
|
||||
|
||||
void get_backlight_range(connection& conn, const monitor_t& mon, backlight_values& dst);
|
||||
|
@ -46,7 +46,8 @@ bar::~bar() { // {{{
|
||||
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_rootpixmap();
|
||||
restack_window();
|
||||
map_window();
|
||||
set_wmhints();
|
||||
|
||||
// m_log.trace("bar: Listen to X RandR events");
|
||||
// m_connection.select_input(m_window, XCB_RANDR_NOTIFY_MASK_SCREEN_CHANGE);
|
||||
|
||||
m_connection.map_window(m_window);
|
||||
m_connection.flush();
|
||||
|
||||
// }}}
|
||||
// Connect signal handlers {{{
|
||||
@ -174,8 +176,6 @@ void bar::bootstrap(bool nodraw) { // {{{
|
||||
m_sinkattached = true;
|
||||
|
||||
load_fonts();
|
||||
|
||||
m_connection.flush();
|
||||
} // }}}
|
||||
|
||||
/**
|
||||
@ -271,12 +271,12 @@ void bar::bootstrap_tray() { // {{{
|
||||
auto offset_y = atoi(offset_y_def.c_str());
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
@ -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
|
||||
*/
|
||||
@ -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_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");
|
||||
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");
|
||||
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 value_list[12]{none};
|
||||
uint32_t strut[12]{none};
|
||||
|
||||
auto mt = m_conf.get<int>("global/wm", "margin-top", 0);
|
||||
auto mb = m_conf.get<int>("global/wm", "margin-bottom", 0);
|
||||
auto ml = m_conf.get<int>("global/wm", "margin-left", 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) {
|
||||
value_list[3] = m_opts.monitor->y + m_opts.height + mt;
|
||||
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;
|
||||
auto base_y = geom->y + geom->height - m_opts.monitor->h - m_opts.monitor->y;
|
||||
|
||||
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 {
|
||||
value_list[2] = m_opts.monitor->y + m_opts.height + mb;
|
||||
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;
|
||||
auto base_y = geom->y + m_opts.monitor->y;
|
||||
|
||||
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(
|
||||
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, XCB_ATOM_CARDINAL, 32, 4, strut);
|
||||
m_connection.change_property(XCB_PROP_MODE_REPLACE, m_window, _NET_WM_STRUT_PARTIAL, XCB_ATOM_CARDINAL, 32, 12, strut);
|
||||
// clang-format on
|
||||
}
|
||||
} // }}}
|
||||
|
||||
|
@ -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 {
|
||||
if (target == XCB_NONE)
|
||||
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);
|
||||
}
|
||||
|
||||
|
@ -6,7 +6,7 @@ namespace randr_util {
|
||||
/**
|
||||
* 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{}};
|
||||
mon->output = randr;
|
||||
mon->name = name;
|
||||
@ -27,6 +27,8 @@ namespace randr_util {
|
||||
for (auto it = outputs.begin(); it != outputs.end(); it++) {
|
||||
try {
|
||||
auto info = conn.get_output_info(*it);
|
||||
if (info->crtc == XCB_NONE)
|
||||
continue;
|
||||
if (connected_only && info->connection != XCB_RANDR_CONNECTION_CONNECTED)
|
||||
continue;
|
||||
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 {
|
||||
if (m1->x < m2->x || m1->y + m1->h <= m2->y)
|
||||
return 1;
|
||||
|
Loading…
Reference in New Issue
Block a user