2016-11-02 19:22:45 +00:00
|
|
|
#include "modules/script.hpp"
|
2016-12-03 20:07:40 +00:00
|
|
|
#include "drawtypes/label.hpp"
|
2016-11-20 22:04:31 +00:00
|
|
|
#include "modules/meta/base.inl"
|
|
|
|
|
2016-11-19 05:22:44 +00:00
|
|
|
POLYBAR_NS
|
2016-11-02 19:22:45 +00:00
|
|
|
|
|
|
|
namespace modules {
|
2016-11-20 22:04:31 +00:00
|
|
|
template class module<script_module>;
|
|
|
|
|
2017-01-10 04:12:53 +00:00
|
|
|
/**
|
|
|
|
* Construct script module by loading configuration values
|
|
|
|
* and setting up formatting objects
|
|
|
|
*/
|
|
|
|
script_module::script_module(const bar_settings& bar, string name_)
|
|
|
|
: module<script_module>(bar, move(name_)), m_handler([&]() -> function<chrono::duration<double>()> {
|
|
|
|
// Handler for continuous tail commands {{{
|
|
|
|
|
|
|
|
if (m_conf.get(name(), "tail", false)) {
|
|
|
|
return [&] {
|
|
|
|
if (!m_command || !m_command->is_running()) {
|
|
|
|
string exec{string_util::replace_all(m_exec, "%counter%", to_string(++m_counter))};
|
|
|
|
m_log.info("%s: Invoking shell command: \"%s\"", name(), exec);
|
|
|
|
m_command = command_util::make_command(exec);
|
|
|
|
|
|
|
|
try {
|
|
|
|
m_command->exec(false);
|
|
|
|
} catch (const exception& err) {
|
|
|
|
m_log.err("%s: %s", name(), err.what());
|
|
|
|
throw module_error("Failed to execute command, stopping module...");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-01-11 17:15:46 +00:00
|
|
|
int fd = m_command->get_stdout(PIPE_READ);
|
|
|
|
while (!m_stopping && fd != -1 && m_command->is_running() && !io_util::poll(fd, POLLHUP, 0)) {
|
|
|
|
if (!io_util::poll_read(fd, 25)) {
|
|
|
|
continue;
|
|
|
|
} else if ((m_output = m_command->readline()) != m_prev) {
|
2017-01-10 04:12:53 +00:00
|
|
|
m_prev = m_output;
|
|
|
|
broadcast();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-01-11 17:15:46 +00:00
|
|
|
if (m_stopping) {
|
|
|
|
return chrono::duration<double>{0};
|
|
|
|
} else if (m_command && !m_command->is_running()) {
|
2017-01-10 04:12:53 +00:00
|
|
|
return std::max(m_command->get_exit_status() == 0 ? m_interval : 1s, m_interval);
|
|
|
|
} else {
|
|
|
|
return m_interval;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
|
|
|
// }}}
|
|
|
|
// Handler for basic shell commands {{{
|
|
|
|
|
|
|
|
return [&] {
|
|
|
|
try {
|
|
|
|
auto exec = string_util::replace_all(m_exec, "%counter%", to_string(++m_counter));
|
|
|
|
m_log.info("%s: Invoking shell command: \"%s\"", name(), exec);
|
|
|
|
m_command = command_util::make_command(exec);
|
|
|
|
m_command->exec(true);
|
|
|
|
} catch (const exception& err) {
|
|
|
|
m_log.err("%s: %s", name(), err.what());
|
|
|
|
throw module_error("Failed to execute command, stopping module...");
|
|
|
|
}
|
|
|
|
|
2017-01-11 17:15:46 +00:00
|
|
|
int fd = m_command->get_stdout(PIPE_READ);
|
|
|
|
if (fd != -1 && io_util::poll_read(fd) && (m_output = m_command->readline()) != m_prev) {
|
2017-01-10 04:12:53 +00:00
|
|
|
broadcast();
|
|
|
|
m_prev = m_output;
|
2017-01-11 17:15:46 +00:00
|
|
|
} else if (m_command->get_exit_status() != 0) {
|
|
|
|
m_output.clear();
|
|
|
|
m_prev.clear();
|
|
|
|
broadcast();
|
2017-01-10 04:12:53 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return std::max(m_command->get_exit_status() == 0 ? m_interval : 1s, m_interval);
|
|
|
|
};
|
|
|
|
|
|
|
|
// }}}
|
|
|
|
}()) {
|
|
|
|
// Load configuration values
|
2016-12-30 22:32:05 +00:00
|
|
|
m_exec = m_conf.get(name(), "exec", m_exec);
|
2017-01-10 02:01:59 +00:00
|
|
|
m_exec_if = m_conf.get(name(), "exec-if", m_exec_if);
|
2017-01-01 07:58:33 +00:00
|
|
|
m_interval = m_conf.get<decltype(m_interval)>(name(), "interval", 5s);
|
2016-11-02 19:22:45 +00:00
|
|
|
|
2017-01-10 04:12:53 +00:00
|
|
|
// Load configured click handlers
|
2016-12-30 22:32:05 +00:00
|
|
|
m_actions[mousebtn::LEFT] = m_conf.get(name(), "click-left", ""s);
|
|
|
|
m_actions[mousebtn::MIDDLE] = m_conf.get(name(), "click-middle", ""s);
|
|
|
|
m_actions[mousebtn::RIGHT] = m_conf.get(name(), "click-right", ""s);
|
|
|
|
m_actions[mousebtn::SCROLL_UP] = m_conf.get(name(), "scroll-up", ""s);
|
|
|
|
m_actions[mousebtn::SCROLL_DOWN] = m_conf.get(name(), "scroll-down", ""s);
|
2016-12-03 20:07:40 +00:00
|
|
|
|
2017-01-10 04:12:53 +00:00
|
|
|
// Setup formatting
|
|
|
|
m_formatter->add(DEFAULT_FORMAT, TAG_LABEL, {TAG_LABEL});
|
2016-12-03 20:07:40 +00:00
|
|
|
if (m_formatter->has(TAG_LABEL)) {
|
|
|
|
m_label = load_optional_label(m_conf, name(), "label", "%output%");
|
|
|
|
}
|
2016-11-02 19:22:45 +00:00
|
|
|
}
|
|
|
|
|
2017-01-10 04:12:53 +00:00
|
|
|
/**
|
|
|
|
* Start the module worker
|
|
|
|
*/
|
2017-01-01 07:58:33 +00:00
|
|
|
void script_module::start() {
|
2017-01-10 04:12:53 +00:00
|
|
|
m_mainthread = thread([&] {
|
2016-12-31 13:08:44 +00:00
|
|
|
try {
|
2017-01-01 07:58:33 +00:00
|
|
|
while (running() && !m_stopping) {
|
2017-01-10 04:12:53 +00:00
|
|
|
if (check_condition()) {
|
|
|
|
sleep(process(m_handler));
|
|
|
|
} else if (m_interval > 1s) {
|
|
|
|
sleep(m_interval);
|
2017-01-10 02:01:59 +00:00
|
|
|
} else {
|
2017-01-10 04:12:53 +00:00
|
|
|
sleep(1s);
|
2017-01-10 02:01:59 +00:00
|
|
|
}
|
2017-01-01 07:58:33 +00:00
|
|
|
}
|
|
|
|
} catch (const exception& err) {
|
|
|
|
halt(err.what());
|
2016-11-02 19:22:45 +00:00
|
|
|
}
|
2017-01-01 07:58:33 +00:00
|
|
|
});
|
2016-11-02 19:22:45 +00:00
|
|
|
}
|
|
|
|
|
2017-01-10 04:12:53 +00:00
|
|
|
/**
|
|
|
|
* Stop the module worker by terminating any running commands
|
|
|
|
*/
|
2017-01-01 07:58:33 +00:00
|
|
|
void script_module::stop() {
|
|
|
|
m_stopping = true;
|
2017-01-10 04:12:53 +00:00
|
|
|
wakeup();
|
2016-11-02 19:22:45 +00:00
|
|
|
|
2017-01-11 17:15:46 +00:00
|
|
|
std::lock_guard<decltype(m_handler)> guard(m_handler);
|
2016-11-02 19:22:45 +00:00
|
|
|
|
2017-01-10 04:12:53 +00:00
|
|
|
m_command.reset();
|
|
|
|
module::stop();
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Check if defined condition is met
|
|
|
|
*/
|
|
|
|
bool script_module::check_condition() {
|
|
|
|
if (m_exec_if.empty()) {
|
|
|
|
return true;
|
|
|
|
} else if (command_util::make_command(m_exec_if)->exec(true) == 0) {
|
|
|
|
return true;
|
|
|
|
} else if (!m_output.empty()) {
|
|
|
|
broadcast();
|
|
|
|
m_output.clear();
|
|
|
|
m_prev.clear();
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Process mutex wrapped script handler
|
|
|
|
*/
|
|
|
|
chrono::duration<double> script_module::process(const decltype(m_handler) & handler) const {
|
|
|
|
std::lock_guard<decltype(handler)> guard(handler);
|
|
|
|
return handler();
|
2016-11-02 19:22:45 +00:00
|
|
|
}
|
|
|
|
|
2017-01-10 04:12:53 +00:00
|
|
|
/**
|
|
|
|
* Generate module output
|
|
|
|
*/
|
2016-11-02 19:22:45 +00:00
|
|
|
string script_module::get_output() {
|
2016-11-25 12:55:15 +00:00
|
|
|
if (m_output.empty()) {
|
2017-01-10 02:01:59 +00:00
|
|
|
return "";
|
2016-12-03 20:07:40 +00:00
|
|
|
}
|
2016-11-02 19:22:45 +00:00
|
|
|
|
2016-12-03 20:07:40 +00:00
|
|
|
if (m_label) {
|
|
|
|
m_label->reset_tokens();
|
|
|
|
m_label->replace_token("%output%", m_output);
|
2016-11-25 12:55:15 +00:00
|
|
|
}
|
2016-12-03 20:07:40 +00:00
|
|
|
|
2017-01-10 04:12:53 +00:00
|
|
|
string cnt{to_string(m_counter)};
|
2016-12-05 04:32:10 +00:00
|
|
|
string output{module::get_output()};
|
|
|
|
|
2017-01-01 07:58:33 +00:00
|
|
|
if (!m_actions[mousebtn::LEFT].empty()) {
|
2017-01-10 04:12:53 +00:00
|
|
|
m_builder->cmd(mousebtn::LEFT, string_util::replace_all(m_actions[mousebtn::LEFT], "%counter%", cnt));
|
2017-01-01 07:58:33 +00:00
|
|
|
}
|
|
|
|
if (!m_actions[mousebtn::MIDDLE].empty()) {
|
2017-01-10 04:12:53 +00:00
|
|
|
m_builder->cmd(mousebtn::MIDDLE, string_util::replace_all(m_actions[mousebtn::MIDDLE], "%counter%", cnt));
|
2017-01-01 07:58:33 +00:00
|
|
|
}
|
|
|
|
if (!m_actions[mousebtn::RIGHT].empty()) {
|
2017-01-10 04:12:53 +00:00
|
|
|
m_builder->cmd(mousebtn::RIGHT, string_util::replace_all(m_actions[mousebtn::RIGHT], "%counter%", cnt));
|
2017-01-01 07:58:33 +00:00
|
|
|
}
|
|
|
|
if (!m_actions[mousebtn::SCROLL_UP].empty()) {
|
2017-01-10 04:12:53 +00:00
|
|
|
m_builder->cmd(mousebtn::SCROLL_UP, string_util::replace_all(m_actions[mousebtn::SCROLL_UP], "%counter%", cnt));
|
2017-01-01 07:58:33 +00:00
|
|
|
}
|
|
|
|
if (!m_actions[mousebtn::SCROLL_DOWN].empty()) {
|
|
|
|
m_builder->cmd(
|
2017-01-10 04:12:53 +00:00
|
|
|
mousebtn::SCROLL_DOWN, string_util::replace_all(m_actions[mousebtn::SCROLL_DOWN], "%counter%", cnt));
|
2017-01-01 07:58:33 +00:00
|
|
|
}
|
2016-12-05 04:32:10 +00:00
|
|
|
|
|
|
|
m_builder->append(output);
|
2016-11-02 19:22:45 +00:00
|
|
|
|
|
|
|
return m_builder->flush();
|
|
|
|
}
|
|
|
|
|
2017-01-10 04:12:53 +00:00
|
|
|
/**
|
|
|
|
* Output format tags
|
|
|
|
*/
|
2016-11-25 12:55:15 +00:00
|
|
|
bool script_module::build(builder* builder, const string& tag) const {
|
2017-01-10 04:12:53 +00:00
|
|
|
if (tag == TAG_LABEL) {
|
2016-12-03 20:07:40 +00:00
|
|
|
builder->node(m_label);
|
2016-11-02 19:22:45 +00:00
|
|
|
} else {
|
|
|
|
return false;
|
|
|
|
}
|
2016-12-03 20:07:40 +00:00
|
|
|
|
|
|
|
return true;
|
2016-11-02 19:22:45 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-11-19 05:22:44 +00:00
|
|
|
POLYBAR_NS_END
|