From 869c5fe718caae4de3b63fe53f484a326bc55079 Mon Sep 17 00:00:00 2001 From: Michael Carlberg Date: Fri, 4 Nov 2016 18:54:33 +0100 Subject: [PATCH] refactor: Code cleanup --- cmake/build/summary.cmake | 4 + include/components/bar.hpp | 16 +- include/components/controller.hpp | 10 +- include/utils/color.hpp | 9 + include/x11/color.hpp | 1 + include/x11/window.hpp | 6 + include/x11/wm.hpp | 20 ++ include/x11/xutils.hpp | 4 + src/components/bar.cpp | 382 +++++++++++++++++++----------- src/components/controller.cpp | 60 ++--- src/components/signals.cpp | 1 + src/main.cpp | 1 - src/x11/color.cpp | 10 +- src/x11/draw.cpp | 9 +- src/x11/wm.cpp | 50 ++++ src/x11/xlib.cpp | 2 +- src/x11/xutils.cpp | 18 +- 17 files changed, 394 insertions(+), 209 deletions(-) create mode 100644 include/x11/wm.hpp create mode 100644 src/x11/wm.cpp diff --git a/cmake/build/summary.cmake b/cmake/build/summary.cmake index 3708ccca..ecc11464 100644 --- a/cmake/build/summary.cmake +++ b/cmake/build/summary.cmake @@ -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 "---------------------------") diff --git a/include/components/bar.hpp b/include/components/bar.hpp index 21a9cb94..06967e00 100644 --- a/include/components/bar.hpp +++ b/include/components/bar.hpp @@ -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 { public: explicit bar(connection& conn, const config& config, const logger& logger, - unique_ptr fontmanager) + unique_ptr fontmanager, unique_ptr traymanager) : m_connection(conn) , m_conf(config) , m_log(logger) - , m_fontmanager(forward(fontmanager)) {} + , m_fontmanager(forward(fontmanager)) + , m_traymanager(forward(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 m_fontmanager; + unique_ptr m_traymanager; threading_util::spin_lock m_lock; throttle_util::throttle_t m_throttler; @@ -78,6 +84,9 @@ class bar : public xpp::event::sink m_borders; @@ -105,7 +114,8 @@ namespace { configure_connection(), configure_config(), configure_logger(), - configure_fontmanager()); + configure_fontmanager(), + configure_traymanager()); // clang-format on } } diff --git a/include/components/controller.hpp b/include/components/controller.hpp index e684a7d1..a1ce69f6 100644 --- a/include/components/controller.hpp +++ b/include/components/controller.hpp @@ -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, unique_ptr bar, unique_ptr tray, + unique_ptr eventloop, unique_ptr bar, inotify_util::watch_t& confwatch) : m_connection(conn) , m_log(logger) , m_conf(config) , m_eventloop(forward(eventloop)) , m_bar(forward(bar)) - , m_traymanager(forward(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 m_eventloop; unique_ptr m_bar; - unique_ptr 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 } } diff --git a/include/utils/color.hpp b/include/utils/color.hpp index 926ce2ed..24f5679f 100644 --- a/include/utils/color.hpp +++ b/include/utils/color.hpp @@ -45,6 +45,15 @@ namespace color_util { return b << 8 | b << 8 / 0xff; } + template + 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 string hex(uint32_t color) { char s[12]; diff --git a/include/x11/color.hpp b/include/x11/color.hpp index db09a34e..331625e2 100644 --- a/include/x11/color.hpp +++ b/include/x11/color.hpp @@ -21,6 +21,7 @@ class color { static color parse(string input); protected: + uint32_t m_value; uint32_t m_color; string m_source; }; diff --git a/include/x11/window.hpp b/include/x11/window.hpp index d7d507c9..7f8ddef0 100644 --- a/include/x11/window.hpp +++ b/include/x11/window.hpp @@ -17,6 +17,12 @@ class window : public xpp::window { 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 { diff --git a/include/x11/wm.hpp b/include/x11/wm.hpp new file mode 100644 index 00000000..4aa4d1a7 --- /dev/null +++ b/include/x11/wm.hpp @@ -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 flags); + void set_windowtype(connection& conn, xcb_window_t win, vector types); + void set_wmstate(connection& conn, xcb_window_t win, vector 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 diff --git a/include/x11/xutils.hpp b/include/x11/xutils.hpp index a5c698db..bcb09703 100644 --- a/include/x11/xutils.hpp +++ b/include/x11/xutils.hpp @@ -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 diff --git a/src/components/bar.cpp b/src/components/bar.cpp index d5ab892f..30acac34 100644 --- a/src/components/bar.cpp +++ b/src/components/bar.cpp @@ -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"); - } + 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 image_data; + // std::back_insert_iterator 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 {{{ @@ -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(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(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(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(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(bs, "tray-padding", 0); - - // Add user-defiend offset - auto offset_x_def = m_conf.get(bs, "tray-offset-x", ""); - auto offset_y_def = m_conf.get(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(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(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(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(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(bs, "tray-transparent", m_tray.transparent); + + if (m_tray.transparent) { + m_tray.background = 0; + } else { + auto bg = m_conf.get(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(bs, "tray-padding", 0); + + // Add user-defiend offset + auto offset_x_def = m_conf.get(bs, "tray-offset-x", ""); + auto offset_y_def = m_conf.get(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(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 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(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); diff --git a/src/components/controller.cpp b/src/components/controller.cpp index 81824304..53faf280 100644 --- a/src/components/controller.cpp +++ b/src/components/controller.cpp @@ -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 diff --git a/src/components/signals.cpp b/src/components/signals.cpp index 736aac5a..40745f91 100644 --- a/src/components/signals.cpp +++ b/src/components/signals.cpp @@ -7,6 +7,7 @@ LEMONBUDDY_NS */ callback g_signals::bar::action_click = nullptr; callback g_signals::bar::visibility_change = nullptr; +callback<> g_signals::bar::redraw = nullptr; /** * Signals used to communicate with the input parser diff --git a/src/main.cpp b/src/main.cpp index 8c666dcf..80e18bfc 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1,5 +1,4 @@ #include -#include #include "common.hpp" #include "components/command_line.hpp" diff --git a/src/x11/color.cpp b/src/x11/color.cpp index 1057a37f..1d59c6a1 100644 --- a/src/x11/color.cpp +++ b/src/x11/color.cpp @@ -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; } diff --git a/src/x11/draw.cpp b/src/x11/draw.cpp index 37254a24..5f959094 100644 --- a/src/x11/draw.cpp +++ b/src/x11/draw.cpp @@ -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 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); } /** diff --git a/src/x11/wm.cpp b/src/x11/wm.cpp new file mode 100644 index 00000000..4de19208 --- /dev/null +++ b/src/x11/wm.cpp @@ -0,0 +1,50 @@ +#include + +#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 flags) { + xcb_icccm_set_wm_protocols(conn, win, WM_PROTOCOLS, flags.size(), flags.data()); + } + + void set_windowtype(connection& conn, xcb_window_t win, vector 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 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 diff --git a/src/x11/xlib.cpp b/src/x11/xlib.cpp index 27de3d22..383e0640 100644 --- a/src/x11/xlib.cpp +++ b/src/x11/xlib.cpp @@ -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); } } diff --git a/src/x11/xutils.cpp b/src/x11/xutils.cpp index 0937787d..1bd9aab6 100644 --- a/src/x11/xutils.cpp +++ b/src/x11/xutils.cpp @@ -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(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(src), dest); } + + void visibility_notify(connection& conn, const xcb_window_t& win, xcb_visibility_t state) { + auto notify = memory_util::make_malloc_ptr(32); + notify->response_type = XCB_VISIBILITY_NOTIFY; + notify->window = win; + notify->state = state; + const char* data = reinterpret_cast(notify.get()); + conn.send_event(true, win, XCB_EVENT_MASK_NO_EVENT, data); + } } LEMONBUDDY_NS_END