feat(ipc): New message type "action:"

Adds a new message type, prefixed "action:"
that will perform the same task as mouse actions.

This could be used to control menu modules:

  echo action:menu-open-1 > /tmp/lemonbuddy_mqueue.<pid>
  echo action:menu-close > /tmp/lemonbuddy_mqueue.<pid>

Ref #84
This commit is contained in:
Michael Carlberg 2016-11-18 18:37:52 +01:00
parent 0a1e9c86c4
commit 2fd88c4f60
4 changed files with 48 additions and 2 deletions

View File

@ -42,6 +42,7 @@ class controller {
void bootstrap_modules(); void bootstrap_modules();
void on_ipc_action(const ipc_action& message);
void on_mouse_event(string input); void on_mouse_event(string input);
void on_unrecognized_action(string input); void on_unrecognized_action(string input);
void on_update(); void on_update();

View File

@ -16,6 +16,10 @@ struct ipc_hook {
static constexpr auto prefix{"hook:"}; static constexpr auto prefix{"hook:"};
string payload; string payload;
}; };
struct ipc_action {
static constexpr auto prefix{"action:"};
string payload;
};
/** /**
* Component used for inter-process communication. * Component used for inter-process communication.
@ -31,18 +35,21 @@ class ipc {
void attach_callback(callback<const ipc_command&>&& cb); void attach_callback(callback<const ipc_command&>&& cb);
void attach_callback(callback<const ipc_hook&>&& cb); void attach_callback(callback<const ipc_hook&>&& cb);
void attach_callback(callback<const ipc_action&>&& cb);
void receive_messages(); void receive_messages();
protected: protected:
void parse(const string& payload) const; void parse(const string& payload) const;
void delegate(const ipc_command& msg) const; void delegate(const ipc_command& msg) const;
void delegate(const ipc_hook& msg) const; void delegate(const ipc_hook& msg) const;
void delegate(const ipc_action& msg) const;
private: private:
const logger& m_log; const logger& m_log;
vector<callback<const ipc_command&>> m_command_callbacks; vector<callback<const ipc_command&>> m_command_callbacks;
vector<callback<const ipc_hook&>> m_hook_callbacks; vector<callback<const ipc_hook&>> m_hook_callbacks;
vector<callback<const ipc_action&>> m_action_callbacks;
stateflag m_running{false}; stateflag m_running{false};

View File

@ -107,8 +107,9 @@ void controller::bootstrap(bool writeback, bool dump_wmname) {
if (m_conf.get<bool>(m_conf.bar_section(), "enable-ipc", false)) { if (m_conf.get<bool>(m_conf.bar_section(), "enable-ipc", false)) {
m_log.trace("controller: Create IPC handler"); m_log.trace("controller: Create IPC handler");
m_ipc = configure_ipc().create<decltype(m_ipc)>(); m_ipc = configure_ipc().create<decltype(m_ipc)>();
m_ipc->attach_callback(bind(&controller::on_ipc_action, this, placeholders::_1));
} else { } else {
m_log.warn("Inter-process communication support disabled"); m_log.info("Inter-process messaging disabled");
} }
// Listen for events on the root window to be able to // Listen for events on the root window to be able to
@ -389,7 +390,7 @@ void controller::bootstrap_modules() {
module.reset(new menu_module(bar, m_log, m_conf, module_name)); module.reset(new menu_module(bar, m_log, m_conf, module_name));
else if (type == "custom/ipc") { else if (type == "custom/ipc") {
if (!m_ipc) if (!m_ipc)
throw application_error("Inter-process communication support needs to be enabled"); throw application_error("Inter-process messaging needs to be enabled");
module.reset(new ipc_module(bar, m_log, m_conf, module_name)); module.reset(new ipc_module(bar, m_log, m_conf, module_name));
m_ipc->attach_callback( m_ipc->attach_callback(
bind(&ipc_module::on_message, dynamic_cast<ipc_module*>(module.get()), placeholders::_1)); bind(&ipc_module::on_message, dynamic_cast<ipc_module*>(module.get()), placeholders::_1));
@ -416,6 +417,24 @@ void controller::bootstrap_modules() {
throw application_error("No modules created"); throw application_error("No modules created");
} }
/**
* Callback for received ipc actions
*/
void controller::on_ipc_action(const ipc_action& message) {
string action = message.payload.substr(strlen(ipc_action::prefix));
if (action.empty()) {
m_log.err("Cannot enqueue empty IPC action");
return;
}
eventloop::entry_t evt{static_cast<int>(event_type::INPUT)};
snprintf(evt.data, sizeof(evt.data), "%s", action.c_str());
m_log.info("Enqueuing IPC action: %s", action);
m_eventloop->enqueue(evt);
}
/** /**
* Callback for clicked bar actions * Callback for clicked bar actions
*/ */

View File

@ -41,6 +41,13 @@ void ipc::attach_callback(callback<const ipc_hook&>&& cb) {
m_hook_callbacks.emplace_back(cb); m_hook_callbacks.emplace_back(cb);
} }
/**
* Register listener callback for ipc_action messages
*/
void ipc::attach_callback(callback<const ipc_action&>&& cb) {
m_action_callbacks.emplace_back(cb);
}
/** /**
* Start listening for event messages * Start listening for event messages
*/ */
@ -71,6 +78,8 @@ void ipc::parse(const string& payload) const {
delegate(ipc_command{payload}); delegate(ipc_command{payload});
} else if (payload.find(ipc_hook::prefix) == 0) { } else if (payload.find(ipc_hook::prefix) == 0) {
delegate(ipc_hook{payload}); delegate(ipc_hook{payload});
} else if (payload.find(ipc_action::prefix) == 0) {
delegate(ipc_action{payload});
} else { } else {
m_log.warn("Received unknown ipc message: (payload=%s)", payload); m_log.warn("Received unknown ipc message: (payload=%s)", payload);
} }
@ -96,4 +105,14 @@ void ipc::delegate(const ipc_hook& message) const {
m_log.warn("Unhandled message (payload=%s)", message.payload); m_log.warn("Unhandled message (payload=%s)", message.payload);
} }
/**
* Send ipc message to attached listeners
*/
void ipc::delegate(const ipc_action& message) const {
if (!m_action_callbacks.empty())
for (auto&& callback : m_action_callbacks) callback(message);
else
m_log.warn("Unhandled message (payload=%s)", message.payload);
}
LEMONBUDDY_NS_END LEMONBUDDY_NS_END