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_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()};
|
||||||
|
|
||||||
|
@ -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;
|
||||||
|
|
||||||
|
@ -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);
|
||||||
|
@ -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
|
||||||
}
|
}
|
||||||
} // }}}
|
} // }}}
|
||||||
|
|
||||||
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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;
|
||||||
|
Loading…
Reference in New Issue
Block a user