95 lines
2.2 KiB
C++
95 lines
2.2 KiB
C++
|
#pragma once
|
||
|
|
||
|
#include <cassert>
|
||
|
#include <stdexcept>
|
||
|
#include <unordered_map>
|
||
|
|
||
|
#include "common.hpp"
|
||
|
|
||
|
POLYBAR_NS
|
||
|
|
||
|
/**
|
||
|
* Maps action names to function pointers in this module and invokes them.
|
||
|
*
|
||
|
* Each module has one instance of this class and uses it to register action.
|
||
|
* For each action the module has to register the name, whether it can take
|
||
|
* additional data, and a pointer to the member function implementing that
|
||
|
* action.
|
||
|
*
|
||
|
* Ref: https://isocpp.org/wiki/faq/pointers-to-members
|
||
|
*
|
||
|
* The input() function in the base class uses this for invoking the actions
|
||
|
* of that module.
|
||
|
*
|
||
|
* Any module that does not reimplement that function will automatically use
|
||
|
* this class for action routing.
|
||
|
*/
|
||
|
template <typename Impl>
|
||
|
class action_router {
|
||
|
typedef void (Impl::*callback)();
|
||
|
typedef void (Impl::*callback_data)(const std::string&);
|
||
|
|
||
|
public:
|
||
|
explicit action_router(Impl* This) : m_this(This) {}
|
||
|
|
||
|
void register_action(const string& name, callback func) {
|
||
|
entry e;
|
||
|
e.with_data = false;
|
||
|
e.without = func;
|
||
|
register_entry(name, e);
|
||
|
}
|
||
|
|
||
|
void register_action_with_data(const string& name, callback_data func) {
|
||
|
entry e;
|
||
|
e.with_data = true;
|
||
|
e.with = func;
|
||
|
register_entry(name, e);
|
||
|
}
|
||
|
|
||
|
bool has_action(const string& name) {
|
||
|
return callbacks.find(name) != callbacks.end();
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Invokes the given action name on the passed module pointer.
|
||
|
*
|
||
|
* The action must exist.
|
||
|
*/
|
||
|
void invoke(const string& name, const string& data) {
|
||
|
auto it = callbacks.find(name);
|
||
|
assert(it != callbacks.end());
|
||
|
|
||
|
entry e = it->second;
|
||
|
|
||
|
#define CALL_MEMBER_FN(object, ptrToMember) ((object).*(ptrToMember))
|
||
|
if (e.with_data) {
|
||
|
CALL_MEMBER_FN(*m_this, e.with)(data);
|
||
|
} else {
|
||
|
CALL_MEMBER_FN(*m_this, e.without)();
|
||
|
}
|
||
|
#undef CALL_MEMBER_FN
|
||
|
}
|
||
|
|
||
|
protected:
|
||
|
struct entry {
|
||
|
union {
|
||
|
callback without;
|
||
|
callback_data with;
|
||
|
};
|
||
|
bool with_data;
|
||
|
};
|
||
|
|
||
|
void register_entry(const string& name, const entry& e) {
|
||
|
if (has_action(name)) {
|
||
|
throw std::invalid_argument("Tried to register action '" + name + "' twice. THIS IS A BUG!");
|
||
|
}
|
||
|
callbacks[name] = e;
|
||
|
}
|
||
|
|
||
|
private:
|
||
|
std::unordered_map<string, entry> callbacks;
|
||
|
Impl* m_this;
|
||
|
};
|
||
|
|
||
|
POLYBAR_NS_END
|