refactor: Code cleanup
This commit is contained in:
parent
ae501d6ae1
commit
869c5fe718
@ -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 "---------------------------")
|
||||
|
@ -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
|
||||
}
|
||||
}
|
||||
|
@ -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
|
||||
}
|
||||
}
|
||||
|
@ -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];
|
||||
|
@ -21,6 +21,7 @@ class color {
|
||||
static color parse(string input);
|
||||
|
||||
protected:
|
||||
uint32_t m_value;
|
||||
uint32_t m_color;
|
||||
string m_source;
|
||||
};
|
||||
|
@ -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
20
include/x11/wm.hpp
Normal 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
|
@ -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
|
||||
|
@ -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, ¶ms, back_pixel, 0);
|
||||
XCB_AUX_ADD_PARAM(&mask, ¶ms, border_pixel, 0);
|
||||
XCB_AUX_ADD_PARAM(&mask, ¶ms, backing_store, XCB_BACKING_STORE_WHEN_MAPPED);
|
||||
XCB_AUX_ADD_PARAM(&mask, ¶ms, colormap, m_colormap);
|
||||
XCB_AUX_ADD_PARAM(&mask, ¶ms, override_redirect, m_bar.dock);
|
||||
XCB_AUX_ADD_PARAM(&mask, ¶ms, 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");
|
||||
}
|
||||
|
||||
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, ¶ms, foreground, colors[i - 1]);
|
||||
XCB_AUX_ADD_PARAM(&mask, ¶ms, graphics_exposures, 0);
|
||||
|
||||
xutils::pack_values(mask, ¶ms, 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, ¶ms, back_pixmap, m_pixmap);
|
||||
// xutils::pack_values(mask, ¶ms, 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 {{{
|
||||
|
||||
@ -376,7 +411,46 @@ void bar::bootstrap(bool nodraw) { // {{{
|
||||
m_fontmanager->allocate_color(m_bar.foreground, true);
|
||||
|
||||
// }}}
|
||||
// Set tray settings {{{
|
||||
// Connect signal handlers {{{
|
||||
|
||||
m_log.trace("bar: Attach parser callbacks");
|
||||
|
||||
// clang-format off
|
||||
g_signals::parser::alignment_change = bind(&bar::on_alignment_change, this, placeholders::_1);
|
||||
g_signals::parser::attribute_set = bind(&bar::on_attribute_set, this, placeholders::_1);
|
||||
g_signals::parser::attribute_unset = bind(&bar::on_attribute_unset, this, placeholders::_1);
|
||||
g_signals::parser::attribute_toggle = bind(&bar::on_attribute_toggle, this, placeholders::_1);
|
||||
g_signals::parser::action_block_open = bind(&bar::on_action_block_open, this, placeholders::_1, placeholders::_2);
|
||||
g_signals::parser::action_block_close = bind(&bar::on_action_block_close, this, placeholders::_1);
|
||||
g_signals::parser::color_change = bind(&bar::on_color_change, this, placeholders::_1, placeholders::_2);
|
||||
g_signals::parser::font_change = bind(&bar::on_font_change, this, placeholders::_1);
|
||||
g_signals::parser::pixel_offset = bind(&bar::on_pixel_offset, this, placeholders::_1);
|
||||
g_signals::parser::ascii_text_write = bind(&bar::draw_character, this, placeholders::_1);
|
||||
g_signals::parser::unicode_text_write = bind(&bar::draw_character, this, placeholders::_1);
|
||||
g_signals::parser::string_write = bind(&bar::draw_textstring, this, placeholders::_1, placeholders::_2);
|
||||
// clang-format on
|
||||
|
||||
// }}}
|
||||
// Attach event sink to registry {{{
|
||||
|
||||
m_log.trace("bar: Aattaching sink to registry");
|
||||
m_connection.attach_sink(this, 1);
|
||||
m_sinkattached = true;
|
||||
|
||||
// }}}
|
||||
|
||||
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");
|
||||
@ -393,7 +467,12 @@ void bar::bootstrap(bool nodraw) { // {{{
|
||||
m_tray.align = alignment::NONE;
|
||||
}
|
||||
|
||||
if (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;
|
||||
@ -426,11 +505,20 @@ void bar::bootstrap(bool nodraw) { // {{{
|
||||
}
|
||||
|
||||
// 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);
|
||||
m_conf.get<bool>(bs, "tray-transparent", m_tray.transparent);
|
||||
|
||||
if (m_tray.transparent) {
|
||||
m_tray.background = 0;
|
||||
} else {
|
||||
m_tray.background = m_bar.background;
|
||||
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
|
||||
@ -463,38 +551,34 @@ void bar::bootstrap(bool nodraw) { // {{{
|
||||
|
||||
// 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;
|
||||
}
|
||||
|
||||
// }}}
|
||||
// Connect signal handlers {{{
|
||||
m_log.trace("controller: Activate tray manager");
|
||||
|
||||
m_log.trace("bar: Attach parser callbacks");
|
||||
|
||||
// clang-format off
|
||||
g_signals::parser::alignment_change = bind(&bar::on_alignment_change, this, placeholders::_1);
|
||||
g_signals::parser::attribute_set = bind(&bar::on_attribute_set, this, placeholders::_1);
|
||||
g_signals::parser::attribute_unset = bind(&bar::on_attribute_unset, this, placeholders::_1);
|
||||
g_signals::parser::attribute_toggle = bind(&bar::on_attribute_toggle, this, placeholders::_1);
|
||||
g_signals::parser::action_block_open = bind(&bar::on_action_block_open, this, placeholders::_1, placeholders::_2);
|
||||
g_signals::parser::action_block_close = bind(&bar::on_action_block_close, this, placeholders::_1);
|
||||
g_signals::parser::color_change = bind(&bar::on_color_change, this, placeholders::_1, placeholders::_2);
|
||||
g_signals::parser::font_change = bind(&bar::on_font_change, this, placeholders::_1);
|
||||
g_signals::parser::pixel_offset = bind(&bar::on_pixel_offset, this, placeholders::_1);
|
||||
g_signals::parser::ascii_text_write = bind(&bar::draw_character, this, placeholders::_1);
|
||||
g_signals::parser::unicode_text_write = bind(&bar::draw_character, this, placeholders::_1);
|
||||
g_signals::parser::string_write = bind(&bar::draw_textstring, this, placeholders::_1, placeholders::_2);
|
||||
// clang-format on
|
||||
|
||||
// }}}
|
||||
// Attach event sink to registry {{{
|
||||
|
||||
m_log.trace("bar: Aattaching sink to registry");
|
||||
m_connection.attach_sink(this, 1);
|
||||
m_sinkattached = true;
|
||||
|
||||
// }}}
|
||||
|
||||
m_connection.flush();
|
||||
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();
|
||||
}
|
||||
} // }}}
|
||||
|
||||
/**
|
||||
@ -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);
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -1,5 +1,4 @@
|
||||
#include <X11/Xlib-xcb.h>
|
||||
#include <thread>
|
||||
|
||||
#include "common.hpp"
|
||||
#include "components/command_line.hpp"
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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
50
src/x11/wm.cpp
Normal 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
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,4 +1,5 @@
|
||||
#include "x11/xutils.hpp"
|
||||
#include "x11/connection.hpp"
|
||||
#include "x11/xlib.hpp"
|
||||
|
||||
LEMONBUDDY_NS
|
||||
@ -17,10 +18,12 @@ 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) {
|
||||
xutils::pack_values(mask, reinterpret_cast<const uint32_t*>(src), dest);
|
||||
@ -33,6 +36,15 @@ namespace xutils {
|
||||
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
|
||||
|
Loading…
Reference in New Issue
Block a user