2016-11-14 08:21:18 +00:00
|
|
|
#include "modules/ipc.hpp"
|
|
|
|
|
2021-09-21 19:27:42 +00:00
|
|
|
#include <unistd.h>
|
|
|
|
|
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-14 08:21:18 +00:00
|
|
|
|
|
|
|
namespace modules {
|
2016-11-20 22:04:31 +00:00
|
|
|
template class module<ipc_module>;
|
|
|
|
|
2016-11-14 08:21:18 +00:00
|
|
|
/**
|
|
|
|
* Load user-defined ipc hooks and
|
|
|
|
* create formatting tags
|
|
|
|
*/
|
2021-10-30 19:00:52 +00:00
|
|
|
ipc_module::ipc_module(const bar_settings& bar, string name_) : module<ipc_module>(bar, move(name_)) {
|
2021-10-03 00:57:49 +00:00
|
|
|
m_router->register_action_with_data(EVENT_SEND, [this](const std::string& data) { action_send(data); });
|
2021-10-10 18:22:24 +00:00
|
|
|
m_router->register_action_with_data(EVENT_HOOK, [this](const std::string& data) { action_hook(data); });
|
|
|
|
m_router->register_action(EVENT_NEXT, [this]() { action_next(); });
|
|
|
|
m_router->register_action(EVENT_PREV, [this]() { action_prev(); });
|
|
|
|
m_router->register_action(EVENT_RESET, [this]() { action_reset(); });
|
2021-07-11 18:42:28 +00:00
|
|
|
|
2016-11-14 08:21:18 +00:00
|
|
|
size_t index = 0;
|
|
|
|
|
2021-07-11 18:42:28 +00:00
|
|
|
for (auto&& command : m_conf.get_list<string>(name(), "hook", {})) {
|
2021-02-15 22:32:56 +00:00
|
|
|
m_hooks.emplace_back(std::make_unique<hook>(hook{name() + to_string(++index), command}));
|
2016-11-14 08:21:18 +00:00
|
|
|
}
|
|
|
|
|
2021-07-11 18:42:28 +00:00
|
|
|
m_log.info("%s: Loaded %d hooks", name(), m_hooks.size());
|
2017-01-09 22:06:39 +00:00
|
|
|
|
2021-10-30 19:00:52 +00:00
|
|
|
// Negative initial values should always be -1
|
|
|
|
m_initial = std::max(-1, m_conf.get(name(), "initial", 0) - 1);
|
|
|
|
if (has_initial()) {
|
|
|
|
if ((size_t)m_initial >= m_hooks.size()) {
|
|
|
|
throw module_error("Initial hook out of bounds: '" + to_string(m_initial + 1) +
|
|
|
|
"'. Defined hooks go from 1 to " + to_string(m_hooks.size()) + ")");
|
2021-10-10 18:22:24 +00:00
|
|
|
}
|
2021-10-30 19:00:52 +00:00
|
|
|
m_current_hook = m_initial;
|
2021-10-10 18:22:24 +00:00
|
|
|
} else {
|
2021-10-30 19:00:52 +00:00
|
|
|
m_current_hook = -1;
|
2016-11-14 08:21:18 +00:00
|
|
|
}
|
|
|
|
|
2017-01-13 23:55:55 +00:00
|
|
|
// clang-format off
|
2017-01-13 23:27:29 +00:00
|
|
|
m_actions.emplace(make_pair<mousebtn, string>(mousebtn::LEFT, m_conf.get(name(), "click-left", ""s)));
|
|
|
|
m_actions.emplace(make_pair<mousebtn, string>(mousebtn::MIDDLE, m_conf.get(name(), "click-middle", ""s)));
|
|
|
|
m_actions.emplace(make_pair<mousebtn, string>(mousebtn::RIGHT, m_conf.get(name(), "click-right", ""s)));
|
|
|
|
m_actions.emplace(make_pair<mousebtn, string>(mousebtn::SCROLL_UP, m_conf.get(name(), "scroll-up", ""s)));
|
|
|
|
m_actions.emplace(make_pair<mousebtn, string>(mousebtn::SCROLL_DOWN, m_conf.get(name(), "scroll-down", ""s)));
|
|
|
|
m_actions.emplace(make_pair<mousebtn, string>(mousebtn::DOUBLE_LEFT, m_conf.get(name(), "double-click-left", ""s)));
|
|
|
|
m_actions.emplace(make_pair<mousebtn, string>(mousebtn::DOUBLE_MIDDLE, m_conf.get(name(), "double-click-middle", ""s)));
|
|
|
|
m_actions.emplace(make_pair<mousebtn, string>(mousebtn::DOUBLE_RIGHT, m_conf.get(name(), "double-click-right", ""s)));
|
2017-01-13 23:55:55 +00:00
|
|
|
// clang-format on
|
|
|
|
|
2021-09-21 19:27:42 +00:00
|
|
|
const auto pid_token = [](const string& s) { return string_util::replace_all(s, "%pid%", to_string(getpid())); };
|
2017-01-13 23:55:55 +00:00
|
|
|
|
|
|
|
for (auto& action : m_actions) {
|
2021-09-13 12:06:08 +00:00
|
|
|
action.second = pid_token(action.second);
|
2017-01-13 23:55:55 +00:00
|
|
|
}
|
|
|
|
for (auto& hook : m_hooks) {
|
2021-09-13 12:06:08 +00:00
|
|
|
hook->command = pid_token(hook->command);
|
2017-01-13 23:55:55 +00:00
|
|
|
}
|
2016-11-14 08:21:18 +00:00
|
|
|
|
|
|
|
m_formatter->add(DEFAULT_FORMAT, TAG_OUTPUT, {TAG_OUTPUT});
|
|
|
|
}
|
|
|
|
|
2017-01-09 22:06:39 +00:00
|
|
|
/**
|
|
|
|
* Start module and run first defined hook if configured to
|
|
|
|
*/
|
|
|
|
void ipc_module::start() {
|
2021-10-15 08:33:10 +00:00
|
|
|
this->module::start();
|
2021-09-30 13:11:31 +00:00
|
|
|
m_mainthread = thread([&] {
|
|
|
|
m_log.trace("%s: Thread id = %i", this->name(), concurrency_util::thread_id(this_thread::get_id()));
|
|
|
|
update();
|
|
|
|
broadcast();
|
|
|
|
});
|
2021-10-30 19:00:52 +00:00
|
|
|
}
|
2021-09-30 13:11:31 +00:00
|
|
|
|
2021-10-30 19:00:52 +00:00
|
|
|
void ipc_module::update() {
|
|
|
|
if (has_hook()) {
|
2021-10-10 18:22:24 +00:00
|
|
|
exec_hook();
|
2017-01-09 22:06:39 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-11-14 08:21:18 +00:00
|
|
|
/**
|
|
|
|
* Wrap the output with defined mouse actions
|
|
|
|
*/
|
|
|
|
string ipc_module::get_output() {
|
2016-12-05 04:32:10 +00:00
|
|
|
// Get the module output early so that
|
|
|
|
// the format prefix/suffix also gets wrapper
|
|
|
|
// with the cmd handlers
|
|
|
|
string output{module::get_output()};
|
2021-11-04 15:55:16 +00:00
|
|
|
if (output.empty()) {
|
|
|
|
return "";
|
|
|
|
}
|
2016-12-05 04:32:10 +00:00
|
|
|
|
2017-01-13 23:10:55 +00:00
|
|
|
for (auto&& action : m_actions) {
|
|
|
|
if (!action.second.empty()) {
|
2020-05-24 16:35:12 +00:00
|
|
|
m_builder->action(action.first, action.second);
|
2017-01-13 23:10:55 +00:00
|
|
|
}
|
2016-11-25 12:55:15 +00:00
|
|
|
}
|
2016-11-14 08:21:18 +00:00
|
|
|
|
2016-12-05 04:32:10 +00:00
|
|
|
m_builder->append(output);
|
2016-11-14 08:21:18 +00:00
|
|
|
return m_builder->flush();
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Output content retrieved from hook commands
|
|
|
|
*/
|
2016-11-25 12:55:15 +00:00
|
|
|
bool ipc_module::build(builder* builder, const string& tag) const {
|
|
|
|
if (tag == TAG_OUTPUT) {
|
2016-11-14 08:21:18 +00:00
|
|
|
builder->node(m_output);
|
2017-01-09 22:06:39 +00:00
|
|
|
return true;
|
2016-11-25 12:55:15 +00:00
|
|
|
} else {
|
2016-11-14 08:21:18 +00:00
|
|
|
return false;
|
2016-11-25 12:55:15 +00:00
|
|
|
}
|
2016-11-14 08:21:18 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Map received message hook to the ones
|
|
|
|
* configured from the user config and
|
|
|
|
* execute its command
|
2021-10-30 19:00:52 +00:00
|
|
|
*
|
|
|
|
* This code path is deprecated, all messages to ipc modules should go through actions.
|
2016-11-14 08:21:18 +00:00
|
|
|
*/
|
2016-12-26 09:36:14 +00:00
|
|
|
void ipc_module::on_message(const string& message) {
|
2021-10-10 18:22:24 +00:00
|
|
|
for (size_t i = 0; i < m_hooks.size(); i++) {
|
|
|
|
const auto& hook = m_hooks[i];
|
|
|
|
if (hook->payload == message) {
|
|
|
|
m_log.info("%s: Found matching hook (%s)", name(), hook->payload);
|
2021-10-30 19:00:52 +00:00
|
|
|
set_hook(i);
|
2021-10-10 18:22:24 +00:00
|
|
|
break;
|
2016-11-14 08:21:18 +00:00
|
|
|
}
|
2021-10-10 18:22:24 +00:00
|
|
|
}
|
|
|
|
}
|
2016-11-14 08:21:18 +00:00
|
|
|
|
2021-10-10 18:22:24 +00:00
|
|
|
void ipc_module::action_send(const string& data) {
|
|
|
|
m_output = data;
|
|
|
|
broadcast();
|
|
|
|
}
|
|
|
|
|
|
|
|
void ipc_module::action_hook(const string& data) {
|
|
|
|
try {
|
|
|
|
int hook = std::stoi(data);
|
|
|
|
|
|
|
|
if (hook < 0 || (size_t)hook >= m_hooks.size()) {
|
2021-10-30 19:00:52 +00:00
|
|
|
m_log.err("%s: Hook action received with an out of bounds hook '%s'. Defined hooks go from 0 to %zu.", name(),
|
2021-10-10 18:22:24 +00:00
|
|
|
data, m_hooks.size() - 1);
|
|
|
|
} else {
|
2021-10-30 19:00:52 +00:00
|
|
|
set_hook(hook);
|
2017-01-13 04:33:33 +00:00
|
|
|
}
|
2021-10-10 18:22:24 +00:00
|
|
|
} catch (const std::invalid_argument& err) {
|
|
|
|
m_log.err(
|
|
|
|
"%s: Hook action received '%s' cannot be converted to a valid hook index. Defined hooks goes from 0 to %zu.",
|
|
|
|
name(), data, m_hooks.size() - 1);
|
|
|
|
}
|
|
|
|
}
|
2016-11-14 08:21:18 +00:00
|
|
|
|
2021-10-10 18:22:24 +00:00
|
|
|
void ipc_module::action_next() {
|
2021-10-30 19:00:52 +00:00
|
|
|
hook_offset(1);
|
2021-10-10 18:22:24 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void ipc_module::action_prev() {
|
2021-10-30 19:00:52 +00:00
|
|
|
hook_offset(-1);
|
2021-10-10 18:22:24 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void ipc_module::action_reset() {
|
2021-10-30 19:00:52 +00:00
|
|
|
if (has_initial()) {
|
|
|
|
set_hook(m_initial);
|
2021-10-10 18:22:24 +00:00
|
|
|
} else {
|
2021-10-30 19:00:52 +00:00
|
|
|
m_current_hook = -1;
|
2021-10-10 18:22:24 +00:00
|
|
|
m_output.clear();
|
2016-11-14 08:21:18 +00:00
|
|
|
broadcast();
|
|
|
|
}
|
|
|
|
}
|
2021-07-11 18:42:28 +00:00
|
|
|
|
2021-10-30 19:00:52 +00:00
|
|
|
/**
|
|
|
|
* Changes the current hook by the given offset.
|
|
|
|
*
|
|
|
|
* Also deals with the case where the there is no active hook, in which case a positive offset starts from -1 and a
|
|
|
|
* negative from 0. This ensures that 'next' executes the first and 'prev' the last hook if no hook is set.
|
|
|
|
*/
|
|
|
|
void ipc_module::hook_offset(int offset) {
|
|
|
|
int start_hook;
|
|
|
|
|
|
|
|
if (has_hook()) {
|
|
|
|
start_hook = m_current_hook;
|
|
|
|
} else {
|
|
|
|
if (offset > 0) {
|
|
|
|
start_hook = -1;
|
|
|
|
} else {
|
|
|
|
start_hook = 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
set_hook((start_hook + offset + m_hooks.size()) % m_hooks.size());
|
|
|
|
}
|
|
|
|
|
|
|
|
bool ipc_module::has_initial() const {
|
|
|
|
return m_initial >= 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool ipc_module::has_hook() const {
|
|
|
|
return m_current_hook >= 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
void ipc_module::set_hook(int h) {
|
2022-01-22 19:35:37 +00:00
|
|
|
assert(h >= 0 && (size_t)h < m_hooks.size());
|
2021-10-30 19:00:52 +00:00
|
|
|
m_current_hook = h;
|
|
|
|
exec_hook();
|
|
|
|
}
|
|
|
|
|
2021-10-10 18:22:24 +00:00
|
|
|
void ipc_module::exec_hook() {
|
|
|
|
// Clear the output in case the command produces no output
|
|
|
|
m_output.clear();
|
|
|
|
|
|
|
|
try {
|
|
|
|
auto command = command_util::make_command<output_policy::REDIRECTED>(m_hooks[m_current_hook]->command);
|
|
|
|
command->exec(false);
|
|
|
|
command->tail([this](string line) { m_output = line; });
|
|
|
|
} catch (const exception& err) {
|
|
|
|
m_log.err("%s: Failed to execute hook command (err: %s)", name(), err.what());
|
|
|
|
m_output.clear();
|
|
|
|
}
|
|
|
|
|
2021-07-11 18:42:28 +00:00
|
|
|
broadcast();
|
|
|
|
}
|
2019-12-11 20:32:43 +00:00
|
|
|
} // namespace modules
|
2016-11-14 08:21:18 +00:00
|
|
|
|
2016-11-19 05:22:44 +00:00
|
|
|
POLYBAR_NS_END
|