diff --git a/include/components/controller.hpp b/include/components/controller.hpp index 3fb4da5a..6e32cf93 100644 --- a/include/components/controller.hpp +++ b/include/components/controller.hpp @@ -76,8 +76,8 @@ class controller { m_log.trace("controller: Stop modules"); for (auto&& block : m_modules) { for (auto&& module : block.second) { - module->on_update.disconnect(this, &controller::on_module_update); - module->on_stop.disconnect(this, &controller::on_module_stop); + module->on_update.clear(); + module->on_stop.clear(); module->stop(); } } @@ -88,7 +88,7 @@ class controller { } m_log.trace("controller: Deconstruct bar instance"); - g_signals::bar::action_click.disconnect(this, &controller::on_module_click); + g_signals::bar::action_click.clear(); m_bar.reset(); m_log.trace("controller: Interrupt X event loop"); diff --git a/include/modules/script.hpp b/include/modules/script.hpp index 605cc121..c94c1be4 100644 --- a/include/modules/script.hpp +++ b/include/modules/script.hpp @@ -5,7 +5,7 @@ LEMONBUDDY_NS -#define SHELL_CMD "/usr/bin/env\nsh\n-c\n" +#define SHELL_CMD "/usr/bin/env\nsh\n-c\n%cmd%" #define OUTPUT_ACTION(BUTTON) \ if (!m_actions[BUTTON].empty()) \ m_builder->cmd(BUTTON, string_util::replace_all(m_actions[BUTTON], "%counter%", counter_str)) @@ -18,7 +18,8 @@ namespace modules { void setup() { m_formatter->add(DEFAULT_FORMAT, TAG_OUTPUT, {TAG_OUTPUT}); - // Load configuration values {{{ + // Load configuration values + REQ_CONFIG_VALUE(name(), m_exec, "exec"); GET_CONFIG_VALUE(name(), m_tail, "tail"); GET_CONFIG_VALUE(name(), m_maxlen, "maxlen"); @@ -30,113 +31,99 @@ namespace modules { m_actions[mousebtn::SCROLL_UP] = m_conf.get(name(), "scroll-up", ""); m_actions[mousebtn::SCROLL_DOWN] = m_conf.get(name(), "scroll-down", ""); - if (!m_tail) { - m_interval = interval_t{m_conf.get(name(), "interval", m_interval.count())}; - } - // }}} - // Execute the tail command {{{ - if (m_tail) { - try { - auto exec = string_util::replace_all(m_exec, "%counter%", to_string(++m_counter)); - m_log.trace("%s: Executing '%s'", name(), exec); - - m_command = command_util::make_command(SHELL_CMD + exec); - m_command->exec(false); - } catch (const std::exception& err) { - m_log.err("%s: Failed to execute tail command, stopping module..", name()); - m_log.err("%s: %s", name(), err.what()); - stop(); - } - } - // }}} + m_interval = interval_t{m_conf.get(name(), "interval", 0.0f)}; } void stop() { - // Put the module in stopped state {{{ - event_module::stop(); - // }}} - // Terminate running command {{{ - try { - if (m_tail && m_command) - m_command.reset(); - } catch (const std::exception& err) { - m_log.err("%s: %s", name(), err.what()); - } - // }}} + wakeup(); + enable(false); + m_command.reset(); + std::lock_guard lck(this->update_lock); + wakeup(); + } + + void idle() { + if (!enabled()) + sleep(100ms); + if (!m_tail) + sleep(m_interval); + else if (!m_command || !m_command->is_running()) + sleep(m_interval); } bool has_event() { - // Handle non-tailing command {{{ - if (!m_tail) { - sleep(m_interval); - return enabled(); - } - // }}} - // Handle tailing command {{{ - if (!m_command || !m_command->is_running()) { - m_log.warn("%s: Tail command finished, stopping module...", name()); - stop(); - return false; - } else if ((m_output = m_command->readline()) != m_prev) { - m_prev = m_output; + // Non tail commands should always run + if (!m_tail) return true; - } else { + + if (!enabled()) return false; + + try { + if (!m_command || !m_command->is_running()) { + auto exec = string_util::replace_all(m_exec, "%counter%", to_string(++m_counter)); + m_log.trace("%s: Executing '%s'", name(), exec); + + m_command = command_util::make_command(string_util::replace(SHELL_CMD, "%cmd%", exec)); + m_command->exec(false); + } + } catch (const std::exception& err) { + m_log.err("%s: %s", name(), err.what()); + throw module_error(name() + ": Failed to execute tail command, stopping module..."); } - // }}} + + if (!m_command) + return false; + + if ((m_output = m_command->readline()) == m_prev) + return false; + + m_prev = m_output; + + return true; } bool update() { - // Handle tailing command {{{ + // Tailing commands always update if (m_tail) return true; - // }}} - // Handle non-tailing command {{{ + try { auto exec = string_util::replace_all(m_exec, "%counter%", to_string(++m_counter)); - auto cmd = command_util::make_command(SHELL_CMD + exec); + auto cmd = command_util::make_command(string_util::replace(SHELL_CMD, "%cmd%", exec)); m_log.trace("%s: Executing '%s'", name(), exec); cmd->exec(); cmd->tail([this](string contents) { m_output = contents; }); } catch (const std::exception& err) { - m_log.err("%s: Failed to execute command, stopping module..", name()); m_log.err("%s: %s", name(), err.what()); - stop(); + throw module_error(name() + ": Failed to execute command, stopping module..."); + } + + if (m_output == m_prev) return false; - } - if (m_output != m_prev) { - m_prev = m_output; - return true; - } - - return false; - // }}} + m_prev = m_output; + return true; } string get_output() { if (m_output.empty()) return " "; - // Truncate output to the defined max length {{{ - + // Truncate output to the defined max length if (m_maxlen > 0 && m_output.length() > m_maxlen) { m_output.erase(m_maxlen); m_output += m_ellipsis ? "..." : ""; } - // }}} - // Add mousebtn command handlers {{{ - auto counter_str = to_string(m_counter); + auto counter_str = to_string(m_counter); OUTPUT_ACTION(mousebtn::LEFT); OUTPUT_ACTION(mousebtn::MIDDLE); OUTPUT_ACTION(mousebtn::RIGHT); OUTPUT_ACTION(mousebtn::SCROLL_UP); OUTPUT_ACTION(mousebtn::SCROLL_DOWN); - // }}} - m_builder->node(module::get_output()); return m_builder->flush(); @@ -156,7 +143,7 @@ namespace modules { string m_exec; bool m_tail = false; - interval_t m_interval = 1s; + interval_t m_interval = 0s; size_t m_maxlen = 0; bool m_ellipsis = true; map m_actions; diff --git a/include/utils/command.hpp b/include/utils/command.hpp index b67bdd97..e6ba02ed 100644 --- a/include/utils/command.hpp +++ b/include/utils/command.hpp @@ -60,15 +60,8 @@ namespace command_util { } ~command() { - if (is_running()) { - try { - m_log.trace("command: Sending SIGTERM to running child process (%d)", m_forkpid); - killpg(m_forkpid, SIGTERM); - wait(); - } catch (const std::exception& err) { - m_log.err("command: %s", err.what()); - } - } + if (is_running()) + terminate(); if (m_stdin[PIPE_READ] > 0) close(m_stdin[PIPE_READ]); @@ -119,13 +112,30 @@ namespace command_util { if ((m_stdout[PIPE_WRITE] = close(m_stdout[PIPE_WRITE])) == -1) throw command_strerror("Failed to close fd"); - if (wait_for_completion) - return wait(); + if (wait_for_completion) { + auto status = wait(); + m_forkpid = -1; + return status; + } } return EXIT_SUCCESS; } + void terminate() { + try { + if (is_running()) { + m_log.trace("command: Sending SIGTERM to running child process (%d)", m_forkpid); + killpg(m_forkpid, SIGTERM); + wait(); + } + } catch (const command_error& err) { + m_log.warn("%s", err.what()); + } + + m_forkpid = -1; + } + /** * Wait for the child processs to finish */ @@ -133,11 +143,12 @@ namespace command_util { auto waitflags = WCONTINUED | WUNTRACED; do { - if (process_util::wait_for_completion(m_forkpid, &m_forkstatus, waitflags) == -1) - throw command_error("Process did not finish successfully"); + process_util::wait_for_completion(m_forkpid, &m_forkstatus, waitflags); - if (WIFEXITED(m_forkstatus)) - m_log.trace("command: Exited with status %d", WEXITSTATUS(m_forkstatus)); + 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)); else if (WIFSIGNALED(m_forkstatus)) m_log.trace("command: killed by signal %d", WTERMSIG(m_forkstatus)); else if (WIFSTOPPED(m_forkstatus)) @@ -197,7 +208,9 @@ namespace command_util { * Check if command is running */ bool is_running() { - return process_util::wait_for_completion_nohang(m_forkpid, &m_forkstatus) > -1; + if (m_forkpid > 0) + return process_util::wait_for_completion_nohang(m_forkpid, &m_forkstatus) > -1; + return false; } /**