refactor: Code cleanup

This commit is contained in:
Michael Carlberg 2016-11-04 18:54:33 +01:00
parent ae501d6ae1
commit 869c5fe718
17 changed files with 394 additions and 209 deletions

View File

@ -43,3 +43,7 @@ message(STATUS " Enable i3 support ${ENABLE_I3}")
message(STATUS " Enable mpd support ${ENABLE_MPD}")
message(STATUS " Enable network support ${ENABLE_NETWORK}")
message(STATUS "---------------------------")
message(STATUS " Enable X RandR ${ENABLE_RANDR_EXT}")
message(STATUS " Enable X Render ${ENABLE_RENDER_EXT}")
message(STATUS " Enable X Damage ${ENABLE_DAMAGE_EXT}")
message(STATUS "---------------------------")

View File

@ -11,6 +11,7 @@
#include "x11/connection.hpp"
#include "x11/draw.hpp"
#include "x11/fontmanager.hpp"
#include "x11/graphics.hpp"
#include "x11/tray.hpp"
#include "x11/types.hpp"
#include "x11/window.hpp"
@ -20,21 +21,25 @@ LEMONBUDDY_NS
class bar : public xpp::event::sink<evt::button_press, evt::expose, evt::property_notify> {
public:
explicit bar(connection& conn, const config& config, const logger& logger,
unique_ptr<fontmanager> fontmanager)
unique_ptr<fontmanager> fontmanager, unique_ptr<traymanager> traymanager)
: m_connection(conn)
, m_conf(config)
, m_log(logger)
, m_fontmanager(forward<decltype(fontmanager)>(fontmanager)) {}
, m_fontmanager(forward<decltype(fontmanager)>(fontmanager))
, m_traymanager(forward<decltype(traymanager)>(traymanager)) {}
~bar();
void bootstrap(bool nodraw = false);
void bootstrap_tray();
void activate_tray();
const bar_settings settings() const;
const tray_settings tray() const;
void parse(string data, bool force = false);
void flush();
void refresh_window();
void handle(const evt::button_press& evt);
void handle(const evt::expose& evt);
@ -67,6 +72,7 @@ class bar : public xpp::event::sink<evt::button_press, evt::expose, evt::propert
const config& m_conf;
const logger& m_log;
unique_ptr<fontmanager> m_fontmanager;
unique_ptr<traymanager> m_traymanager;
threading_util::spin_lock m_lock;
throttle_util::throttle_t m_throttler;
@ -78,6 +84,9 @@ class bar : public xpp::event::sink<evt::button_press, evt::expose, evt::propert
colormap m_colormap{m_connection, m_connection.generate_id()};
pixmap m_pixmap{m_connection, m_connection.generate_id()};
// xcb_gcontext_t m_root_gc{0};
// graphics_util::root_pixmap m_rootpixmap;
bar_settings m_bar;
tray_settings m_tray;
map<border, border_settings> m_borders;
@ -105,7 +114,8 @@ namespace {
configure_connection(),
configure_config(),
configure_logger(),
configure_fontmanager());
configure_fontmanager(),
configure_traymanager());
// clang-format on
}
}

View File

@ -10,7 +10,6 @@
#include "utils/command.hpp"
#include "utils/inotify.hpp"
#include "x11/connection.hpp"
#include "x11/tray.hpp"
#include "x11/types.hpp"
LEMONBUDDY_NS
@ -18,14 +17,13 @@ LEMONBUDDY_NS
class controller {
public:
explicit controller(connection& conn, const logger& logger, const config& config,
unique_ptr<eventloop> eventloop, unique_ptr<bar> bar, unique_ptr<traymanager> tray,
unique_ptr<eventloop> eventloop, unique_ptr<bar> bar,
inotify_util::watch_t& confwatch)
: m_connection(conn)
, m_log(logger)
, m_conf(config)
, m_eventloop(forward<decltype(eventloop)>(eventloop))
, m_bar(forward<decltype(bar)>(bar))
, m_traymanager(forward<decltype(tray)>(tray))
, m_confwatch(confwatch) {}
~controller();
@ -43,7 +41,6 @@ class controller {
void wait_for_signal();
void wait_for_xevent();
void activate_tray();
void bootstrap_modules();
void on_mouse_event(string input);
@ -57,11 +54,11 @@ class controller {
const config& m_conf;
unique_ptr<eventloop> m_eventloop;
unique_ptr<bar> m_bar;
unique_ptr<traymanager> m_traymanager;
stateflag m_running{false};
stateflag m_reload{false};
stateflag m_waiting{false};
stateflag m_trayactivated{false};
sigset_t m_waitmask;
sigset_t m_ignmask;
@ -87,8 +84,7 @@ namespace {
configure_logger(),
configure_config(),
configure_eventloop(),
configure_bar(),
configure_traymanager());
configure_bar());
// clang-format on
}
}

View File

@ -45,6 +45,15 @@ namespace color_util {
return b << 8 | b << 8 / 0xff;
}
template <typename T = uint32_t>
uint32_t premultiply_alpha(const T value) {
auto a = color_util::alpha_channel(value);
auto r = color_util::red_channel(value) * a / 255;
auto g = color_util::green_channel(value) * a / 255;
auto b = color_util::blue_channel(value) * a / 255;
return (a << 24) | (r << 16) | (g << 8) | b;
}
template <typename T = uint8_t>
string hex(uint32_t color) {
char s[12];

View File

@ -21,6 +21,7 @@ class color {
static color parse(string input);
protected:
uint32_t m_value;
uint32_t m_color;
string m_source;
};

View File

@ -17,6 +17,12 @@ class window : public xpp::window<connection_t&> {
int16_t x, int16_t y, uint16_t w, uint16_t h, uint32_t mask, const xcb_params_cw_t* params);
window create_checked(uint16_t w, uint16_t h, uint32_t mask, const xcb_params_cw_t* params);
void refresh() {
xutils::visibility_notify(connection(), *this, XCB_VISIBILITY_FULLY_OBSCURED);
xutils::visibility_notify(connection(), *this, XCB_VISIBILITY_UNOBSCURED);
connection().flush();
}
};
// struct cw_size {

20
include/x11/wm.hpp Normal file
View File

@ -0,0 +1,20 @@
#pragma once
#include "common.hpp"
#include "x11/connection.hpp"
LEMONBUDDY_NS
namespace wm_util {
void set_wmname(connection& conn, xcb_window_t win, string wm_name, string wm_class);
void set_wmprotocols(connection& conn, xcb_window_t win, vector<xcb_atom_t> flags);
void set_windowtype(connection& conn, xcb_window_t win, vector<xcb_atom_t> types);
void set_wmstate(connection& conn, xcb_window_t win, vector<xcb_atom_t> states);
void set_wmpid(connection& conn, xcb_window_t win, pid_t pid);
void set_wmdesktop(connection& conn, xcb_window_t win, uint32_t desktop = -1u);
void set_trayorientation(connection& conn, xcb_window_t win, uint32_t orientation);
void set_trayvisual(connection& conn, xcb_window_t win, xcb_visualid_t visual);
}
LEMONBUDDY_NS_END

View File

@ -7,6 +7,8 @@
LEMONBUDDY_NS
class connection;
namespace xutils {
xcb_connection_t* get_connection();
@ -14,6 +16,8 @@ namespace xutils {
void pack_values(uint32_t mask, const xcb_params_cw_t* src, uint32_t* dest);
void pack_values(uint32_t mask, const xcb_params_gc_t* src, uint32_t* dest);
void pack_values(uint32_t mask, const xcb_params_configure_window_t* src, uint32_t* dest);
void visibility_notify(connection& conn, const xcb_window_t& win, xcb_visibility_t state);
}
LEMONBUDDY_NS_END

View File

@ -7,6 +7,7 @@
#include "utils/string.hpp"
#include "x11/draw.hpp"
#include "x11/randr.hpp"
#include "x11/wm.hpp"
#include "x11/xlib.hpp"
#include "x11/xutils.hpp"
@ -37,8 +38,14 @@ bar::~bar() { // {{{
g_signals::parser::string_write = nullptr;
g_signals::tray::report_slotcount = nullptr; // }}}
if (m_sinkattached)
if (m_traymanager) {
m_traymanager.reset();
}
if (m_sinkattached) {
m_connection.detach_sink(this, 1);
}
m_window.destroy();
} // }}}
@ -208,6 +215,7 @@ void bar::bootstrap(bool nodraw) { // {{{
// clang-format off
XCB_AUX_ADD_PARAM(&mask, &params, back_pixel, 0);
XCB_AUX_ADD_PARAM(&mask, &params, border_pixel, 0);
XCB_AUX_ADD_PARAM(&mask, &params, backing_store, XCB_BACKING_STORE_WHEN_MAPPED);
XCB_AUX_ADD_PARAM(&mask, &params, colormap, m_colormap);
XCB_AUX_ADD_PARAM(&mask, &params, override_redirect, m_bar.dock);
XCB_AUX_ADD_PARAM(&mask, &params, event_mask, XCB_EVENT_MASK_PROPERTY_CHANGE | XCB_EVENT_MASK_EXPOSURE | XCB_EVENT_MASK_BUTTON_PRESS);
@ -216,25 +224,21 @@ void bar::bootstrap(bool nodraw) { // {{{
}
m_log.trace("bar: Set WM_NAME");
{
xcb_icccm_set_wm_name(
m_connection, m_window, XCB_ATOM_STRING, 8, m_bar.wmname.length(), m_bar.wmname.c_str());
xcb_icccm_set_wm_class(m_connection, m_window, 21, "lemonbuddy\0Lemonbuddy");
}
xcb_icccm_set_wm_name(
m_connection, m_window, XCB_ATOM_STRING, 8, m_bar.wmname.length(), m_bar.wmname.c_str());
xcb_icccm_set_wm_class(m_connection, m_window, 21, "lemonbuddy\0Lemonbuddy");
m_log.trace("bar: Set _NET_WM_WINDOW_TYPE");
{
const uint32_t win_types[1] = {_NET_WM_WINDOW_TYPE_DOCK};
m_connection.change_property(
XCB_PROP_MODE_REPLACE, m_window, _NET_WM_WINDOW_TYPE, XCB_ATOM_ATOM, 32, 1, win_types);
}
wm_util::set_windowtype(m_connection, m_window, {_NET_WM_WINDOW_TYPE_DOCK});
m_log.trace("bar: Set _NET_WM_STATE");
{
const uint32_t win_states[2] = {_NET_WM_STATE_STICKY, _NET_WM_STATE_ABOVE};
m_connection.change_property(
XCB_PROP_MODE_REPLACE, m_window, _NET_WM_STATE, XCB_ATOM_ATOM, 32, 2, win_states);
}
wm_util::set_wmstate(m_connection, m_window, {_NET_WM_STATE_STICKY, _NET_WM_STATE_ABOVE});
m_log.trace("bar: Set _NET_WM_DESKTOP");
wm_util::set_wmdesktop(m_connection, m_window, -1u);
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");
{
@ -255,20 +259,6 @@ void bar::bootstrap(bool nodraw) { // {{{
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(
XCB_PROP_MODE_REPLACE, m_window, _NET_WM_DESKTOP, XCB_ATOM_CARDINAL, 32, 1, value_list);
}
m_log.trace("bar: Set _NET_WM_PID");
{
const uint32_t value_list[1]{uint32_t(getpid())};
m_connection.change_property(
XCB_PROP_MODE_REPLACE, m_window, _NET_WM_PID, XCB_ATOM_CARDINAL, 32, 1, value_list);
}
m_log.trace("bar: Create pixmap");
{
m_connection.create_pixmap(
@ -278,8 +268,8 @@ void bar::bootstrap(bool nodraw) { // {{{
m_log.trace("bar: Map window");
{
m_connection.flush();
m_connection.map_window(m_window);
m_connection.flush();
}
// }}}
@ -336,14 +326,59 @@ void bar::bootstrap(bool nodraw) { // {{{
uint32_t mask = 0;
uint32_t value_list[32];
xcb_params_gc_t params;
m_gcontexts.emplace(gc(i), gcontext{m_connection, m_connection.generate_id()});
XCB_AUX_ADD_PARAM(&mask, &params, foreground, colors[i - 1]);
XCB_AUX_ADD_PARAM(&mask, &params, graphics_exposures, 0);
xutils::pack_values(mask, &params, value_list);
m_gcontexts.emplace(gc(i), gcontext{m_connection, m_connection.generate_id()});
m_connection.create_gc(m_gcontexts.at(gc(i)), m_pixmap, mask, value_list);
}
}
// }}}
// Setup root pixmap {{{
m_log.trace("bar: Setup root pixmap");
{
// graphics_util::get_root_pixmap(m_connection, &m_rootpixmap);
// graphics_util::simple_gc(m_connection, m_pixmap, &m_root_gc);
//
// if (!m_rootpixmap.pixmap || !m_pixmap || !m_root_gc) {
// m_log.warn("Failed to get root pixmap for bar window background");
// } else {
// m_log.trace("bar: rootpixmap=%x (%dx%d+%d+%d)", m_rootpixmap.pixmap, m_rootpixmap.width,
// m_rootpixmap.height, m_rootpixmap.x, m_rootpixmap.y);
//
// m_connection.copy_area(m_rootpixmap.pixmap, m_pixmap, m_root_gc, m_bar.x, m_bar.y, 0, 0,
// m_bar.width, m_bar.height);
//
// auto image_reply = m_connection.get_image(
// XCB_IMAGE_FORMAT_Z_PIXMAP, m_pixmap, 0, 0, m_bar.width, m_bar.height, XAllPlanes());
//
// std::vector<uint8_t> image_data;
// std::back_insert_iterator<decltype(image_data)> back_it(image_data);
// std::copy(image_reply.data().begin(), image_reply.data().end(), back_it);
//
// m_connection.put_image(XCB_IMAGE_FORMAT_Z_PIXMAP, m_pixmap, m_root_gc, m_bar.width,
// m_bar.height, 0, 0, 0, image_reply->depth, image_data.size(), image_data.data());
//
// m_connection.copy_area(m_rootpixmap.pixmap, m_pixmap, m_root_gc, m_bar.x, m_bar.y, 0, 0,
// m_bar.width, m_bar.height);
//
// uint32_t mask = 0;
// uint32_t values[16];
// xcb_params_cw_t params;
// XCB_AUX_ADD_PARAM(&mask, &params, back_pixmap, m_pixmap);
// xutils::pack_values(mask, &params, values);
// m_connection.change_window_attributes_checked(m_window, mask, values);
//
// m_connection.copy_area(
// m_pixmap, m_window, m_root_gc, m_bar.x, m_bar.y, 0, 0, m_bar.width, m_bar.height);
// }
}
// }}}
// Load fonts {{{
@ -375,96 +410,6 @@ void bar::bootstrap(bool nodraw) { // {{{
m_fontmanager->allocate_color(m_bar.foreground, true);
// }}}
// Set tray settings {{{
try {
auto tray_position = m_conf.get<string>(bs, "tray-position");
if (tray_position == "left")
m_tray.align = alignment::LEFT;
else if (tray_position == "right")
m_tray.align = alignment::RIGHT;
else if (tray_position == "center")
m_tray.align = alignment::CENTER;
else
m_tray.align = alignment::NONE;
} catch (const key_error& err) {
m_tray.align = alignment::NONE;
}
if (m_tray.align != alignment::NONE) {
m_tray.height = m_bar.height;
m_tray.height -= m_borders.at(border::BOTTOM).size;
m_tray.height -= m_borders.at(border::TOP).size;
m_tray.height_fill = m_tray.height;
if (m_tray.height % 2 != 0) {
m_tray.height--;
}
auto maxsize = m_conf.get<int>(bs, "tray-maxsize", 16);
if (m_tray.height > maxsize) {
m_tray.spacing += (m_tray.height - maxsize) / 2;
m_tray.height = maxsize;
}
m_tray.width = m_tray.height;
m_tray.orig_y = m_bar.y + m_borders.at(border::TOP).size;
// Apply user-defined scaling
auto scale = m_conf.get<float>(bs, "tray-scale", 1.0);
m_tray.width *= scale;
m_tray.height_fill *= scale;
if (m_tray.align == alignment::RIGHT) {
m_tray.orig_x = m_bar.x + m_bar.width - m_borders.at(border::RIGHT).size;
} else if (m_tray.align == alignment::LEFT) {
m_tray.orig_x = m_bar.x + m_borders.at(border::LEFT).size;
} else if (m_tray.align == alignment::CENTER) {
m_tray.orig_x = center_x() - (m_tray.width / 2);
}
// Set user-defined background color
auto tray_bg = m_conf.get<string>(bs, "tray-background", "");
if (!tray_bg.empty()) {
m_tray.background = color::parse(tray_bg);
} else {
m_tray.background = m_bar.background;
}
// Add user-defined padding
m_tray.spacing += m_conf.get<int>(bs, "tray-padding", 0);
// Add user-defiend offset
auto offset_x_def = m_conf.get<string>(bs, "tray-offset-x", "");
auto offset_y_def = m_conf.get<string>(bs, "tray-offset-y", "");
auto offset_x = std::atoi(offset_x_def.c_str());
auto offset_y = std::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_bar.monitor->w);
offset_x -= m_tray.width / 2;
}
if (offset_y != 0 && offset_y_def.find("%") != string::npos) {
offset_y = math_util::percentage_to_value(offset_y, m_bar.monitor->h);
offset_y -= m_tray.width / 2;
}
m_tray.orig_x += offset_x;
m_tray.orig_y += offset_y;
// Add tray update callback unless explicitly disabled
if (!m_conf.get<bool>(bs, "tray-detached", false)) {
g_signals::tray::report_slotcount = bind(&bar::on_tray_report, this, placeholders::_1);
}
// Put the tray next to the bar in the window stack
m_tray.sibling = m_window;
}
// }}}
// Connect signal handlers {{{
@ -494,9 +439,148 @@ void bar::bootstrap(bool nodraw) { // {{{
// }}}
if (!nodraw) {
bootstrap_tray();
}
m_connection.flush();
} // }}}
/**
* Setup tray manager
*/
void bar::bootstrap_tray() { // {{{
auto bs = m_conf.bar_section();
try {
auto tray_position = m_conf.get<string>(bs, "tray-position");
if (tray_position == "left")
m_tray.align = alignment::LEFT;
else if (tray_position == "right")
m_tray.align = alignment::RIGHT;
else if (tray_position == "center")
m_tray.align = alignment::CENTER;
else
m_tray.align = alignment::NONE;
} catch (const key_error& err) {
m_tray.align = alignment::NONE;
}
if (m_tray.align == alignment::NONE) {
m_log.warn("Disabling tray manager (reason: disabled in config)");
m_traymanager.reset();
return;
}
m_tray.height = m_bar.height;
m_tray.height -= m_borders.at(border::BOTTOM).size;
m_tray.height -= m_borders.at(border::TOP).size;
m_tray.height_fill = m_tray.height;
if (m_tray.height % 2 != 0) {
m_tray.height--;
}
auto maxsize = m_conf.get<int>(bs, "tray-maxsize", 16);
if (m_tray.height > maxsize) {
m_tray.spacing += (m_tray.height - maxsize) / 2;
m_tray.height = maxsize;
}
m_tray.width = m_tray.height;
m_tray.orig_y = m_bar.y + m_borders.at(border::TOP).size;
// Apply user-defined scaling
auto scale = m_conf.get<float>(bs, "tray-scale", 1.0);
m_tray.width *= scale;
m_tray.height_fill *= scale;
if (m_tray.align == alignment::RIGHT) {
m_tray.orig_x = m_bar.x + m_bar.width - m_borders.at(border::RIGHT).size;
} else if (m_tray.align == alignment::LEFT) {
m_tray.orig_x = m_bar.x + m_borders.at(border::LEFT).size;
} else if (m_tray.align == alignment::CENTER) {
m_tray.orig_x = center_x() - (m_tray.width / 2);
}
// Set user-defined background color
m_conf.get<bool>(bs, "tray-transparent", m_tray.transparent);
if (m_tray.transparent) {
m_tray.background = 0;
} else {
auto bg = m_conf.get<string>(bs, "tray-background", "");
if (!bg.empty()) {
m_tray.background = color::parse(bg, g_colorempty);
}
}
if (color_util::alpha_channel(m_tray.background) == 0) {
m_tray.transparent = true;
m_tray.background = 0;
}
// Add user-defined padding
m_tray.spacing += m_conf.get<int>(bs, "tray-padding", 0);
// Add user-defiend offset
auto offset_x_def = m_conf.get<string>(bs, "tray-offset-x", "");
auto offset_y_def = m_conf.get<string>(bs, "tray-offset-y", "");
auto offset_x = std::atoi(offset_x_def.c_str());
auto offset_y = std::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_bar.monitor->w);
offset_x -= m_tray.width / 2;
}
if (offset_y != 0 && offset_y_def.find("%") != string::npos) {
offset_y = math_util::percentage_to_value(offset_y, m_bar.monitor->h);
offset_y -= m_tray.width / 2;
}
m_tray.orig_x += offset_x;
m_tray.orig_y += offset_y;
// Add tray update callback unless explicitly disabled
if (!m_conf.get<bool>(bs, "tray-detached", false)) {
g_signals::tray::report_slotcount = bind(&bar::on_tray_report, this, placeholders::_1);
}
// Put the tray next to the bar in the window stack
m_tray.sibling = m_window;
try {
m_log.trace("controller: Setup tray manager");
m_traymanager->bootstrap(tray());
} catch (const std::exception& err) {
m_log.err(err.what());
m_log.warn("Failed to setup tray, disabling...");
m_traymanager.reset();
}
} // }}}
/**
* Activate tray manager
*/
void bar::activate_tray() { // {{{
if (!m_traymanager) {
return;
}
m_log.trace("controller: Activate tray manager");
try {
m_traymanager->activate();
} catch (const std::exception& err) {
m_log.err(err.what());
m_log.err("Failed to activate tray manager, disabling...");
m_traymanager.reset();
}
} // }}}
/**
* Get the bar settings container
*/
@ -542,8 +626,8 @@ void bar::parse(string data, bool force) { // {{{
draw_background();
if (m_tray.align == alignment::LEFT && m_tray.slots)
m_xpos += ((m_tray.width + m_tray.spacing) * m_tray.slots) + m_tray.spacing;
if (m_tray.align == alignment::LEFT && m_tray.configured_slots)
m_xpos += ((m_tray.width + m_tray.spacing) * m_tray.configured_slots) + m_tray.spacing;
try {
parser parser(m_bar);
@ -552,8 +636,9 @@ void bar::parse(string data, bool force) { // {{{
m_log.err("Unrecognized syntax token '%s'", err.what());
}
if (m_tray.align == alignment::RIGHT && m_tray.slots)
draw_shift(m_xpos, ((m_tray.width + m_tray.spacing) * m_tray.slots) + m_tray.spacing);
if (m_tray.align == alignment::RIGHT && m_tray.configured_slots)
draw_shift(
m_xpos, ((m_tray.width + m_tray.spacing) * m_tray.configured_slots) + m_tray.spacing);
draw_border(border::ALL);
@ -569,16 +654,16 @@ void bar::parse(string data, bool force) { // {{{
void bar::flush() { // {{{
m_connection.copy_area(
m_pixmap, m_window, m_gcontexts.at(gc::FG), 0, 0, 0, 0, m_bar.width, m_bar.height);
m_connection.copy_area(
m_pixmap, m_window, m_gcontexts.at(gc::BT), 0, 0, 0, 0, m_bar.width, m_bar.height);
m_connection.copy_area(
m_pixmap, m_window, m_gcontexts.at(gc::BB), 0, 0, 0, 0, m_bar.width, m_bar.height);
m_connection.copy_area(
m_pixmap, m_window, m_gcontexts.at(gc::BL), 0, 0, 0, 0, m_bar.width, m_bar.height);
m_connection.copy_area(
m_pixmap, m_window, m_gcontexts.at(gc::BR), 0, 0, 0, 0, m_bar.width, m_bar.height);
// m_connection.copy_area(
// m_pixmap, m_window, m_root_gc, m_bar.x, m_bar.y, 0, 0, m_bar.width, m_bar.height);
m_connection.flush();
if (g_signals::bar::redraw) {
g_signals::bar::redraw();
}
#if DEBUG and DRAW_CLICKABLE_AREA_HINTS
map<alignment, int> hint_num{{
{alignment::LEFT, 0}, {alignment::CENTER, 0}, {alignment::RIGHT, 0},
@ -617,6 +702,13 @@ void bar::flush() { // {{{
}
} // }}}
/**
* Refresh the bar window by clearing and redrawing the pixmaps
*/
void bar::refresh_window() { // {{{
m_log.info("Refresh bar window");
} // }}}
/**
* Event handler for XCB_BUTTON_PRESS events
*
@ -693,8 +785,12 @@ void bar::handle(const evt::expose& evt) { // {{{
* Some might call it a dirty hack, others a crappy
* solution... I choose to call it a masterpiece! Plus
* it's not really any overhead worth talking about.
*
* Also tracks the root pixmap
*/
void bar::handle(const evt::property_notify& evt) { // {{{
m_log.trace("bar: property_notify");
if (evt->window == m_window && evt->atom == WM_STATE) {
if (!g_signals::bar::visibility_change) {
return;
@ -713,6 +809,12 @@ void bar::handle(const evt::property_notify& evt) { // {{{
} catch (const std::exception& err) {
m_log.warn("Failed to emit bar window's visibility change event");
}
} else if (evt->atom == _XROOTMAP_ID) {
refresh_window();
} else if (evt->atom == _XSETROOT_ID) {
refresh_window();
} else if (evt->atom == ESETROOT_PMAP_ID) {
refresh_window();
}
} // }}}
@ -744,6 +846,7 @@ int bar::width_inner() { // {{{
void bar::on_alignment_change(alignment align) { // {{{
if (align == m_bar.align)
return;
m_log.trace_x("bar: alignment_change(%i)", static_cast<int>(align));
m_bar.align = align;
@ -876,9 +979,9 @@ void bar::on_pixel_offset(int px) { // {{{
* Proess systray report
*/
void bar::on_tray_report(uint16_t slots) { // {{{
if (m_tray.slots != slots) {
if (m_tray.configured_slots != slots) {
m_log.trace("bar: tray_report(%lu)", slots);
m_tray.slots = slots;
m_tray.configured_slots = slots;
if (!m_prevdata.empty()) {
parse(m_prevdata, true);
@ -999,9 +1102,7 @@ int bar::draw_shift(int x, int chr_width) { // {{{
* Draw text character
*/
void bar::draw_character(uint16_t character) { // {{{
// TODO: cache
auto& font = m_fontmanager->match_char(character);
if (!font) {
m_log.warn("No suitable font found for character at index %i", character);
return;
@ -1012,7 +1113,6 @@ void bar::draw_character(uint16_t character) { // {{{
m_fontmanager->set_gcontext_font(m_gcontexts.at(gc::FG), m_gcfont);
}
// TODO: cache
auto chr_width = m_fontmanager->char_width(font, character);
// Avoid odd glyph width's for center-aligned text
@ -1029,9 +1129,9 @@ void bar::draw_character(uint16_t character) { // {{{
auto color = m_fontmanager->xftcolor();
XftDrawString16(m_xftdraw, &color, font->xft, x, y, &character, 1);
} else {
character = (character >> 8) | (character << 8);
uint16_t ucs = ((character >> 8) | (character << 8));
draw_util::xcb_poly_text_16_patched(
m_connection, m_pixmap, m_gcontexts.at(gc::FG), x, y, 1, &character);
m_connection, m_pixmap, m_gcontexts.at(gc::FG), x, y, 1, &ucs);
}
draw_lines(x, chr_width);

View File

@ -59,10 +59,6 @@ controller::~controller() {
m_bar.reset();
}
if (m_traymanager) {
m_traymanager.reset();
}
m_log.info("Interrupting X event loop");
m_connection.send_dummy_event(m_connection.root());
@ -97,7 +93,7 @@ void controller::bootstrap(bool writeback, bool dump_wmname) {
// break the blocking wait call when cleaning up
m_log.trace("controller: Listen for events on the root window");
try {
const uint32_t value_list[1]{XCB_EVENT_MASK_STRUCTURE_NOTIFY};
const uint32_t value_list[2]{XCB_EVENT_MASK_PROPERTY_CHANGE | XCB_EVENT_MASK_STRUCTURE_NOTIFY};
m_connection.change_window_attributes_checked(
m_connection.root(), XCB_CW_EVENT_MASK, value_list);
} catch (const std::exception& err) {
@ -124,23 +120,6 @@ void controller::bootstrap(bool writeback, bool dump_wmname) {
m_eventloop->set_input_db(bind(&controller::on_unrecognized_action, this, placeholders::_1));
}
try {
if (m_writeback) {
m_log.trace("controller: Disabling tray (reason: stdout mode)");
m_traymanager.reset();
} else if (m_bar->tray().align == alignment::NONE) {
m_log.trace("controller: Disabling tray (reason: tray-position)");
m_traymanager.reset();
} else {
m_log.trace("controller: Setup tray manager");
m_traymanager->bootstrap(m_bar->tray());
}
} catch (const std::exception& err) {
m_log.err(err.what());
m_log.warn("Failed to setup tray, disabling...");
m_traymanager.reset();
}
m_log.trace("controller: Setup user-defined modules");
bootstrap_modules();
}
@ -157,11 +136,6 @@ bool controller::run() {
install_sigmask();
install_confwatch();
// Activate traymanager in separate thread
if (!m_writeback && m_traymanager) {
m_threads.emplace_back(thread(&controller::activate_tray, this));
}
// Listen for X events in separate thread
if (!m_writeback) {
m_threads.emplace_back(thread(&controller::wait_for_xevent, this));
@ -260,6 +234,9 @@ void controller::install_confwatch() {
});
}
/**
* Remove the config inotify watch
*/
void controller::uninstall_confwatch() {
try {
if (m_confwatch) {
@ -271,7 +248,7 @@ void controller::uninstall_confwatch() {
}
/**
* TODO: docstring
* Wait for termination signal
*/
void controller::wait_for_signal() {
m_log.trace("controller: Wait for signal");
@ -292,7 +269,8 @@ void controller::wait_for_signal() {
}
/**
* TODO: docstring
* Wait for X events and forward them to
* the event registry
*/
void controller::wait_for_xevent() {
m_log.trace("controller: Listen for X events");
@ -319,21 +297,6 @@ void controller::wait_for_xevent() {
}
}
/**
* TODO: docstring
*/
void controller::activate_tray() {
m_log.trace("controller: Activate tray manager");
try {
m_traymanager->activate();
} catch (const std::exception& err) {
m_log.err(err.what());
m_log.err("Failed to activate tray manager, disabling...");
m_traymanager.reset();
}
}
/**
* Create and initialize bar modules
*/
@ -433,7 +396,7 @@ void controller::on_mouse_event(string input) {
}
/**
* TODO: docstring
* Callback for actions not handled internally by a module
*/
void controller::on_unrecognized_action(string input) {
try {
@ -453,7 +416,7 @@ void controller::on_unrecognized_action(string input) {
}
/**
* TODO: docstring
* Callback for module content update
*/
void controller::on_update() {
string contents{""};
@ -520,6 +483,11 @@ void controller::on_update() {
} else {
m_bar->parse(contents);
}
if (!m_trayactivated) {
m_trayactivated = true;
m_bar->activate_tray();
}
}
LEMONBUDDY_NS_END

View File

@ -7,6 +7,7 @@ LEMONBUDDY_NS
*/
callback<string> g_signals::bar::action_click = nullptr;
callback<bool> g_signals::bar::visibility_change = nullptr;
callback<> g_signals::bar::redraw = nullptr;
/**
* Signals used to communicate with the input parser

View File

@ -1,5 +1,4 @@
#include <X11/Xlib-xcb.h>
#include <thread>
#include "common.hpp"
#include "components/command_line.hpp"

View File

@ -16,13 +16,13 @@ color::color(string hex) : m_source(hex) {
throw application_error("Cannot create color from empty hex");
}
uint32_t value = std::strtoul(&hex[1], nullptr, 16);
m_value = std::strtoul(&hex[1], nullptr, 16);
// Premultiply alpha
auto a = color_util::alpha_channel(value);
auto r = color_util::red_channel(value) * a / 255;
auto g = color_util::green_channel(value) * a / 255;
auto b = color_util::blue_channel(value) * a / 255;
auto a = color_util::alpha_channel(m_value);
auto r = color_util::red_channel(m_value) * a / 255;
auto g = color_util::green_channel(m_value) * a / 255;
auto b = color_util::blue_channel(m_value) * a / 255;
m_color = (a << 24) | (r << 16) | (g << 8) | b;
}

View File

@ -12,8 +12,13 @@ namespace draw_util {
*/
void fill(connection& c, xcb_drawable_t d, xcb_gcontext_t g, int16_t x, int16_t y, uint16_t w,
uint16_t h) {
array<xcb_rectangle_t, 1> rects{{xcb_rectangle_t({x, y, w, h})}};
c.poly_fill_rectangle(d, g, rects.size(), rects.data());
xcb_rectangle_t rect;
rect.x = x;
rect.y = y;
rect.width = w;
rect.height = h;
const xcb_rectangle_t rects[1]{rect};
c.poly_fill_rectangle(d, g, 1, rects);
}
/**

50
src/x11/wm.cpp Normal file
View File

@ -0,0 +1,50 @@
#include <xcb/xcb_icccm.h>
#include "x11/atoms.hpp"
#include "x11/wm.hpp"
LEMONBUDDY_NS
namespace wm_util {
void set_wmname(connection& conn, xcb_window_t win, string wm_name, string wm_class) {
xcb_icccm_set_wm_name(conn, win, XCB_ATOM_STRING, 8, wm_name.length(), wm_name.c_str());
xcb_icccm_set_wm_class(conn, win, wm_class.length(), wm_class.c_str());
}
void set_wmprotocols(connection& conn, xcb_window_t win, vector<xcb_atom_t> flags) {
xcb_icccm_set_wm_protocols(conn, win, WM_PROTOCOLS, flags.size(), flags.data());
}
void set_windowtype(connection& conn, xcb_window_t win, vector<xcb_atom_t> types) {
conn.change_property(XCB_PROP_MODE_REPLACE, win, _NET_WM_WINDOW_TYPE, XCB_ATOM_ATOM, 32,
types.size(), types.data());
}
void set_wmstate(connection& conn, xcb_window_t win, vector<xcb_atom_t> states) {
conn.change_property(
XCB_PROP_MODE_REPLACE, win, _NET_WM_STATE, XCB_ATOM_ATOM, 32, states.size(), states.data());
}
void set_wmpid(connection& conn, xcb_window_t win, pid_t pid) {
pid = getpid();
conn.change_property(XCB_PROP_MODE_REPLACE, win, _NET_WM_PID, XCB_ATOM_CARDINAL, 32, 1, &pid);
}
void set_wmdesktop(connection& conn, xcb_window_t win, uint32_t desktop) {
const uint32_t value_list[1]{desktop};
conn.change_property(
XCB_PROP_MODE_REPLACE, win, _NET_WM_DESKTOP, XCB_ATOM_CARDINAL, 32, 1, value_list);
}
void set_trayorientation(connection& conn, xcb_window_t win, uint32_t orientation) {
conn.change_property(XCB_PROP_MODE_REPLACE, win, _NET_SYSTEM_TRAY_ORIENTATION,
_NET_SYSTEM_TRAY_ORIENTATION, 32, 1, &orientation);
}
void set_trayvisual(connection& conn, xcb_window_t win, xcb_visualid_t visual) {
conn.change_property(
XCB_PROP_MODE_REPLACE, win, _NET_SYSTEM_TRAY_VISUAL, XCB_ATOM_VISUALID, 32, 1, &visual);
}
}
LEMONBUDDY_NS_END

View File

@ -24,7 +24,7 @@ namespace xlib {
}
Colormap create_colormap(int screen) {
return XCreateColormap(get_display(), XRootWindow(get_display(), screen), get_visual(), screen);
return XDefaultColormap(get_display(), screen);
}
}

View File

@ -1,4 +1,5 @@
#include "x11/xutils.hpp"
#include "x11/connection.hpp"
#include "x11/xlib.hpp"
LEMONBUDDY_NS
@ -17,9 +18,11 @@ namespace xutils {
}
void pack_values(uint32_t mask, const uint32_t* src, uint32_t* dest) {
for (; mask; mask >>= 1, src++)
if (mask & 1)
for (; mask; mask >>= 1, src++) {
if (mask & 1) {
*dest++ = *src;
}
}
}
void pack_values(uint32_t mask, const xcb_params_cw_t* src, uint32_t* dest) {
@ -30,9 +33,18 @@ namespace xutils {
xutils::pack_values(mask, reinterpret_cast<const uint32_t*>(src), dest);
}
void pack_values(uint32_t mask, const xcb_params_configure_window_t * src, uint32_t* dest) {
void pack_values(uint32_t mask, const xcb_params_configure_window_t* src, uint32_t* dest) {
xutils::pack_values(mask, reinterpret_cast<const uint32_t*>(src), dest);
}
void visibility_notify(connection& conn, const xcb_window_t& win, xcb_visibility_t state) {
auto notify = memory_util::make_malloc_ptr<xcb_visibility_notify_event_t>(32);
notify->response_type = XCB_VISIBILITY_NOTIFY;
notify->window = win;
notify->state = state;
const char* data = reinterpret_cast<const char*>(notify.get());
conn.send_event(true, win, XCB_EVENT_MASK_NO_EVENT, data);
}
}
LEMONBUDDY_NS_END