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:
Patrick Ziegler 2021-09-27 17:35:45 +02:00 committed by GitHub
parent 55eb19fdc7
commit 8afd5b71df
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
18 changed files with 156 additions and 471 deletions

View File

@ -59,6 +59,9 @@ 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 triggers if they happen directly after one another, leading to only a single
bar update. bar update.
### Removed
- `DEBUG_SHADED` cmake variable and its associated functionality.
### Added ### Added
- `drawtypes/ramp`: Add support for ramp weights. - `drawtypes/ramp`: Add support for ramp weights.
([1750](https://github.com/polybar/polybar/issues/1750)) ([1750](https://github.com/polybar/polybar/issues/1750))
@ -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)) ([`#2427`](https://github.com/polybar/polybar/issues/2427))
- `custom/ipc`: `send` action to send arbitrary strings to be displayed in the module. - `custom/ipc`: `send` action to send arbitrary strings to be displayed in the module.
([`#2455`](https://github.com/polybar/polybar/issues/2455)) ([`#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 ### Changed
- We rewrote polybar's main event loop. This shouldn't change any behavior for - 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`: - `internal/network`:
- Increased precision for upload and download speeds: 0 decimal places for - Increased precision for upload and download speeds: 0 decimal places for
KB/s (as before), 1 for MB/s and 2 for GB/s. 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 ### Fixed
- Trailing space after the layout label when indicators are empty and made sure right amount - Trailing space after the layout label when indicators are empty and made sure right amount

View File

@ -55,6 +55,5 @@ if (BUILD_LIBPOLY)
colored_option(" Trace logging (verbose)" DEBUG_LOGGER_VERBOSE) colored_option(" Trace logging (verbose)" DEBUG_LOGGER_VERBOSE)
colored_option(" Draw clickable areas" DEBUG_HINTS) colored_option(" Draw clickable areas" DEBUG_HINTS)
colored_option(" Print fc-match details" DEBUG_FONTCONFIG) colored_option(" Print fc-match details" DEBUG_FONTCONFIG)
colored_option(" Enable window shading" DEBUG_SHADED)
endif() endif()
endif() endif()

View File

@ -5,6 +5,7 @@
#include <mutex> #include <mutex>
#include "common.hpp" #include "common.hpp"
#include "components/eventloop.hpp"
#include "components/types.hpp" #include "components/types.hpp"
#include "errors.hpp" #include "errors.hpp"
#include "events/signal_fwd.hpp" #include "events/signal_fwd.hpp"
@ -23,7 +24,6 @@ class connection;
class logger; class logger;
class renderer; class renderer;
class screen; class screen;
class taskqueue;
class tray_manager; class tray_manager;
namespace tags { 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, 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>, 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, public signal_receiver<SIGN_PRIORITY_BAR, signals::ui::dim_window
signals::ui::unshade_window, signals::ui::dim_window
#if WITH_XCURSOR #if WITH_XCURSOR
, ,
signals::ui::cursor_change signals::ui::cursor_change
@ -64,11 +63,11 @@ class bar : public xpp::event::sink<evt::button_press, evt::expose, evt::propert
> { > {
public: public:
using make_type = unique_ptr<bar>; 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<tray_manager>&&, unique_ptr<tags::dispatch>&&, unique_ptr<tags::action_context>&&,
unique_ptr<taskqueue>&&, bool only_initialize_values); bool only_initialize_values);
~bar(); ~bar();
const bar_settings settings() const; 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 reconfigure_wm_hints();
void broadcast_visibility(); void broadcast_visibility();
void trigger_click(mousebtn btn, int pos);
void handle(const evt::client_message& evt) override; void handle(const evt::client_message& evt) override;
void handle(const evt::destroy_notify& evt) override; void handle(const evt::destroy_notify& evt) override;
void handle(const evt::enter_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::property_notify& evt) override;
void handle(const evt::configure_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; bool on(const signals::ui::dim_window&) override;
#if WITH_XCURSOR #if WITH_XCURSOR
bool on(const signals::ui::cursor_change&) override; 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; signal_emitter& m_sig;
const config& m_conf; const config& m_conf;
const logger& m_log; const logger& m_log;
eventloop& m_loop;
unique_ptr<screen> m_screen; unique_ptr<screen> m_screen;
unique_ptr<tray_manager> m_tray; unique_ptr<tray_manager> m_tray;
unique_ptr<renderer> m_renderer; unique_ptr<renderer> m_renderer;
unique_ptr<tags::dispatch> m_dispatch; unique_ptr<tags::dispatch> m_dispatch;
unique_ptr<tags::action_context> m_action_ctxt; unique_ptr<tags::action_context> m_action_ctxt;
unique_ptr<taskqueue> m_taskqueue;
bar_settings m_opts{}; bar_settings m_opts{};
string m_lastinput{}; string m_lastinput{};
std::mutex m_mutex{}; bool m_dblclicks{false};
std::atomic<bool> m_dblclicks{false};
mousebtn m_buttonpress_btn{mousebtn::NONE};
int m_buttonpress_pos{0};
#if WITH_XCURSOR #if WITH_XCURSOR
int m_motion_pos{0}; int m_motion_pos{0};
#endif #endif
event_timer m_buttonpress{0L, 5L}; TimerHandle_t m_leftclick_timer{m_loop.timer_handle(nullptr)};
event_timer m_doubleclick{0L, 150L}; TimerHandle_t m_middleclick_timer{m_loop.timer_handle(nullptr)};
TimerHandle_t m_rightclick_timer{m_loop.timer_handle(nullptr)};
double m_anim_step{0.0}; TimerHandle_t m_dim_timer{m_loop.timer_handle(nullptr)};
bool m_visible{true}; bool m_visible{true};
}; };

View File

@ -2,7 +2,6 @@
#include <atomic> #include <atomic>
#include <mutex> #include <mutex>
#include <thread>
#include "common.hpp" #include "common.hpp"
#include "components/eventloop.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>; using make_type = unique_ptr<controller>;
static make_type make(unique_ptr<ipc>&& ipc); 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(); ~controller();
bool run(bool writeback, string snapshot_dst, bool confwatch); 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; signal_emitter& m_sig;
const logger& m_log; const logger& m_log;
const config& m_conf; const config& m_conf;
unique_ptr<eventloop> m_loop;
unique_ptr<bar> m_bar; unique_ptr<bar> m_bar;
unique_ptr<ipc> m_ipc; 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 * \brief Async handle to notify the eventloop

View File

@ -45,11 +45,19 @@ struct UVHandleGeneric {
} }
void close() { void close() {
if (handle && !uv_is_closing((uv_handle_t*)handle)) { if (!is_closing()) {
uv_close((uv_handle_t*)handle, close_callback); 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() { void cleanup_resources() {
if (handle) { if (handle) {
delete 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> { struct TimerHandle : public UVHandle<uv_timer_t> {
TimerHandle(uv_loop_t* loop, function<void(void)> fun); 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> { 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 PollHandle_t = std::unique_ptr<PollHandle>;
using FSEventHandle_t = std::unique_ptr<FSEventHandle>; using FSEventHandle_t = std::unique_ptr<FSEventHandle>;
using PipeHandle_t = std::unique_ptr<PipeHandle>; using PipeHandle_t = std::unique_ptr<PipeHandle>;
using TimerHandle_t = std::unique_ptr<TimerHandle>; // shared_ptr because we also return the pointer in order to call methods on it
// shared_ptr because we need a reference outside to call send using TimerHandle_t = std::shared_ptr<TimerHandle>;
using AsyncHandle_t = std::shared_ptr<AsyncHandle>; using AsyncHandle_t = std::shared_ptr<AsyncHandle>;
class eventloop { 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 fs_event_handle(const string& path, function<void(const char*, uv_fs_event)> fun, function<void(int)> err_cb);
void pipe_handle( void pipe_handle(
const string& path, function<void(const string)> fun, function<void(void)> eof_cb, function<void(int)> err_cb); 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); AsyncHandle_t async_handle(function<void(void)> fun);
protected: protected:

View File

@ -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

View File

@ -46,6 +46,19 @@ enum class mousebtn {
BTN_COUNT, 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 { enum class strut {
LEFT = 0, LEFT = 0,
RIGHT, RIGHT,
@ -146,6 +159,8 @@ struct bar_settings {
bool override_redirect{false}; bool override_redirect{false};
int double_click_interval{400};
string cursor{}; string cursor{};
string cursor_click{}; string cursor_click{};
string cursor_scroll{}; string cursor_scroll{};
@ -155,12 +170,6 @@ struct bar_settings {
bool dimmed{false}; bool dimmed{false};
double dimvalue{1.0}; 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 { const xcb_rectangle_t inner_area(bool abspos = false) const {
xcb_rectangle_t rect = this->outer_area(abspos); xcb_rectangle_t rect = this->outer_area(abspos);

View File

@ -80,9 +80,6 @@ namespace signals {
struct changed : public detail::base_signal<changed> { struct changed : public detail::base_signal<changed> {
using base_type::base_type; 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> { struct button_press : public detail::value_signal<button_press, string> {
using base_type::base_type; using base_type::base_type;
}; };
@ -95,12 +92,6 @@ namespace signals {
struct dim_window : public detail::value_signal<dim_window, double> { struct dim_window : public detail::value_signal<dim_window, double> {
using base_type::base_type; 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> { struct request_snapshot : public detail::value_signal<request_snapshot, string> {
using base_type::base_type; using base_type::base_type;
}; };

View File

@ -27,13 +27,10 @@ namespace signals {
} // namespace ipc } // namespace ipc
namespace ui { namespace ui {
struct changed; struct changed;
struct tick;
struct button_press; struct button_press;
struct cursor_change; struct cursor_change;
struct visibility_change; struct visibility_change;
struct dim_window; struct dim_window;
struct shade_window;
struct unshade_window;
struct request_snapshot; struct request_snapshot;
struct update_background; struct update_background;
struct update_geometry; struct update_geometry;

View File

@ -41,7 +41,6 @@ extern const char* const APP_VERSION;
#cmakedefine DEBUG_LOGGER_VERBOSE #cmakedefine DEBUG_LOGGER_VERBOSE
#cmakedefine DEBUG_HINTS #cmakedefine DEBUG_HINTS
#cmakedefine DEBUG_WHITESPACE #cmakedefine DEBUG_WHITESPACE
#cmakedefine DEBUG_SHADED
#cmakedefine DEBUG_FONTCONFIG #cmakedefine DEBUG_FONTCONFIG
#endif #endif

View File

@ -66,7 +66,6 @@ if(BUILD_LIBPOLY)
${src_dir}/components/logger.cpp ${src_dir}/components/logger.cpp
${src_dir}/components/renderer.cpp ${src_dir}/components/renderer.cpp
${src_dir}/components/screen.cpp ${src_dir}/components/screen.cpp
${src_dir}/components/taskqueue.cpp
${src_dir}/components/eventloop.cpp ${src_dir}/components/eventloop.cpp
${src_dir}/drawtypes/animation.cpp ${src_dir}/drawtypes/animation.cpp

View File

@ -5,7 +5,6 @@
#include "components/config.hpp" #include "components/config.hpp"
#include "components/renderer.hpp" #include "components/renderer.hpp"
#include "components/screen.hpp" #include "components/screen.hpp"
#include "components/taskqueue.hpp"
#include "components/types.hpp" #include "components/types.hpp"
#include "drawtypes/label.hpp" #include "drawtypes/label.hpp"
#include "events/signal.hpp" #include "events/signal.hpp"
@ -37,7 +36,7 @@ using namespace signals::ui;
/** /**
* Create instance * 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>(); auto action_ctxt = make_unique<tags::action_context>();
// clang-format off // clang-format off
@ -46,11 +45,11 @@ bar::make_type bar::make(bool only_initialize_values) {
signal_emitter::make(), signal_emitter::make(),
config::make(), config::make(),
logger::make(), logger::make(),
loop,
screen::make(), screen::make(),
tray_manager::make(), tray_manager::make(),
tags::dispatch::make(*action_ctxt), tags::dispatch::make(*action_ctxt),
std::move(action_ctxt), std::move(action_ctxt),
taskqueue::make(),
only_initialize_values); only_initialize_values);
// clang-format on // clang-format on
} }
@ -60,18 +59,18 @@ bar::make_type bar::make(bool only_initialize_values) {
* *
* TODO: Break out all tray handling * 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<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_connection(conn)
, m_sig(emitter) , m_sig(emitter)
, m_conf(config) , m_conf(config)
, m_log(logger) , m_log(logger)
, m_loop(loop)
, m_screen(forward<decltype(screen)>(screen)) , m_screen(forward<decltype(screen)>(screen))
, m_tray(forward<decltype(tray_manager)>(tray_manager)) , m_tray(forward<decltype(tray_manager)>(tray_manager))
, m_dispatch(forward<decltype(dispatch)>(dispatch)) , m_dispatch(forward<decltype(dispatch)>(dispatch))
, m_action_ctxt(forward<decltype(action_ctxt)>(action_ctxt)) , m_action_ctxt(forward<decltype(action_ctxt)>(action_ctxt)) {
, m_taskqueue(forward<decltype(taskqueue)>(taskqueue)) {
string bs{m_conf.section()}; string bs{m_conf.section()};
// Get available RandR outputs // 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.left = m_conf.get(bs, "module-margin-left", margin);
m_opts.module_margin.right = m_conf.get(bs, "module-margin-right", 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) { if (only_initialize_values) {
return; return;
} }
@ -308,7 +309,6 @@ bar::bar(connection& conn, signal_emitter& emitter, const config& config, const
* Cleanup signal handlers and destroy the bar window * Cleanup signal handlers and destroy the bar window
*/ */
bar::~bar() { bar::~bar() {
std::lock_guard<std::mutex> guard(m_mutex);
m_connection.detach_sink(this, SINK_PRIORITY_BAR); m_connection.detach_sink(this, SINK_PRIORITY_BAR);
m_sig.detach(this); m_sig.detach(this);
} }
@ -327,12 +327,6 @@ const bar_settings bar::settings() const {
* \param force Unless true, do not parse unchanged data * \param force Unless true, do not parse unchanged data
*/ */
void bar::parse(string&& data, bool force) { 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; bool unchanged = data == m_lastinput;
m_lastinput = data; m_lastinput = data;
@ -341,8 +335,6 @@ void bar::parse(string&& data, bool force) {
m_log.trace("bar: Force update"); m_log.trace("bar: Force update");
} else if (!m_visible) { } else if (!m_visible) {
return m_log.trace("bar: Ignoring update (invisible)"); return m_log.trace("bar: Ignoring update (invisible)");
} else if (m_opts.shaded) {
return m_log.trace("bar: Ignoring update (shaded)");
} else if (unchanged) { } else if (unchanged) {
return m_log.trace("bar: Ignoring update (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 * 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 * _NET_WM_WINDOW_OPACITY atom value
*/ */
void bar::handle(const evt::enter_notify&) { 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) { 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_opts.dimmed = false;
m_sig.emit(dim_window{1.0}); m_sig.emit(dim_window{1.0});
}); });
} else if (m_taskqueue->exist("window-dim")) { } else if (m_dim_timer->is_active()) {
m_taskqueue->purge("window-dim"); m_dim_timer->stop();
} }
} }
@ -626,19 +629,14 @@ void bar::handle(const evt::enter_notify&) {
* _NET_WM_WINDOW_OPACITY atom value * _NET_WM_WINDOW_OPACITY atom value
*/ */
void bar::handle(const evt::leave_notify&) { void bar::handle(const evt::leave_notify&) {
#if 0 // Only trigger dimming, if the dim-value is not fully opaque.
#ifdef DEBUG_SHADED if (m_opts.dimvalue < 1.0) {
if (m_opts.origin == edge::TOP) { if (!m_opts.dimmed) {
m_taskqueue->defer_unique("window-hover", 25ms, [&](size_t) { m_sig.emit(signals::ui::shade_window{}); }); m_dim_timer->start(3000, 0, [this]() {
return; m_opts.dimmed = true;
} m_sig.emit(dim_window{double(m_opts.dimvalue)});
#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)});
});
} }
} }
@ -648,12 +646,6 @@ void bar::handle(const evt::leave_notify&) {
* Used to change the cursor depending on the module * Used to change the cursor depending on the module
*/ */
void bar::handle(const evt::motion_notify& evt) { 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); m_log.trace("bar: Detected motion: %i at pos(%i, %i)", evt->detail, evt->event_x, evt->event_y);
#if WITH_XCURSOR #if WITH_XCURSOR
m_motion_pos = evt->event_x; 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 * Used to map mouse clicks to bar actions
*/ */
void bar::handle(const evt::button_press& evt) { 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_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); mousebtn btn = static_cast<mousebtn>(evt->detail);
m_buttonpress_pos = evt->event_x; 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); * 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
if (action != tags::NO_ACTION) { * need to trigger a double click.
m_log.trace("Found matching input area"); */
m_sig.emit(button_press{m_action_ctxt->get_action(action)}); const auto check_double = [this](TimerHandle_t handle, mousebtn btn, int pos) {
return; if (!handle->is_active()) {
} handle->start(m_opts.double_click_interval, 0, [=]() { trigger_click(btn, pos); });
} else {
for (auto&& action : m_opts.actions) { handle->stop();
if (action.button == m_buttonpress_btn && !action.command.empty()) { trigger_click(mousebtn_get_double(btn), pos);
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);
} }
}; };
// If there are no double click handlers defined we can // If there are no double click handlers defined we can
// just by-pass the click timer handling // just by-pass the click timer handling
if (!m_dblclicks) { if (!m_dblclicks) {
deferred_fn(0); trigger_click(btn, pos);
} else if (evt->detail == static_cast<int>(mousebtn::LEFT)) { } else if (btn == mousebtn::LEFT) {
check_double("buttonpress-left", mousebtn::DOUBLE_LEFT); check_double(m_leftclick_timer, btn, pos);
} else if (evt->detail == static_cast<int>(mousebtn::MIDDLE)) { } else if (btn == mousebtn::MIDDLE) {
check_double("buttonpress-middle", mousebtn::DOUBLE_MIDDLE); check_double(m_middleclick_timer, btn, pos);
} else if (evt->detail == static_cast<int>(mousebtn::RIGHT)) { } else if (btn == mousebtn::RIGHT) {
check_double("buttonpress-right", mousebtn::DOUBLE_RIGHT); check_double(m_rightclick_timer, btn, pos);
} else { } else {
deferred_fn(0); trigger_click(btn, pos);
} }
} }
@ -876,110 +842,6 @@ void bar::start() {
broadcast_visibility(); 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, &params, 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, &params, 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, &params, 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, &params, 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, &params, values);
m_connection.configure_window(m_opts.window, mask, values);
m_connection.flush();
return false;
}
bool bar::on(const signals::ui::dim_window& sig) { bool bar::on(const signals::ui::dim_window& sig) {
m_opts.dimmed = sig.cast() != 1.0; m_opts.dimmed = sig.cast() != 1.0;
ewmh_util::set_wm_window_opacity(m_opts.window, sig.cast() * 0xFFFFFFFF); ewmh_util::set_wm_window_opacity(m_opts.window, sig.cast() * 0xFFFFFFFF);

View File

@ -31,20 +31,21 @@ POLYBAR_NS
* Build controller instance * Build controller instance
*/ */
controller::make_type controller::make(unique_ptr<ipc>&& ipc) { controller::make_type controller::make(unique_ptr<ipc>&& ipc) {
return std::make_unique<controller>(connection::make(), signal_emitter::make(), logger::make(), config::make(), return std::make_unique<controller>(
bar::make(), forward<decltype(ipc)>(ipc)); connection::make(), signal_emitter::make(), logger::make(), config::make(), forward<decltype(ipc)>(ipc));
} }
/** /**
* Construct controller * Construct controller
*/ */
controller::controller(connection& conn, signal_emitter& emitter, const logger& logger, const config& config, controller::controller(
unique_ptr<bar>&& bar, unique_ptr<ipc>&& ipc) connection& conn, signal_emitter& emitter, const logger& logger, const config& config, unique_ptr<ipc>&& ipc)
: m_connection(conn) : m_connection(conn)
, m_sig(emitter) , m_sig(emitter)
, m_log(logger) , m_log(logger)
, m_conf(config) , 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_ipc(forward<decltype(ipc)>(ipc)) {
m_conf.ignore_key("settings", "throttle-input-for"); m_conf.ignore_key("settings", "throttle-input-for");
m_conf.ignore_key("settings", "throttle-output"); m_conf.ignore_key("settings", "throttle-output");
@ -152,14 +153,14 @@ void controller::trigger_update(bool force) {
} }
void controller::trigger_notification() { void controller::trigger_notification() {
if (m_eloop_ready) { if (m_loop_ready) {
m_notifier->send(); m_notifier->send();
} }
} }
void controller::stop(bool reload) { void controller::stop(bool reload) {
update_reload(reload); update_reload(reload);
eloop->stop(); m_loop->stop();
} }
void controller::conn_cb(uv_poll_event) { void controller::conn_cb(uv_poll_event) {
@ -210,7 +211,7 @@ void controller::notifier_handler() {
if (data.quit) { if (data.quit) {
update_reload(data.reload); update_reload(data.reload);
eloop->stop(); m_loop->stop();
return; return;
} }
@ -234,29 +235,23 @@ void controller::screenshot_handler() {
void controller::read_events(bool confwatch) { void controller::read_events(bool confwatch) {
m_log.info("Entering event loop (thread-id=%lu)", this_thread::get_id()); m_log.info("Entering event loop (thread-id=%lu)", this_thread::get_id());
if (!m_writeback) {
m_bar->start();
}
try { try {
eloop = std::make_unique<eventloop>(); m_loop->poll_handle(
eloop->poll_handle(
UV_READABLE, m_connection.get_file_descriptor(), [this](uv_poll_event events) { conn_cb(events); }, 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)); }); [](int status) { throw runtime_error("libuv error while polling X connection: "s + uv_strerror(status)); });
for (auto s : {SIGINT, SIGQUIT, SIGTERM, SIGUSR1, SIGALRM}) { 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) { 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); }, 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)); }); [this](int err) { m_log.err("libuv error while watching config file for changes: %s", uv_strerror(err)); });
} }
if (m_ipc) { if (m_ipc) {
eloop->pipe_handle( m_loop->pipe_handle(
m_ipc->get_path(), [this](const string payload) { m_ipc->receive_data(payload); }, m_ipc->get_path(), [this](const string payload) { m_ipc->receive_data(payload); },
[this]() { m_ipc->receive_eof(); }, [this]() { m_ipc->receive_eof(); },
[this](int err) { m_log.err("libuv error while listening to IPC channel: %s", uv_strerror(err)); }); [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()) { if (!m_snapshot_dst.empty()) {
// Trigger a single screenshot after 3 seconds // 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. * Immediately trigger and update so that the bar displays something.
*/ */
trigger_update(true); trigger_update(true);
eloop->run(); m_loop->run();
} catch (const exception& err) { } catch (const exception& err) {
m_log.err("Fatal Error in eventloop: %s", err.what()); m_log.err("Fatal Error in eventloop: %s", err.what());
stop(false); stop(false);
@ -284,7 +283,8 @@ void controller::read_events(bool confwatch) {
m_log.info("Eventloop finished"); m_log.info("Eventloop finished");
eloop.reset(); m_loop_ready = false;
m_loop.reset();
} }
/** /**

View File

@ -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 * 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) { uv_close((uv_handle_t*)handle, [](uv_handle_t* handle) {
PipeHandle* This = static_cast<PipeHandle*>(handle->data); PipeHandle* This = static_cast<PipeHandle*>(handle->data);
UV(uv_pipe_init, This->loop(), This->handle, false); 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); 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); UV(uv_timer_start, handle, callback, timeout, repeat);
} }
void TimerHandle::stop() {
UV(uv_timer_stop, handle);
}
// }}} // }}}
// AsyncHandle {{{ // AsyncHandle {{{
@ -243,9 +251,9 @@ void eventloop::pipe_handle(
m_pipe_handles.back()->start(); m_pipe_handles.back()->start();
} }
void eventloop::timer_handle(uint64_t timeout, uint64_t repeat, function<void(void)> fun) { TimerHandle_t eventloop::timer_handle(function<void(void)> fun) {
m_timer_handles.emplace_back(std::make_unique<TimerHandle>(get(), fun)); m_timer_handles.emplace_back(std::make_shared<TimerHandle>(get(), fun));
m_timer_handles.back()->start(timeout, repeat); return m_timer_handles.back();
} }
AsyncHandle_t eventloop::async_handle(function<void(void)> fun) { AsyncHandle_t eventloop::async_handle(function<void(void)> fun) {

View File

@ -381,25 +381,6 @@ void renderer::flush() {
highlight_clickable_areas(); 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_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.copy_area(m_pixmap, m_window, m_gcontext, 0, 0, 0, 0, m_bar.size.w, m_bar.size.h);
m_connection.flush(); m_connection.flush();

View File

@ -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

View File

@ -127,7 +127,8 @@ int main(int argc, char** argv) {
return EXIT_SUCCESS; return EXIT_SUCCESS;
} }
if (cli->has("print-wmname")) { 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; return EXIT_SUCCESS;
} }

View File

@ -1,10 +1,9 @@
#include "utils/env.hpp"
#include <cstdlib> #include <cstdlib>
#include <cstring> #include <cstring>
#include <thread>
#include <utility> #include <utility>
#include "utils/env.hpp"
POLYBAR_NS POLYBAR_NS
namespace env_util { namespace env_util {
@ -17,6 +16,6 @@ namespace env_util {
const char* value{std::getenv(var.c_str())}; const char* value{std::getenv(var.c_str())};
return value != nullptr ? value : move(fallback); return value != nullptr ? value : move(fallback);
} }
} } // namespace env_util
POLYBAR_NS_END POLYBAR_NS_END