diff --git a/CHANGELOG.md b/CHANGELOG.md index eab17012..6aa79782 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -59,10 +59,13 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 triggers if they happen directly after one another, leading to only a single bar update. +### Removed +- `DEBUG_SHADED` cmake variable and its associated functionality. + ### Added - `drawtypes/ramp`: Add support for ramp weights. ([1750](https://github.com/polybar/polybar/issues/1750)) -- `internal/memory`: New tokens `%used%`, `%free%`, `%total%`, `%swap_total%`, +- `internal/memory`: New tokens `%used%`, `%free%`, `%total%`, `%swap_total%`, `%swap_free%`, and `%swap_used%` that automatically switch between MiB and GiB when below or above 1GiB. ([`2472`](https://github.com/polybar/polybar/issues/2472)) @@ -114,6 +117,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ([`#2427`](https://github.com/polybar/polybar/issues/2427)) - `custom/ipc`: `send` action to send arbitrary strings to be displayed in the module. ([`#2455`](https://github.com/polybar/polybar/issues/2455)) +- Added `double-click-interval` setting to the bar section to control the time + interval in which a double-click is recognized. Defaults to 400 (ms) + ([`#1441`](https://github.com/polybar/polybar/issues/1441)) ### Changed - We rewrote polybar's main event loop. This shouldn't change any behavior for @@ -130,6 +136,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - `internal/network`: - Increased precision for upload and download speeds: 0 decimal places for KB/s (as before), 1 for MB/s and 2 for GB/s. +- Clicks arriving in close succession, no longer get dropped. Before polybar + would drop any click that arrived within 5ms of the previous one. +- Increased the double click interval from 150ms to 400ms. ### Fixed - Trailing space after the layout label when indicators are empty and made sure right amount diff --git a/cmake/05-summary.cmake b/cmake/05-summary.cmake index c992d285..c15f3674 100644 --- a/cmake/05-summary.cmake +++ b/cmake/05-summary.cmake @@ -55,6 +55,5 @@ if (BUILD_LIBPOLY) colored_option(" Trace logging (verbose)" DEBUG_LOGGER_VERBOSE) colored_option(" Draw clickable areas" DEBUG_HINTS) colored_option(" Print fc-match details" DEBUG_FONTCONFIG) - colored_option(" Enable window shading" DEBUG_SHADED) endif() endif() diff --git a/include/components/bar.hpp b/include/components/bar.hpp index 101e6c87..63d8d472 100644 --- a/include/components/bar.hpp +++ b/include/components/bar.hpp @@ -5,6 +5,7 @@ #include #include "common.hpp" +#include "components/eventloop.hpp" #include "components/types.hpp" #include "errors.hpp" #include "events/signal_fwd.hpp" @@ -23,7 +24,6 @@ class connection; class logger; class renderer; class screen; -class taskqueue; class tray_manager; namespace tags { @@ -55,8 +55,7 @@ inline double geom_format_to_pixels(std::string str, double max) { class bar : public xpp::event::sink, - public signal_receiver { public: using make_type = unique_ptr; - static make_type make(bool only_initialize_values = false); + static make_type make(eventloop&, bool only_initialize_values = false); - explicit bar(connection&, signal_emitter&, const config&, const logger&, unique_ptr&&, + explicit bar(connection&, signal_emitter&, const config&, const logger&, eventloop&, unique_ptr&&, unique_ptr&&, unique_ptr&&, unique_ptr&&, - unique_ptr&&, bool only_initialize_values); + bool only_initialize_values); ~bar(); const bar_settings settings() const; @@ -90,6 +89,8 @@ class bar : public xpp::event::sink m_screen; unique_ptr m_tray; unique_ptr m_renderer; unique_ptr m_dispatch; unique_ptr m_action_ctxt; - unique_ptr m_taskqueue; bar_settings m_opts{}; string m_lastinput{}; - std::mutex m_mutex{}; - std::atomic m_dblclicks{false}; + bool m_dblclicks{false}; - mousebtn m_buttonpress_btn{mousebtn::NONE}; - int m_buttonpress_pos{0}; #if WITH_XCURSOR int m_motion_pos{0}; #endif - event_timer m_buttonpress{0L, 5L}; - event_timer m_doubleclick{0L, 150L}; - - double m_anim_step{0.0}; + TimerHandle_t m_leftclick_timer{m_loop.timer_handle(nullptr)}; + TimerHandle_t m_middleclick_timer{m_loop.timer_handle(nullptr)}; + TimerHandle_t m_rightclick_timer{m_loop.timer_handle(nullptr)}; + TimerHandle_t m_dim_timer{m_loop.timer_handle(nullptr)}; bool m_visible{true}; }; diff --git a/include/components/controller.hpp b/include/components/controller.hpp index 5f016b38..4d8555a3 100644 --- a/include/components/controller.hpp +++ b/include/components/controller.hpp @@ -2,7 +2,6 @@ #include #include -#include #include "common.hpp" #include "components/eventloop.hpp" @@ -42,7 +41,7 @@ class controller : public signal_receiver; static make_type make(unique_ptr&& ipc); - explicit controller(connection&, signal_emitter&, const logger&, const config&, unique_ptr&&, unique_ptr&&); + explicit controller(connection&, signal_emitter&, const logger&, const config&, unique_ptr&&); ~controller(); bool run(bool writeback, string snapshot_dst, bool confwatch); @@ -98,15 +97,14 @@ class controller : public signal_receiver m_loop; unique_ptr m_bar; unique_ptr m_ipc; - std::unique_ptr eloop; - /** - * Once this is set to true, 'eloop' and any uv handles can be used. + * Once this is set to true, 'm_loop' and any uv handles can be used. */ - std::atomic_bool m_eloop_ready{false}; + std::atomic_bool m_loop_ready{false}; /** * \brief Async handle to notify the eventloop diff --git a/include/components/eventloop.hpp b/include/components/eventloop.hpp index 4798a3e1..26f030be 100644 --- a/include/components/eventloop.hpp +++ b/include/components/eventloop.hpp @@ -45,11 +45,19 @@ struct UVHandleGeneric { } void close() { - if (handle && !uv_is_closing((uv_handle_t*)handle)) { + if (!is_closing()) { uv_close((uv_handle_t*)handle, close_callback); } } + bool is_closing() { + return !handle || uv_is_closing((uv_handle_t*)handle); + } + + bool is_active() { + return uv_is_active((uv_handle_t*)handle) != 0; + } + void cleanup_resources() { if (handle) { delete handle; @@ -109,7 +117,8 @@ struct PipeHandle : public UVHandleGeneric { TimerHandle(uv_loop_t* loop, function fun); - void start(uint64_t timeout, uint64_t repeat); + void start(uint64_t timeout, uint64_t repeat, function new_cb = function(nullptr)); + void stop(); }; struct AsyncHandle : public UVHandle { @@ -121,8 +130,8 @@ using SignalHandle_t = std::unique_ptr; using PollHandle_t = std::unique_ptr; using FSEventHandle_t = std::unique_ptr; using PipeHandle_t = std::unique_ptr; -using TimerHandle_t = std::unique_ptr; -// shared_ptr because we need a reference outside to call send +// shared_ptr because we also return the pointer in order to call methods on it +using TimerHandle_t = std::shared_ptr; using AsyncHandle_t = std::shared_ptr; class eventloop { @@ -136,7 +145,7 @@ class eventloop { void fs_event_handle(const string& path, function fun, function err_cb); void pipe_handle( const string& path, function fun, function eof_cb, function err_cb); - void timer_handle(uint64_t timeout, uint64_t repeat, function fun); + TimerHandle_t timer_handle(function fun); AsyncHandle_t async_handle(function fun); protected: diff --git a/include/components/taskqueue.hpp b/include/components/taskqueue.hpp deleted file mode 100644 index d693b637..00000000 --- a/include/components/taskqueue.hpp +++ /dev/null @@ -1,62 +0,0 @@ -#pragma once - -#include -#include -#include -#include -#include - -#include "common.hpp" -#include "utils/mixins.hpp" - -POLYBAR_NS - -namespace chrono = std::chrono; -using namespace std::chrono_literals; - -class taskqueue : non_copyable_mixin { - public: - struct deferred { - using clock = chrono::high_resolution_clock; - using duration = chrono::milliseconds; - using timepoint = chrono::time_point; - using callback = function; - - explicit deferred(string id, timepoint now, duration wait, callback fn, size_t count) - : id(move(id)), func(move(fn)), now(move(now)), wait(move(wait)), count(move(count)) {} - - const string id; - const callback func; - timepoint now; - duration wait; - size_t count; - }; - - public: - using make_type = unique_ptr; - static make_type make(); - - explicit taskqueue(); - ~taskqueue(); - - void defer( - string id, deferred::duration ms, deferred::callback fn, deferred::duration offset = 0ms, size_t count = 1); - void defer_unique( - string id, deferred::duration ms, deferred::callback fn, deferred::duration offset = 0ms, size_t count = 1); - - bool exist(const string& id); - bool purge(const string& id); - - protected: - void tick(); - - private: - std::thread m_thread; - std::mutex m_lock{}; - std::condition_variable m_hold; - std::atomic_bool m_active{true}; - - vector> m_deferred; -}; - -POLYBAR_NS_END diff --git a/include/components/types.hpp b/include/components/types.hpp index 0ec11440..01c9d72a 100644 --- a/include/components/types.hpp +++ b/include/components/types.hpp @@ -46,6 +46,19 @@ enum class mousebtn { BTN_COUNT, }; +static inline mousebtn mousebtn_get_double(mousebtn btn) { + switch (btn) { + case mousebtn::LEFT: + return mousebtn::DOUBLE_LEFT; + case mousebtn::MIDDLE: + return mousebtn::DOUBLE_MIDDLE; + case mousebtn::RIGHT: + return mousebtn::DOUBLE_RIGHT; + default: + return mousebtn::NONE; + } +} + enum class strut { LEFT = 0, RIGHT, @@ -146,6 +159,8 @@ struct bar_settings { bool override_redirect{false}; + int double_click_interval{400}; + string cursor{}; string cursor_click{}; string cursor_scroll{}; @@ -155,12 +170,6 @@ struct bar_settings { bool dimmed{false}; double dimvalue{1.0}; - bool shaded{false}; - struct size shade_size { - 1U, 1U - }; - position shade_pos{1U, 1U}; - const xcb_rectangle_t inner_area(bool abspos = false) const { xcb_rectangle_t rect = this->outer_area(abspos); diff --git a/include/events/signal.hpp b/include/events/signal.hpp index c9a4f694..1a823d72 100644 --- a/include/events/signal.hpp +++ b/include/events/signal.hpp @@ -80,9 +80,6 @@ namespace signals { struct changed : public detail::base_signal { using base_type::base_type; }; - struct tick : public detail::base_signal { - using base_type::base_type; - }; struct button_press : public detail::value_signal { using base_type::base_type; }; @@ -95,12 +92,6 @@ namespace signals { struct dim_window : public detail::value_signal { using base_type::base_type; }; - struct shade_window : public detail::base_signal { - using base_type::base_type; - }; - struct unshade_window : public detail::base_signal { - using base_type::base_type; - }; struct request_snapshot : public detail::value_signal { using base_type::base_type; }; diff --git a/include/events/signal_fwd.hpp b/include/events/signal_fwd.hpp index ff51e8f4..376683a0 100644 --- a/include/events/signal_fwd.hpp +++ b/include/events/signal_fwd.hpp @@ -27,13 +27,10 @@ namespace signals { } // namespace ipc namespace ui { struct changed; - struct tick; struct button_press; struct cursor_change; struct visibility_change; struct dim_window; - struct shade_window; - struct unshade_window; struct request_snapshot; struct update_background; struct update_geometry; diff --git a/include/settings.hpp.cmake b/include/settings.hpp.cmake index 776b38eb..d1016db8 100644 --- a/include/settings.hpp.cmake +++ b/include/settings.hpp.cmake @@ -41,7 +41,6 @@ extern const char* const APP_VERSION; #cmakedefine DEBUG_LOGGER_VERBOSE #cmakedefine DEBUG_HINTS #cmakedefine DEBUG_WHITESPACE -#cmakedefine DEBUG_SHADED #cmakedefine DEBUG_FONTCONFIG #endif diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 250287d3..31f08d19 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -66,7 +66,6 @@ if(BUILD_LIBPOLY) ${src_dir}/components/logger.cpp ${src_dir}/components/renderer.cpp ${src_dir}/components/screen.cpp - ${src_dir}/components/taskqueue.cpp ${src_dir}/components/eventloop.cpp ${src_dir}/drawtypes/animation.cpp diff --git a/src/components/bar.cpp b/src/components/bar.cpp index 3c096efa..7a95f668 100644 --- a/src/components/bar.cpp +++ b/src/components/bar.cpp @@ -5,7 +5,6 @@ #include "components/config.hpp" #include "components/renderer.hpp" #include "components/screen.hpp" -#include "components/taskqueue.hpp" #include "components/types.hpp" #include "drawtypes/label.hpp" #include "events/signal.hpp" @@ -37,7 +36,7 @@ using namespace signals::ui; /** * Create instance */ -bar::make_type bar::make(bool only_initialize_values) { +bar::make_type bar::make(eventloop& loop, bool only_initialize_values) { auto action_ctxt = make_unique(); // clang-format off @@ -46,11 +45,11 @@ bar::make_type bar::make(bool only_initialize_values) { signal_emitter::make(), config::make(), logger::make(), + loop, screen::make(), tray_manager::make(), tags::dispatch::make(*action_ctxt), std::move(action_ctxt), - taskqueue::make(), only_initialize_values); // clang-format on } @@ -60,18 +59,18 @@ bar::make_type bar::make(bool only_initialize_values) { * * TODO: Break out all tray handling */ -bar::bar(connection& conn, signal_emitter& emitter, const config& config, const logger& logger, +bar::bar(connection& conn, signal_emitter& emitter, const config& config, const logger& logger, eventloop& loop, unique_ptr&& screen, unique_ptr&& tray_manager, unique_ptr&& dispatch, - unique_ptr&& action_ctxt, unique_ptr&& taskqueue, bool only_initialize_values) + unique_ptr&& action_ctxt, bool only_initialize_values) : m_connection(conn) , m_sig(emitter) , m_conf(config) , m_log(logger) + , m_loop(loop) , m_screen(forward(screen)) , m_tray(forward(tray_manager)) , m_dispatch(forward(dispatch)) - , m_action_ctxt(forward(action_ctxt)) - , m_taskqueue(forward(taskqueue)) { + , m_action_ctxt(forward(action_ctxt)) { string bs{m_conf.section()}; // Get available RandR outputs @@ -179,6 +178,8 @@ bar::bar(connection& conn, signal_emitter& emitter, const config& config, const m_opts.module_margin.left = m_conf.get(bs, "module-margin-left", margin); m_opts.module_margin.right = m_conf.get(bs, "module-margin-right", margin); + m_opts.double_click_interval = m_conf.get(bs, "double-click-interval", m_opts.double_click_interval); + if (only_initialize_values) { return; } @@ -308,7 +309,6 @@ bar::bar(connection& conn, signal_emitter& emitter, const config& config, const * Cleanup signal handlers and destroy the bar window */ bar::~bar() { - std::lock_guard guard(m_mutex); m_connection.detach_sink(this, SINK_PRIORITY_BAR); m_sig.detach(this); } @@ -327,12 +327,6 @@ const bar_settings bar::settings() const { * \param force Unless true, do not parse unchanged data */ void bar::parse(string&& data, bool force) { - if (!m_mutex.try_lock()) { - return; - } - - std::lock_guard guard(m_mutex, std::adopt_lock); - bool unchanged = data == m_lastinput; m_lastinput = data; @@ -341,8 +335,6 @@ void bar::parse(string&& data, bool force) { m_log.trace("bar: Force update"); } else if (!m_visible) { return m_log.trace("bar: Ignoring update (invisible)"); - } else if (m_opts.shaded) { - return m_log.trace("bar: Ignoring update (shaded)"); } else if (unchanged) { return m_log.trace("bar: Ignoring update (unchanged)"); } @@ -575,6 +567,25 @@ void bar::broadcast_visibility() { } } +void bar::trigger_click(mousebtn btn, int pos) { + tags::action_t action = m_action_ctxt->has_action(btn, pos); + + if (action != tags::NO_ACTION) { + m_log.trace("Found matching input area"); + m_sig.emit(button_press{m_action_ctxt->get_action(action)}); + return; + } + + for (auto&& action : m_opts.actions) { + if (action.button == btn && !action.command.empty()) { + m_log.trace("Found matching fallback handler"); + m_sig.emit(button_press{string{action.command}}); + return; + } + } + m_log.info("No matching input area found (btn=%i)", static_cast(btn)); +} + /** * Event handler for XCB_DESTROY_NOTIFY events */ @@ -601,21 +612,13 @@ void bar::handle(const evt::destroy_notify& evt) { * _NET_WM_WINDOW_OPACITY atom value */ void bar::handle(const evt::enter_notify&) { -#if 0 -#ifdef DEBUG_SHADED - if (m_opts.origin == edge::TOP) { - m_taskqueue->defer_unique("window-hover", 25ms, [&](size_t) { m_sig.emit(signals::ui::unshade_window{}); }); - return; - } -#endif -#endif if (m_opts.dimmed) { - m_taskqueue->defer_unique("window-dim", 25ms, [&](size_t) { + m_dim_timer->start(25, 0, [this]() { m_opts.dimmed = false; m_sig.emit(dim_window{1.0}); }); - } else if (m_taskqueue->exist("window-dim")) { - m_taskqueue->purge("window-dim"); + } else if (m_dim_timer->is_active()) { + m_dim_timer->stop(); } } @@ -626,19 +629,14 @@ void bar::handle(const evt::enter_notify&) { * _NET_WM_WINDOW_OPACITY atom value */ void bar::handle(const evt::leave_notify&) { -#if 0 -#ifdef DEBUG_SHADED - if (m_opts.origin == edge::TOP) { - m_taskqueue->defer_unique("window-hover", 25ms, [&](size_t) { m_sig.emit(signals::ui::shade_window{}); }); - return; - } -#endif -#endif - if (!m_opts.dimmed) { - m_taskqueue->defer_unique("window-dim", 3s, [&](size_t) { - m_opts.dimmed = true; - m_sig.emit(dim_window{double(m_opts.dimvalue)}); - }); + // Only trigger dimming, if the dim-value is not fully opaque. + if (m_opts.dimvalue < 1.0) { + if (!m_opts.dimmed) { + m_dim_timer->start(3000, 0, [this]() { + m_opts.dimmed = true; + m_sig.emit(dim_window{double(m_opts.dimvalue)}); + }); + } } } @@ -648,12 +646,6 @@ void bar::handle(const evt::leave_notify&) { * Used to change the cursor depending on the module */ void bar::handle(const evt::motion_notify& evt) { - if (!m_mutex.try_lock()) { - return; - } - - std::lock_guard guard(m_mutex, std::adopt_lock); - m_log.trace("bar: Detected motion: %i at pos(%i, %i)", evt->detail, evt->event_x, evt->event_y); #if WITH_XCURSOR m_motion_pos = evt->event_x; @@ -735,63 +727,37 @@ void bar::handle(const evt::motion_notify& evt) { * Used to map mouse clicks to bar actions */ void bar::handle(const evt::button_press& evt) { - if (!m_mutex.try_lock()) { - return; - } - - std::lock_guard guard(m_mutex, std::adopt_lock); - - if (m_buttonpress.deny(evt->time)) { - return m_log.trace_x("bar: Ignoring button press (throttled)..."); - } - m_log.trace("bar: Received button press: %i at pos(%i, %i)", evt->detail, evt->event_x, evt->event_y); - m_buttonpress_btn = static_cast(evt->detail); - m_buttonpress_pos = evt->event_x; + mousebtn btn = static_cast(evt->detail); + int pos = evt->event_x; - const auto deferred_fn = [&](size_t) { - tags::action_t action = m_action_ctxt->has_action(m_buttonpress_btn, m_buttonpress_pos); - - if (action != tags::NO_ACTION) { - m_log.trace("Found matching input area"); - m_sig.emit(button_press{m_action_ctxt->get_action(action)}); - return; - } - - for (auto&& action : m_opts.actions) { - if (action.button == m_buttonpress_btn && !action.command.empty()) { - m_log.trace("Found matching fallback handler"); - m_sig.emit(button_press{string{action.command}}); - return; - } - } - m_log.info("No matching input area found (btn=%i)", static_cast(m_buttonpress_btn)); - }; - - const auto check_double = [&](string&& id, mousebtn&& btn) { - if (!m_taskqueue->exist(id)) { - m_doubleclick.event = evt->time; - m_taskqueue->defer(id, taskqueue::deferred::duration{m_doubleclick.offset}, deferred_fn); - } else if (m_doubleclick.deny(evt->time)) { - m_doubleclick.event = 0; - m_buttonpress_btn = btn; - m_taskqueue->defer_unique(id, 0ms, deferred_fn); + /* + * For possible double-clicks we need to delay the triggering of the click by + * the configured interval and if in that time another click arrives, we + * need to trigger a double click. + */ + const auto check_double = [this](TimerHandle_t handle, mousebtn btn, int pos) { + if (!handle->is_active()) { + handle->start(m_opts.double_click_interval, 0, [=]() { trigger_click(btn, pos); }); + } else { + handle->stop(); + trigger_click(mousebtn_get_double(btn), pos); } }; // If there are no double click handlers defined we can // just by-pass the click timer handling if (!m_dblclicks) { - deferred_fn(0); - } else if (evt->detail == static_cast(mousebtn::LEFT)) { - check_double("buttonpress-left", mousebtn::DOUBLE_LEFT); - } else if (evt->detail == static_cast(mousebtn::MIDDLE)) { - check_double("buttonpress-middle", mousebtn::DOUBLE_MIDDLE); - } else if (evt->detail == static_cast(mousebtn::RIGHT)) { - check_double("buttonpress-right", mousebtn::DOUBLE_RIGHT); + trigger_click(btn, pos); + } else if (btn == mousebtn::LEFT) { + check_double(m_leftclick_timer, btn, pos); + } else if (btn == mousebtn::MIDDLE) { + check_double(m_middleclick_timer, btn, pos); + } else if (btn == mousebtn::RIGHT) { + check_double(m_rightclick_timer, btn, pos); } else { - deferred_fn(0); + trigger_click(btn, pos); } } @@ -876,110 +842,6 @@ void bar::start() { broadcast_visibility(); } -bool bar::on(const signals::ui::unshade_window&) { - m_opts.shaded = false; - m_opts.shade_size.w = m_opts.size.w; - m_opts.shade_size.h = m_opts.size.h; - m_opts.shade_pos.x = m_opts.pos.x; - m_opts.shade_pos.y = m_opts.pos.y; - - double distance{static_cast(m_opts.shade_size.h - m_connection.get_geometry(m_opts.window)->height)}; - double steptime{25.0 / 2.0}; - m_anim_step = distance / steptime / 2.0; - - m_taskqueue->defer_unique( - "window-shade", 25ms, - [&](size_t remaining) { - if (!m_opts.shaded) { - m_sig.emit(signals::ui::tick{}); - } - if (!remaining) { - m_renderer->flush(); - } - if (m_opts.dimmed) { - m_opts.dimmed = false; - m_sig.emit(dim_window{1.0}); - } - }, - taskqueue::deferred::duration{25ms}, 10U); - - return true; -} - -bool bar::on(const signals::ui::shade_window&) { - taskqueue::deferred::duration offset{2000ms}; - - if (!m_opts.shaded && m_opts.shade_size.h != m_opts.size.h) { - offset = taskqueue::deferred::duration{25ms}; - } - - m_opts.shaded = true; - m_opts.shade_size.h = 5; - m_opts.shade_size.w = m_opts.size.w; - m_opts.shade_pos.x = m_opts.pos.x; - m_opts.shade_pos.y = m_opts.pos.y; - - if (m_opts.origin == edge::BOTTOM) { - m_opts.shade_pos.y = m_opts.pos.y + m_opts.size.h - m_opts.shade_size.h; - } - - double distance{static_cast(m_connection.get_geometry(m_opts.window)->height - m_opts.shade_size.h)}; - double steptime{25.0 / 2.0}; - m_anim_step = distance / steptime / 2.0; - - m_taskqueue->defer_unique( - "window-shade", 25ms, - [&](size_t remaining) { - if (m_opts.shaded) { - m_sig.emit(signals::ui::tick{}); - } - if (!remaining) { - m_renderer->flush(); - } - if (!m_opts.dimmed) { - m_opts.dimmed = true; - m_sig.emit(dim_window{double{m_opts.dimvalue}}); - } - }, - move(offset), 10U); - - return true; -} - -bool bar::on(const signals::ui::tick&) { - auto geom = m_connection.get_geometry(m_opts.window); - if (geom->y == m_opts.shade_pos.y && geom->height == m_opts.shade_size.h) { - return false; - } - - unsigned int mask{0}; - unsigned int values[7]{0}; - xcb_params_configure_window_t params{}; - - if (m_opts.shade_size.h > geom->height) { - XCB_AUX_ADD_PARAM(&mask, ¶ms, height, static_cast(geom->height + m_anim_step)); - params.height = std::max(1U, std::min(params.height, static_cast(m_opts.shade_size.h))); - } else if (m_opts.shade_size.h < geom->height) { - XCB_AUX_ADD_PARAM(&mask, ¶ms, height, static_cast(geom->height - m_anim_step)); - params.height = std::max(1U, std::max(params.height, static_cast(m_opts.shade_size.h))); - } - - if (m_opts.shade_pos.y > geom->y) { - XCB_AUX_ADD_PARAM(&mask, ¶ms, y, static_cast(geom->y + m_anim_step)); - params.y = std::min(params.y, static_cast(m_opts.shade_pos.y)); - } else if (m_opts.shade_pos.y < geom->y) { - XCB_AUX_ADD_PARAM(&mask, ¶ms, y, static_cast(geom->y - m_anim_step)); - params.y = std::max(params.y, static_cast(m_opts.shade_pos.y)); - } - - connection::pack_values(mask, ¶ms, values); - - m_connection.configure_window(m_opts.window, mask, values); - m_connection.flush(); - - return false; -} - bool bar::on(const signals::ui::dim_window& sig) { m_opts.dimmed = sig.cast() != 1.0; ewmh_util::set_wm_window_opacity(m_opts.window, sig.cast() * 0xFFFFFFFF); diff --git a/src/components/controller.cpp b/src/components/controller.cpp index 85bca3b2..392daa4b 100644 --- a/src/components/controller.cpp +++ b/src/components/controller.cpp @@ -31,20 +31,21 @@ POLYBAR_NS * Build controller instance */ controller::make_type controller::make(unique_ptr&& ipc) { - return std::make_unique(connection::make(), signal_emitter::make(), logger::make(), config::make(), - bar::make(), forward(ipc)); + return std::make_unique( + connection::make(), signal_emitter::make(), logger::make(), config::make(), forward(ipc)); } /** * Construct controller */ -controller::controller(connection& conn, signal_emitter& emitter, const logger& logger, const config& config, - unique_ptr&& bar, unique_ptr&& ipc) +controller::controller( + connection& conn, signal_emitter& emitter, const logger& logger, const config& config, unique_ptr&& ipc) : m_connection(conn) , m_sig(emitter) , m_log(logger) , m_conf(config) - , m_bar(forward(bar)) + , m_loop(make_unique()) + , m_bar(bar::make(*m_loop)) , m_ipc(forward(ipc)) { m_conf.ignore_key("settings", "throttle-input-for"); m_conf.ignore_key("settings", "throttle-output"); @@ -152,14 +153,14 @@ void controller::trigger_update(bool force) { } void controller::trigger_notification() { - if (m_eloop_ready) { + if (m_loop_ready) { m_notifier->send(); } } void controller::stop(bool reload) { update_reload(reload); - eloop->stop(); + m_loop->stop(); } void controller::conn_cb(uv_poll_event) { @@ -210,7 +211,7 @@ void controller::notifier_handler() { if (data.quit) { update_reload(data.reload); - eloop->stop(); + m_loop->stop(); return; } @@ -234,29 +235,23 @@ void controller::screenshot_handler() { void controller::read_events(bool confwatch) { m_log.info("Entering event loop (thread-id=%lu)", this_thread::get_id()); - if (!m_writeback) { - m_bar->start(); - } - try { - eloop = std::make_unique(); - - eloop->poll_handle( + m_loop->poll_handle( UV_READABLE, m_connection.get_file_descriptor(), [this](uv_poll_event events) { conn_cb(events); }, [](int status) { throw runtime_error("libuv error while polling X connection: "s + uv_strerror(status)); }); for (auto s : {SIGINT, SIGQUIT, SIGTERM, SIGUSR1, SIGALRM}) { - eloop->signal_handle(s, [this](int signum) { signal_handler(signum); }); + m_loop->signal_handle(s, [this](int signum) { signal_handler(signum); }); } if (confwatch) { - eloop->fs_event_handle( + m_loop->fs_event_handle( m_conf.filepath(), [this](const char* path, uv_fs_event events) { confwatch_handler(path, events); }, [this](int err) { m_log.err("libuv error while watching config file for changes: %s", uv_strerror(err)); }); } if (m_ipc) { - eloop->pipe_handle( + m_loop->pipe_handle( m_ipc->get_path(), [this](const string payload) { m_ipc->receive_data(payload); }, [this]() { m_ipc->receive_eof(); }, [this](int err) { m_log.err("libuv error while listening to IPC channel: %s", uv_strerror(err)); }); @@ -264,19 +259,23 @@ void controller::read_events(bool confwatch) { if (!m_snapshot_dst.empty()) { // Trigger a single screenshot after 3 seconds - eloop->timer_handle(3000, 0, [this]() { screenshot_handler(); }); + m_loop->timer_handle([this]() { screenshot_handler(); })->start(3000, 0); } - m_notifier = eloop->async_handle([this]() { notifier_handler(); }); + m_notifier = m_loop->async_handle([this]() { notifier_handler(); }); - m_eloop_ready.store(true); + m_loop_ready = true; + + if (!m_writeback) { + m_bar->start(); + } /* * Immediately trigger and update so that the bar displays something. */ trigger_update(true); - eloop->run(); + m_loop->run(); } catch (const exception& err) { m_log.err("Fatal Error in eventloop: %s", err.what()); stop(false); @@ -284,7 +283,8 @@ void controller::read_events(bool confwatch) { m_log.info("Eventloop finished"); - eloop.reset(); + m_loop_ready = false; + m_loop.reset(); } /** diff --git a/src/components/eventloop.cpp b/src/components/eventloop.cpp index cca21ebb..66947c52 100644 --- a/src/components/eventloop.cpp +++ b/src/components/eventloop.cpp @@ -141,7 +141,7 @@ void PipeHandle::read_cb(ssize_t nread, const uv_buf_t* buf) { * * We reuse the memory for the underlying uv handle */ - if (!uv_is_closing((uv_handle_t*)handle)) { + if (!is_closing()) { uv_close((uv_handle_t*)handle, [](uv_handle_t* handle) { PipeHandle* This = static_cast(handle->data); UV(uv_pipe_init, This->loop(), This->handle, false); @@ -158,9 +158,17 @@ TimerHandle::TimerHandle(uv_loop_t* loop, function fun) : UVHandle(f UV(uv_timer_init, loop, handle); } -void TimerHandle::start(uint64_t timeout, uint64_t repeat) { +void TimerHandle::start(uint64_t timeout, uint64_t repeat, function new_cb) { + if (new_cb) { + this->func = new_cb; + } + UV(uv_timer_start, handle, callback, timeout, repeat); } + +void TimerHandle::stop() { + UV(uv_timer_stop, handle); +} // }}} // AsyncHandle {{{ @@ -243,9 +251,9 @@ void eventloop::pipe_handle( m_pipe_handles.back()->start(); } -void eventloop::timer_handle(uint64_t timeout, uint64_t repeat, function fun) { - m_timer_handles.emplace_back(std::make_unique(get(), fun)); - m_timer_handles.back()->start(timeout, repeat); +TimerHandle_t eventloop::timer_handle(function fun) { + m_timer_handles.emplace_back(std::make_shared(get(), fun)); + return m_timer_handles.back(); } AsyncHandle_t eventloop::async_handle(function fun) { diff --git a/src/components/renderer.cpp b/src/components/renderer.cpp index 2a668e47..c79e5e74 100644 --- a/src/components/renderer.cpp +++ b/src/components/renderer.cpp @@ -381,25 +381,6 @@ void renderer::flush() { highlight_clickable_areas(); -#if 0 -#ifdef DEBUG_SHADED - if (m_bar.shaded && m_bar.origin == edge::TOP) { - m_log.trace_x( - "renderer: copy pixmap (shaded=1, geom=%dx%d+%d+%d)", m_rect.width, m_rect.height, m_rect.x, m_rect.y); - auto geom = m_connection.get_geometry(m_window); - auto x1 = 0; - auto y1 = m_rect.height - m_bar.shade_size.h - m_rect.y - geom->height; - auto x2 = m_rect.x; - auto y2 = m_rect.y; - auto w = m_rect.width; - auto h = m_rect.height - m_bar.shade_size.h + geom->height; - m_connection.copy_area(m_pixmap, m_window, m_gcontext, x1, y1, x2, y2, w, h); - m_connection.flush(); - return; - } -#endif -#endif - m_surface->flush(); m_connection.copy_area(m_pixmap, m_window, m_gcontext, 0, 0, 0, 0, m_bar.size.w, m_bar.size.h); m_connection.flush(); diff --git a/src/components/taskqueue.cpp b/src/components/taskqueue.cpp deleted file mode 100644 index b0ba3bbe..00000000 --- a/src/components/taskqueue.cpp +++ /dev/null @@ -1,109 +0,0 @@ -#include "components/taskqueue.hpp" - -#include - -POLYBAR_NS - -taskqueue::make_type taskqueue::make() { - return std::make_unique(); -} - -taskqueue::taskqueue() { - m_thread = std::thread([&] { - while (m_active) { - std::unique_lock guard(m_lock); - - if (m_deferred.empty()) { - m_hold.wait(guard); - } else { - auto now = deferred::clock::now(); - auto wait = m_deferred.front()->now + m_deferred.front()->wait; - for (auto&& task : m_deferred) { - auto when = task->now + task->wait; - if (when < wait) { - wait = move(when); - } - } - if (wait > now) { - m_hold.wait_for(guard, wait - now); - } - } - if (!m_deferred.empty()) { - guard.unlock(); - tick(); - } - } - }); -} - -taskqueue::~taskqueue() { - if (m_active && m_thread.joinable()) { - m_active = false; - m_hold.notify_all(); - m_thread.join(); - } -} - -void taskqueue::defer( - string id, deferred::duration ms, deferred::callback fn, deferred::duration offset, size_t count) { - std::unique_lock guard(m_lock); - deferred::timepoint now{chrono::time_point_cast(deferred::clock::now() + move(offset))}; - m_deferred.emplace_back(make_unique(move(id), move(now), move(ms), move(fn), move(count))); - guard.unlock(); - m_hold.notify_one(); -} - -void taskqueue::defer_unique( - string id, deferred::duration ms, deferred::callback fn, deferred::duration offset, size_t count) { - purge(id); - std::unique_lock guard(m_lock); - deferred::timepoint now{chrono::time_point_cast(deferred::clock::now() + move(offset))}; - m_deferred.emplace_back(make_unique(move(id), move(now), move(ms), move(fn), move(count))); - guard.unlock(); - m_hold.notify_one(); -} - -void taskqueue::tick() { - if (!m_lock.try_lock()) { - return; - } - std::unique_lock guard(m_lock, std::adopt_lock); - auto now = chrono::time_point_cast(deferred::clock::now()); - vector> cbs; - for (auto it = m_deferred.rbegin(); it != m_deferred.rend(); ++it) { - auto& task = *it; - if (task->now + task->wait > now) { - continue; - } else if (task->count--) { - cbs.emplace_back(make_pair(task->func, task->count)); - task->now = now; - } else { - m_deferred.erase(std::remove_if(m_deferred.begin(), m_deferred.end(), - [&](const unique_ptr& d) { return d == task; }), - m_deferred.end()); - } - } - guard.unlock(); - for (auto&& p : cbs) { - p.first(p.second); - } -} - -bool taskqueue::purge(const string& id) { - std::lock_guard guard(m_lock); - return m_deferred.erase(std::remove_if(m_deferred.begin(), m_deferred.end(), - [id](const unique_ptr& d) { return d->id == id; }), - m_deferred.end()) == m_deferred.end(); -} - -bool taskqueue::exist(const string& id) { - std::lock_guard guard(m_lock); - for (const auto& task : m_deferred) { - if (task->id == id) { - return true; - } - } - return false; -} - -POLYBAR_NS_END diff --git a/src/main.cpp b/src/main.cpp index 5320dd75..f0d8ddb2 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -127,7 +127,8 @@ int main(int argc, char** argv) { return EXIT_SUCCESS; } if (cli->has("print-wmname")) { - printf("%s\n", bar::make(true)->settings().wmname.c_str()); + eventloop loop{}; + printf("%s\n", bar::make(loop, true)->settings().wmname.c_str()); return EXIT_SUCCESS; } diff --git a/src/utils/env.cpp b/src/utils/env.cpp index 575ffb42..b28ce768 100644 --- a/src/utils/env.cpp +++ b/src/utils/env.cpp @@ -1,10 +1,9 @@ +#include "utils/env.hpp" + #include #include -#include #include -#include "utils/env.hpp" - POLYBAR_NS namespace env_util { @@ -17,6 +16,6 @@ namespace env_util { const char* value{std::getenv(var.c_str())}; return value != nullptr ? value : move(fallback); } -} +} // namespace env_util POLYBAR_NS_END