Make the event loop return shared_ptrs (#2842)

* Return shared_ptr from eventloop

* Add -Wdeprecated-copy-dtor warning

Produces a warning if classes don't have explicit copy operations if
they have a user-defined constructor.
This helps us stick to the rule of 5 (kinda, no warnings for missing
move operators).

* Clean up eventloop

* Fix compiler warnings

* Fix fs_event_handle_t name
This commit is contained in:
Patrick Ziegler 2022-10-15 23:21:40 +02:00 committed by GitHub
parent 54b75f23ab
commit 56779a5902
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
18 changed files with 266 additions and 144 deletions

View File

@ -16,6 +16,7 @@ Checks: '
-modernize-raw-string-literal, -modernize-raw-string-literal,
-modernize-use-bool-literals, -modernize-use-bool-literals,
-modernize-use-trailing-return-type, -modernize-use-trailing-return-type,
-readability-identifier-length,
-readability-implicit-bool-cast, -readability-implicit-bool-cast,
-readability-else-after-return, -readability-else-after-return,
-readability-named-parameter, -readability-named-parameter,
@ -26,7 +27,8 @@ Checks: '
-cppcoreguidelines-pro-type-reinterpret-cast, -cppcoreguidelines-pro-type-reinterpret-cast,
-cppcoreguidelines-pro-type-union-access, -cppcoreguidelines-pro-type-union-access,
-cppcoreguidelines-pro-type-cstyle-cast, -cppcoreguidelines-pro-type-cstyle-cast,
-cppcoreguidelines-pro-bounds-constant-array-index -cppcoreguidelines-pro-bounds-constant-array-index,
-cppcoreguidelines-owning-memory,
' '
CheckOptions: CheckOptions:

3
.gitignore vendored
View File

@ -8,4 +8,7 @@
.tags .tags
*.user *.user
# clangd
/.cache
polybar-*.tar polybar-*.tar

View File

@ -24,7 +24,7 @@ set(THREADS_PREFER_PTHREAD_FLAG ON)
set(POLYBAR_FLAGS "" CACHE STRING "C++ compiler flags used for compiling polybar") set(POLYBAR_FLAGS "" CACHE STRING "C++ compiler flags used for compiling polybar")
list(APPEND cxx_base -Wall -Wextra -Wpedantic) list(APPEND cxx_base -Wall -Wextra -Wpedantic -Wdeprecated-copy-dtor)
list(APPEND cxx_debug -DDEBUG -g2) list(APPEND cxx_debug -DDEBUG -g2)
list(APPEND cxx_minsizerel "") list(APPEND cxx_minsizerel "")
list(APPEND cxx_sanitize -O0 -g -fsanitize=address -fsanitize=undefined -fno-omit-frame-pointer -fno-optimize-sibling-calls) list(APPEND cxx_sanitize -O0 -g -fsanitize=address -fsanitize=undefined -fno-omit-frame-pointer -fno-optimize-sibling-calls)

View File

@ -107,10 +107,10 @@ class bar : public xpp::event::sink<evt::button_press, evt::expose, evt::propert
string m_lastinput{}; string m_lastinput{};
std::set<mousebtn> m_dblclicks; std::set<mousebtn> m_dblclicks;
eventloop::TimerHandle& m_leftclick_timer{m_loop.handle<eventloop::TimerHandle>()}; eventloop::timer_handle_t m_leftclick_timer{m_loop.handle<eventloop::TimerHandle>()};
eventloop::TimerHandle& m_middleclick_timer{m_loop.handle<eventloop::TimerHandle>()}; eventloop::timer_handle_t m_middleclick_timer{m_loop.handle<eventloop::TimerHandle>()};
eventloop::TimerHandle& m_rightclick_timer{m_loop.handle<eventloop::TimerHandle>()}; eventloop::timer_handle_t m_rightclick_timer{m_loop.handle<eventloop::TimerHandle>()};
eventloop::TimerHandle& m_dim_timer{m_loop.handle<eventloop::TimerHandle>()}; eventloop::timer_handle_t m_dim_timer{m_loop.handle<eventloop::TimerHandle>()};
bool m_visible{true}; bool m_visible{true};
}; };

View File

@ -55,7 +55,7 @@ class controller : public signal_receiver<SIGN_PRIORITY_CONTROLLER, signals::eve
void signal_handler(int signum); void signal_handler(int signum);
void conn_cb(); void conn_cb();
void create_config_watcher(const string& fname); void create_config_watcher(const string& filename);
void confwatch_handler(const char* fname); void confwatch_handler(const char* fname);
void notifier_handler(); void notifier_handler();
void screenshot_handler(); void screenshot_handler();
@ -109,7 +109,7 @@ class controller : public signal_receiver<SIGN_PRIORITY_CONTROLLER, signals::eve
* This handle is used to notify the eventloop of changes which are not otherwise covered by other handles. * This handle is used to notify the eventloop of changes which are not otherwise covered by other handles.
* E.g. click actions. * E.g. click actions.
*/ */
eventloop::AsyncHandle& m_notifier{m_loop.handle<eventloop::AsyncHandle>([this]() { notifier_handler(); })}; eventloop::async_handle_t m_notifier{m_loop.handle<eventloop::AsyncHandle>([this]() { notifier_handler(); })};
/** /**
* Notification data for the controller. * Notification data for the controller.

View File

@ -3,6 +3,7 @@
#include <uv.h> #include <uv.h>
#include <stdexcept> #include <stdexcept>
#include <utility>
#include "common.hpp" #include "common.hpp"
#include "components/logger.hpp" #include "components/logger.hpp"
@ -36,12 +37,12 @@ namespace eventloop {
get()->data = this; get()->data = this;
} }
Self& leak(std::unique_ptr<Self> h) { void leak(std::shared_ptr<Self> h) {
lifetime_extender = std::move(h); lifetime_extender = std::move(h);
return *lifetime_extender;
} }
void unleak() { void unleak() {
reset_callbacks();
lifetime_extender.reset(); lifetime_extender.reset();
} }
@ -73,6 +74,15 @@ namespace eventloop {
} }
protected: protected:
~Handle() = default;
/**
* Resets all callbacks stored in the handle as part of closing the handle.
*
* This releases any lambda captures, breaking possible cyclic dependencies in shared_ptr.
*/
virtual void reset_callbacks() = 0;
/** /**
* Generic callback function that can be used for all uv handle callbacks. * Generic callback function that can be used for all uv handle callbacks.
* *
@ -128,14 +138,14 @@ namespace eventloop {
uv_loop_t* uv_loop; uv_loop_t* uv_loop;
/** /**
* The handle stores the unique_ptr to itself so that it effectively leaks memory. * The handle stores the shared_ptr to itself so that it effectively leaks memory.
* *
* This saves us from having to guarantee that the handle's lifetime extends to at least after it is closed. * This saves us from having to guarantee that the handle's lifetime extends to at least after it is closed.
* *
* Once the handle is closed, either explicitly or by walking all handles when the loop shuts down, this reference * Once the handle is closed, either explicitly or by walking all handles when the loop shuts down, this reference
* is reset and the object is explicitly destroyed. * is reset and the object is explicitly destroyed.
*/ */
std::unique_ptr<Self> lifetime_extender; std::shared_ptr<Self> lifetime_extender;
}; };
struct ErrorEvent { struct ErrorEvent {
@ -144,54 +154,32 @@ namespace eventloop {
using cb_error = cb_event<ErrorEvent>; using cb_error = cb_event<ErrorEvent>;
class WriteRequest : public non_copyable_mixin { class WriteRequest : public non_copyable_mixin, public non_movable_mixin {
public: public:
using cb_write = cb_void; using cb_write = cb_void;
WriteRequest(cb_write user_cb, cb_error err_cb) : write_callback(user_cb), write_err_cb(err_cb) { WriteRequest(cb_write&& user_cb, cb_error&& err_cb);
get()->data = this;
};
static WriteRequest& create(cb_write user_cb, cb_error err_cb) { static WriteRequest& create(cb_write&& user_cb, cb_error&& err_cb);
auto r = std::make_unique<WriteRequest>(user_cb, err_cb);
return r->leak(std::move(r));
};
uv_write_t* get() { uv_write_t* get();
return &req;
}
/** /**
* Trigger the write callback. * Trigger the write callback.
* *
* After that, this object is destroyed. * After that, this object is destroyed.
*/ */
void trigger(int status) { void trigger(int status);
if (status < 0) {
if (write_err_cb) {
write_err_cb(ErrorEvent{status});
}
} else {
if (write_callback) {
write_callback();
}
}
unleak();
}
protected: protected:
WriteRequest& leak(std::unique_ptr<WriteRequest> h) { WriteRequest& leak(std::unique_ptr<WriteRequest> h);
lifetime_extender = std::move(h);
return *lifetime_extender;
}
void unleak() { void unleak();
lifetime_extender.reset();
} void reset_callbacks();
private: private:
uv_write_t req; uv_write_t req{};
cb_write write_callback; cb_write write_callback;
cb_error write_err_cb; cb_error write_err_cb;
@ -208,13 +196,16 @@ namespace eventloop {
int signum; int signum;
}; };
class SignalHandle : public Handle<SignalHandle, uv_signal_t> { class SignalHandle final : public Handle<SignalHandle, uv_signal_t> {
public: public:
using Handle::Handle; using Handle::Handle;
using cb = cb_event<SignalEvent>; using cb = cb_event<SignalEvent>;
void init(); void init();
void start(int signum, cb user_cb); void start(int signum, cb&& user_cb);
protected:
void reset_callbacks() override;
private: private:
cb callback; cb callback;
@ -224,15 +215,18 @@ namespace eventloop {
uv_poll_event event; uv_poll_event event;
}; };
class PollHandle : public Handle<PollHandle, uv_poll_t> { class PollHandle final : public Handle<PollHandle, uv_poll_t> {
public: public:
using Handle::Handle; using Handle::Handle;
using cb = cb_event<PollEvent>; using cb = cb_event<PollEvent>;
void init(int fd); void init(int fd);
void start(int events, cb user_cb, cb_error err_cb); void start(int events, cb&& user_cb, cb_error&& err_cb);
static void poll_callback(uv_poll_t*, int status, int events); static void poll_callback(uv_poll_t*, int status, int events);
protected:
void reset_callbacks() override;
private: private:
cb callback; cb callback;
cb_error err_cb; cb_error err_cb;
@ -243,41 +237,50 @@ namespace eventloop {
uv_fs_event event; uv_fs_event event;
}; };
class FSEventHandle : public Handle<FSEventHandle, uv_fs_event_t> { class FSEventHandle final : public Handle<FSEventHandle, uv_fs_event_t> {
public: public:
using Handle::Handle; using Handle::Handle;
using cb = cb_event<FSEvent>; using cb = cb_event<FSEvent>;
void init(); void init();
void start(const string& path, int flags, cb user_cb, cb_error err_cb); void start(const string& path, int flags, cb&& user_cb, cb_error&& err_cb);
static void fs_event_callback(uv_fs_event_t*, const char* path, int events, int status); static void fs_event_callback(uv_fs_event_t*, const char* path, int events, int status);
protected:
void reset_callbacks() override;
private: private:
cb callback; cb callback;
cb_error err_cb; cb_error err_cb;
}; };
class TimerHandle : public Handle<TimerHandle, uv_timer_t> { class TimerHandle final : public Handle<TimerHandle, uv_timer_t> {
public: public:
using Handle::Handle; using Handle::Handle;
using cb = cb_void; using cb = cb_void;
void init(); void init();
void start(uint64_t timeout, uint64_t repeat, cb user_cb); void start(uint64_t timeout, uint64_t repeat, cb&& user_cb);
void stop(); void stop();
protected:
void reset_callbacks() override;
private: private:
cb callback; cb callback;
}; };
class AsyncHandle : public Handle<AsyncHandle, uv_async_t> { class AsyncHandle final : public Handle<AsyncHandle, uv_async_t> {
public: public:
using Handle::Handle; using Handle::Handle;
using cb = cb_void; using cb = cb_void;
void init(cb user_cb); void init(cb&& user_cb);
void send(); void send();
protected:
void reset_callbacks() override;
private: private:
cb callback; cb callback;
}; };
@ -295,9 +298,9 @@ namespace eventloop {
using cb_read_eof = cb_void; using cb_read_eof = cb_void;
using cb_connection = cb_void; using cb_connection = cb_void;
void listen(int backlog, cb_connection user_cb, cb_error err_cb) { void listen(int backlog, cb_connection&& user_cb, cb_error&& err_cb) {
this->connection_callback = user_cb; this->connection_callback = std::move(user_cb);
this->connection_err_cb = err_cb; this->connection_err_cb = std::move(err_cb);
UV(uv_listen, this->template get<uv_stream_t>(), backlog, connection_cb); UV(uv_listen, this->template get<uv_stream_t>(), backlog, connection_cb);
}; };
@ -316,11 +319,11 @@ namespace eventloop {
UV(uv_accept, this->template get<uv_stream_t>(), client.template get<uv_stream_t>()); UV(uv_accept, this->template get<uv_stream_t>(), client.template get<uv_stream_t>());
} }
void read_start(cb_read fun, cb_void eof_cb, cb_error err_cb) { void read_start(cb_read &&fun, cb_void&& eof_cb, cb_error&& err_cb) {
this->read_callback = fun; this->read_callback = std::move(fun);
this->read_eof_cb = eof_cb; this->read_eof_cb = std::move(eof_cb);
this->read_err_cb = err_cb; this->read_err_cb = std::move(err_cb);
UV(uv_read_start, this->template get<uv_stream_t>(), &this->alloc_callback, read_cb); UV(uv_read_start, this->template get<uv_stream_t>(), &this->alloc_callback, &read_cb);
}; };
static void read_cb(uv_stream_t* handle, ssize_t nread, const uv_buf_t* buf) { static void read_cb(uv_stream_t* handle, ssize_t nread, const uv_buf_t* buf) {
@ -340,8 +343,8 @@ namespace eventloop {
} }
}; };
void write(const vector<uint8_t>& data, WriteRequest::cb_write user_cb = {}, cb_error err_cb = {}) { void write(const vector<uint8_t>& data, WriteRequest::cb_write&& user_cb = {}, cb_error&& err_cb = {}) {
WriteRequest& req = WriteRequest::create(user_cb, err_cb); WriteRequest& req = WriteRequest::create(std::move(user_cb), std::move(err_cb));
uv_buf_t buf{(char*)data.data(), data.size()}; uv_buf_t buf{(char*)data.data(), data.size()};
@ -349,6 +352,17 @@ namespace eventloop {
[](uv_write_t* r, int status) { static_cast<WriteRequest*>(r->data)->trigger(status); }); [](uv_write_t* r, int status) { static_cast<WriteRequest*>(r->data)->trigger(status); });
} }
protected:
~StreamHandle() = default;
void reset_callbacks() override {
read_callback = nullptr;
read_eof_cb = nullptr;
read_err_cb = nullptr;
connection_callback = nullptr;
connection_err_cb = nullptr;
}
private: private:
/** /**
* Callback for receiving data * Callback for receiving data
@ -371,7 +385,7 @@ namespace eventloop {
cb_error connection_err_cb; cb_error connection_err_cb;
}; };
class PipeHandle : public StreamHandle<PipeHandle, uv_pipe_t> { class PipeHandle final : public StreamHandle<PipeHandle, uv_pipe_t> {
public: public:
using StreamHandle::StreamHandle; using StreamHandle::StreamHandle;
using cb_connect = cb_void; using cb_connect = cb_void;
@ -381,7 +395,10 @@ namespace eventloop {
void bind(const string& path); void bind(const string& path);
void connect(const string& name, cb_connect user_cb, cb_error err_cb); void connect(const string& name, cb_connect&& user_cb, cb_error&& err_cb);
protected:
void reset_callbacks() override;
private: private:
static void connect_cb(uv_connect_t* req, int status); static void connect_cb(uv_connect_t* req, int status);
@ -390,13 +407,16 @@ namespace eventloop {
cb_connect connect_callback; cb_connect connect_callback;
}; };
class PrepareHandle : public Handle<PrepareHandle, uv_prepare_t> { class PrepareHandle final : public Handle<PrepareHandle, uv_prepare_t> {
public: public:
using Handle::Handle; using Handle::Handle;
using cb = cb_void; using cb = cb_void;
void init(); void init();
void start(cb user_cb); void start(cb&& user_cb);
protected:
void reset_callbacks() override;
private: private:
static void connect_cb(uv_connect_t* req, int status); static void connect_cb(uv_connect_t* req, int status);
@ -404,6 +424,14 @@ namespace eventloop {
cb callback; cb callback;
}; };
using signal_handle_t = shared_ptr<SignalHandle>;
using poll_handle_t = shared_ptr<PollHandle>;
using fs_event_handle_t = shared_ptr<FSEventHandle>;
using timer_handle_t = shared_ptr<TimerHandle>;
using async_handle_t = shared_ptr<AsyncHandle>;
using pipe_handle_t = shared_ptr<PipeHandle>;
using prepare_handle_t = shared_ptr<PrepareHandle>;
class loop : public non_copyable_mixin, public non_movable_mixin { class loop : public non_copyable_mixin, public non_movable_mixin {
public: public:
loop(); loop();
@ -413,10 +441,11 @@ namespace eventloop {
uint64_t now() const; uint64_t now() const;
template <typename H, typename... Args> template <typename H, typename... Args>
H& handle(Args... args) { shared_ptr<H> handle(Args&&... args) {
auto ptr = make_unique<H>(get()); auto ptr = make_shared<H>(get());
ptr->init(std::forward<Args>(args)...); ptr->init(std::forward<Args>(args)...);
return ptr->leak(std::move(ptr)); ptr->leak(ptr);
return ptr;
} }
uv_loop_t* get() const; uv_loop_t* get() const;

View File

@ -8,14 +8,13 @@
POLYBAR_NS POLYBAR_NS
using std::strerror;
using std::exception; using std::exception;
using std::runtime_error; using std::runtime_error;
using std::strerror;
class application_error : public runtime_error { class application_error : public runtime_error {
public: public:
explicit application_error(const string& message, int code = 0) : runtime_error(message), code(code) {} explicit application_error(const string& message, int code = 0) : runtime_error(message), code(code) {}
virtual ~application_error() {}
int code{0}; int code{0};
}; };
@ -24,7 +23,6 @@ class system_error : public application_error {
explicit system_error() : application_error(strerror(errno), errno) {} explicit system_error() : application_error(strerror(errno), errno) {}
explicit system_error(const string& message) explicit system_error(const string& message)
: application_error(message + " (reason: " + strerror(errno) + ")", errno) {} : application_error(message + " (reason: " + strerror(errno) + ")", errno) {}
virtual ~system_error() {}
}; };
#define DEFINE_CHILD_ERROR(error, parent) \ #define DEFINE_CHILD_ERROR(error, parent) \

View File

@ -42,14 +42,14 @@ namespace ipc {
const logger& m_log; const logger& m_log;
eventloop::loop& m_loop; eventloop::loop& m_loop;
eventloop::PipeHandle& socket; eventloop::pipe_handle_t socket;
class connection : public non_copyable_mixin, public non_movable_mixin { class connection : public non_copyable_mixin, public non_movable_mixin {
public: public:
using cb = std::function<void(connection&, uint8_t, type_t, const std::vector<uint8_t>&)>; using cb = std::function<void(connection&, uint8_t, type_t, const std::vector<uint8_t>&)>;
connection(eventloop::loop& loop, cb msg_callback); connection(eventloop::loop& loop, cb msg_callback);
~connection(); ~connection();
eventloop::PipeHandle& client_pipe; eventloop::pipe_handle_t client_pipe;
decoder dec; decoder dec;
}; };
@ -79,7 +79,7 @@ namespace ipc {
struct fifo { struct fifo {
fifo(eventloop::loop& loop, ipc& ipc, const string& path); fifo(eventloop::loop& loop, ipc& ipc, const string& path);
~fifo(); ~fifo();
eventloop::PipeHandle& pipe_handle; eventloop::pipe_handle_t pipe_handle;
}; };
unique_ptr<fifo> ipc_pipe; unique_ptr<fifo> ipc_pipe;

View File

@ -55,7 +55,6 @@ namespace modules {
watches.back().attach(w.second); watches.back().attach(w.second);
} }
} catch (const system_error& e) { } catch (const system_error& e) {
watches.clear();
this->m_log.err("%s: Error while creating inotify watch (what: %s)", this->name(), e.what()); this->m_log.err("%s: Error while creating inotify watch (what: %s)", this->name(), e.what());
CAST_MOD(Impl)->sleep(0.1s); CAST_MOD(Impl)->sleep(0.1s);
return; return;
@ -67,11 +66,6 @@ namespace modules {
if (w.poll(1000 / watches.size())) { if (w.poll(1000 / watches.size())) {
auto event = w.get_event(); auto event = w.get_event();
for (auto&& w : watches) {
w.remove(true);
}
if (CAST_MOD(Impl)->on_event(event)) { if (CAST_MOD(Impl)->on_event(event)) {
CAST_MOD(Impl)->broadcast(); CAST_MOD(Impl)->broadcast();
} }
@ -79,8 +73,9 @@ namespace modules {
return; return;
} }
if (!this->running()) if (!this->running()) {
break; break;
}
} }
CAST_MOD(Impl)->idle(); CAST_MOD(Impl)->idle();
} }

View File

@ -6,6 +6,7 @@
#include <cstdio> #include <cstdio>
#include "common.hpp" #include "common.hpp"
#include "utils/mixins.hpp"
POLYBAR_NS POLYBAR_NS
@ -18,16 +19,19 @@ struct inotify_event {
int mask = 0; int mask = 0;
}; };
class inotify_watch { class inotify_watch : public non_copyable_mixin {
public: public:
explicit inotify_watch(string path); explicit inotify_watch(string path);
~inotify_watch(); ~inotify_watch();
inotify_watch(inotify_watch&& other) noexcept;
inotify_watch& operator=(inotify_watch&& other) noexcept;
void attach(int mask = IN_MODIFY); void attach(int mask = IN_MODIFY);
void remove(bool force = false); void remove(bool force = false);
bool poll(int wait_ms = 1000) const; bool poll(int wait_ms = 1000) const;
inotify_event get_event() const; inotify_event get_event() const;
const string path() const; string path() const;
int get_file_descriptor() const; int get_file_descriptor() const;
protected: protected:

View File

@ -13,8 +13,8 @@ class non_copyable_mixin {
non_copyable_mixin& operator=(const non_copyable_mixin&) = delete; non_copyable_mixin& operator=(const non_copyable_mixin&) = delete;
protected: protected:
non_copyable_mixin() {} non_copyable_mixin() = default;
~non_copyable_mixin() {} ~non_copyable_mixin() = default;
}; };
/** /**
@ -26,8 +26,8 @@ class non_movable_mixin {
non_movable_mixin& operator=(non_movable_mixin&&) = delete; non_movable_mixin& operator=(non_movable_mixin&&) = delete;
protected: protected:
non_movable_mixin() {} non_movable_mixin() = default;
~non_movable_mixin() {} ~non_movable_mixin() = default;
}; };
POLYBAR_NS_END POLYBAR_NS_END

View File

@ -43,8 +43,6 @@ namespace detail {
m_root_window = screen_of_display(default_screen())->root; m_root_window = screen_of_display(default_screen())->root;
} }
virtual ~connection_base() {}
void operator()(const shared_ptr<xcb_generic_error_t>& error) const override { void operator()(const shared_ptr<xcb_generic_error_t>& error) const override {
check<xpp::x::extension, Extensions...>(error); check<xpp::x::extension, Extensions...>(error);
} }

View File

@ -692,12 +692,12 @@ void bar::handle(const evt::destroy_notify& evt) {
*/ */
void bar::handle(const evt::enter_notify&) { void bar::handle(const evt::enter_notify&) {
if (m_opts.dimmed) { if (m_opts.dimmed) {
m_dim_timer.start(25, 0, [this]() { 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_dim_timer.is_active()) { } else if (m_dim_timer->is_active()) {
m_dim_timer.stop(); m_dim_timer->stop();
} }
} }
@ -711,7 +711,7 @@ void bar::handle(const evt::leave_notify&) {
// Only trigger dimming, if the dim-value is not fully opaque. // Only trigger dimming, if the dim-value is not fully opaque.
if (m_opts.dimvalue < 1.0) { if (m_opts.dimvalue < 1.0) {
if (!m_opts.dimmed) { if (!m_opts.dimmed) {
m_dim_timer.start(3000, 0, [this]() { m_dim_timer->start(3000, 0, [this]() {
m_opts.dimmed = true; m_opts.dimmed = true;
m_sig.emit(dim_window{double(m_opts.dimvalue)}); m_sig.emit(dim_window{double(m_opts.dimvalue)});
}); });
@ -820,11 +820,11 @@ void bar::handle(const evt::button_press& evt) {
if (!has_dblclick) { if (!has_dblclick) {
trigger_click(btn, pos); trigger_click(btn, pos);
} else if (btn == mousebtn::LEFT) { } else if (btn == mousebtn::LEFT) {
check_double(m_leftclick_timer, btn, pos); check_double(*m_leftclick_timer, btn, pos);
} else if (btn == mousebtn::MIDDLE) { } else if (btn == mousebtn::MIDDLE) {
check_double(m_middleclick_timer, btn, pos); check_double(*m_middleclick_timer, btn, pos);
} else if (btn == mousebtn::RIGHT) { } else if (btn == mousebtn::RIGHT) {
check_double(m_rightclick_timer, btn, pos); check_double(*m_rightclick_timer, btn, pos);
} else { } else {
trigger_click(btn, pos); trigger_click(btn, pos);
} }

View File

@ -154,7 +154,7 @@ void controller::trigger_update(bool force) {
} }
void controller::trigger_notification() { void controller::trigger_notification() {
m_notifier.send(); m_notifier->send();
} }
void controller::stop(bool reload) { void controller::stop(bool reload) {
@ -196,12 +196,12 @@ void controller::signal_handler(int signum) {
} }
void controller::create_config_watcher(const string& filename) { void controller::create_config_watcher(const string& filename) {
auto& fs_event_handler = m_loop.handle<FSEventHandle>(); auto fs_event_handle = m_loop.handle<FSEventHandle>();
fs_event_handler.start( fs_event_handle->start(
filename, 0, [this](const auto& e) { confwatch_handler(e.path); }, filename, 0, [this](const auto& e) { confwatch_handler(e.path); },
[this, &fs_event_handler](const auto& e) { [this, &handle = *fs_event_handle](const auto& e) {
m_log.err("libuv error while watching included file for changes: %s", uv_strerror(e.status)); m_log.err("libuv error while watching included file for changes: %s", uv_strerror(e.status));
fs_event_handler.close(); handle.close();
}); });
} }
@ -247,16 +247,16 @@ 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());
try { try {
auto& x_poll_handle = m_loop.handle<PollHandle>(m_connection.get_file_descriptor()); auto x_poll_handle = m_loop.handle<PollHandle>(m_connection.get_file_descriptor());
x_poll_handle.start( x_poll_handle->start(
UV_READABLE, [this](const auto&) { conn_cb(); }, UV_READABLE, [this](const auto&) { conn_cb(); },
[this](const auto& e) { [this](const auto& e) {
m_log.err("libuv error while polling X connection: "s + uv_strerror(e.status)); m_log.err("libuv error while polling X connection: "s + uv_strerror(e.status));
stop(false); stop(false);
}); });
auto& x_prepare_handle = m_loop.handle<PrepareHandle>(); auto x_prepare_handle = m_loop.handle<PrepareHandle>();
x_prepare_handle.start([this]() { x_prepare_handle->start([this]() {
/* /*
* We have to also handle events in the prepare handle (which runs right * We have to also handle events in the prepare handle (which runs right
* before polling for IO) to process any already queued X events which * before polling for IO) to process any already queued X events which
@ -267,8 +267,8 @@ void controller::read_events(bool confwatch) {
}); });
for (auto s : {SIGINT, SIGQUIT, SIGTERM, SIGUSR1, SIGALRM}) { for (auto s : {SIGINT, SIGQUIT, SIGTERM, SIGUSR1, SIGALRM}) {
auto& signal_handle = m_loop.handle<SignalHandle>(); auto signal_handle = m_loop.handle<SignalHandle>();
signal_handle.start(s, [this](const auto& e) { signal_handler(e.signum); }); signal_handle->start(s, [this](const auto& e) { signal_handler(e.signum); });
} }
if (confwatch) { if (confwatch) {
@ -281,8 +281,8 @@ 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
auto& timer_handle = m_loop.handle<TimerHandle>(); auto timer_handle = m_loop.handle<TimerHandle>();
timer_handle.start(3000, 0, [this]() { screenshot_handler(); }); timer_handle->start(3000, 0, [this]() { screenshot_handler(); });
} }
if (!m_writeback) { if (!m_writeback) {

View File

@ -1,6 +1,7 @@
#include "components/eventloop.hpp" #include "components/eventloop.hpp"
#include <cassert> #include <cassert>
#include <utility>
#include "errors.hpp" #include "errors.hpp"
@ -46,15 +47,64 @@ namespace eventloop {
} }
} }
// WriteRequest {{{
WriteRequest::WriteRequest(cb_write&& user_cb, cb_error&& err_cb)
: write_callback(std::move(user_cb)), write_err_cb(std::move(err_cb)) {
get()->data = this;
}
WriteRequest& WriteRequest::create(cb_write&& user_cb, cb_error&& err_cb) {
auto r = std::make_unique<WriteRequest>(std::move(user_cb), std::move(err_cb));
return r->leak(std::move(r));
}
uv_write_t* WriteRequest::get() {
return &req;
}
void WriteRequest::trigger(int status) {
if (status < 0) {
if (write_err_cb) {
write_err_cb(ErrorEvent{status});
}
} else {
if (write_callback) {
write_callback();
}
}
unleak();
}
WriteRequest& WriteRequest::leak(std::unique_ptr<WriteRequest> h) {
lifetime_extender = std::move(h);
return *lifetime_extender;
}
void WriteRequest::unleak() {
reset_callbacks();
lifetime_extender.reset();
}
void WriteRequest::reset_callbacks() {
write_callback = nullptr;
write_err_cb = nullptr;
}
// }}}
// SignalHandle {{{ // SignalHandle {{{
void SignalHandle::init() { void SignalHandle::init() {
UV(uv_signal_init, loop(), get()); UV(uv_signal_init, loop(), get());
} }
void SignalHandle::start(int signum, cb user_cb) { void SignalHandle::start(int signum, cb&& user_cb) {
this->callback = user_cb; this->callback = std::move(user_cb);
UV(uv_signal_start, get(), event_cb<SignalEvent, &SignalHandle::callback>, signum); UV(uv_signal_start, get(), event_cb<SignalEvent, &SignalHandle::callback>, signum);
} }
void SignalHandle::reset_callbacks() {
callback = nullptr;
}
// }}} // }}}
// PollHandle {{{ // PollHandle {{{
@ -62,9 +112,9 @@ namespace eventloop {
UV(uv_poll_init, loop(), get(), fd); UV(uv_poll_init, loop(), get(), fd);
} }
void PollHandle::start(int events, cb user_cb, cb_error err_cb) { void PollHandle::start(int events, cb&& user_cb, cb_error&& err_cb) {
this->callback = user_cb; this->callback = std::move(user_cb);
this->err_cb = err_cb; this->err_cb = std::move(err_cb);
UV(uv_poll_start, get(), events, &poll_callback); UV(uv_poll_start, get(), events, &poll_callback);
} }
@ -77,6 +127,11 @@ namespace eventloop {
self.callback(PollEvent{(uv_poll_event)events}); self.callback(PollEvent{(uv_poll_event)events});
} }
void PollHandle::reset_callbacks() {
callback = nullptr;
err_cb = nullptr;
}
// }}} // }}}
// FSEventHandle {{{ // FSEventHandle {{{
@ -84,9 +139,9 @@ namespace eventloop {
UV(uv_fs_event_init, loop(), get()); UV(uv_fs_event_init, loop(), get());
} }
void FSEventHandle::start(const string& path, int flags, cb user_cb, cb_error err_cb) { void FSEventHandle::start(const string& path, int flags, cb&& user_cb, cb_error&& err_cb) {
this->callback = user_cb; this->callback = std::move(user_cb);
this->err_cb = err_cb; this->err_cb = std::move(err_cb);
UV(uv_fs_event_start, get(), fs_event_callback, path.c_str(), flags); UV(uv_fs_event_start, get(), fs_event_callback, path.c_str(), flags);
} }
@ -100,6 +155,10 @@ namespace eventloop {
self.callback(FSEvent{path, (uv_fs_event)events}); self.callback(FSEvent{path, (uv_fs_event)events});
} }
void FSEventHandle::reset_callbacks() {
callback = nullptr;
err_cb = nullptr;
}
// }}} // }}}
// PipeHandle {{{ // PipeHandle {{{
@ -115,9 +174,9 @@ namespace eventloop {
UV(uv_pipe_bind, get(), path.c_str()); UV(uv_pipe_bind, get(), path.c_str());
} }
void PipeHandle::connect(const string& name, cb_connect user_cb, cb_error err_cb) { void PipeHandle::connect(const string& name, cb_connect&& user_cb, cb_error&& err_cb) {
this->connect_callback = user_cb; this->connect_callback = std::move(user_cb);
this->connect_err_cb = err_cb; this->connect_err_cb = std::move(err_cb);
uv_pipe_connect(new uv_connect_t(), get(), name.c_str(), connect_cb); uv_pipe_connect(new uv_connect_t(), get(), name.c_str(), connect_cb);
} }
@ -132,6 +191,12 @@ namespace eventloop {
delete req; delete req;
} }
void PipeHandle::reset_callbacks() {
StreamHandle::reset_callbacks();
connect_callback = nullptr;
connect_err_cb = nullptr;
}
// }}} // }}}
// TimerHandle {{{ // TimerHandle {{{
@ -139,25 +204,33 @@ namespace eventloop {
UV(uv_timer_init, loop(), get()); UV(uv_timer_init, loop(), get());
} }
void TimerHandle::start(uint64_t timeout, uint64_t repeat, cb user_cb) { void TimerHandle::start(uint64_t timeout, uint64_t repeat, cb&& user_cb) {
this->callback = user_cb; this->callback = std::move(user_cb);
UV(uv_timer_start, get(), void_event_cb<&TimerHandle::callback>, timeout, repeat); UV(uv_timer_start, get(), void_event_cb<&TimerHandle::callback>, timeout, repeat);
} }
void TimerHandle::stop() { void TimerHandle::stop() {
UV(uv_timer_stop, get()); UV(uv_timer_stop, get());
} }
void TimerHandle::reset_callbacks() {
callback = nullptr;
}
// }}} // }}}
// AsyncHandle {{{ // AsyncHandle {{{
void AsyncHandle::init(cb user_cb) { void AsyncHandle::init(cb&& user_cb) {
this->callback = user_cb; this->callback = std::move(user_cb);
UV(uv_async_init, loop(), get(), void_event_cb<&AsyncHandle::callback>); UV(uv_async_init, loop(), get(), void_event_cb<&AsyncHandle::callback>);
} }
void AsyncHandle::send() { void AsyncHandle::send() {
UV(uv_async_send, get()); UV(uv_async_send, get());
} }
void AsyncHandle::reset_callbacks() {
callback = nullptr;
}
// }}} // }}}
// PrepareHandle {{{ // PrepareHandle {{{
@ -165,10 +238,14 @@ namespace eventloop {
UV(uv_prepare_init, loop(), get()); UV(uv_prepare_init, loop(), get());
} }
void PrepareHandle::start(cb user_cb) { void PrepareHandle::start(cb&& user_cb) {
this->callback = user_cb; this->callback = std::move(user_cb);
UV(uv_prepare_start, get(), void_event_cb<&PrepareHandle::callback>); UV(uv_prepare_start, get(), void_event_cb<&PrepareHandle::callback>);
} }
void PrepareHandle::reset_callbacks() {
callback = nullptr;
}
// }}} // }}}
// eventloop {{{ // eventloop {{{
@ -227,3 +304,4 @@ namespace eventloop {
} // namespace eventloop } // namespace eventloop
POLYBAR_NS_END POLYBAR_NS_END

View File

@ -57,12 +57,12 @@ namespace ipc {
m_log.info("Opening ipc socket at '%s'", sock_path); m_log.info("Opening ipc socket at '%s'", sock_path);
m_log.notice("Listening for IPC messages (PID: %d)", getpid()); m_log.notice("Listening for IPC messages (PID: %d)", getpid());
socket.bind(sock_path); socket->bind(sock_path);
socket.listen( socket->listen(
4, [this]() { on_connection(); }, 4, [this]() { on_connection(); },
[this](const auto& e) { [this](const auto& e) {
m_log.err("libuv error while listening to IPC socket: %s", uv_strerror(e.status)); m_log.err("libuv error while listening to IPC socket: %s", uv_strerror(e.status));
socket.close(); socket->close();
}); });
} }
@ -124,7 +124,7 @@ namespace ipc {
} else { } else {
response = encode(TYPE_ERR, "Unrecognized IPC message type " + to_string(type)); response = encode(TYPE_ERR, "Unrecognized IPC message type " + to_string(type));
} }
c.client_pipe.write( c.client_pipe->write(
response, [this, &c]() { remove_client(c); }, response, [this, &c]() { remove_client(c); },
[this, &c](const auto& e) { [this, &c](const auto& e) {
m_log.err("ipc: libuv error while writing to IPC socket: %s", uv_strerror(e.status)); m_log.err("ipc: libuv error while writing to IPC socket: %s", uv_strerror(e.status));
@ -133,16 +133,16 @@ namespace ipc {
}); });
auto& c = *connection; auto& c = *connection;
socket.accept(c.client_pipe); socket->accept(*c.client_pipe);
c.client_pipe.read_start( c.client_pipe->read_start(
[this, &c](const auto& e) { [this, &c](const auto& e) {
try { try {
c.dec.on_read((const uint8_t*)e.data, e.len); c.dec.on_read((const uint8_t*)e.data, e.len);
} catch (const decoder::error& e) { } catch (const decoder::error& e) {
m_log.err("ipc: Failed to decode IPC message (reason: %s)", e.what()); m_log.err("ipc: Failed to decode IPC message (reason: %s)", e.what());
c.client_pipe.write( c.client_pipe->write(
encode(TYPE_ERR, "Invalid binary message format: "s + e.what()), [this, &c]() { remove_client(c); }, encode(TYPE_ERR, "Invalid binary message format: "s + e.what()), [this, &c]() { remove_client(c); },
[this, &c](const auto& e) { [this, &c](const auto& e) {
m_log.err("ipc: libuv error while writing to IPC socket: %s", uv_strerror(e.status)); m_log.err("ipc: libuv error while writing to IPC socket: %s", uv_strerror(e.status));
@ -171,7 +171,7 @@ namespace ipc {
}) {} }) {}
ipc::connection::~connection() { ipc::connection::~connection() {
client_pipe.close(); client_pipe->close();
} }
ipc::fifo::fifo(loop& loop, ipc& ipc, const string& path) : pipe_handle(loop.handle<PipeHandle>()) { ipc::fifo::fifo(loop& loop, ipc& ipc, const string& path) : pipe_handle(loop.handle<PipeHandle>()) {
@ -180,8 +180,8 @@ namespace ipc {
throw system_error("Failed to open pipe '" + path + "'"); throw system_error("Failed to open pipe '" + path + "'");
} }
pipe_handle.open(fd); pipe_handle->open(fd);
pipe_handle.read_start([&ipc](const auto& e) mutable { ipc.receive_data(string(e.data, e.len)); }, pipe_handle->read_start([&ipc](const auto& e) mutable { ipc.receive_data(string(e.data, e.len)); },
[&ipc]() { ipc.receive_eof(); }, [&ipc]() { ipc.receive_eof(); },
[&ipc](const auto& e) mutable { [&ipc](const auto& e) mutable {
ipc.m_log.err("libuv error while listening to IPC channel: %s", uv_strerror(e.status)); ipc.m_log.err("libuv error while listening to IPC channel: %s", uv_strerror(e.status));
@ -190,7 +190,7 @@ namespace ipc {
} }
ipc::fifo::~fifo() { ipc::fifo::~fifo() {
pipe_handle.close(); pipe_handle->close();
} }
/** /**

View File

@ -262,11 +262,11 @@ int run(int argc, char** argv) {
*/ */
int idx = decoders.size() - 1; int idx = decoders.size() - 1;
auto& conn = loop.handle<PipeHandle>(); auto conn = loop.handle<PipeHandle>();
conn.connect( conn->connect(
channel, channel,
[&conn, &decoders, pid, type, payload, channel, idx]() { [&conn, &decoders, pid, type, payload, channel, idx]() {
on_connection(conn, decoders[idx], pid, type, payload); on_connection(*conn, decoders[idx], pid, type, payload);
}, },
[&](const auto& e) { [&](const auto& e) {
fprintf(stderr, "%s: Failed to connect to '%s' (err: '%s')\n", exec, channel.c_str(), uv_strerror(e.status)); fprintf(stderr, "%s: Failed to connect to '%s' (err: '%s')\n", exec, channel.c_str(), uv_strerror(e.status));

View File

@ -24,6 +24,21 @@ inotify_watch::~inotify_watch() {
} }
} }
inotify_watch::inotify_watch(inotify_watch&& other) noexcept {
std::swap(m_path, other.m_path);
std::swap(m_wd, other.m_wd);
std::swap(m_fd, other.m_fd);
std::swap(m_mask, other.m_mask);
}
inotify_watch& inotify_watch::operator=(inotify_watch&& other) noexcept {
std::swap(m_path, other.m_path);
std::swap(m_wd, other.m_wd);
std::swap(m_fd, other.m_fd);
std::swap(m_mask, other.m_mask);
return *this;
}
/** /**
* Attach inotify watch * Attach inotify watch
*/ */
@ -101,7 +116,7 @@ inotify_event inotify_watch::get_event() const {
/** /**
* Get watch file path * Get watch file path
*/ */
const string inotify_watch::path() const { string inotify_watch::path() const {
return m_path; return m_path;
} }