diff --git a/CMakeLists.txt b/CMakeLists.txt index 3e7d4ee1..a67fb858 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -8,7 +8,7 @@ set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} ${PROJECT_SOURCE_DIR}/cmake/modules) set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++14 -Wall -Wno-unused-parameter -Wno-unused-local-typedefs") set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -DDEBUG -O0 -g2") -set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -O1") +set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -O3") set(CMAKE_C_STANDARD 11) set(CMAKE_C_STANDARD_REQUIRED ON) diff --git a/include/components/bar.hpp b/include/components/bar.hpp index bf7420d9..eb944ef6 100644 --- a/include/components/bar.hpp +++ b/include/components/bar.hpp @@ -22,6 +22,7 @@ #include "utils/math.hpp" #include "utils/string.hpp" #include "utils/threading.hpp" +#include "utils/throttle.hpp" #if ENABLE_I3 #include "utils/i3.hpp" #endif @@ -83,6 +84,9 @@ class bar : public xpp::event::sinkroot); @@ -588,6 +592,10 @@ class bar : public xpp::event::sinkpassthrough(throttle_util::strategy::try_once_or_leave_yolo{})) { + return; + } + std::lock_guard lck(m_lock); { m_log.trace("bar: Received button press event: %i at pos(%i, %i)", @@ -980,6 +988,7 @@ class bar : public xpp::event::sink m_fontmanager; threading_util::spin_lock m_lock; + throttle_util::throttle_t m_throttler; xcb_screen_t* m_screen; xcb_visualtype_t* m_visual; diff --git a/include/components/controller.hpp b/include/components/controller.hpp index 6e32cf93..fde2268d 100644 --- a/include/components/controller.hpp +++ b/include/components/controller.hpp @@ -76,8 +76,6 @@ class controller { m_log.trace("controller: Stop modules"); for (auto&& block : m_modules) { for (auto&& module : block.second) { - module->on_update.clear(); - module->on_stop.clear(); module->stop(); } } @@ -211,9 +209,6 @@ class controller { m_log.trace("controller: Start modules"); for (auto&& block : m_modules) { for (auto&& module : block.second) { - module->on_update.connect(this, &controller::on_module_update); - module->on_stop.connect(this, &controller::on_module_stop); - try { module->start(); } catch (const application_error& err) { @@ -407,6 +402,11 @@ class controller { else throw application_error("Unknown module: " + module_name); + auto& module = modules.back(); + + module->set_writer(delegate::MakeDelegate(this, &controller::on_module_update)); + module->set_terminator(delegate::MakeDelegate(this, &controller::on_module_stop)); + module_count++; } } @@ -415,14 +415,15 @@ class controller { throw application_error("No modules created"); } - void on_module_update(string module_name) { - if (!m_mutex.try_lock_for(50ms)) + void on_module_update(string /* module_name */) { + if (!m_mutex.try_lock_for(50ms)) { + this_thread::yield(); return; + } std::lock_guard guard(m_mutex, std::adopt_lock); if (!m_running) return; - if (!m_throttler->passthrough(m_throttle_strategy)) { m_log.trace("controller: Update event throttled"); return; @@ -489,7 +490,10 @@ class controller { m_bar->parse(contents); } - void on_module_stop(string module_name) { + void on_module_stop(string /* module_name */) { + if (!m_running) + return; + for (auto&& block : m_modules) { for (auto&& module : block.second) { if (module->running()) @@ -502,9 +506,12 @@ class controller { } void on_module_click(string input) { - if (!m_mutex.try_lock()) + if (!m_clickmtx.try_lock()) { + this_thread::yield(); return; - std::lock_guard guard(m_mutex, std::adopt_lock); + } + + std::lock_guard guard(m_clickmtx, std::adopt_lock); for (auto&& block : m_modules) { for (auto&& module : block.second) { @@ -538,6 +545,7 @@ class controller { unique_ptr m_traymanager; std::timed_mutex m_mutex; + std::mutex m_clickmtx; stateflag m_stdout{false}; stateflag m_running{false}; diff --git a/include/modules/meta.hpp b/include/modules/meta.hpp index 19778ed8..ce387b65 100644 --- a/include/modules/meta.hpp +++ b/include/modules/meta.hpp @@ -18,8 +18,8 @@ LEMONBUDDY_NS #define DEFAULT_FORMAT "format" #define DEFINE_MODULE(name, type) struct name : public type -#define CONST_CAST_MODULE(name) static_cast(*this) -#define CAST_MODULE(name) static_cast(this) +#define CONST_MOD(name) static_cast(*this) +#define CAST_MOD(name) static_cast(this) namespace modules { using namespace drawtypes; @@ -153,14 +153,13 @@ namespace modules { virtual void setup() = 0; virtual void start() = 0; virtual void stop() = 0; - virtual void refresh() = 0; virtual string contents() = 0; virtual bool handle_event(string cmd) = 0; virtual bool receive_events() const = 0; - delegate::Signal1 on_update; - delegate::Signal1 on_stop; + virtual void set_writer(delegate::Delegate1&& fn) = 0; + virtual void set_terminator(delegate::Delegate1&& fn) = 0; }; // }}} @@ -178,10 +177,11 @@ namespace modules { , m_formatter(make_unique(m_conf, m_name)) {} ~module() { - stop(); + CAST_MOD(Impl)->stop(); - this->update_lock.unlock(); - std::lock_guard lck(this->update_lock); + m_updatelock.unlock(); + + std::lock_guard lck(m_updatelock); { if (m_broadcast_thread.joinable()) m_broadcast_thread.join(); @@ -190,43 +190,51 @@ namespace modules { if (thread_.joinable()) thread_.join(); } + m_threads.clear(); } m_log.trace("%s: Done cleaning up", name()); } + void set_writer(delegate::Delegate1&& fn) { + m_writer = forward(fn); + } + + void set_terminator(delegate::Delegate1&& fn) { + m_terminator = forward(fn); + } + string name() const { return m_name; } bool running() const { - return enabled(); + return CONST_MOD(Impl).enabled(); } void setup() { m_log.trace("%s: Setup", name()); - CAST_MODULE(Impl)->setup(); + CAST_MOD(Impl)->setup(); } void stop() { if (!enabled()) return; - std::unique_lock lck(this->update_lock); - enable(false); - CAST_MODULE(Impl)->teardown(); - lck.unlock(); - m_log.trace("%s: Stop", name()); - if (!on_stop.empty()) - on_stop.emit(name()); + + std::unique_lock lck(m_updatelock); + { + enable(false); + CAST_MOD(Impl)->teardown(); + m_log.trace("%s: Stop", name()); + } + + if (m_terminator) + m_terminator(name()); } void teardown() { - wakeup(); - } - - void refresh() { - m_cache = CAST_MODULE(Impl)->get_output(); + CAST_MOD(Impl)->wakeup(); } string contents() { @@ -234,7 +242,7 @@ namespace modules { } bool handle_event(string cmd) { - return CAST_MODULE(Impl)->handle_event(cmd); + return CAST_MOD(Impl)->handle_event(cmd); } bool receive_events() const { @@ -253,15 +261,11 @@ namespace modules { void broadcast() { if (!enabled()) return; + else if (!m_writer) + m_log.warn("%s: No attach writer, ignoring broadcast...", name()); - refresh(); - - if (contents().empty()) - return; - else if (on_update.empty()) - m_log.warn("%s: No signal handlers connected... ignoring broadcast", name()); - else - on_update.emit(name()); + m_cache = CAST_MOD(Impl)->get_output(); + m_writer(name()); } void idle() {} @@ -287,7 +291,7 @@ namespace modules { return ""; } - auto format_name = CONST_CAST_MODULE(Impl).get_format(); + auto format_name = CONST_MOD(Impl).get_format(); auto format = m_formatter->get(format_name); int i = 0; @@ -299,7 +303,7 @@ namespace modules { if (tag[0] == '<' && tag[tag.length() - 1] == '>') { if (i > 0) m_builder->space(format->spacing); - if (!(tag_built = CONST_CAST_MODULE(Impl).build(m_builder.get(), tag)) && i > 0) + if (!(tag_built = CONST_MOD(Impl).build(m_builder.get(), tag)) && i > 0) m_builder->remove_trailing_space(format->spacing); if (tag_built) i++; @@ -314,19 +318,11 @@ namespace modules { } protected: - // Called by modules after handling action events - void event_handled() { - std::lock_guard lck(this->update_lock); - { - if (m_broadcast_thread.joinable()) - m_broadcast_thread.join(); - m_broadcast_thread = thread(&module::broadcast, this); - } - } + delegate::Delegate1 m_writer; + delegate::Delegate1 m_terminator; - // concurrency::SpinLock output_lock; - // concurrency::SpinLock broadcast_lock; - threading_util::spin_lock update_lock; + threading_util::spin_lock m_updatelock; + // std::timed_mutex m_mutex; const bar_settings m_bar; const logger& m_log; @@ -356,9 +352,9 @@ namespace modules { using module::module; void start() { - CAST_MODULE(Impl)->setup(); - CAST_MODULE(Impl)->enable(true); - CAST_MODULE(Impl)->broadcast(); + CAST_MOD(Impl)->setup(); + CAST_MOD(Impl)->enable(true); + CAST_MOD(Impl)->broadcast(); } bool build(builder*, string) const { @@ -377,8 +373,8 @@ namespace modules { using module::module; void start() { - CAST_MODULE(Impl)->enable(true); - CAST_MODULE(Impl)->m_threads.emplace_back(thread(&timer_module::runner, this)); + CAST_MOD(Impl)->enable(true); + CAST_MOD(Impl)->m_threads.emplace_back(thread(&timer_module::runner, this)); } protected: @@ -386,20 +382,20 @@ namespace modules { void runner() { try { - CAST_MODULE(Impl)->setup(); + CAST_MOD(Impl)->setup(); - while (CONST_CAST_MODULE(Impl).enabled()) { + while (CONST_MOD(Impl).enabled()) { { - std::lock_guard lck(this->update_lock); - if (CAST_MODULE(Impl)->update()) - CAST_MODULE(Impl)->broadcast(); + std::lock_guard lck(this->m_updatelock); + if (CAST_MOD(Impl)->update()) + CAST_MOD(Impl)->broadcast(); } - CAST_MODULE(Impl)->sleep(m_interval); + CAST_MOD(Impl)->sleep(m_interval); } } catch (const std::exception& err) { - this->m_log.err("%s: %s", this->name(), err.what()); - this->m_log.warn("Stopping '%s'...", this->name()); - CAST_MODULE(Impl)->stop(); + this->m_log.err("%s: %s", CONST_MOD(Impl).name(), err.what()); + this->m_log.warn("Stopping '%s'...", CONST_MOD(Impl).name()); + CAST_MOD(Impl)->stop(); } } }; @@ -413,33 +409,33 @@ namespace modules { using module::module; void start() { - CAST_MODULE(Impl)->enable(true); - CAST_MODULE(Impl)->m_threads.emplace_back(thread(&event_module::runner, this)); + CAST_MOD(Impl)->enable(true); + CAST_MOD(Impl)->m_threads.emplace_back(thread(&event_module::runner, this)); } protected: void runner() { try { - CAST_MODULE(Impl)->setup(); + CAST_MOD(Impl)->setup(); // warmup - CAST_MODULE(Impl)->update(); - CAST_MODULE(Impl)->broadcast(); + CAST_MOD(Impl)->update(); + CAST_MOD(Impl)->broadcast(); - while (CONST_CAST_MODULE(Impl).enabled()) { - std::lock_guard lck(this->update_lock); + while (CONST_MOD(Impl).enabled()) { + std::lock_guard lck(this->m_updatelock); - if (!CAST_MODULE(Impl)->has_event()) - CAST_MODULE(Impl)->idle(); - else if (!CAST_MODULE(Impl)->update()) - CAST_MODULE(Impl)->idle(); + if (!CAST_MOD(Impl)->has_event()) + CAST_MOD(Impl)->idle(); + else if (!CAST_MOD(Impl)->update()) + CAST_MOD(Impl)->idle(); else - CAST_MODULE(Impl)->broadcast(); + CAST_MOD(Impl)->broadcast(); } } catch (const std::exception& err) { - this->m_log.err("%s: %s", this->name(), err.what()); - this->m_log.warn("Stopping '%s'...", this->name()); - CAST_MODULE(Impl)->stop(); + this->m_log.err("%s: %s", CONST_MOD(Impl).name(), err.what()); + this->m_log.warn("Stopping '%s'...", CONST_MOD(Impl).name()); + CAST_MOD(Impl)->stop(); } } }; @@ -453,34 +449,34 @@ namespace modules { using module::module; void start() { - CAST_MODULE(Impl)->enable(true); - CAST_MODULE(Impl)->m_threads.emplace_back(thread(&inotify_module::runner, this)); + CAST_MOD(Impl)->enable(true); + CAST_MOD(Impl)->m_threads.emplace_back(thread(&inotify_module::runner, this)); } protected: void runner() { try { - CAST_MODULE(Impl)->setup(); - CAST_MODULE(Impl)->on_event(nullptr); // warmup - CAST_MODULE(Impl)->broadcast(); + CAST_MOD(Impl)->setup(); + CAST_MOD(Impl)->on_event(nullptr); // warmup + CAST_MOD(Impl)->broadcast(); - while (CAST_MODULE(Impl)->enabled()) { - CAST_MODULE(Impl)->poll_events(); + while (CAST_MOD(Impl)->enabled()) { + CAST_MOD(Impl)->poll_events(); } } catch (const std::exception& err) { - this->m_log.err("%s: %s", this->name(), err.what()); - this->m_log.warn("Stopping '%s'...", this->name()); - CAST_MODULE(Impl)->stop(); + this->m_log.err("%s: %s", CONST_MOD(Impl).name(), err.what()); + this->m_log.warn("Stopping '%s'...", CONST_MOD(Impl).name()); + CAST_MOD(Impl)->stop(); } } void watch(string path, int mask = IN_ALL_EVENTS) { - this->m_log.trace("%s: Attach inotify at %s", this->name(), path); + this->m_log.trace("%s: Attach inotify at %s", CONST_MOD(Impl).name(), path); m_watchlist.insert(make_pair(path, mask)); } void idle() { - CAST_MODULE(Impl)->sleep(200ms); + CAST_MOD(Impl)->sleep(200ms); } void poll_events() { @@ -494,28 +490,28 @@ namespace modules { } catch (const system_error& e) { watches.clear(); this->m_log.err( - "%s: Error while creating inotify watch (what: %s)", this->name(), e.what()); - CAST_MODULE(Impl)->sleep(0.1s); + "%s: Error while creating inotify watch (what: %s)", CONST_MOD(Impl).name(), e.what()); + CAST_MOD(Impl)->sleep(0.1s); return; } - while (CONST_CAST_MODULE(Impl).enabled()) { + while (CONST_MOD(Impl).enabled()) { for (auto&& w : watches) { - this->m_log.trace("%s: Poll inotify watch %s", this->name(), w->path()); - std::lock_guard lck(this->update_lock); + this->m_log.trace("%s: Poll inotify watch %s", CONST_MOD(Impl).name(), w->path()); + std::lock_guard lck(this->m_updatelock); if (w->poll(1000 / watches.size())) { auto event = w->get_event(); w->remove(); - if (CAST_MODULE(Impl)->on_event(event.get())) - CAST_MODULE(Impl)->broadcast(); + if (CAST_MOD(Impl)->on_event(event.get())) + CAST_MOD(Impl)->broadcast(); return; } } - CAST_MODULE(Impl)->idle(); + CAST_MOD(Impl)->idle(); } } diff --git a/include/modules/script.hpp b/include/modules/script.hpp index 273cad13..c8f54309 100644 --- a/include/modules/script.hpp +++ b/include/modules/script.hpp @@ -38,7 +38,7 @@ namespace modules { wakeup(); enable(false); m_command.reset(); - std::lock_guard lck(this->update_lock); + std::lock_guard lck(m_updatelock); wakeup(); } @@ -94,8 +94,8 @@ namespace modules { m_log.trace("%s: Executing '%s'", name(), exec); - cmd->exec(); - cmd->tail([this](string contents) { m_output = contents; }); + cmd->exec(true); + cmd->tail([&](string output) { m_output = output; }); } catch (const std::exception& err) { m_log.err("%s: %s", name(), err.what()); throw module_error("Failed to execute command, stopping module..."); @@ -130,10 +130,12 @@ namespace modules { } bool build(builder* builder, string tag) const { - if (tag != TAG_OUTPUT) + if (tag == TAG_OUTPUT) { + builder->node(m_output); + return true; + } else { return false; - builder->node(string_util::replace_all(m_output, "\n", "")); - return true; + } } protected: diff --git a/include/modules/volume.hpp b/include/modules/volume.hpp index 16978774..9e898e3f 100644 --- a/include/modules/volume.hpp +++ b/include/modules/volume.hpp @@ -195,6 +195,7 @@ namespace modules { m_builder->cmd(mousebtn::SCROLL_DOWN, EVENT_VOLUME_DOWN); m_builder->node(module::get_output()); + return m_builder->flush(); } @@ -251,8 +252,6 @@ namespace modules { // sending the broadcast related to this event m_muted = !m_muted; - event_handled(); - return true; } diff --git a/include/utils/command.hpp b/include/utils/command.hpp index e6ba02ed..9491505a 100644 --- a/include/utils/command.hpp +++ b/include/utils/command.hpp @@ -148,7 +148,7 @@ namespace command_util { if (WIFEXITED(m_forkstatus) && m_forkstatus > 0) m_log.warn("command: Exited with failed status %d", WEXITSTATUS(m_forkstatus)); else if (WIFEXITED(m_forkstatus)) - m_log.warn("command: Exited with status %d", WEXITSTATUS(m_forkstatus)); + m_log.trace("command: Exited with status %d", WEXITSTATUS(m_forkstatus)); else if (WIFSIGNALED(m_forkstatus)) m_log.trace("command: killed by signal %d", WTERMSIG(m_forkstatus)); else if (WIFSTOPPED(m_forkstatus)) diff --git a/include/utils/throttle.hpp b/include/utils/throttle.hpp index 1cef6a4d..c6248e9c 100644 --- a/include/utils/throttle.hpp +++ b/include/utils/throttle.hpp @@ -101,8 +101,10 @@ namespace throttle_util { timewindow m_timewindow; }; + using throttle_t = unique_ptr; + template - auto make_throttler(Args&&... args) { + throttle_t make_throttler(Args&&... args) { return make_unique(forward(args)...); } }