Integrate bar taskqueue into eventloop (#2510)
* Remove DEBUG_SHADED Was disabled by default AND behind an #if 0 * Make TimerHandle expose more libuv functions * Prepare for moving double clicks into eventloop * Make eventloop available to bar * Remove bar mutex Everything in the bar is now in the same thread * Move double-click handling to eventloop * Extract double click deferred function into method * Stop throttling clicks * Increase double click interval to 400 and add option double-click-interval in the bar section Closes #1441 * Implement dimming using timer handles * Remove taskqueue * Remove unused dependencies * Cleanup & Comments
This commit is contained in:
parent
55eb19fdc7
commit
8afd5b71df
11
CHANGELOG.md
11
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
|
||||
|
@ -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()
|
||||
|
@ -5,6 +5,7 @@
|
||||
#include <mutex>
|
||||
|
||||
#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<evt::button_press, evt::expose, evt::property_notify, evt::enter_notify,
|
||||
evt::leave_notify, evt::motion_notify, evt::destroy_notify, evt::client_message, evt::configure_notify>,
|
||||
public signal_receiver<SIGN_PRIORITY_BAR, signals::ui::tick, signals::ui::shade_window,
|
||||
signals::ui::unshade_window, signals::ui::dim_window
|
||||
public signal_receiver<SIGN_PRIORITY_BAR, signals::ui::dim_window
|
||||
#if WITH_XCURSOR
|
||||
,
|
||||
signals::ui::cursor_change
|
||||
@ -64,11 +63,11 @@ class bar : public xpp::event::sink<evt::button_press, evt::expose, evt::propert
|
||||
> {
|
||||
public:
|
||||
using make_type = unique_ptr<bar>;
|
||||
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<screen>&&,
|
||||
explicit bar(connection&, signal_emitter&, const config&, const logger&, eventloop&, unique_ptr<screen>&&,
|
||||
unique_ptr<tray_manager>&&, unique_ptr<tags::dispatch>&&, unique_ptr<tags::action_context>&&,
|
||||
unique_ptr<taskqueue>&&, bool only_initialize_values);
|
||||
bool only_initialize_values);
|
||||
~bar();
|
||||
|
||||
const bar_settings settings() const;
|
||||
@ -90,6 +89,8 @@ class bar : public xpp::event::sink<evt::button_press, evt::expose, evt::propert
|
||||
void reconfigure_wm_hints();
|
||||
void broadcast_visibility();
|
||||
|
||||
void trigger_click(mousebtn btn, int pos);
|
||||
|
||||
void handle(const evt::client_message& evt) override;
|
||||
void handle(const evt::destroy_notify& evt) override;
|
||||
void handle(const evt::enter_notify& evt) override;
|
||||
@ -100,9 +101,6 @@ class bar : public xpp::event::sink<evt::button_press, evt::expose, evt::propert
|
||||
void handle(const evt::property_notify& evt) override;
|
||||
void handle(const evt::configure_notify& evt) override;
|
||||
|
||||
bool on(const signals::ui::unshade_window&) override;
|
||||
bool on(const signals::ui::shade_window&) override;
|
||||
bool on(const signals::ui::tick&) override;
|
||||
bool on(const signals::ui::dim_window&) override;
|
||||
#if WITH_XCURSOR
|
||||
bool on(const signals::ui::cursor_change&) override;
|
||||
@ -113,29 +111,26 @@ class bar : public xpp::event::sink<evt::button_press, evt::expose, evt::propert
|
||||
signal_emitter& m_sig;
|
||||
const config& m_conf;
|
||||
const logger& m_log;
|
||||
eventloop& m_loop;
|
||||
unique_ptr<screen> m_screen;
|
||||
unique_ptr<tray_manager> m_tray;
|
||||
unique_ptr<renderer> m_renderer;
|
||||
unique_ptr<tags::dispatch> m_dispatch;
|
||||
unique_ptr<tags::action_context> m_action_ctxt;
|
||||
unique_ptr<taskqueue> m_taskqueue;
|
||||
|
||||
bar_settings m_opts{};
|
||||
|
||||
string m_lastinput{};
|
||||
std::mutex m_mutex{};
|
||||
std::atomic<bool> 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};
|
||||
};
|
||||
|
@ -2,7 +2,6 @@
|
||||
|
||||
#include <atomic>
|
||||
#include <mutex>
|
||||
#include <thread>
|
||||
|
||||
#include "common.hpp"
|
||||
#include "components/eventloop.hpp"
|
||||
@ -42,7 +41,7 @@ class controller : public signal_receiver<SIGN_PRIORITY_CONTROLLER, signals::eve
|
||||
using make_type = unique_ptr<controller>;
|
||||
static make_type make(unique_ptr<ipc>&& ipc);
|
||||
|
||||
explicit controller(connection&, signal_emitter&, const logger&, const config&, unique_ptr<bar>&&, unique_ptr<ipc>&&);
|
||||
explicit controller(connection&, signal_emitter&, const logger&, const config&, unique_ptr<ipc>&&);
|
||||
~controller();
|
||||
|
||||
bool run(bool writeback, string snapshot_dst, bool confwatch);
|
||||
@ -98,15 +97,14 @@ class controller : public signal_receiver<SIGN_PRIORITY_CONTROLLER, signals::eve
|
||||
signal_emitter& m_sig;
|
||||
const logger& m_log;
|
||||
const config& m_conf;
|
||||
unique_ptr<eventloop> m_loop;
|
||||
unique_ptr<bar> m_bar;
|
||||
unique_ptr<ipc> m_ipc;
|
||||
|
||||
std::unique_ptr<eventloop> 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
|
||||
|
@ -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<uv_pipe_t, uv_stream_t, ssize_t, cons
|
||||
|
||||
struct TimerHandle : public UVHandle<uv_timer_t> {
|
||||
TimerHandle(uv_loop_t* loop, function<void(void)> fun);
|
||||
void start(uint64_t timeout, uint64_t repeat);
|
||||
void start(uint64_t timeout, uint64_t repeat, function<void(void)> new_cb = function<void(void)>(nullptr));
|
||||
void stop();
|
||||
};
|
||||
|
||||
struct AsyncHandle : public UVHandle<uv_async_t> {
|
||||
@ -121,8 +130,8 @@ using SignalHandle_t = std::unique_ptr<SignalHandle>;
|
||||
using PollHandle_t = std::unique_ptr<PollHandle>;
|
||||
using FSEventHandle_t = std::unique_ptr<FSEventHandle>;
|
||||
using PipeHandle_t = std::unique_ptr<PipeHandle>;
|
||||
using TimerHandle_t = std::unique_ptr<TimerHandle>;
|
||||
// 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<TimerHandle>;
|
||||
using AsyncHandle_t = std::shared_ptr<AsyncHandle>;
|
||||
|
||||
class eventloop {
|
||||
@ -136,7 +145,7 @@ class eventloop {
|
||||
void fs_event_handle(const string& path, function<void(const char*, uv_fs_event)> fun, function<void(int)> err_cb);
|
||||
void pipe_handle(
|
||||
const string& path, function<void(const string)> fun, function<void(void)> eof_cb, function<void(int)> err_cb);
|
||||
void timer_handle(uint64_t timeout, uint64_t repeat, function<void(void)> fun);
|
||||
TimerHandle_t timer_handle(function<void(void)> fun);
|
||||
AsyncHandle_t async_handle(function<void(void)> fun);
|
||||
|
||||
protected:
|
||||
|
@ -1,62 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <atomic>
|
||||
#include <chrono>
|
||||
#include <condition_variable>
|
||||
#include <mutex>
|
||||
#include <thread>
|
||||
|
||||
#include "common.hpp"
|
||||
#include "utils/mixins.hpp"
|
||||
|
||||
POLYBAR_NS
|
||||
|
||||
namespace chrono = std::chrono;
|
||||
using namespace std::chrono_literals;
|
||||
|
||||
class taskqueue : non_copyable_mixin<taskqueue> {
|
||||
public:
|
||||
struct deferred {
|
||||
using clock = chrono::high_resolution_clock;
|
||||
using duration = chrono::milliseconds;
|
||||
using timepoint = chrono::time_point<clock, duration>;
|
||||
using callback = function<void(size_t remaining)>;
|
||||
|
||||
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<taskqueue>;
|
||||
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<unique_ptr<deferred>> m_deferred;
|
||||
};
|
||||
|
||||
POLYBAR_NS_END
|
@ -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);
|
||||
|
||||
|
@ -80,9 +80,6 @@ namespace signals {
|
||||
struct changed : public detail::base_signal<changed> {
|
||||
using base_type::base_type;
|
||||
};
|
||||
struct tick : public detail::base_signal<tick> {
|
||||
using base_type::base_type;
|
||||
};
|
||||
struct button_press : public detail::value_signal<button_press, string> {
|
||||
using base_type::base_type;
|
||||
};
|
||||
@ -95,12 +92,6 @@ namespace signals {
|
||||
struct dim_window : public detail::value_signal<dim_window, double> {
|
||||
using base_type::base_type;
|
||||
};
|
||||
struct shade_window : public detail::base_signal<shade_window> {
|
||||
using base_type::base_type;
|
||||
};
|
||||
struct unshade_window : public detail::base_signal<unshade_window> {
|
||||
using base_type::base_type;
|
||||
};
|
||||
struct request_snapshot : public detail::value_signal<request_snapshot, string> {
|
||||
using base_type::base_type;
|
||||
};
|
||||
|
@ -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;
|
||||
|
@ -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
|
||||
|
||||
|
@ -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
|
||||
|
@ -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<tags::action_context>();
|
||||
|
||||
// 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>&& screen, unique_ptr<tray_manager>&& tray_manager, unique_ptr<tags::dispatch>&& dispatch,
|
||||
unique_ptr<tags::action_context>&& action_ctxt, unique_ptr<taskqueue>&& taskqueue, bool only_initialize_values)
|
||||
unique_ptr<tags::action_context>&& action_ctxt, bool only_initialize_values)
|
||||
: m_connection(conn)
|
||||
, m_sig(emitter)
|
||||
, m_conf(config)
|
||||
, m_log(logger)
|
||||
, m_loop(loop)
|
||||
, m_screen(forward<decltype(screen)>(screen))
|
||||
, m_tray(forward<decltype(tray_manager)>(tray_manager))
|
||||
, m_dispatch(forward<decltype(dispatch)>(dispatch))
|
||||
, m_action_ctxt(forward<decltype(action_ctxt)>(action_ctxt))
|
||||
, m_taskqueue(forward<decltype(taskqueue)>(taskqueue)) {
|
||||
, m_action_ctxt(forward<decltype(action_ctxt)>(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<std::mutex> 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<std::mutex> 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<int>(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<std::mutex> 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<std::mutex> 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<mousebtn>(evt->detail);
|
||||
m_buttonpress_pos = evt->event_x;
|
||||
mousebtn btn = static_cast<mousebtn>(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<int>(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<int>(mousebtn::LEFT)) {
|
||||
check_double("buttonpress-left", mousebtn::DOUBLE_LEFT);
|
||||
} else if (evt->detail == static_cast<int>(mousebtn::MIDDLE)) {
|
||||
check_double("buttonpress-middle", mousebtn::DOUBLE_MIDDLE);
|
||||
} else if (evt->detail == static_cast<int>(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<double>(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<double>(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<unsigned int>(geom->height + m_anim_step));
|
||||
params.height = std::max(1U, std::min(params.height, static_cast<unsigned int>(m_opts.shade_size.h)));
|
||||
} else if (m_opts.shade_size.h < geom->height) {
|
||||
XCB_AUX_ADD_PARAM(&mask, ¶ms, height, static_cast<unsigned int>(geom->height - m_anim_step));
|
||||
params.height = std::max(1U, std::max(params.height, static_cast<unsigned int>(m_opts.shade_size.h)));
|
||||
}
|
||||
|
||||
if (m_opts.shade_pos.y > geom->y) {
|
||||
XCB_AUX_ADD_PARAM(&mask, ¶ms, y, static_cast<int>(geom->y + m_anim_step));
|
||||
params.y = std::min(params.y, static_cast<int>(m_opts.shade_pos.y));
|
||||
} else if (m_opts.shade_pos.y < geom->y) {
|
||||
XCB_AUX_ADD_PARAM(&mask, ¶ms, y, static_cast<int>(geom->y - m_anim_step));
|
||||
params.y = std::max(params.y, static_cast<int>(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);
|
||||
|
@ -31,20 +31,21 @@ POLYBAR_NS
|
||||
* Build controller instance
|
||||
*/
|
||||
controller::make_type controller::make(unique_ptr<ipc>&& ipc) {
|
||||
return std::make_unique<controller>(connection::make(), signal_emitter::make(), logger::make(), config::make(),
|
||||
bar::make(), forward<decltype(ipc)>(ipc));
|
||||
return std::make_unique<controller>(
|
||||
connection::make(), signal_emitter::make(), logger::make(), config::make(), forward<decltype(ipc)>(ipc));
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct controller
|
||||
*/
|
||||
controller::controller(connection& conn, signal_emitter& emitter, const logger& logger, const config& config,
|
||||
unique_ptr<bar>&& bar, unique_ptr<ipc>&& ipc)
|
||||
controller::controller(
|
||||
connection& conn, signal_emitter& emitter, const logger& logger, const config& config, unique_ptr<ipc>&& ipc)
|
||||
: m_connection(conn)
|
||||
, m_sig(emitter)
|
||||
, m_log(logger)
|
||||
, m_conf(config)
|
||||
, m_bar(forward<decltype(bar)>(bar))
|
||||
, m_loop(make_unique<eventloop>())
|
||||
, m_bar(bar::make(*m_loop))
|
||||
, m_ipc(forward<decltype(ipc)>(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<eventloop>();
|
||||
|
||||
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();
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -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<PipeHandle*>(handle->data);
|
||||
UV(uv_pipe_init, This->loop(), This->handle, false);
|
||||
@ -158,9 +158,17 @@ TimerHandle::TimerHandle(uv_loop_t* loop, function<void(void)> 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<void(void)> 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<void(void)> fun) {
|
||||
m_timer_handles.emplace_back(std::make_unique<TimerHandle>(get(), fun));
|
||||
m_timer_handles.back()->start(timeout, repeat);
|
||||
TimerHandle_t eventloop::timer_handle(function<void(void)> fun) {
|
||||
m_timer_handles.emplace_back(std::make_shared<TimerHandle>(get(), fun));
|
||||
return m_timer_handles.back();
|
||||
}
|
||||
|
||||
AsyncHandle_t eventloop::async_handle(function<void(void)> fun) {
|
||||
|
@ -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();
|
||||
|
@ -1,109 +0,0 @@
|
||||
#include "components/taskqueue.hpp"
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
POLYBAR_NS
|
||||
|
||||
taskqueue::make_type taskqueue::make() {
|
||||
return std::make_unique<taskqueue>();
|
||||
}
|
||||
|
||||
taskqueue::taskqueue() {
|
||||
m_thread = std::thread([&] {
|
||||
while (m_active) {
|
||||
std::unique_lock<std::mutex> 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<std::mutex> guard(m_lock);
|
||||
deferred::timepoint now{chrono::time_point_cast<deferred::duration>(deferred::clock::now() + move(offset))};
|
||||
m_deferred.emplace_back(make_unique<deferred>(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<std::mutex> guard(m_lock);
|
||||
deferred::timepoint now{chrono::time_point_cast<deferred::duration>(deferred::clock::now() + move(offset))};
|
||||
m_deferred.emplace_back(make_unique<deferred>(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<std::mutex> guard(m_lock, std::adopt_lock);
|
||||
auto now = chrono::time_point_cast<deferred::duration>(deferred::clock::now());
|
||||
vector<pair<deferred::callback, size_t>> 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<deferred>& 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<std::mutex> guard(m_lock);
|
||||
return m_deferred.erase(std::remove_if(m_deferred.begin(), m_deferred.end(),
|
||||
[id](const unique_ptr<deferred>& d) { return d->id == id; }),
|
||||
m_deferred.end()) == m_deferred.end();
|
||||
}
|
||||
|
||||
bool taskqueue::exist(const string& id) {
|
||||
std::lock_guard<std::mutex> guard(m_lock);
|
||||
for (const auto& task : m_deferred) {
|
||||
if (task->id == id) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
POLYBAR_NS_END
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -1,10 +1,9 @@
|
||||
#include "utils/env.hpp"
|
||||
|
||||
#include <cstdlib>
|
||||
#include <cstring>
|
||||
#include <thread>
|
||||
#include <utility>
|
||||
|
||||
#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
|
||||
|
Loading…
Reference in New Issue
Block a user