2016-12-19 23:05:43 -05:00
|
|
|
#include <csignal>
|
|
|
|
|
2016-11-20 17:04:31 -05:00
|
|
|
#include "components/bar.hpp"
|
2016-11-21 09:07:00 -05:00
|
|
|
#include "components/config.hpp"
|
2016-12-19 23:05:43 -05:00
|
|
|
#include "components/controller.hpp"
|
2016-11-21 09:07:00 -05:00
|
|
|
#include "components/ipc.hpp"
|
|
|
|
#include "components/logger.hpp"
|
2016-12-19 23:05:43 -05:00
|
|
|
#include "components/renderer.hpp"
|
|
|
|
#include "components/types.hpp"
|
2016-12-05 14:41:00 -05:00
|
|
|
#include "events/signal.hpp"
|
2016-12-19 23:05:43 -05:00
|
|
|
#include "events/signal_emitter.hpp"
|
2016-12-26 04:36:14 -05:00
|
|
|
#include "events/signal_receiver.hpp"
|
2016-12-22 23:08:19 -05:00
|
|
|
#include "modules/meta/event_handler.hpp"
|
2016-12-05 14:41:00 -05:00
|
|
|
#include "modules/meta/factory.hpp"
|
2016-12-09 03:40:46 -05:00
|
|
|
#include "utils/command.hpp"
|
2016-12-05 14:41:00 -05:00
|
|
|
#include "utils/factory.hpp"
|
2016-12-09 03:40:46 -05:00
|
|
|
#include "utils/inotify.hpp"
|
2016-11-02 15:22:45 -04:00
|
|
|
#include "utils/string.hpp"
|
2016-12-19 23:05:43 -05:00
|
|
|
#include "utils/time.hpp"
|
2016-12-09 03:40:46 -05:00
|
|
|
#include "x11/connection.hpp"
|
2016-12-26 04:36:14 -05:00
|
|
|
#include "x11/events.hpp"
|
2016-12-26 03:40:15 -05:00
|
|
|
#include "x11/extensions/all.hpp"
|
2016-12-19 23:05:43 -05:00
|
|
|
#include "x11/tray_manager.hpp"
|
2016-12-26 04:36:14 -05:00
|
|
|
#include "x11/types.hpp"
|
2016-11-20 19:19:44 -05:00
|
|
|
|
2016-11-19 00:22:44 -05:00
|
|
|
POLYBAR_NS
|
2016-11-02 15:22:45 -04:00
|
|
|
|
2016-12-26 22:58:41 -05:00
|
|
|
array<int, 2> g_eventpipe{{-1, -1}};
|
2016-12-19 23:05:43 -05:00
|
|
|
sig_atomic_t g_reload{0};
|
|
|
|
sig_atomic_t g_terminate{0};
|
|
|
|
|
|
|
|
void interrupt_handler(int signum) {
|
|
|
|
g_terminate = 1;
|
|
|
|
g_reload = (signum == SIGUSR1);
|
2016-12-19 23:36:10 -05:00
|
|
|
if (write(g_eventpipe[PIPE_WRITE], &g_terminate, 1) == -1) {
|
|
|
|
throw system_error("Failed to write to eventpipe");
|
|
|
|
}
|
2016-12-19 23:05:43 -05:00
|
|
|
}
|
2016-11-02 15:22:45 -04:00
|
|
|
|
2016-12-09 03:02:47 -05:00
|
|
|
/**
|
2016-12-19 23:05:43 -05:00
|
|
|
* Build controller instance
|
2016-12-09 03:02:47 -05:00
|
|
|
*/
|
2016-12-19 23:05:43 -05:00
|
|
|
controller::make_type controller::make(unique_ptr<ipc>&& ipc, unique_ptr<inotify_watch>&& config_watch) {
|
|
|
|
return factory_util::unique<controller>(connection::make(), signal_emitter::make(), logger::make(), config::make(),
|
|
|
|
bar::make(), forward<decltype(ipc)>(ipc), forward<decltype(config_watch)>(config_watch));
|
2016-12-09 03:02:47 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2016-12-19 23:05:43 -05:00
|
|
|
* Construct controller
|
2016-12-09 03:02:47 -05:00
|
|
|
*/
|
2016-12-05 14:41:00 -05:00
|
|
|
controller::controller(connection& conn, signal_emitter& emitter, const logger& logger, const config& config,
|
2016-12-19 23:05:43 -05:00
|
|
|
unique_ptr<bar>&& bar, unique_ptr<ipc>&& ipc, unique_ptr<inotify_watch>&& confwatch)
|
2016-12-05 14:41:00 -05:00
|
|
|
: m_connection(conn)
|
|
|
|
, m_sig(emitter)
|
|
|
|
, m_log(logger)
|
|
|
|
, m_conf(config)
|
2016-12-13 23:42:46 -05:00
|
|
|
, m_bar(forward<decltype(bar)>(bar))
|
|
|
|
, m_ipc(forward<decltype(ipc)>(ipc))
|
2016-12-19 23:05:43 -05:00
|
|
|
, m_confwatch(forward<decltype(confwatch)>(confwatch)) {
|
|
|
|
m_swallow_input = m_conf.get("settings", "throttle-input-for", m_swallow_input);
|
|
|
|
m_swallow_limit = m_conf.deprecated("settings", "eventqueue-swallow", "throttle-output", m_swallow_limit);
|
|
|
|
m_swallow_update = m_conf.deprecated("settings", "eventqueue-swallow-time", "throttle-output-for", m_swallow_update);
|
2016-11-20 17:04:31 -05:00
|
|
|
|
2016-12-26 22:58:41 -05:00
|
|
|
if (pipe(g_eventpipe.data()) == 0) {
|
|
|
|
m_queuefd[PIPE_READ] = make_unique<file_descriptor>(g_eventpipe[PIPE_READ]);
|
|
|
|
m_queuefd[PIPE_WRITE] = make_unique<file_descriptor>(g_eventpipe[PIPE_WRITE]);
|
|
|
|
} else {
|
2016-12-19 23:05:43 -05:00
|
|
|
throw system_error("Failed to create event channel pipes");
|
2016-11-02 15:22:45 -04:00
|
|
|
}
|
|
|
|
|
2016-12-19 23:05:43 -05:00
|
|
|
m_log.trace("controller: Install signal handler");
|
|
|
|
struct sigaction act {};
|
|
|
|
memset(&act, 0, sizeof(act));
|
|
|
|
act.sa_handler = &interrupt_handler;
|
|
|
|
sigaction(SIGINT, &act, nullptr);
|
|
|
|
sigaction(SIGQUIT, &act, nullptr);
|
|
|
|
sigaction(SIGTERM, &act, nullptr);
|
|
|
|
sigaction(SIGUSR1, &act, nullptr);
|
|
|
|
sigaction(SIGALRM, &act, nullptr);
|
2016-11-02 15:22:45 -04:00
|
|
|
|
2016-12-05 14:41:00 -05:00
|
|
|
m_log.trace("controller: Setup user-defined modules");
|
2016-12-19 23:05:43 -05:00
|
|
|
size_t created_modules{0};
|
2016-12-01 02:41:49 -05:00
|
|
|
|
2016-12-05 14:41:00 -05:00
|
|
|
for (int i = 0; i < 3; i++) {
|
2016-12-19 23:05:43 -05:00
|
|
|
alignment align{static_cast<alignment>(i + 1)};
|
|
|
|
string configured_modules;
|
2016-11-02 15:22:45 -04:00
|
|
|
|
2016-12-05 14:41:00 -05:00
|
|
|
if (align == alignment::LEFT) {
|
2016-12-30 17:32:05 -05:00
|
|
|
configured_modules = m_conf.get(m_conf.section(), "modules-left", ""s);
|
2016-12-05 14:41:00 -05:00
|
|
|
} else if (align == alignment::CENTER) {
|
2016-12-30 17:32:05 -05:00
|
|
|
configured_modules = m_conf.get(m_conf.section(), "modules-center", ""s);
|
2016-12-05 14:41:00 -05:00
|
|
|
} else if (align == alignment::RIGHT) {
|
2016-12-30 17:32:05 -05:00
|
|
|
configured_modules = m_conf.get(m_conf.section(), "modules-right", ""s);
|
2016-12-05 14:41:00 -05:00
|
|
|
}
|
2016-11-02 15:22:45 -04:00
|
|
|
|
2016-12-19 23:05:43 -05:00
|
|
|
for (auto& module_name : string_util::split(configured_modules, ' ')) {
|
2016-12-05 14:41:00 -05:00
|
|
|
if (module_name.empty()) {
|
|
|
|
continue;
|
|
|
|
}
|
2016-11-02 15:22:45 -04:00
|
|
|
|
2016-12-05 14:41:00 -05:00
|
|
|
try {
|
2016-12-30 17:32:05 -05:00
|
|
|
auto type = m_conf.get("module/" + module_name, "type");
|
2016-12-19 23:05:43 -05:00
|
|
|
|
2016-12-05 14:41:00 -05:00
|
|
|
if (type == "custom/ipc" && !m_ipc) {
|
|
|
|
throw application_error("Inter-process messaging needs to be enabled");
|
|
|
|
}
|
2016-11-14 03:21:18 -05:00
|
|
|
|
2016-12-21 17:22:02 -05:00
|
|
|
m_modules[align].emplace_back(make_module(move(type), m_bar->settings(), module_name));
|
2016-12-19 23:05:43 -05:00
|
|
|
created_modules++;
|
|
|
|
} catch (const runtime_error& err) {
|
2016-12-05 14:41:00 -05:00
|
|
|
m_log.err("Disabling module \"%s\" (reason: %s)", module_name, err.what());
|
|
|
|
}
|
|
|
|
}
|
2016-11-02 15:22:45 -04:00
|
|
|
}
|
|
|
|
|
2016-12-19 23:05:43 -05:00
|
|
|
if (!created_modules) {
|
2016-12-05 14:41:00 -05:00
|
|
|
throw application_error("No modules created");
|
2016-11-02 15:22:45 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-12-19 23:05:43 -05:00
|
|
|
/**
|
|
|
|
* Deconstruct controller
|
|
|
|
*/
|
|
|
|
controller::~controller() {
|
|
|
|
m_log.trace("controller: Uninstall sighandler");
|
|
|
|
signal(SIGINT, SIG_DFL);
|
|
|
|
signal(SIGQUIT, SIG_DFL);
|
|
|
|
signal(SIGTERM, SIG_DFL);
|
|
|
|
|
|
|
|
m_log.trace("controller: Detach signal receiver");
|
|
|
|
m_sig.detach(this);
|
|
|
|
|
|
|
|
m_log.trace("controller: Stop modules");
|
|
|
|
for (auto&& block : m_modules) {
|
|
|
|
for (auto&& module : block.second) {
|
|
|
|
auto module_name = module->name();
|
|
|
|
auto cleanup_ms = time_util::measure([&module] {
|
|
|
|
module->stop();
|
|
|
|
module.reset();
|
|
|
|
});
|
|
|
|
m_log.info("Deconstruction of %s took %lu ms.", module_name, cleanup_ms);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Run the main loop
|
|
|
|
*/
|
|
|
|
bool controller::run(bool writeback) {
|
2016-12-22 18:54:09 -05:00
|
|
|
m_log.info("Starting application");
|
|
|
|
|
2016-11-02 15:22:45 -04:00
|
|
|
assert(!m_connection.connection_has_error());
|
|
|
|
|
2016-12-19 23:05:43 -05:00
|
|
|
m_writeback = writeback;
|
2016-11-02 15:22:45 -04:00
|
|
|
|
2016-12-22 18:54:09 -05:00
|
|
|
m_sig.attach(this);
|
2016-12-13 23:42:46 -05:00
|
|
|
|
2016-12-19 23:05:43 -05:00
|
|
|
size_t started_modules{0};
|
|
|
|
for (const auto& block : m_modules) {
|
|
|
|
for (const auto& module : block.second) {
|
2016-12-22 23:08:19 -05:00
|
|
|
auto inp_handler = dynamic_cast<input_handler*>(&*module);
|
|
|
|
auto evt_handler = dynamic_cast<event_handler_interface*>(&*module);
|
|
|
|
|
|
|
|
if (inp_handler != nullptr) {
|
|
|
|
m_inputhandlers.emplace_back(inp_handler);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (evt_handler != nullptr) {
|
|
|
|
evt_handler->connect(m_connection);
|
2016-12-22 18:54:09 -05:00
|
|
|
}
|
|
|
|
|
2016-12-19 23:05:43 -05:00
|
|
|
try {
|
|
|
|
m_log.info("Starting %s", module->name());
|
|
|
|
module->start();
|
|
|
|
started_modules++;
|
|
|
|
} catch (const application_error& err) {
|
|
|
|
m_log.err("Failed to start '%s' (reason: %s)", module->name(), err.what());
|
|
|
|
}
|
|
|
|
}
|
2016-11-02 15:22:45 -04:00
|
|
|
}
|
2016-12-19 23:05:43 -05:00
|
|
|
|
|
|
|
if (!started_modules) {
|
|
|
|
throw application_error("No modules started");
|
2016-11-02 15:22:45 -04:00
|
|
|
}
|
|
|
|
|
2016-12-19 23:05:43 -05:00
|
|
|
m_connection.flush();
|
2016-11-02 15:22:45 -04:00
|
|
|
|
2016-12-22 23:10:05 -05:00
|
|
|
m_event_thread = thread(&controller::process_eventqueue, this);
|
|
|
|
|
2016-12-19 23:05:43 -05:00
|
|
|
read_events();
|
2016-11-02 15:22:45 -04:00
|
|
|
|
2016-12-22 23:10:05 -05:00
|
|
|
if (m_event_thread.joinable()) {
|
2016-12-23 16:19:42 -05:00
|
|
|
enqueue(make_quit_evt(static_cast<bool>(g_reload)));
|
2016-12-22 23:10:05 -05:00
|
|
|
m_event_thread.join();
|
|
|
|
}
|
|
|
|
|
2016-12-19 23:05:43 -05:00
|
|
|
m_log.warn("Termination signal received, shutting down...");
|
2016-11-02 15:22:45 -04:00
|
|
|
|
2016-12-19 23:05:43 -05:00
|
|
|
return !g_reload;
|
|
|
|
}
|
2016-11-02 15:22:45 -04:00
|
|
|
|
2016-12-19 23:05:43 -05:00
|
|
|
/**
|
|
|
|
* Enqueue event
|
|
|
|
*/
|
|
|
|
bool controller::enqueue(event&& evt) {
|
2016-12-23 07:03:03 -05:00
|
|
|
if (!m_queue.enqueue(forward<decltype(evt)>(evt))) {
|
2016-12-19 23:05:43 -05:00
|
|
|
m_log.warn("Failed to enqueue event");
|
|
|
|
return false;
|
2016-11-25 07:55:15 -05:00
|
|
|
}
|
2016-12-22 23:10:05 -05:00
|
|
|
// if (write(g_eventpipe[PIPE_WRITE], " ", 1) == -1) {
|
|
|
|
// m_log.err("Failed to write to eventpipe (reason: %s)", strerror(errno));
|
|
|
|
// }
|
2016-12-19 23:05:43 -05:00
|
|
|
return true;
|
|
|
|
}
|
2016-11-02 15:22:45 -04:00
|
|
|
|
2016-12-19 23:05:43 -05:00
|
|
|
/**
|
|
|
|
* Enqueue input data
|
|
|
|
*/
|
|
|
|
bool controller::enqueue(string&& input_data) {
|
|
|
|
if (!m_inputdata.empty()) {
|
|
|
|
m_log.trace("controller: Swallowing input event (pending data)");
|
|
|
|
} else if (chrono::system_clock::now() - m_swallow_input < m_lastinput) {
|
|
|
|
m_log.trace("controller: Swallowing input event (throttled)");
|
|
|
|
} else {
|
2016-12-23 07:03:03 -05:00
|
|
|
m_inputdata = input_data;
|
2016-12-19 23:05:43 -05:00
|
|
|
return enqueue(make_input_evt());
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
2016-11-02 15:22:45 -04:00
|
|
|
|
2016-12-19 23:05:43 -05:00
|
|
|
/**
|
|
|
|
* Read events from configured file descriptors
|
|
|
|
*/
|
|
|
|
void controller::read_events() {
|
2016-12-22 23:10:05 -05:00
|
|
|
m_log.info("Entering event loop (thread-id=%lu)", this_thread::get_id());
|
|
|
|
|
2016-12-26 22:58:41 -05:00
|
|
|
int fd_connection{-1};
|
|
|
|
int fd_confwatch{-1};
|
|
|
|
int fd_ipc{-1};
|
2016-12-05 14:41:00 -05:00
|
|
|
|
2016-12-19 23:05:43 -05:00
|
|
|
vector<int> fds;
|
2016-12-26 22:58:41 -05:00
|
|
|
fds.emplace_back(*m_queuefd[PIPE_READ]);
|
2016-12-30 17:32:05 -05:00
|
|
|
fds.emplace_back((fd_connection = m_connection.get_file_descriptor()));
|
2016-12-13 23:42:46 -05:00
|
|
|
|
2016-12-19 23:05:43 -05:00
|
|
|
if (m_confwatch) {
|
|
|
|
m_log.trace("controller: Attach config watch");
|
|
|
|
m_confwatch->attach(IN_MODIFY);
|
|
|
|
fds.emplace_back((fd_confwatch = m_confwatch->get_file_descriptor()));
|
2016-11-25 07:55:15 -05:00
|
|
|
}
|
2016-12-13 23:42:46 -05:00
|
|
|
|
|
|
|
if (m_ipc) {
|
2016-12-19 23:05:43 -05:00
|
|
|
fds.emplace_back((fd_ipc = m_ipc->get_file_descriptor()));
|
2016-12-13 23:42:46 -05:00
|
|
|
}
|
|
|
|
|
2016-12-19 23:05:43 -05:00
|
|
|
while (!g_terminate) {
|
|
|
|
fd_set readfds{};
|
|
|
|
FD_ZERO(&readfds);
|
2016-11-02 15:22:45 -04:00
|
|
|
|
2016-12-19 23:05:43 -05:00
|
|
|
int maxfd{0};
|
|
|
|
for (auto&& fd : fds) {
|
|
|
|
FD_SET(fd, &readfds);
|
|
|
|
maxfd = std::max(maxfd, fd);
|
|
|
|
}
|
2016-11-02 15:22:45 -04:00
|
|
|
|
2016-12-19 23:05:43 -05:00
|
|
|
// Wait until event is ready on one of the configured streams
|
|
|
|
int events = select(maxfd + 1, &readfds, nullptr, nullptr, nullptr);
|
2016-12-05 14:41:00 -05:00
|
|
|
|
2016-12-19 23:05:43 -05:00
|
|
|
// Check for errors
|
|
|
|
if (events == -1 || g_terminate || m_connection.connection_has_error()) {
|
|
|
|
break;
|
|
|
|
}
|
2016-11-02 15:22:45 -04:00
|
|
|
|
2016-12-19 23:05:43 -05:00
|
|
|
// Process event on the internal fd
|
2016-12-26 22:58:41 -05:00
|
|
|
if (m_queuefd[PIPE_READ] && FD_ISSET(static_cast<int>(*m_queuefd[PIPE_READ]), &readfds)) {
|
2016-12-19 23:05:43 -05:00
|
|
|
char buffer[BUFSIZ]{'\0'};
|
2016-12-26 22:58:41 -05:00
|
|
|
if (read(static_cast<int>(*m_queuefd[PIPE_READ]), &buffer, BUFSIZ) == -1) {
|
2016-12-19 23:36:10 -05:00
|
|
|
m_log.err("Failed to read from eventpipe (err: %s)", strerror(errno));
|
|
|
|
}
|
2016-12-01 02:41:49 -05:00
|
|
|
}
|
2016-11-02 15:22:45 -04:00
|
|
|
|
2016-12-19 23:05:43 -05:00
|
|
|
// Process event on the config inotify watch fd
|
2016-12-30 17:28:58 -05:00
|
|
|
if (fd_confwatch > -1 && FD_ISSET(fd_confwatch, &readfds) && m_confwatch->await_match()) {
|
2016-12-19 23:05:43 -05:00
|
|
|
m_log.info("Configuration file changed");
|
|
|
|
g_terminate = 1;
|
|
|
|
g_reload = 1;
|
|
|
|
}
|
2016-11-02 15:22:45 -04:00
|
|
|
|
2016-12-19 23:05:43 -05:00
|
|
|
// Process event on the xcb connection fd
|
2016-12-30 17:28:58 -05:00
|
|
|
if (fd_connection > -1 && FD_ISSET(fd_connection, &readfds)) {
|
2016-12-21 17:22:02 -05:00
|
|
|
shared_ptr<xcb_generic_event_t> evt{};
|
|
|
|
while ((evt = shared_ptr<xcb_generic_event_t>(xcb_poll_for_event(m_connection), free)) != nullptr) {
|
|
|
|
try {
|
|
|
|
m_connection.dispatch_event(evt);
|
|
|
|
} catch (xpp::connection_error& err) {
|
|
|
|
m_log.err("X connection error, terminating... (what: %s)", m_connection.error_str(err.code()));
|
|
|
|
} catch (const exception& err) {
|
|
|
|
m_log.err("Error in X event loop: %s", err.what());
|
|
|
|
}
|
2016-11-02 15:22:45 -04:00
|
|
|
}
|
|
|
|
}
|
2016-12-19 23:05:43 -05:00
|
|
|
|
|
|
|
// Process event on the ipc fd
|
2016-12-30 17:28:58 -05:00
|
|
|
if (fd_ipc > -1 && FD_ISSET(fd_ipc, &readfds)) {
|
2016-12-19 23:05:43 -05:00
|
|
|
m_ipc->receive_message();
|
2016-12-21 08:55:19 -05:00
|
|
|
fds.erase(std::remove_if(fds.begin(), fds.end(), [fd_ipc](int fd) { return fd == fd_ipc; }), fds.end());
|
2016-12-19 23:05:43 -05:00
|
|
|
fds.emplace_back((fd_ipc = m_ipc->get_file_descriptor()));
|
2016-12-03 09:12:11 -05:00
|
|
|
}
|
|
|
|
}
|
2016-12-19 23:05:43 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2016-12-22 23:10:05 -05:00
|
|
|
* Eventqueue worker loop
|
2016-12-19 23:05:43 -05:00
|
|
|
*/
|
|
|
|
void controller::process_eventqueue() {
|
2016-12-22 23:10:05 -05:00
|
|
|
m_log.info("Eventqueue worker (thread-id=%lu)", this_thread::get_id());
|
2016-12-03 09:12:11 -05:00
|
|
|
|
2016-12-23 16:19:42 -05:00
|
|
|
enqueue(make_update_evt(true));
|
2016-11-02 15:22:45 -04:00
|
|
|
|
2016-12-22 23:10:05 -05:00
|
|
|
while (!g_terminate) {
|
|
|
|
event evt{};
|
|
|
|
m_queue.wait_dequeue(evt);
|
|
|
|
|
2016-12-22 23:51:33 -05:00
|
|
|
if (g_terminate) {
|
2016-12-22 23:10:05 -05:00
|
|
|
break;
|
2016-12-23 16:19:42 -05:00
|
|
|
} else if (evt.type == event_type::QUIT) {
|
|
|
|
if (evt.flag) {
|
|
|
|
on(sig_ev::exit_reload{});
|
|
|
|
} else {
|
|
|
|
on(sig_ev::exit_terminate{});
|
|
|
|
}
|
|
|
|
} else if (evt.type == event_type::INPUT) {
|
2016-12-19 23:05:43 -05:00
|
|
|
process_inputdata();
|
|
|
|
} else {
|
2016-12-22 23:10:05 -05:00
|
|
|
event next{};
|
|
|
|
size_t swallowed{0};
|
|
|
|
while (swallowed++ < m_swallow_limit && m_queue.wait_dequeue_timed(next, m_swallow_update)) {
|
2016-12-23 16:19:42 -05:00
|
|
|
if (next.type == event_type::QUIT) {
|
2016-12-22 23:10:05 -05:00
|
|
|
evt = next;
|
|
|
|
break;
|
2016-12-23 16:19:42 -05:00
|
|
|
} else if (next.type == event_type::INPUT) {
|
2016-12-22 23:10:05 -05:00
|
|
|
evt = next;
|
|
|
|
break;
|
|
|
|
} else if (evt.type != next.type) {
|
2016-12-23 16:19:42 -05:00
|
|
|
enqueue(move(next));
|
2016-12-22 23:10:05 -05:00
|
|
|
break;
|
|
|
|
} else {
|
|
|
|
m_log.trace_x("controller: Swallowing event within timeframe");
|
|
|
|
evt = next;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-12-23 16:19:42 -05:00
|
|
|
if (evt.type == event_type::UPDATE) {
|
|
|
|
on(sig_ev::update{});
|
|
|
|
} else if (evt.type == event_type::INPUT) {
|
2016-12-22 23:10:05 -05:00
|
|
|
process_inputdata();
|
2016-12-23 16:19:42 -05:00
|
|
|
} else if (evt.type == event_type::QUIT) {
|
|
|
|
if (evt.flag) {
|
|
|
|
on(sig_ev::exit_reload{});
|
|
|
|
} else {
|
|
|
|
on(sig_ev::exit_terminate{});
|
|
|
|
}
|
|
|
|
} else if (evt.type == event_type::CHECK) {
|
|
|
|
on(sig_ev::check_state{});
|
2016-12-22 23:10:05 -05:00
|
|
|
} else {
|
|
|
|
m_log.warn("Unknown event type for enqueued event (%d)", evt.type);
|
|
|
|
}
|
2016-12-19 23:05:43 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2016-12-01 02:41:49 -05:00
|
|
|
|
2016-12-19 23:05:43 -05:00
|
|
|
/**
|
|
|
|
* Process stored input data
|
|
|
|
*/
|
|
|
|
void controller::process_inputdata() {
|
|
|
|
if (!m_inputdata.empty()) {
|
2016-12-23 14:43:52 -05:00
|
|
|
string cmd = m_inputdata;
|
2016-12-19 23:05:43 -05:00
|
|
|
m_lastinput = chrono::time_point_cast<decltype(m_swallow_input)>(chrono::system_clock::now());
|
|
|
|
m_inputdata.clear();
|
2016-12-22 18:54:09 -05:00
|
|
|
|
|
|
|
for (auto&& handler : m_inputhandlers) {
|
2016-12-23 14:43:52 -05:00
|
|
|
if (handler->input(string{cmd})) {
|
2016-12-22 18:54:09 -05:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-12-23 14:43:52 -05:00
|
|
|
try {
|
|
|
|
m_log.warn("Uncaught input event, forwarding to shell... (input: %s)", cmd);
|
|
|
|
|
|
|
|
if (m_command) {
|
|
|
|
m_log.warn("Terminating previous shell command");
|
|
|
|
m_command->terminate();
|
|
|
|
}
|
|
|
|
|
|
|
|
m_log.info("Executing shell command: %s", cmd);
|
|
|
|
m_command = command_util::make_command(move(cmd));
|
|
|
|
m_command->exec();
|
|
|
|
m_command.reset();
|
|
|
|
} catch (const application_error& err) {
|
|
|
|
m_log.err("controller: Error while forwarding input to shell -> %s", err.what());
|
|
|
|
}
|
2016-12-01 02:41:49 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-12-22 16:11:03 -05:00
|
|
|
/**
|
|
|
|
* Process broadcast events
|
|
|
|
*/
|
2016-12-23 16:19:42 -05:00
|
|
|
bool controller::on(const sig_ev::notify_change&) {
|
2016-12-22 16:11:03 -05:00
|
|
|
enqueue(make_update_evt(false));
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2016-12-19 23:05:43 -05:00
|
|
|
/**
|
|
|
|
* Process eventqueue update event
|
|
|
|
*/
|
2016-12-23 16:19:42 -05:00
|
|
|
bool controller::on(const sig_ev::update&) {
|
2016-11-21 09:07:00 -05:00
|
|
|
const bar_settings& bar{m_bar->settings()};
|
2016-11-25 07:55:15 -05:00
|
|
|
string contents;
|
2016-11-21 09:07:00 -05:00
|
|
|
string separator{bar.separator};
|
|
|
|
string padding_left(bar.padding.left, ' ');
|
|
|
|
string padding_right(bar.padding.right, ' ');
|
2016-12-14 13:03:59 -05:00
|
|
|
string margin_left(bar.module_margin.left, ' ');
|
|
|
|
string margin_right(bar.module_margin.right, ' ');
|
2016-11-02 15:22:45 -04:00
|
|
|
|
2016-12-19 23:05:43 -05:00
|
|
|
for (const auto& block : m_modules) {
|
2016-11-02 15:22:45 -04:00
|
|
|
string block_contents;
|
|
|
|
bool is_left = false;
|
|
|
|
bool is_center = false;
|
|
|
|
bool is_right = false;
|
|
|
|
|
2016-11-25 07:55:15 -05:00
|
|
|
if (block.first == alignment::LEFT) {
|
2016-11-02 15:22:45 -04:00
|
|
|
is_left = true;
|
2016-11-25 07:55:15 -05:00
|
|
|
} else if (block.first == alignment::CENTER) {
|
2016-11-02 15:22:45 -04:00
|
|
|
is_center = true;
|
2016-11-25 07:55:15 -05:00
|
|
|
} else if (block.first == alignment::RIGHT) {
|
2016-11-02 15:22:45 -04:00
|
|
|
is_right = true;
|
2016-11-25 07:55:15 -05:00
|
|
|
}
|
2016-11-02 15:22:45 -04:00
|
|
|
|
|
|
|
for (const auto& module : block.second) {
|
2016-12-14 13:03:59 -05:00
|
|
|
string module_contents{module->contents()};
|
2016-11-02 15:22:45 -04:00
|
|
|
|
2016-11-25 07:55:15 -05:00
|
|
|
if (module_contents.empty()) {
|
2016-11-02 15:22:45 -04:00
|
|
|
continue;
|
2016-11-25 07:55:15 -05:00
|
|
|
}
|
2016-11-02 15:22:45 -04:00
|
|
|
|
2016-12-14 13:03:59 -05:00
|
|
|
if (!block_contents.empty() && !margin_right.empty()) {
|
|
|
|
block_contents += margin_right;
|
2016-12-08 20:44:12 -05:00
|
|
|
}
|
|
|
|
|
2016-11-25 07:55:15 -05:00
|
|
|
if (!block_contents.empty() && !separator.empty()) {
|
2016-11-02 15:22:45 -04:00
|
|
|
block_contents += separator;
|
2016-11-25 07:55:15 -05:00
|
|
|
}
|
2016-11-02 15:22:45 -04:00
|
|
|
|
2016-12-14 13:03:59 -05:00
|
|
|
if (!block_contents.empty() && !margin_left.empty() && !(is_left && module == block.second.front())) {
|
|
|
|
block_contents += margin_left;
|
2016-11-25 07:55:15 -05:00
|
|
|
}
|
2016-11-02 15:22:45 -04:00
|
|
|
|
2016-12-26 22:58:41 -05:00
|
|
|
block_contents.reserve(module_contents.size());
|
2016-12-14 13:03:59 -05:00
|
|
|
block_contents += module_contents;
|
2016-11-02 15:22:45 -04:00
|
|
|
}
|
|
|
|
|
2016-11-25 07:55:15 -05:00
|
|
|
if (block_contents.empty()) {
|
2016-11-02 15:22:45 -04:00
|
|
|
continue;
|
2016-12-05 14:41:00 -05:00
|
|
|
} else if (is_left) {
|
2016-11-02 15:22:45 -04:00
|
|
|
contents += "%{l}";
|
|
|
|
contents += padding_left;
|
|
|
|
} else if (is_center) {
|
|
|
|
contents += "%{c}";
|
|
|
|
} else if (is_right) {
|
|
|
|
contents += "%{r}";
|
|
|
|
block_contents += padding_right;
|
|
|
|
}
|
|
|
|
|
2016-11-22 16:45:12 -05:00
|
|
|
// Strip unnecessary reset tags
|
|
|
|
block_contents = string_util::replace_all(block_contents, "T-}%{T", "T");
|
2016-11-02 15:22:45 -04:00
|
|
|
block_contents = string_util::replace_all(block_contents, "B-}%{B#", "B#");
|
|
|
|
block_contents = string_util::replace_all(block_contents, "F-}%{F#", "F#");
|
2016-11-22 16:45:12 -05:00
|
|
|
block_contents = string_util::replace_all(block_contents, "U-}%{U#", "U#");
|
2016-11-24 13:24:47 -05:00
|
|
|
block_contents = string_util::replace_all(block_contents, "u-}%{u#", "u#");
|
|
|
|
block_contents = string_util::replace_all(block_contents, "o-}%{o#", "o#");
|
2016-11-22 16:45:12 -05:00
|
|
|
|
|
|
|
// Join consecutive tags
|
2016-11-02 15:22:45 -04:00
|
|
|
contents += string_util::replace_all(block_contents, "}%{", " ");
|
|
|
|
}
|
|
|
|
|
2016-11-24 13:24:47 -05:00
|
|
|
try {
|
2016-12-05 14:41:00 -05:00
|
|
|
if (!m_writeback) {
|
2016-12-30 17:32:05 -05:00
|
|
|
m_bar->parse(move(contents));
|
2016-12-05 14:41:00 -05:00
|
|
|
} else {
|
|
|
|
std::cout << contents << std::endl;
|
2016-11-24 13:24:47 -05:00
|
|
|
}
|
|
|
|
} catch (const exception& err) {
|
2016-12-05 14:41:00 -05:00
|
|
|
m_log.err("Failed to update bar contents (reason: %s)", err.what());
|
2016-11-04 13:54:33 -04:00
|
|
|
}
|
2016-12-03 16:54:58 -05:00
|
|
|
|
2016-12-05 14:41:00 -05:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2016-12-19 23:05:43 -05:00
|
|
|
/**
|
2016-12-23 16:19:42 -05:00
|
|
|
* Process eventqueue terminate event
|
|
|
|
*/
|
|
|
|
bool controller::on(const sig_ev::exit_terminate&) {
|
|
|
|
raise(SIGALRM);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Process eventqueue reload event
|
2016-12-19 23:05:43 -05:00
|
|
|
*/
|
2016-12-23 16:19:42 -05:00
|
|
|
bool controller::on(const sig_ev::exit_reload&) {
|
|
|
|
raise(SIGUSR1);
|
2016-12-19 23:05:43 -05:00
|
|
|
return true;
|
2016-12-05 14:41:00 -05:00
|
|
|
}
|
|
|
|
|
2016-12-19 23:05:43 -05:00
|
|
|
/**
|
|
|
|
* Process eventqueue check event
|
|
|
|
*/
|
2016-12-23 16:19:42 -05:00
|
|
|
bool controller::on(const sig_ev::check_state&) {
|
2016-12-19 23:05:43 -05:00
|
|
|
for (const auto& block : m_modules) {
|
|
|
|
for (const auto& module : block.second) {
|
|
|
|
if (module->running()) {
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
2016-12-05 14:41:00 -05:00
|
|
|
}
|
2016-12-19 23:05:43 -05:00
|
|
|
m_log.warn("No running modules...");
|
2016-12-23 16:19:42 -05:00
|
|
|
on(exit_terminate{});
|
2016-12-19 23:05:43 -05:00
|
|
|
return true;
|
|
|
|
}
|
2016-12-05 14:41:00 -05:00
|
|
|
|
2016-12-19 23:05:43 -05:00
|
|
|
/**
|
|
|
|
* Process ui button press event
|
|
|
|
*/
|
|
|
|
bool controller::on(const sig_ui::button_press& evt) {
|
2016-12-22 23:10:05 -05:00
|
|
|
string input{*evt()};
|
2016-12-05 14:41:00 -05:00
|
|
|
|
2016-12-13 23:42:46 -05:00
|
|
|
if (input.empty()) {
|
|
|
|
m_log.err("Cannot enqueue empty input");
|
|
|
|
return false;
|
2016-12-05 14:41:00 -05:00
|
|
|
}
|
|
|
|
|
2016-12-19 23:05:43 -05:00
|
|
|
enqueue(move(input));
|
|
|
|
return true;
|
2016-12-05 14:41:00 -05:00
|
|
|
}
|
|
|
|
|
2016-12-19 23:05:43 -05:00
|
|
|
/**
|
|
|
|
* Process ipc action messages
|
|
|
|
*/
|
2016-12-26 04:36:14 -05:00
|
|
|
bool controller::on(const sig_ipc::action& evt) {
|
|
|
|
string action{*evt()};
|
2016-12-05 14:41:00 -05:00
|
|
|
|
2016-12-13 23:42:46 -05:00
|
|
|
if (action.empty()) {
|
2016-12-05 14:41:00 -05:00
|
|
|
m_log.err("Cannot enqueue empty ipc action");
|
2016-12-13 23:42:46 -05:00
|
|
|
return false;
|
2016-12-03 16:54:58 -05:00
|
|
|
}
|
2016-12-13 23:42:46 -05:00
|
|
|
|
|
|
|
m_log.info("Enqueuing ipc action: %s", action);
|
2016-12-19 23:05:43 -05:00
|
|
|
enqueue(move(action));
|
|
|
|
return true;
|
2016-12-05 14:41:00 -05:00
|
|
|
}
|
|
|
|
|
2016-12-19 23:05:43 -05:00
|
|
|
/**
|
|
|
|
* Process ipc command messages
|
|
|
|
*/
|
2016-12-26 04:36:14 -05:00
|
|
|
bool controller::on(const sig_ipc::command& evt) {
|
|
|
|
string command{*evt()};
|
2016-12-05 14:41:00 -05:00
|
|
|
|
|
|
|
if (command.empty()) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (command == "quit") {
|
2016-12-19 23:05:43 -05:00
|
|
|
enqueue(make_quit_evt(false));
|
2016-12-05 14:41:00 -05:00
|
|
|
} else if (command == "restart") {
|
2016-12-19 23:05:43 -05:00
|
|
|
enqueue(make_quit_evt(true));
|
2016-12-05 14:41:00 -05:00
|
|
|
} else {
|
|
|
|
m_log.warn("\"%s\" is not a valid ipc command", command);
|
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2016-12-19 23:05:43 -05:00
|
|
|
/**
|
|
|
|
* Process ipc hook messages
|
|
|
|
*/
|
2016-12-26 04:36:14 -05:00
|
|
|
bool controller::on(const sig_ipc::hook& evt) {
|
|
|
|
string hook{*evt()};
|
2016-12-05 14:41:00 -05:00
|
|
|
|
2016-12-19 23:05:43 -05:00
|
|
|
for (const auto& block : m_modules) {
|
2016-12-05 14:41:00 -05:00
|
|
|
for (const auto& module : block.second) {
|
|
|
|
auto ipc = dynamic_cast<ipc_module*>(module.get());
|
|
|
|
if (ipc != nullptr) {
|
|
|
|
ipc->on_message(hook);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
2016-11-02 15:22:45 -04:00
|
|
|
}
|
|
|
|
|
2016-11-19 00:22:44 -05:00
|
|
|
POLYBAR_NS_END
|