diff --git a/cmake/build/options.cmake b/cmake/build/options.cmake index 4bb493a6..4ba46652 100644 --- a/cmake/build/options.cmake +++ b/cmake/build/options.cmake @@ -43,6 +43,7 @@ option(CXXLIB_GCC "Link against stdlibc++" OFF) option(BUILD_TESTS "Build testsuite" OFF) option(DEBUG_LOGGER "Enable extra debug logging" OFF) option(VERBOSE_TRACELOG "Enable verbose trace logs" OFF) +option(DEBUG_HINTS "Enable hints rendering" OFF) option(ENABLE_CCACHE "Enable ccache support" OFF) option(ENABLE_ALSA "Enable alsa support" ON) @@ -82,4 +83,7 @@ set(SETTING_PATH_MESSAGING_FIFO "/tmp/polybar_mqueue.%pid%" set(SETTING_PATH_TEMPERATURE_INFO "/sys/class/thermal/thermal_zone%zone%/temp" CACHE STRING "Path to file containing the current temperature") +set(DEBUG_HINTS_OFFSET_X 0 CACHE INTEGER "Debug hint offset x") +set(DEBUG_HINTS_OFFSET_Y 0 CACHE INTEGER "Debug hint offset y") + # }}} diff --git a/cmake/build/summary.cmake b/cmake/build/summary.cmake index da8cd7da..755a27f2 100644 --- a/cmake/build/summary.cmake +++ b/cmake/build/summary.cmake @@ -47,6 +47,7 @@ message(STATUS "--------------------------") colored_option(STATUS " Build testsuite ${BUILD_TESTS}" BUILD_TESTS "32;1" "37;2") colored_option(STATUS " Debug logging ${DEBUG_LOGGER}" DEBUG_LOGGER "32;1" "37;2") colored_option(STATUS " Verbose tracing ${VERBOSE_TRACELOG}" VERBOSE_TRACELOG "32;1" "37;2") +colored_option(STATUS " Draw debug hints ${DEBUG_HINTS}" DEBUG_HINTS "32;1" "37;2") colored_option(STATUS " Enable ccache ${ENABLE_CCACHE}" ENABLE_CCACHE "32;1" "37;2") message(STATUS "--------------------------") colored_option(STATUS " Enable alsa ${ENABLE_ALSA}" ENABLE_ALSA "32;1" "37;2") @@ -58,20 +59,3 @@ colored_option(STATUS " Enable X RandR ${ENABLE_RANDR_EXT}" ENABLE_RANDR_E colored_option(STATUS " Enable X Render ${ENABLE_RENDER_EXT}" ENABLE_RENDER_EXT "32;1" "37;2") colored_option(STATUS " Enable X Damage ${ENABLE_DAMAGE_EXT}" ENABLE_DAMAGE_EXT "32;1" "37;2") message(STATUS "--------------------------") -# message(STATUS " ALSA_SOUNDCARD ${SETTING_ALSA_SOUNDCARD}") -# message(STATUS " BSPWM_SOCKET_PATH ${SETTING_BSPWM_SOCKET_PATH}") -# message(STATUS " BSPWM_STATUS_PREFIX ${SETTING_BSPWM_STATUS_PREFIX}") -# message(STATUS " CONNECTION_TEST_IP ${SETTING_CONNECTION_TEST_IP}") -# message(STATUS " PATH_ADAPTER_STATUS ${SETTING_PATH_ADAPTER_STATUS}") -# message(STATUS " PATH_BACKLIGHT_VAL ${SETTING_PATH_BACKLIGHT_VAL}") -# message(STATUS " PATH_BACKLIGHT_MAX ${SETTING_PATH_BACKLIGHT_MAX}") -# message(STATUS " PATH_BATTERY_CAPACITY ${SETTING_PATH_BATTERY_CAPACITY}") -# message(STATUS " PATH_BATTERY_CAPACITY_MAX ${SETTING_PATH_BATTERY_CAPACITY_MAX}") -# message(STATUS " PATH_BATTERY_CAPACITY_PERC ${SETTING_PATH_BATTERY_CAPACITY_PERC}") -# message(STATUS " PATH_BATTERY_VOLTAGE ${SETTING_PATH_BATTERY_VOLTAGE}") -# message(STATUS " PATH_BATTERY_RATE ${SETTING_PATH_BATTERY_RATE}") -# message(STATUS " PATH_CPU_INFO ${SETTING_PATH_CPU_INFO}") -# message(STATUS " PATH_MEMORY_INFO ${SETTING_PATH_MEMORY_INFO}") -# message(STATUS " PATH_MESSAGING_FIFO ${SETTING_PATH_MESSAGING_FIFO}") -# message(STATUS " PATH_TEMPERATURE_INFO ${SETTING_PATH_TEMPERATURE_INFO}") -# message(STATUS "--------------------------") diff --git a/include/components/parser.hpp b/include/components/parser.hpp index 437010a7..cb96cd81 100644 --- a/include/components/parser.hpp +++ b/include/components/parser.hpp @@ -9,8 +9,10 @@ struct bar_settings; enum class attribute : uint8_t; enum class mousebtn : uint8_t; -DEFINE_ERROR(unrecognized_token); -DEFINE_ERROR(unrecognized_attribute); +DEFINE_ERROR(parser_error); +DEFINE_CHILD_ERROR(unrecognized_token, parser_error); +DEFINE_CHILD_ERROR(unrecognized_attribute, parser_error); +DEFINE_CHILD_ERROR(unclosed_actionblocks, parser_error); class parser { public: diff --git a/include/components/renderer.hpp b/include/components/renderer.hpp index 576f6f3b..d84d5bee 100644 --- a/include/components/renderer.hpp +++ b/include/components/renderer.hpp @@ -21,7 +21,7 @@ class renderer { void begin(); void end(); - void redraw(); + void flush(bool clear); void reserve_space(edge side, uint16_t w); @@ -36,7 +36,6 @@ class renderer { bool check_attribute(const attribute attr); void fill_background(); - void fill_border(const map& borders, edge border); void fill_overline(int16_t x, uint16_t w); void fill_underline(int16_t x, uint16_t w); void fill_shift(const int16_t px); @@ -49,10 +48,13 @@ class renderer { const vector get_actions(); protected: - int16_t shift_content(const int16_t x, const int16_t shift_x); + int16_t shift_content(int16_t x, const int16_t shift_x); int16_t shift_content(const int16_t shift_x); - void debughints(); +#ifdef DEBUG_HINTS + vector m_debughints; + void debug_hints(); +#endif private: connection& m_connection; @@ -61,6 +63,8 @@ class renderer { const bar_settings& m_bar; + xcb_rectangle_t m_rect{0, 0, 0U, 0U}; + xcb_window_t m_window; xcb_colormap_t m_colormap; xcb_visualtype_t* m_visual; @@ -79,9 +83,6 @@ class renderer { int8_t m_fontindex{DEFAULT_FONT_INDEX}; xcb_font_t m_gcfont{XCB_NONE}; - - edge m_reserve_at{edge::NONE}; - uint16_t m_reserve; }; di::injector> configure_renderer(const bar_settings& bar, const vector& fonts); diff --git a/include/components/types.hpp b/include/components/types.hpp index f39438c6..8b87bbc0 100644 --- a/include/components/types.hpp +++ b/include/components/types.hpp @@ -103,12 +103,14 @@ struct bar_settings { bool force_docking{false}; - const xcb_rectangle_t inner_area(bool local_coords = false) const { - xcb_rectangle_t rect{pos.x, pos.y, size.w, size.h}; - if (local_coords) { - rect.x = 0; - rect.y = 0; + const xcb_rectangle_t inner_area(bool abspos = false) const { + xcb_rectangle_t rect{0, 0, size.w, size.h}; + + if (abspos) { + rect.x = pos.x; + rect.y = pos.y; } + rect.y += borders.at(edge::TOP).size; rect.height -= borders.at(edge::TOP).size; rect.height -= borders.at(edge::BOTTOM).size; @@ -126,9 +128,10 @@ struct action_block { mousebtn button{mousebtn::NONE}; string command; bool active{true}; -#if DEBUG and DRAW_CLICKABLE_AREA_HINTS - xcb_window_t hint; -#endif + + uint16_t width() const { + return end_x - start_x; + } }; POLYBAR_NS_END diff --git a/include/config.hpp.cmake b/include/config.hpp.cmake index 6b9dc443..4f456c9c 100644 --- a/include/config.hpp.cmake +++ b/include/config.hpp.cmake @@ -19,31 +19,28 @@ #cmakedefine DEBUG_LOGGER #cmakedefine VERBOSE_TRACELOG +#cmakedefine DEBUG_HINTS -#ifdef DEBUG -#cmakedefine01 DRAW_CLICKABLE_AREA_HINTS -#cmakedefine DRAW_CLICKABLE_AREA_HINTS_OFFSET_Y @DRAW_CLICKABLE_AREA_HINTS_OFFSET_Y @ -#ifndef DRAW_CLICKABLE_AREA_HINTS_OFFSET_Y -#define DRAW_CLICKABLE_AREA_HINTS_OFFSET_Y 0 -#endif +#ifdef DEBUG_HINTS +static const int DEBUG_HINTS_OFFSET_X{@DEBUG_HINTS_OFFSET_X@}; +static const int DEBUG_HINTS_OFFSET_Y{@DEBUG_HINTS_OFFSET_Y@}; #endif -static constexpr const char* ALSA_SOUNDCARD{"default"}; -static constexpr const char* BSPWM_SOCKET_PATH{"/tmp/bspwm_0_0-socket"}; -static constexpr const char* BSPWM_STATUS_PREFIX{"W"}; -static constexpr const char* CONNECTION_TEST_IP{"8.8.8.8"}; -static constexpr const char* PATH_ADAPTER{"/sys/class/power_supply/%adapter%"}; -static constexpr const char* PATH_BACKLIGHT_MAX{"/sys/class/backlight/%card%/max_brightness"}; -static constexpr const char* PATH_BACKLIGHT_VAL{"/sys/class/backlight/%card%/brightness"}; -static constexpr const char* PATH_BATTERY{"/sys/class/power_supply/%battery%"}; -static constexpr const char* PATH_CPU_INFO{"/proc/stat"}; -static constexpr const char* PATH_MEMORY_INFO{"/proc/meminfo"}; -static constexpr const char* PATH_MESSAGING_FIFO{"/tmp/polybar_mqueue.%pid%"}; -static constexpr const char* PATH_TEMPERATURE_INFO{"/sys/class/thermal/thermal_zone%zone%/temp"}; - -static constexpr const char* BUILDER_SPACE_TOKEN{"%__"}; +static constexpr const char* ALSA_SOUNDCARD{"@SETTING_ALSA_SOUNDCARD@"}; +static constexpr const char* BSPWM_SOCKET_PATH{"@SETTING_BSPWM_SOCKET_PATH@"}; +static constexpr const char* BSPWM_STATUS_PREFIX{"@SETTING_BSPWM_STATUS_PREFIX@"}; +static constexpr const char* CONNECTION_TEST_IP{"@SETTING_CONNECTION_TEST_IP@"}; +static constexpr const char* PATH_ADAPTER{"@SETTING_PATH_ADAPTER@"}; +static constexpr const char* PATH_BACKLIGHT_MAX{"@SETTING_PATH_BACKLIGHT_MAX@"}; +static constexpr const char* PATH_BACKLIGHT_VAL{"@SETTING_PATH_BACKLIGHT_VAL@"}; +static constexpr const char* PATH_BATTERY{"@SETTING_PATH_BATTERY@"}; +static constexpr const char* PATH_CPU_INFO{"@SETTING_PATH_CPU_INFO@"}; +static constexpr const char* PATH_MEMORY_INFO{"@SETTING_PATH_MEMORY_INFO@"}; +static constexpr const char* PATH_MESSAGING_FIFO{"@SETTING_PATH_MESSAGING_FIFO@"}; +static constexpr const char* PATH_TEMPERATURE_INFO{"@SETTING_PATH_TEMPERATURE_INFO@"}; static const int8_t DEFAULT_FONT_INDEX{-1}; +static constexpr const char* BUILDER_SPACE_TOKEN{"%__"}; auto version_details = [](const std::vector& args) { for (auto&& arg : args) { diff --git a/include/modules/mpd.hpp b/include/modules/mpd.hpp index 0f0920a0..d99cbeb1 100644 --- a/include/modules/mpd.hpp +++ b/include/modules/mpd.hpp @@ -80,10 +80,6 @@ namespace modules { chrono::system_clock::time_point m_lastsync; float m_synctime = 1.0f; - string m_progress_fill; - string m_progress_empty; - string m_progress_indicator; - // This flag is used to let thru a broadcast once every time // the connection state changes mpd::connection_state m_statebroadcasted; diff --git a/include/x11/atoms.hpp b/include/x11/atoms.hpp index 49e50625..42c229f4 100644 --- a/include/x11/atoms.hpp +++ b/include/x11/atoms.hpp @@ -8,7 +8,7 @@ struct cached_atom { xcb_atom_t* atom; }; -extern cached_atom ATOMS[33]; +extern cached_atom ATOMS[34]; extern xcb_atom_t _NET_SUPPORTED; extern xcb_atom_t _NET_CURRENT_DESKTOP; @@ -43,3 +43,4 @@ extern xcb_atom_t BACKLIGHT; extern xcb_atom_t _XROOTMAP_ID; extern xcb_atom_t _XSETROOT_ID; extern xcb_atom_t ESETROOT_PMAP_ID; +extern xcb_atom_t _COMPTON_SHADOW; diff --git a/include/x11/draw.hpp b/include/x11/draw.hpp index 130bbe95..9fc97f25 100644 --- a/include/x11/draw.hpp +++ b/include/x11/draw.hpp @@ -6,11 +6,11 @@ POLYBAR_NS 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); + void fill(connection& conn, xcb_drawable_t d, xcb_gcontext_t g, const xcb_rectangle_t rect); + void fill(connection& conn, xcb_drawable_t d, xcb_gcontext_t g, int16_t x, int16_t y, uint16_t w, uint16_t h); - xcb_void_cookie_t xcb_poly_text_16_patched(xcb_connection_t* conn, xcb_drawable_t d, - xcb_gcontext_t gc, int16_t x, int16_t y, uint8_t len, uint16_t* str); + xcb_void_cookie_t xcb_poly_text_16_patched( + xcb_connection_t* conn, xcb_drawable_t d, xcb_gcontext_t gc, int16_t x, int16_t y, uint8_t len, uint16_t* str); } POLYBAR_NS_END diff --git a/include/x11/tray.hpp b/include/x11/tray.hpp index f5755bd4..397fd0ed 100644 --- a/include/x11/tray.hpp +++ b/include/x11/tray.hpp @@ -6,6 +6,7 @@ #include "components/logger.hpp" #include "components/types.hpp" #include "utils/concurrency.hpp" +#include "x11/events.hpp" #define _NET_SYSTEM_TRAY_ORIENTATION_HORZ 0 #define _NET_SYSTEM_TRAY_ORIENTATION_VERT 1 @@ -99,7 +100,7 @@ class tray_manager : public xpp::event::sink guard(m_mutex); + g_signals::tray::report_slotcount = nullptr; m_connection.detach_sink(this, 1); + m_tray.reset(); } /** @@ -147,6 +149,8 @@ void bar::bootstrap(bool nodraw) { m_renderer = configure_renderer(m_opts, m_conf.get_list(bs, "font", {})).create>(); m_window = m_renderer->window(); + m_log.info("Bar window: %s", m_connection.id(m_window)); + restack_window(); reconfigure_window(); @@ -173,11 +177,10 @@ void bar::bootstrap(bool nodraw) { try { m_renderer->begin(); m_renderer->end(); + m_renderer->flush(false); } catch (const exception& err) { throw application_error("Failed to output empty bar window (reason: " + string{err.what()} + ")"); } - - m_connection.flush(); } /** @@ -239,7 +242,7 @@ void bar::bootstrap_tray() { } else if (settings.align == alignment::LEFT) { settings.orig_x = m_opts.pos.x + m_opts.borders.at(edge::LEFT).size; } else if (settings.align == alignment::CENTER) { - settings.orig_x = m_opts.center.x - (settings.width / 2); + settings.orig_x = m_opts.pos.x + m_opts.center.x - (settings.width / 2); } // Set user-defined background color @@ -357,6 +360,8 @@ void bar::parse(string data, bool force) { m_lastinput = data; + m_renderer->begin(); + if (m_trayclients) { if (m_tray && m_trayalign == alignment::LEFT) m_renderer->reserve_space(edge::LEFT, m_tray->settings().configured_w); @@ -364,21 +369,16 @@ void bar::parse(string data, bool force) { m_renderer->reserve_space(edge::RIGHT, m_tray->settings().configured_w); } - m_renderer->begin(); + m_renderer->fill_background(); try { parser parser{m_log, m_opts}; parser(data); - } catch (const unrecognized_token& err) { - m_log.err("Unrecognized syntax token '%s'", err.what()); - } catch (const unrecognized_attribute& err) { - m_log.err("Unrecognized attribute '%s'", err.what()); - } catch (const exception& err) { - m_log.err("Error parsing contents (err: %s)", err.what()); + } catch (const parser_error& err) { + m_log.err("Failed to parse contents (reason: %s)", err.what()); } m_renderer->end(); - m_connection.flush(); } /** @@ -432,12 +432,17 @@ void bar::configure_geom() { m_opts.size.w = math_util::cap(m_opts.size.w, 0, m_opts.monitor->w); m_opts.size.h = math_util::cap(m_opts.size.h, 0, m_opts.monitor->h); - m_opts.center.y = m_opts.size.h + m_opts.borders[edge::TOP].size - m_opts.borders[edge::BOTTOM].size; + m_opts.center.y = m_opts.size.h; + m_opts.center.y -= m_opts.borders[edge::BOTTOM].size; m_opts.center.y /= 2; - m_opts.center.x = m_opts.pos.x + m_opts.size.w - m_opts.borders[edge::RIGHT].size + m_opts.borders[edge::LEFT].size; - m_opts.center.x /= 2; + m_opts.center.y += m_opts.borders[edge::TOP].size; - m_log.info("Bar geometry %ix%i+%i+%i", m_opts.size.w, m_opts.size.h, m_opts.pos.x, m_opts.pos.y); + m_opts.center.x = m_opts.size.w; + m_opts.center.x -= m_opts.borders[edge::RIGHT].size; + m_opts.center.x /= 2; + m_opts.center.x += m_opts.borders[edge::LEFT].size; + + m_log.info("Bar geometry: %ix%i+%i+%i", m_opts.size.w, m_opts.size.h, m_opts.pos.x, m_opts.pos.y); } /** @@ -575,7 +580,8 @@ void bar::handle(const evt::button_press& evt) { m_log.trace_x("bar: Received button press: %i at pos(%i, %i)", evt->detail, evt->event_x, evt->event_y); - mousebtn button = static_cast(evt->detail); + const mousebtn button{static_cast(evt->detail)}; + const int16_t event_x{static_cast(evt->event_x - m_opts.inner_area().x)}; for (auto&& action : m_renderer->get_actions()) { if (action.active) { @@ -584,11 +590,11 @@ void bar::handle(const evt::button_press& evt) { } else if (action.button != button) { m_log.trace_x("bar: Ignoring action: button mismatch"); continue; - } else if (action.start_x > evt->event_x) { - m_log.trace_x("bar: Ignoring action: start_x(%i) > event_x(%i)", action.start_x, evt->event_x); + } else if (action.start_x >= event_x) { + m_log.trace_x("bar: Ignoring action: start_x(%i) > event_x(%i)", action.start_x, event_x); continue; - } else if (action.end_x < evt->event_x) { - m_log.trace_x("bar: Ignoring action: end_x(%i) < event_x(%i)", action.end_x, evt->event_x); + } else if (action.end_x <= event_x) { + m_log.trace_x("bar: Ignoring action: end_x(%i) < event_x(%i)", action.end_x, event_x); continue; } @@ -617,7 +623,7 @@ void bar::handle(const evt::button_press& evt) { void bar::handle(const evt::expose& evt) { if (evt->window == m_window) { m_log.trace("bar: Received expose event"); - m_renderer->redraw(); + m_renderer->flush(false); } } diff --git a/src/components/builder.cpp b/src/components/builder.cpp index 46986787..3f2de971 100644 --- a/src/components/builder.cpp +++ b/src/components/builder.cpp @@ -12,8 +12,6 @@ POLYBAR_NS * This will also close any unclosed tags */ string builder::flush() { - if (m_tags[syntaxtag::A]) - cmd_close(); if (m_tags[syntaxtag::B]) background_close(); if (m_tags[syntaxtag::F]) @@ -29,11 +27,15 @@ string builder::flush() { if ((m_attributes >> static_cast(attribute::OVERLINE)) & 1U) overline_close(); + while (m_tags[syntaxtag::A]) { + cmd_close(); + } + string output = m_output.data(); // reset values - for (auto& counter : m_tags) counter.second = 0; - for (auto& value : m_colors) value.second = ""; + m_tags.clear(); + m_colors.clear(); m_output.clear(); m_fontindex = 1; @@ -478,8 +480,10 @@ string builder::foreground_hex() { * Insert directive to change value of given tag */ void builder::tag_open(syntaxtag tag, string value) { - if (m_tags.find(tag) != m_tags.end()) - m_tags[tag]++; + if (m_tags.find(tag) == m_tags.end()) + m_tags[tag] = 0; + + m_tags[tag]++; switch (tag) { case syntaxtag::NONE: @@ -536,7 +540,7 @@ void builder::tag_open(attribute attr) { * Insert directive to reset given tag if it's open and closable */ void builder::tag_close(syntaxtag tag) { - if (!m_tags[tag] || m_tags.find(tag) == m_tags.end()) + if (m_tags.find(tag) == m_tags.end() || !m_tags[tag]) return; m_tags[tag]--; diff --git a/src/components/parser.cpp b/src/components/parser.cpp index d246194a..f3e565e3 100644 --- a/src/components/parser.cpp +++ b/src/components/parser.cpp @@ -48,6 +48,10 @@ void parser::operator()(string data) { data.erase(0, text(data.substr(0, pos))); } } + + if (!m_actions.empty()) { + throw unclosed_actionblocks(to_string(m_actions.size()) + " unclosed action block(s)"); + } } /** @@ -151,7 +155,7 @@ void parser::codeblock(string data) { break; default: - throw unrecognized_token(string{tag}); + throw unrecognized_token("Unrecognized token '" + string{tag} + "'"); } if (!data.empty()) @@ -232,7 +236,7 @@ attribute parser::parse_attr(const char attr) { case 'u': return attribute::UNDERLINE; default: - throw unrecognized_attribute(string{attr}); + throw unrecognized_token("Unrecognized attribute '" + string{attr} + "'"); } } diff --git a/src/components/renderer.cpp b/src/components/renderer.cpp index 46dfdc37..02940db0 100644 --- a/src/components/renderer.cpp +++ b/src/components/renderer.cpp @@ -3,6 +3,7 @@ #include "x11/connection.hpp" #include "x11/draw.hpp" #include "x11/fonts.hpp" +#include "x11/winspec.hpp" #include "x11/xlib.hpp" #include "x11/xutils.hpp" @@ -27,41 +28,44 @@ di::injector> configure_renderer(const bar_settings& bar, c */ renderer::renderer(connection& conn, const logger& logger, unique_ptr font_manager, const bar_settings& bar, const vector& fonts) - : m_connection(conn), m_log(logger), m_fontmanager(forward(font_manager)), m_bar(bar) { - auto screen = m_connection.screen(); + : m_connection(conn) + , m_log(logger) + , m_fontmanager(forward(font_manager)) + , m_bar(bar) + , m_rect(bar.inner_area()) { + m_log.trace("renderer: Get TrueColor visual"); + m_visual = m_connection.visual_type(m_connection.screen(), 32).get(); - m_log.trace("renderer: Get true color visual"); - m_visual = m_connection.visual_type(screen, 32).get(); - - m_log.trace("renderer: Create colormap"); + m_log.trace("renderer: Allocate colormap"); m_colormap = m_connection.generate_id(); - m_connection.create_colormap(XCB_COLORMAP_ALLOC_NONE, m_colormap, screen->root, m_visual->visual_id); + m_connection.create_colormap(XCB_COLORMAP_ALLOC_NONE, m_colormap, m_connection.screen()->root, m_visual->visual_id); - m_window = m_connection.generate_id(); - m_log.trace("renderer: Create window (xid=%s)", m_connection.id(m_window)); + m_log.trace("renderer: Allocate output window"); { - uint32_t mask{0}; - uint32_t values[16]{0}; - xcb_params_cw_t params; - - 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.force_docking); - XCB_AUX_ADD_PARAM(&mask, ¶ms, event_mask, - XCB_EVENT_MASK_PROPERTY_CHANGE | XCB_EVENT_MASK_EXPOSURE | XCB_EVENT_MASK_BUTTON_PRESS); - - xutils::pack_values(mask, ¶ms, values); - m_connection.create_window(32, m_window, screen->root, m_bar.pos.x, m_bar.pos.y, m_bar.size.w, m_bar.size.h, 0, - XCB_WINDOW_CLASS_INPUT_OUTPUT, m_visual->visual_id, mask, values); + // clang-format off + m_window = winspec(m_connection) + << cw_size(m_bar.size) + << cw_pos(m_bar.pos) + << cw_depth(32) + << cw_visual(m_visual->visual_id) + << cw_class(XCB_WINDOW_CLASS_INPUT_OUTPUT) + << cw_params_back_pixel(0) + << cw_params_border_pixel(0) + << cw_params_backing_store(XCB_BACKING_STORE_WHEN_MAPPED) + << cw_params_colormap(m_colormap) + << cw_params_event_mask(XCB_EVENT_MASK_PROPERTY_CHANGE + |XCB_EVENT_MASK_EXPOSURE + |XCB_EVENT_MASK_BUTTON_PRESS) + << cw_params_override_redirect(m_bar.force_docking) + << cw_flush(true); + // clang-format on } + m_log.trace("renderer: Allocate window pixmap"); m_pixmap = m_connection.generate_id(); - m_log.trace("renderer: Create pixmap (xid=%s)", m_connection.id(m_pixmap)); - m_connection.create_pixmap(32, m_pixmap, m_window, m_bar.size.w, m_bar.size.h); + m_connection.create_pixmap(32, m_pixmap, m_window, m_rect.width, m_rect.height); - m_log.trace("renderer: Create gcontexts"); + m_log.trace("renderer: Allocate graphic contexts"); { // clang-format off vector colors { @@ -79,15 +83,14 @@ renderer::renderer(connection& conn, const logger& logger, unique_ptrcreate_xftdraw(m_pixmap, m_colormap); } @@ -160,33 +156,64 @@ void renderer::begin() { void renderer::end() { m_log.trace_x("renderer: end"); - redraw(); m_fontmanager->destroy_xftdraw(); -#ifdef DEBUG - debughints(); +#ifdef DEBUG_HINTS + debug_hints(); #endif - m_reserve = 0; - m_reserve_at = edge::NONE; + flush(false); } /** * Redraw window contents */ -void renderer::redraw() { - m_log.info("Redrawing"); +void renderer::flush(bool clear) { + const xcb_rectangle_t& r = m_rect; - xcb_rectangle_t r{0, 0, m_bar.size.w, m_bar.size.h}; + xcb_rectangle_t top{0, 0, 0U, 0U}; + top.x += m_bar.borders.at(edge::LEFT).size; + top.width += m_bar.size.w - m_bar.borders.at(edge::LEFT).size - m_bar.borders.at(edge::RIGHT).size; + top.height += m_bar.borders.at(edge::TOP).size; - if (m_reserve_at == edge::LEFT) { - r.x += m_reserve; - r.width -= m_reserve; - } else if (m_reserve_at == edge::RIGHT) { - r.width -= m_reserve; + xcb_rectangle_t bottom{0, 0, 0U, 0U}; + bottom.x += m_bar.borders.at(edge::LEFT).size; + bottom.y += m_bar.size.h - m_bar.borders.at(edge::BOTTOM).size; + bottom.width += m_bar.size.w - m_bar.borders.at(edge::LEFT).size - m_bar.borders.at(edge::RIGHT).size; + bottom.height += m_bar.borders.at(edge::BOTTOM).size; + + xcb_rectangle_t left{0, 0, 0U, 0U}; + left.width += m_bar.borders.at(edge::LEFT).size; + left.height += m_bar.size.h; + + xcb_rectangle_t right{0, 0, 0U, 0U}; + right.x += m_bar.size.w - m_bar.borders.at(edge::RIGHT).size; + right.width += m_bar.borders.at(edge::RIGHT).size; + right.height += m_bar.size.h; + + m_log.trace("renderer: clear window contents"); + m_connection.clear_area(false, m_window, 0, 0, m_bar.size.w, m_bar.size.h); + + m_log.trace("renderer: copy pixmap (clear=%i)", clear); + m_connection.copy_area(m_pixmap, m_window, m_gcontexts.at(gc::FG), 0, 0, r.x, r.y, r.width, r.height); + + m_log.trace_x("renderer: draw top border (%lupx, %08x)", top.height, m_bar.borders.at(edge::TOP).color); + draw_util::fill(m_connection, m_window, m_gcontexts.at(gc::BT), top); + + m_log.trace_x("renderer: draw bottom border (%lupx, %08x)", bottom.height, m_bar.borders.at(edge::BOTTOM).color); + draw_util::fill(m_connection, m_window, m_gcontexts.at(gc::BB), bottom); + + m_log.trace_x("renderer: draw left border (%lupx, %08x)", left.width, m_bar.borders.at(edge::LEFT).color); + draw_util::fill(m_connection, m_window, m_gcontexts.at(gc::BL), left); + + m_log.trace_x("renderer: draw right border (%lupx, %08x)", right.width, m_bar.borders.at(edge::RIGHT).color); + draw_util::fill(m_connection, m_window, m_gcontexts.at(gc::BR), right); + + if (clear) { + m_connection.clear_area(false, m_pixmap, 0, 0, r.width, r.height); } - m_connection.copy_area(m_pixmap, m_window, m_gcontexts.at(gc::FG), r.x, r.y, r.x, r.y, r.width, r.height); + m_connection.flush(); } /** @@ -194,8 +221,31 @@ void renderer::redraw() { */ void renderer::reserve_space(edge side, uint16_t w) { m_log.trace_x("renderer: reserve_space(%i, %i)", static_cast(side), w); - m_reserve = w; - m_reserve_at = side; + + switch (side) { + case edge::NONE: + break; + case edge::TOP: + m_rect.y += w; + m_rect.height -= w; + break; + case edge::BOTTOM: + m_rect.height -= w; + break; + case edge::LEFT: + m_rect.x += w; + m_rect.width -= w; + break; + case edge::RIGHT: + m_rect.width -= w; + break; + case edge::ALL: + m_rect.x += w; + m_rect.y += w; + m_rect.width -= w * 2; + m_rect.height -= w * 2; + break; + } } /** @@ -268,22 +318,9 @@ void renderer::set_alignment(const alignment align) { return m_log.trace_x("renderer: ignoring unchanged alignment(%i)", static_cast(align)); } - if (align == alignment::LEFT) { - m_currentx = m_bar.borders.at(edge::LEFT).size; - } else if (align == alignment::RIGHT) { - m_currentx = m_bar.borders.at(edge::RIGHT).size; - } else { - m_currentx = 0; - } - - if (align == alignment::LEFT && m_reserve_at == edge::LEFT) { - m_currentx += m_reserve; - } else if (align == alignment::RIGHT && m_reserve_at == edge::RIGHT) { - m_currentx += m_reserve; - } - m_log.trace_x("renderer: set_alignment(%i)", static_cast(align)); m_alignment = align; + m_currentx = 0; } /** @@ -319,52 +356,7 @@ bool renderer::check_attribute(const attribute attr) { */ void renderer::fill_background() { m_log.trace_x("renderer: fill_background"); - - xcb_rectangle_t rect{0, 0, m_bar.size.w, m_bar.size.h}; - - if (m_reserve_at == edge::LEFT) { - rect.x += m_reserve; - rect.width -= m_reserve; - } else if (m_reserve_at == edge::RIGHT) { - rect.width -= m_reserve; - } - - draw_util::fill(m_connection, m_pixmap, m_gcontexts.at(gc::BG), rect.x, rect.y, rect.width, rect.height); -} - -/** - * Fill border area - */ -void renderer::fill_border(const map& borders, edge border) { - m_log.trace_x("renderer: fill_border(%i)", static_cast(border)); - - for (auto&& b : borders) { - if (!b.second.size || (border != edge::ALL && b.first != border)) - continue; - - switch (b.first) { - case edge::TOP: - draw_util::fill(m_connection, m_pixmap, m_gcontexts.at(gc::BT), borders.at(edge::LEFT).size, 0, - m_bar.size.w - borders.at(edge::LEFT).size - borders.at(edge::RIGHT).size, borders.at(edge::TOP).size); - break; - case edge::BOTTOM: - draw_util::fill(m_connection, m_pixmap, m_gcontexts.at(gc::BB), borders.at(edge::LEFT).size, - m_bar.size.h - borders.at(edge::BOTTOM).size, - m_bar.size.w - borders.at(edge::LEFT).size - borders.at(edge::RIGHT).size, borders.at(edge::BOTTOM).size); - break; - case edge::LEFT: - draw_util::fill( - m_connection, m_pixmap, m_gcontexts.at(gc::BL), 0, 0, borders.at(edge::LEFT).size, m_bar.size.h); - break; - case edge::RIGHT: - draw_util::fill(m_connection, m_pixmap, m_gcontexts.at(gc::BR), m_bar.size.w - borders.at(edge::RIGHT).size, 0, - borders.at(edge::RIGHT).size, m_bar.size.h); - break; - - default: - break; - } - } + draw_util::fill(m_connection, m_pixmap, m_gcontexts.at(gc::BG), 0, 0, m_rect.width, m_rect.height); } /** @@ -377,8 +369,7 @@ void renderer::fill_overline(int16_t x, uint16_t w) { return m_log.trace_x("renderer: not filling overline (size=0)"); } m_log.trace_x("renderer: fill_overline(%i, #%08x)", m_bar.overline.size, m_colors[gc::OL]); - const xcb_rectangle_t inner{m_bar.inner_area(true)}; - draw_util::fill(m_connection, m_pixmap, m_gcontexts.at(gc::OL), x, inner.y, w, m_bar.overline.size); + draw_util::fill(m_connection, m_pixmap, m_gcontexts.at(gc::OL), x, 0, w, m_bar.overline.size); } /** @@ -391,8 +382,7 @@ void renderer::fill_underline(int16_t x, uint16_t w) { return m_log.trace_x("renderer: not filling underline (size=0)"); } m_log.trace_x("renderer: fill_underline(%i, #%08x)", m_bar.underline.size, m_colors[gc::UL]); - const xcb_rectangle_t inner{m_bar.inner_area(true)}; - int16_t y{static_cast(inner.height - m_bar.underline.size)}; + int16_t y{static_cast(m_rect.height - m_bar.underline.size)}; draw_util::fill(m_connection, m_pixmap, m_gcontexts.at(gc::UL), x, y, w, m_bar.underline.size); } @@ -407,7 +397,7 @@ void renderer::fill_shift(const int16_t px) { * Draw character glyph */ void renderer::draw_character(uint16_t character) { - m_log.trace_x("renderer: draw_character(\"%c\")", character); + m_log.trace_x("renderer: draw_character"); auto& font = m_fontmanager->match_char(character); @@ -428,7 +418,7 @@ void renderer::draw_character(uint16_t character) { width++; auto x = shift_content(width); - auto y = m_bar.center.y + font->height / 2 - font->descent + font->offset_y; + auto y = m_rect.height / 2 + font->height / 2 - font->descent + font->offset_y; if (font->xft != nullptr) { auto color = m_fontmanager->xftcolor(); @@ -473,7 +463,7 @@ void renderer::draw_textstring(const char* text, size_t len) { width++; auto x = shift_content(width); - auto y = m_bar.center.y + font->height / 2 - font->descent + font->offset_y; + auto y = m_rect.height / 2 + font->height / 2 - font->descent + font->offset_y; if (font->xft != nullptr) { auto color = m_fontmanager->xftcolor(); @@ -510,32 +500,33 @@ void renderer::begin_action(const mousebtn btn, const string cmd) { * End action block at the current position */ void renderer::end_action(const mousebtn btn) { - for (auto action = m_actions.rbegin(); action != m_actions.rend(); action++) { - if (!action->active || action->button != btn) - continue; + int16_t clickable_width{0}; - m_log.trace_x("renderer: end_action(%i, %s)", static_cast(btn), action->command.c_str()); + for (auto action = m_actions.rbegin(); action != m_actions.rend(); action++) { + if (!action->active || action->align != m_alignment || action->button != btn) + continue; action->active = false; - if (action->align == alignment::LEFT) { - action->end_x = m_currentx; - } else if (action->align == alignment::CENTER) { - int base_x{m_bar.size.w}; - int clickable_width{m_currentx - action->start_x}; - base_x -= m_bar.borders.at(edge::RIGHT).size; - base_x /= 2; - base_x += m_bar.borders.at(edge::LEFT).size; - action->start_x = base_x - clickable_width / 2 + action->start_x / 2; - action->end_x = action->start_x + clickable_width; - } else if (action->align == alignment::RIGHT) { - int base_x{m_bar.size.w - m_bar.borders.at(edge::RIGHT).size}; - if (m_reserve_at == edge::RIGHT) - base_x -= m_reserve; - action->start_x = base_x - m_currentx + action->start_x; - action->end_x = base_x; + switch (action->align) { + case alignment::NONE: + break; + case alignment::LEFT: + action->end_x = m_currentx; + break; + case alignment::CENTER: + clickable_width = m_currentx - action->start_x; + action->start_x = m_rect.width / 2 - clickable_width / 2 + action->start_x / 2; + action->end_x = action->start_x + clickable_width; + break; + case alignment::RIGHT: + action->start_x = m_rect.width - m_currentx + action->start_x; + action->end_x = m_rect.width; + break; } + m_log.trace_x("renderer: end_action(%i, %s, %i)", static_cast(btn), action->command, action->width()); + return; } } @@ -550,30 +541,33 @@ const vector renderer::get_actions() { /** * Shift contents by given pixel value */ -int16_t renderer::shift_content(const int16_t x, const int16_t shift_x) { +int16_t renderer::shift_content(int16_t x, const int16_t shift_x) { m_log.trace_x("renderer: shift_content(%i)", shift_x); - int delta = shift_x; - int x2{x}; + int16_t delta{shift_x}; + int16_t base_x{0}; - if (m_alignment == alignment::CENTER) { - int base_x = m_bar.size.w; - base_x -= m_bar.borders.at(edge::RIGHT).size; - base_x /= 2; - base_x += m_bar.borders.at(edge::LEFT).size; - m_connection.copy_area( - m_pixmap, m_pixmap, m_gcontexts.at(gc::FG), base_x - x / 2, 0, base_x - (x + shift_x) / 2, 0, x, m_bar.size.h); - x2 = base_x - (x + shift_x) / 2 + x; - delta /= 2; - } else if (m_alignment == alignment::RIGHT) { - m_connection.copy_area(m_pixmap, m_pixmap, m_gcontexts.at(gc::FG), m_bar.size.w - x, 0, m_bar.size.w - x - shift_x, - 0, x, m_bar.size.h); - x2 = m_bar.size.w - shift_x - m_bar.borders.at(edge::RIGHT).size; - if (m_reserve_at == edge::RIGHT) - x2 -= m_reserve; + switch (m_alignment) { + case alignment::NONE: + break; + case alignment::LEFT: + break; + case alignment::CENTER: + base_x = static_cast(m_rect.width / 2); + m_connection.copy_area(m_pixmap, m_pixmap, m_gcontexts.at(gc::FG), base_x - x / 2, 0, base_x - (x + shift_x) / 2, + 0, x, m_rect.height); + x = base_x - (x + shift_x) / 2 + x; + delta /= 2; + break; + case alignment::RIGHT: + base_x = static_cast(m_rect.width - x); + m_connection.copy_area( + m_pixmap, m_pixmap, m_gcontexts.at(gc::FG), base_x, 0, base_x - shift_x, 0, x, m_rect.height); + x = m_rect.width - shift_x; + break; } - draw_util::fill(m_connection, m_pixmap, m_gcontexts.at(gc::BG), x2, 0, m_bar.size.w - x, m_bar.size.h); + draw_util::fill(m_connection, m_pixmap, m_gcontexts.at(gc::BG), x, 0, m_rect.width - x, m_rect.height); // Translate pos of clickable areas if (m_alignment != alignment::LEFT) { @@ -587,10 +581,10 @@ int16_t renderer::shift_content(const int16_t x, const int16_t shift_x) { m_currentx += shift_x; - fill_underline(x2, shift_x); - fill_overline(x2, shift_x); + fill_underline(x, shift_x); + fill_overline(x, shift_x); - return x2; + return x; } /** @@ -600,39 +594,59 @@ int16_t renderer::shift_content(const int16_t shift_x) { return shift_content(m_currentx, shift_x); } +#ifdef DEBUG_HINTS /** * Draw debugging hints onto the output window */ -void renderer::debughints() { -#if DEBUG and DRAW_CLICKABLE_AREA_HINTS - m_log.info("Drawing debug hints"); - +void renderer::debug_hints() { + uint16_t border_width{1}; map hint_num{{ - {alignment::LEFT, 0}, {alignment::CENTER, 0}, {alignment::RIGHT, 0}, + // clang-format off + {alignment::LEFT, 0}, + {alignment::CENTER, 0}, + {alignment::RIGHT, 0}, + // clang-format on }}; + for (auto&& hintwin : m_debughints) { + m_connection.destroy_window(hintwin); + } + + m_debughints.clear(); + for (auto&& action : m_actions) { if (action.active) { continue; } - hint_num[action.align]++; + uint8_t num{static_cast(hint_num.find(action.align)->second++)}; + int16_t x{static_cast(m_bar.pos.x + m_rect.x + action.start_x)}; + int16_t y{static_cast(m_bar.pos.y + m_rect.y)}; + uint16_t w{static_cast(action.width() - border_width * 2)}; + uint16_t h{static_cast(m_rect.height - border_width * 2)}; - auto x = action.start_x; - auto y = m_bar.y + hint_num[action.align]++ * DRAW_CLICKABLE_AREA_HINTS_OFFSET_Y; - auto w = action.end_x - action.start_x - 2; - auto h = m_bar.size.h - 2; + x += num * DEBUG_HINTS_OFFSET_X; + y += num * DEBUG_HINTS_OFFSET_Y; - const uint32_t mask = XCB_CW_BORDER_PIXEL | XCB_CW_OVERRIDE_REDIRECT; - const uint32_t border_color = hint_num[action.align] % 2 ? 0xff0000 : 0x00ff00; - const uint32_t values[2]{border_color, true}; + xcb_window_t hintwin{m_connection.generate_id()}; + m_debughints.emplace_back(hintwin); - action.hint = m_connection.generate_id(); - m_connection.create_window(m_screen->root_depth, action.hint, m_screen->root, x, y, w, h, 1, - XCB_WINDOW_CLASS_INPUT_OUTPUT, m_screen->root_visual, mask, values); - m_connection.map_window(action.hint); + // clang-format off + winspec(m_connection, hintwin) + << cw_size(w, h) + << cw_pos(x, y) + << cw_border(border_width) + << cw_params_border_pixel(num % 2 ? 0xFFFF0000 : 0xFF00FF00) + << cw_params_override_redirect(true) + << cw_flush() + ; + // clang-format on + + xutils::compton_shadow_exclude(m_connection, hintwin); + m_connection.map_window(hintwin); + m_log.info("Debug hint created (x=%i width=%i)", action.start_x, action.width()); } -#endif } +#endif POLYBAR_NS_END diff --git a/src/modules/volume.cpp b/src/modules/volume.cpp index c0bcc54f..6874616c 100644 --- a/src/modules/volume.cpp +++ b/src/modules/volume.cpp @@ -150,7 +150,7 @@ namespace modules { if (!m_muted && m_volume > 0) m_builder->cmd(mousebtn::SCROLL_DOWN, EVENT_VOLUME_DOWN); - m_builder->node(module::get_output()); + m_builder->append(module::get_output()); return m_builder->flush(); } diff --git a/src/modules/xbacklight.cpp b/src/modules/xbacklight.cpp index f86f07ad..5e16f5d3 100644 --- a/src/modules/xbacklight.cpp +++ b/src/modules/xbacklight.cpp @@ -133,21 +133,12 @@ namespace modules { * Generate the module output */ string xbacklight_module::get_output() { - if (m_scroll) { - if (m_percentage < 100) - m_builder->cmd(mousebtn::SCROLL_UP, EVENT_SCROLLUP); - if (m_percentage > 0) - m_builder->cmd(mousebtn::SCROLL_DOWN, EVENT_SCROLLDOWN); + if (m_scroll && m_percentage < 100) + m_builder->cmd(mousebtn::SCROLL_UP, EVENT_SCROLLUP); + if (m_scroll && m_percentage > 0) + m_builder->cmd(mousebtn::SCROLL_DOWN, EVENT_SCROLLDOWN); - m_builder->node(static_module::get_output()); - - if (m_percentage < 100) - m_builder->cmd_close(); - if (m_percentage > 0) - m_builder->cmd_close(); - } else { - m_builder->node(static_module::get_output()); - } + m_builder->append(static_module::get_output()); return m_builder->flush(); } diff --git a/src/x11/atoms.cpp b/src/x11/atoms.cpp index 25595b8f..de8ede28 100644 --- a/src/x11/atoms.cpp +++ b/src/x11/atoms.cpp @@ -36,9 +36,10 @@ xcb_atom_t BACKLIGHT; xcb_atom_t _XROOTMAP_ID; xcb_atom_t _XSETROOT_ID; xcb_atom_t ESETROOT_PMAP_ID; +xcb_atom_t _COMPTON_SHADOW; // clang-format off -cached_atom ATOMS[33] = { +cached_atom ATOMS[34] = { {"_NET_SUPPORTED", sizeof("_NET_SUPPORTED") - 1, &_NET_SUPPORTED}, {"_NET_CURRENT_DESKTOP", sizeof("_NET_CURRENT_DESKTOP") - 1, &_NET_CURRENT_DESKTOP}, {"_NET_ACTIVE_WINDOW", sizeof("_NET_ACTIVE_WINDOW") - 1, &_NET_ACTIVE_WINDOW}, @@ -72,5 +73,6 @@ cached_atom ATOMS[33] = { {"_XROOTMAP_ID", sizeof("_XROOTMAP_ID") - 1, &_XROOTMAP_ID}, {"_XSETROOT_ID", sizeof("_XSETROOT_ID") - 1, &_XSETROOT_ID}, {"ESETROOT_PMAP_ID", sizeof("ESETROOT_PMAP_ID") - 1, &ESETROOT_PMAP_ID}, + {"_COMPTON_SHADOW", sizeof("_COMPTON_SHADOW") - 1, &_COMPTON_SHADOW}, }; // clang-format on diff --git a/src/x11/draw.cpp b/src/x11/draw.cpp index 1fc3d562..e0974ac1 100644 --- a/src/x11/draw.cpp +++ b/src/x11/draw.cpp @@ -10,15 +10,15 @@ namespace draw_util { /** * Fill region of drawable with color defined by gcontext */ - void fill(connection& c, xcb_drawable_t d, xcb_gcontext_t g, int16_t x, int16_t y, uint16_t w, - uint16_t h) { - 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); + void fill(connection& conn, xcb_drawable_t d, xcb_gcontext_t g, const xcb_rectangle_t rect) { + conn.poly_fill_rectangle(d, g, 1, &rect); + } + + /** + * Fill region of drawable with color defined by gcontext + */ + void fill(connection& conn, xcb_drawable_t d, xcb_gcontext_t g, int16_t x, int16_t y, uint16_t w, uint16_t h) { + fill(conn, d, g, {x, y, w, h}); } /** @@ -26,8 +26,8 @@ namespace draw_util { * * Code: http://wmdia.sourceforge.net/ */ - xcb_void_cookie_t xcb_poly_text_16_patched(xcb_connection_t* conn, xcb_drawable_t d, - xcb_gcontext_t gc, int16_t x, int16_t y, uint8_t len, uint16_t* str) { + xcb_void_cookie_t xcb_poly_text_16_patched( + xcb_connection_t* conn, xcb_drawable_t d, xcb_gcontext_t gc, int16_t x, int16_t y, uint8_t len, uint16_t* str) { static const xcb_protocol_request_t xcb_req = { 5, // count 0, // ext diff --git a/src/x11/tray.cpp b/src/x11/tray.cpp index bc6c99df..af97a8a0 100644 --- a/src/x11/tray.cpp +++ b/src/x11/tray.cpp @@ -12,10 +12,10 @@ #include "x11/color.hpp" #include "x11/connection.hpp" #include "x11/draw.hpp" -#include "x11/events.hpp" #include "x11/graphics.hpp" #include "x11/tray.hpp" #include "x11/window.hpp" +#include "x11/winspec.hpp" #include "x11/wm.hpp" #include "x11/xembed.hpp" @@ -122,14 +122,11 @@ void tray_client::configure_notify(int16_t x, int16_t y) const { // {{{ tray_manager::tray_manager(connection& conn, const logger& logger) : m_connection(conn), m_log(logger) { m_connection.attach_sink(this, 2); - m_sinkattached = true; } tray_manager::~tray_manager() { - if (m_activated) - deactivate(); - if (m_sinkattached) - m_connection.detach_sink(this, 2); + m_connection.detach_sink(this, 2); + deactivate(); } /** @@ -155,7 +152,7 @@ void tray_manager::activate() { // {{{ return; } - m_log.info("Activating tray_manager"); + m_log.info("Activating tray manager"); m_activated = true; try { @@ -166,16 +163,11 @@ void tray_manager::activate() { // {{{ set_traycolors(); } catch (const exception& err) { m_log.err(err.what()); - m_log.err("Cannot activate tray_manager... failed to setup window"); + m_log.err("Cannot activate tray manager... failed to setup window"); m_activated = false; return; } - if (!m_sinkattached) { - m_connection.attach_sink(this, 2); - m_sinkattached = true; - } - // Listen for visibility change events on the bar window if (!m_restacked && !g_signals::bar::visibility_change) { g_signals::bar::visibility_change = bind(&tray_manager::bar_visibility_change, this, std::placeholders::_1); @@ -185,12 +177,7 @@ void tray_manager::activate() { // {{{ // notify clients waiting for a manager. acquire_selection(); - // If replacing an existing manager or if re-activating from getting - // replaced, we delay the notification broadcast to allow the clients - // to get unembedded... - if (m_othermanager) - std::this_thread::sleep_for(std::chrono::seconds{1}); - + // Notify pending tray clients notify_clients(); m_connection.flush(); @@ -199,12 +186,12 @@ void tray_manager::activate() { // {{{ /** * Deactivate systray management */ -void tray_manager::deactivate() { // {{{ +void tray_manager::deactivate(bool clear_selection) { // {{{ if (!m_activated) { return; } - m_log.info("Deactivating tray_manager"); + m_log.info("Deactivating tray manager"); m_activated = false; if (m_delayed_activation.joinable()) @@ -219,11 +206,9 @@ void tray_manager::deactivate() { // {{{ g_signals::bar::visibility_change = nullptr; } - if (!m_connection.connection_has_error()) { - if (m_connection.get_selection_owner_unchecked(m_atom).owner() == m_tray) { - m_log.trace("tray: Unset selection owner"); - m_connection.set_selection_owner(XCB_NONE, m_atom, XCB_CURRENT_TIME); - } + if (!m_connection.connection_has_error() && clear_selection) { + m_log.trace("tray: Unset selection owner"); + m_connection.set_selection_owner(XCB_NONE, m_atom, XCB_CURRENT_TIME); } m_log.trace("tray: Unembed clients"); @@ -255,6 +240,11 @@ void tray_manager::deactivate() { // {{{ m_rootpixmap.pixmap = 0; m_prevwidth = 0; m_prevheight = 0; + m_opts.configured_x = 0; + m_opts.configured_y = 0; + m_opts.configured_w = 0; + m_opts.configured_h = 0; + m_opts.configured_slots = 0; m_connection.flush(); } // }}} @@ -497,36 +487,24 @@ void tray_manager::query_atom() { // {{{ * Create tray window */ void tray_manager::create_window() { // {{{ - auto scr = m_connection.screen(); - auto w = calculate_w(); - auto h = calculate_h(); - auto x = calculate_x(w); - auto y = calculate_y(); + m_log.trace("tray: Create tray window"); - if (w < 1) { - w = 1; - } - - m_tray = m_connection.generate_id(); - m_log.trace("tray: Create tray window %s, (%ix%i+%i+%i)", m_connection.id(m_tray), w, h, x, y); - - uint32_t mask = 0; - uint32_t values[16]; - xcb_params_cw_t params; + auto win = winspec(m_connection, m_tray) + << cw_size(calculate_w(), calculate_h()) + << cw_pos(calculate_x(calculate_w()), calculate_y()) + << cw_class(XCB_WINDOW_CLASS_INPUT_OUTPUT) + << cw_params_backing_store(XCB_BACKING_STORE_WHEN_MAPPED) + << cw_params_event_mask(XCB_EVENT_MASK_SUBSTRUCTURE_REDIRECT | XCB_EVENT_MASK_STRUCTURE_NOTIFY) + << cw_params_override_redirect(true) + ; if (!m_opts.transparent) { - XCB_AUX_ADD_PARAM(&mask, ¶ms, back_pixel, m_opts.background); - XCB_AUX_ADD_PARAM(&mask, ¶ms, border_pixel, m_opts.background); + win << cw_params_back_pixel(m_opts.background); + win << cw_params_border_pixel(m_opts.background); } - XCB_AUX_ADD_PARAM(&mask, ¶ms, backing_store, XCB_BACKING_STORE_WHEN_MAPPED); - XCB_AUX_ADD_PARAM(&mask, ¶ms, override_redirect, true); - XCB_AUX_ADD_PARAM(&mask, ¶ms, event_mask, XCB_EVENT_MASK_SUBSTRUCTURE_REDIRECT | XCB_EVENT_MASK_STRUCTURE_NOTIFY); - - xutils::pack_values(mask, ¶ms, values); - - m_connection.create_window_checked( - scr->root_depth, m_tray, scr->root, x, y, w, h, 0, XCB_WINDOW_CLASS_INPUT_OUTPUT, scr->root_visual, mask, values); + m_tray = win << cw_flush(); + m_log.info("Tray window: %s", m_connection.id(m_tray)); xutils::compton_shadow_exclude(m_connection, m_tray); } // }}} @@ -662,13 +640,14 @@ void tray_manager::set_traycolors() { // {{{ * Acquire the systray selection */ void tray_manager::acquire_selection() { // {{{ - xcb_window_t owner = m_connection.get_selection_owner_unchecked(m_atom)->owner; + xcb_window_t owner{m_connection.get_selection_owner_unchecked(m_atom)->owner}; if (owner == m_tray) { m_log.info("tray: Already managing the systray selection"); return; } else if ((m_othermanager = owner)) { m_log.info("Replacing selection manager %s", m_connection.id(owner)); + std::this_thread::sleep_for(std::chrono::seconds{1}); } m_log.trace("tray: Change selection owner to %s", m_connection.id(m_tray)); @@ -1011,7 +990,7 @@ void tray_manager::handle(const evt::selection_clear& evt) { // {{{ m_othermanager = 0; } - deactivate(); + deactivate(false); } // }}} /** @@ -1073,8 +1052,11 @@ void tray_manager::handle(const evt::reparent_notify& evt) { // {{{ * Event callback : XCB_DESTROY_NOTIFY */ void tray_manager::handle(const evt::destroy_notify& evt) { // {{{ - if (!m_activated && evt->window == m_othermanager) { + if (m_activated && evt->window == m_tray) { + deactivate(); + } else if (!m_activated && evt->window == m_othermanager && evt->window != m_tray) { m_log.trace("tray: Received destroy_notify"); + std::this_thread::sleep_for(std::chrono::seconds{1}); m_log.info("Tray selection available... re-activating"); activate(); window{m_connection, m_tray}.redraw(); @@ -1131,8 +1113,10 @@ void tray_manager::handle(const evt::unmap_notify& evt) { // {{{ } m_log.trace("tray: Update container mapped flag"); m_mapped = false; - m_opts.configured_w = 0; - m_opts.configured_x = 0; + if (!m_hidden) { + m_opts.configured_w = 0; + m_opts.configured_x = 0; + } } else { auto client = find_client(evt->window); if (client) { diff --git a/src/x11/winspec.cpp b/src/x11/winspec.cpp new file mode 100644 index 00000000..2a5c137c --- /dev/null +++ b/src/x11/winspec.cpp @@ -0,0 +1,133 @@ +#include "x11/winspec.hpp" + +POLYBAR_NS + +winspec::winspec(connection& conn) : m_connection(conn) {} +winspec::winspec(connection& conn, const xcb_window_t& window) : m_connection(conn), m_window(window) {} + +winspec::operator xcb_window_t() const { + return m_window; +} +winspec::operator xcb_rectangle_t() const { + return {m_x, m_y, m_width, m_height}; +} + +xcb_window_t winspec::operator<<(const cw_flush& f) { + uint32_t values[16]{0}; + + if (m_window == XCB_NONE) + m_window = m_connection.generate_id(); + if (m_parent == XCB_NONE) + m_parent = m_connection.screen()->root; + + if (m_width <= 0) + m_width = 1; + if (m_height <= 0) + m_height = 1; + + xutils::pack_values(m_mask, &m_params, values); + + if (f.checked) { + m_connection.create_window_checked( + m_depth, m_window, m_parent, m_x, m_y, m_width, m_height, m_border, m_class, m_visual, m_mask, values); + } else { + m_connection.create_window( + m_depth, m_window, m_parent, m_x, m_y, m_width, m_height, m_border, m_class, m_visual, m_mask, values); + } + + return m_window; +} + +winspec& winspec::operator<<(const cw_size& size) { + m_width = size.w; + m_height = size.h; + return *this; +} +winspec& winspec::operator<<(const cw_pos& p) { + m_x = p.x; + m_y = p.y; + return *this; +} +winspec& winspec::operator<<(const cw_border& b) { + m_border = b.border_width; + return *this; +} +winspec& winspec::operator<<(const cw_class& c) { + m_class = c.class_; + return *this; +} +winspec& winspec::operator<<(const cw_parent& p) { + m_parent = p.parent; + return *this; +} +winspec& winspec::operator<<(const cw_depth& d) { + m_depth = d.depth; + return *this; +} +winspec& winspec::operator<<(const cw_visual& v) { + m_visual = v.visualid; + return *this; +} + +winspec& winspec::operator<<(const cw_params_back_pixel& p) { + XCB_AUX_ADD_PARAM(&m_mask, &m_params, back_pixel, p.value); + return *this; +} +winspec& winspec::operator<<(const cw_params_back_pixmap& p) { + XCB_AUX_ADD_PARAM(&m_mask, &m_params, back_pixmap, p.value); + return *this; +} +winspec& winspec::operator<<(const cw_params_backing_pixel& p) { + XCB_AUX_ADD_PARAM(&m_mask, &m_params, backing_pixel, p.value); + return *this; +} +winspec& winspec::operator<<(const cw_params_backing_planes& p) { + XCB_AUX_ADD_PARAM(&m_mask, &m_params, backing_planes, p.value); + return *this; +} +winspec& winspec::operator<<(const cw_params_backing_store& p) { + XCB_AUX_ADD_PARAM(&m_mask, &m_params, backing_store, p.value); + return *this; +} +winspec& winspec::operator<<(const cw_params_bit_gravity& p) { + XCB_AUX_ADD_PARAM(&m_mask, &m_params, bit_gravity, p.value); + return *this; +} +winspec& winspec::operator<<(const cw_params_border_pixel& p) { + XCB_AUX_ADD_PARAM(&m_mask, &m_params, border_pixel, p.value); + return *this; +} +winspec& winspec::operator<<(const cw_params_border_pixmap& p) { + XCB_AUX_ADD_PARAM(&m_mask, &m_params, border_pixmap, p.value); + return *this; +} +winspec& winspec::operator<<(const cw_params_colormap& p) { + XCB_AUX_ADD_PARAM(&m_mask, &m_params, colormap, p.value); + return *this; +} +winspec& winspec::operator<<(const cw_params_cursor& p) { + XCB_AUX_ADD_PARAM(&m_mask, &m_params, cursor, p.value); + return *this; +} +winspec& winspec::operator<<(const cw_params_dont_propagate& p) { + XCB_AUX_ADD_PARAM(&m_mask, &m_params, dont_propagate, p.value); + return *this; +} +winspec& winspec::operator<<(const cw_params_event_mask& p) { + XCB_AUX_ADD_PARAM(&m_mask, &m_params, event_mask, p.value); + return *this; +} +winspec& winspec::operator<<(const cw_params_override_redirect& p) { + XCB_AUX_ADD_PARAM(&m_mask, &m_params, override_redirect, p.value); + return *this; +} +winspec& winspec::operator<<(const cw_params_save_under& p) { + XCB_AUX_ADD_PARAM(&m_mask, &m_params, save_under, p.value); + return *this; +} +winspec& winspec::operator<<(const cw_params_win_gravity& p) { + XCB_AUX_ADD_PARAM(&m_mask, &m_params, win_gravity, p.value); + return *this; +} + +POLYBAR_NS_END