2016-11-20 17:04:31 -05:00
|
|
|
#include <chrono>
|
2016-11-12 06:56:39 -05:00
|
|
|
#include <mutex>
|
2016-11-02 15:22:45 -04:00
|
|
|
|
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-11-02 15:22:45 -04:00
|
|
|
#include "components/controller.hpp"
|
2016-11-21 09:07:00 -05:00
|
|
|
#include "components/eventloop.hpp"
|
|
|
|
#include "components/ipc.hpp"
|
|
|
|
#include "components/logger.hpp"
|
|
|
|
#include "components/signals.hpp"
|
2016-11-02 15:22:45 -04:00
|
|
|
#include "modules/backlight.hpp"
|
|
|
|
#include "modules/battery.hpp"
|
|
|
|
#include "modules/bspwm.hpp"
|
|
|
|
#include "modules/counter.hpp"
|
|
|
|
#include "modules/cpu.hpp"
|
|
|
|
#include "modules/date.hpp"
|
2016-11-13 00:09:51 -05:00
|
|
|
#include "modules/fs.hpp"
|
2016-11-14 03:21:18 -05:00
|
|
|
#include "modules/ipc.hpp"
|
2016-11-02 15:22:45 -04:00
|
|
|
#include "modules/memory.hpp"
|
|
|
|
#include "modules/menu.hpp"
|
|
|
|
#include "modules/script.hpp"
|
2016-11-10 01:52:11 -05:00
|
|
|
#include "modules/temperature.hpp"
|
2016-11-12 06:56:39 -05:00
|
|
|
#include "modules/text.hpp"
|
2016-11-02 15:22:45 -04:00
|
|
|
#include "modules/xbacklight.hpp"
|
2016-11-18 22:03:18 -05:00
|
|
|
#include "modules/xwindow.hpp"
|
2016-11-26 00:14:58 -05:00
|
|
|
#include "modules/xworkspaces.hpp"
|
2016-11-02 15:22:45 -04:00
|
|
|
#include "utils/process.hpp"
|
|
|
|
#include "utils/string.hpp"
|
|
|
|
|
|
|
|
#if ENABLE_I3
|
|
|
|
#include "modules/i3.hpp"
|
|
|
|
#endif
|
|
|
|
#if ENABLE_MPD
|
|
|
|
#include "modules/mpd.hpp"
|
|
|
|
#endif
|
|
|
|
#if ENABLE_NETWORK
|
|
|
|
#include "modules/network.hpp"
|
|
|
|
#endif
|
|
|
|
#if ENABLE_ALSA
|
|
|
|
#include "modules/volume.hpp"
|
|
|
|
#endif
|
2016-11-30 08:26:11 -05:00
|
|
|
#if WITH_XKB
|
|
|
|
#include "modules/xkeyboard.hpp"
|
|
|
|
#endif
|
2016-11-02 15:22:45 -04:00
|
|
|
|
2016-11-30 08:26:11 -05:00
|
|
|
#if not(ENABLE_I3 && ENABLE_MPD && ENABLE_NETWORK && ENABLE_ALSA && WITH_XKB)
|
2016-11-20 19:19:44 -05:00
|
|
|
#include "modules/unsupported.hpp"
|
|
|
|
#endif
|
|
|
|
|
2016-11-19 00:22:44 -05:00
|
|
|
POLYBAR_NS
|
2016-11-02 15:22:45 -04:00
|
|
|
|
|
|
|
using namespace modules;
|
|
|
|
|
2016-11-20 17:04:31 -05:00
|
|
|
namespace chrono = std::chrono;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Configure injection module
|
|
|
|
*/
|
|
|
|
di::injector<unique_ptr<controller>> configure_controller(watch_t& confwatch) {
|
|
|
|
// clang-format off
|
|
|
|
return di::make_injector(
|
|
|
|
di::bind<>().to(confwatch),
|
|
|
|
configure_connection(),
|
|
|
|
configure_logger(),
|
|
|
|
configure_config(),
|
|
|
|
configure_eventloop(),
|
|
|
|
configure_bar());
|
|
|
|
// clang-format on
|
|
|
|
}
|
|
|
|
|
2016-11-02 15:22:45 -04:00
|
|
|
/**
|
|
|
|
* Stop modules and cleanup X components,
|
|
|
|
* threads and spawned processes
|
|
|
|
*/
|
|
|
|
controller::~controller() {
|
2016-12-01 02:41:49 -05:00
|
|
|
pthread_sigmask(SIG_UNBLOCK, &m_blockmask, nullptr);
|
|
|
|
|
|
|
|
sigset_t sig;
|
|
|
|
sigemptyset(&sig);
|
|
|
|
sigaddset(&sig, SIGALRM);
|
|
|
|
pthread_sigmask(SIG_BLOCK, &sig, nullptr);
|
|
|
|
|
2016-11-02 15:22:45 -04:00
|
|
|
if (m_command) {
|
|
|
|
m_log.info("Terminating running shell command");
|
2016-11-25 15:20:50 -05:00
|
|
|
m_command.reset();
|
2016-11-02 15:22:45 -04:00
|
|
|
}
|
|
|
|
|
2016-12-01 02:41:49 -05:00
|
|
|
if (m_bar) {
|
|
|
|
m_log.info("Deconstructing bar");
|
|
|
|
m_bar.reset();
|
2016-11-02 15:22:45 -04:00
|
|
|
}
|
|
|
|
|
2016-11-13 13:05:30 -05:00
|
|
|
if (m_ipc) {
|
|
|
|
m_log.info("Deconstructing ipc");
|
|
|
|
m_ipc.reset();
|
|
|
|
}
|
|
|
|
|
2016-12-01 02:41:49 -05:00
|
|
|
if (m_eventloop) {
|
|
|
|
m_log.info("Deconstructing eventloop");
|
|
|
|
m_eventloop.reset();
|
2016-11-02 15:22:45 -04:00
|
|
|
}
|
|
|
|
|
2016-12-01 02:41:49 -05:00
|
|
|
if (!m_writeback) {
|
|
|
|
m_log.info("Interrupting X event loop");
|
|
|
|
m_connection.send_dummy_event(m_connection.root());
|
|
|
|
}
|
2016-11-02 15:22:45 -04:00
|
|
|
|
2016-12-01 02:41:49 -05:00
|
|
|
m_log.info("Joining active threads");
|
|
|
|
for (auto&& th : m_threads) {
|
|
|
|
if (th.second.joinable()) {
|
|
|
|
th.second.join();
|
2016-11-02 15:22:45 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
m_log.info("Waiting for spawned processes");
|
2016-11-25 07:55:15 -05:00
|
|
|
while (process_util::notify_childprocess()) {
|
2016-11-02 15:22:45 -04:00
|
|
|
;
|
2016-11-25 07:55:15 -05:00
|
|
|
}
|
2016-11-02 15:22:45 -04:00
|
|
|
|
|
|
|
m_connection.flush();
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2016-12-01 02:41:49 -05:00
|
|
|
* Initialize components and setup X environment
|
2016-11-02 15:22:45 -04:00
|
|
|
*/
|
|
|
|
void controller::bootstrap(bool writeback, bool dump_wmname) {
|
2016-12-01 02:41:49 -05:00
|
|
|
// Add all signals to the block mask
|
|
|
|
sigfillset(&m_blockmask);
|
|
|
|
|
|
|
|
if (pthread_sigmask(SIG_BLOCK, &m_blockmask, nullptr) == -1) {
|
|
|
|
throw system_error("Failed to block signals");
|
|
|
|
}
|
|
|
|
|
2016-11-02 15:22:45 -04:00
|
|
|
m_writeback = writeback;
|
|
|
|
|
|
|
|
m_log.trace("controller: Initialize X atom cache");
|
|
|
|
m_connection.preload_atoms();
|
|
|
|
|
|
|
|
m_log.trace("controller: Query X extension data");
|
|
|
|
m_connection.query_extensions();
|
|
|
|
|
2016-11-14 03:21:18 -05:00
|
|
|
if (m_conf.get<bool>(m_conf.bar_section(), "enable-ipc", false)) {
|
|
|
|
m_log.trace("controller: Create IPC handler");
|
|
|
|
m_ipc = configure_ipc().create<decltype(m_ipc)>();
|
2016-11-18 12:37:52 -05:00
|
|
|
m_ipc->attach_callback(bind(&controller::on_ipc_action, this, placeholders::_1));
|
2016-11-14 03:21:18 -05:00
|
|
|
} else {
|
2016-11-18 12:37:52 -05:00
|
|
|
m_log.info("Inter-process messaging disabled");
|
2016-11-14 03:21:18 -05:00
|
|
|
}
|
|
|
|
|
2016-11-02 15:22:45 -04:00
|
|
|
// Listen for events on the root window to be able to
|
|
|
|
// break the blocking wait call when cleaning up
|
|
|
|
m_log.trace("controller: Listen for events on the root window");
|
2016-11-13 13:05:30 -05:00
|
|
|
const uint32_t value_list[2]{XCB_EVENT_MASK_PROPERTY_CHANGE | XCB_EVENT_MASK_STRUCTURE_NOTIFY};
|
|
|
|
m_connection.change_window_attributes_checked(m_connection.root(), XCB_CW_EVENT_MASK, value_list);
|
2016-11-02 15:22:45 -04:00
|
|
|
|
2016-11-13 13:05:30 -05:00
|
|
|
m_log.trace("controller: Setup bar");
|
|
|
|
m_bar->bootstrap(m_writeback || dump_wmname);
|
|
|
|
m_bar->bootstrap_tray();
|
2016-11-02 15:22:45 -04:00
|
|
|
|
|
|
|
if (dump_wmname) {
|
|
|
|
std::cout << m_bar->settings().wmname << std::endl;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2016-11-13 13:05:30 -05:00
|
|
|
m_log.trace("controller: Attach eventloop update callback");
|
2016-11-02 15:22:45 -04:00
|
|
|
m_eventloop->set_update_cb(bind(&controller::on_update, this));
|
|
|
|
|
|
|
|
if (!m_writeback) {
|
2016-11-13 13:05:30 -05:00
|
|
|
m_log.trace("controller: Attach eventloop input callback");
|
2016-11-02 15:22:45 -04:00
|
|
|
g_signals::bar::action_click = bind(&controller::on_mouse_event, this, placeholders::_1);
|
|
|
|
m_eventloop->set_input_db(bind(&controller::on_unrecognized_action, this, placeholders::_1));
|
|
|
|
}
|
|
|
|
|
|
|
|
m_log.trace("controller: Setup user-defined modules");
|
|
|
|
bootstrap_modules();
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Launch the controller
|
|
|
|
*/
|
2016-11-25 02:42:31 -05:00
|
|
|
void controller::run() {
|
2016-11-02 15:22:45 -04:00
|
|
|
assert(!m_connection.connection_has_error());
|
|
|
|
|
|
|
|
m_log.info("Starting application");
|
|
|
|
m_running = true;
|
|
|
|
|
2016-12-01 02:41:49 -05:00
|
|
|
if (m_confwatch && !m_writeback) {
|
|
|
|
m_threads[thread_role::CONF_LISTENER] = thread(&controller::wait_for_configwatch, this);
|
|
|
|
}
|
2016-11-02 15:22:45 -04:00
|
|
|
|
2016-11-14 03:21:18 -05:00
|
|
|
// Start ipc receiver if its enabled
|
|
|
|
if (m_conf.get<bool>(m_conf.bar_section(), "enable-ipc", false)) {
|
2016-12-01 02:41:49 -05:00
|
|
|
m_threads[thread_role::IPC_LISTENER] = thread(&ipc::receive_messages, m_ipc.get());
|
2016-11-14 03:21:18 -05:00
|
|
|
}
|
2016-11-13 13:05:30 -05:00
|
|
|
|
2016-11-02 15:22:45 -04:00
|
|
|
// Listen for X events in separate thread
|
|
|
|
if (!m_writeback) {
|
2016-12-01 02:41:49 -05:00
|
|
|
m_threads[thread_role::EVENT_QUEUE_X] = thread(&controller::wait_for_xevent, this);
|
2016-11-02 15:22:45 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
// Start event loop
|
|
|
|
if (m_eventloop) {
|
2016-12-01 02:41:49 -05:00
|
|
|
m_threads[thread_role::EVENT_QUEUE] = thread(&controller::wait_for_eventloop, this);
|
2016-11-02 15:22:45 -04:00
|
|
|
}
|
|
|
|
|
2016-12-01 02:41:49 -05:00
|
|
|
m_log.trace("controller: Wait for signal");
|
|
|
|
m_waiting = true;
|
2016-11-02 15:22:45 -04:00
|
|
|
|
|
|
|
sigemptyset(&m_waitmask);
|
|
|
|
sigaddset(&m_waitmask, SIGINT);
|
|
|
|
sigaddset(&m_waitmask, SIGQUIT);
|
|
|
|
sigaddset(&m_waitmask, SIGTERM);
|
|
|
|
sigaddset(&m_waitmask, SIGUSR1);
|
2016-12-01 02:41:49 -05:00
|
|
|
sigaddset(&m_waitmask, SIGALRM);
|
2016-11-02 15:22:45 -04:00
|
|
|
|
2016-12-01 02:41:49 -05:00
|
|
|
int caught_signal = 0;
|
|
|
|
sigwait(&m_waitmask, &caught_signal);
|
2016-11-02 15:22:45 -04:00
|
|
|
|
2016-12-01 02:41:49 -05:00
|
|
|
m_running = false;
|
|
|
|
m_waiting = false;
|
2016-11-02 15:22:45 -04:00
|
|
|
|
2016-12-01 02:41:49 -05:00
|
|
|
if (caught_signal == SIGUSR1) {
|
|
|
|
m_reload = true;
|
2016-11-25 07:55:15 -05:00
|
|
|
}
|
2016-11-02 15:22:45 -04:00
|
|
|
|
2016-12-01 02:41:49 -05:00
|
|
|
m_log.warn("Termination signal received, shutting down...");
|
|
|
|
m_log.trace("controller: Caught signal %d", caught_signal);
|
2016-11-02 15:22:45 -04:00
|
|
|
|
2016-12-01 02:41:49 -05:00
|
|
|
if (m_eventloop) {
|
|
|
|
m_log.trace("controller: Stopping event loop");
|
|
|
|
m_eventloop->stop();
|
2016-11-25 07:55:15 -05:00
|
|
|
}
|
2016-11-02 15:22:45 -04:00
|
|
|
|
2016-12-01 02:41:49 -05:00
|
|
|
if (!m_writeback && m_confwatch) {
|
|
|
|
m_log.trace("controller: Removing config watch");
|
|
|
|
m_confwatch->remove(true);
|
2016-11-02 15:22:45 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-11-04 13:54:33 -04:00
|
|
|
/**
|
2016-12-01 02:41:49 -05:00
|
|
|
* Get completion state
|
2016-11-04 13:54:33 -04:00
|
|
|
*/
|
2016-12-01 02:41:49 -05:00
|
|
|
bool controller::completed() {
|
|
|
|
return !m_running && !m_reload;
|
2016-11-02 15:22:45 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2016-12-01 02:41:49 -05:00
|
|
|
* Listen for changes to the config file
|
2016-11-02 15:22:45 -04:00
|
|
|
*/
|
2016-12-01 02:41:49 -05:00
|
|
|
void controller::wait_for_configwatch() {
|
|
|
|
try {
|
|
|
|
m_log.trace("controller: Attach config watch");
|
|
|
|
m_confwatch->attach(IN_MODIFY);
|
2016-11-02 15:22:45 -04:00
|
|
|
|
2016-12-01 02:41:49 -05:00
|
|
|
m_log.trace("controller: Wait for config file inotify event");
|
|
|
|
if (m_confwatch->await_match() && m_running) {
|
|
|
|
m_log.info("Configuration file changed");
|
|
|
|
kill(getpid(), SIGUSR1);
|
|
|
|
}
|
|
|
|
} catch (const system_error& err) {
|
|
|
|
m_log.err(err.what());
|
|
|
|
m_log.trace("controller: Reset config watch");
|
|
|
|
m_confwatch.reset();
|
2016-11-02 15:22:45 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2016-11-04 13:54:33 -04:00
|
|
|
* Wait for X events and forward them to
|
|
|
|
* the event registry
|
2016-11-02 15:22:45 -04:00
|
|
|
*/
|
|
|
|
void controller::wait_for_xevent() {
|
|
|
|
m_log.trace("controller: Listen for X events");
|
|
|
|
|
|
|
|
m_connection.flush();
|
|
|
|
|
2016-11-25 15:20:50 -05:00
|
|
|
shared_ptr<xcb_generic_event_t> evt;
|
2016-11-02 15:22:45 -04:00
|
|
|
while (m_running) {
|
|
|
|
try {
|
2016-12-03 09:12:11 -05:00
|
|
|
if ((evt = m_connection.wait_for_event()) != nullptr && m_running) {
|
2016-11-02 15:22:45 -04:00
|
|
|
m_connection.dispatch_event(evt);
|
|
|
|
}
|
2016-12-03 09:12:11 -05:00
|
|
|
} catch (xpp::connection_error& err) {
|
|
|
|
m_log.err("X connection error, terminating... (what: %s)", m_connection.error_str(err.code()));
|
2016-11-12 06:56:39 -05:00
|
|
|
} catch (const exception& err) {
|
2016-11-02 15:22:45 -04:00
|
|
|
m_log.err("Error in X event loop: %s", err.what());
|
|
|
|
}
|
2016-12-03 09:12:11 -05:00
|
|
|
|
|
|
|
if (m_connection.connection_has_error()) {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (m_running) {
|
|
|
|
kill(getpid(), SIGTERM);
|
2016-11-02 15:22:45 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-12-01 02:41:49 -05:00
|
|
|
/**
|
|
|
|
* Start event loop and wait for it to finish
|
|
|
|
*/
|
|
|
|
void controller::wait_for_eventloop() {
|
|
|
|
m_eventloop->start();
|
|
|
|
m_eventloop->wait();
|
|
|
|
|
|
|
|
this_thread::sleep_for(250ms);
|
|
|
|
|
|
|
|
if (m_running) {
|
|
|
|
m_log.trace("controller: eventloop ended, raising SIGALRM");
|
|
|
|
kill(getpid(), SIGALRM);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-11-02 15:22:45 -04:00
|
|
|
/**
|
|
|
|
* Create and initialize bar modules
|
|
|
|
*/
|
|
|
|
void controller::bootstrap_modules() {
|
|
|
|
const bar_settings bar{m_bar->settings()};
|
|
|
|
string bs{m_conf.bar_section()};
|
|
|
|
|
|
|
|
for (int i = 0; i < 3; i++) {
|
|
|
|
alignment align = static_cast<alignment>(i + 1);
|
|
|
|
string confkey;
|
|
|
|
|
|
|
|
switch (align) {
|
|
|
|
case alignment::LEFT:
|
|
|
|
confkey = "modules-left";
|
|
|
|
break;
|
|
|
|
case alignment::CENTER:
|
|
|
|
confkey = "modules-center";
|
|
|
|
break;
|
|
|
|
case alignment::RIGHT:
|
|
|
|
confkey = "modules-right";
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
for (auto& module_name : string_util::split(m_conf.get<string>(bs, confkey, ""), ' ')) {
|
2016-11-14 03:21:18 -05:00
|
|
|
if (module_name.empty()) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2016-11-02 15:22:45 -04:00
|
|
|
try {
|
|
|
|
auto type = m_conf.get<string>("module/" + module_name, "type");
|
|
|
|
module_t module;
|
|
|
|
|
2016-11-25 07:55:15 -05:00
|
|
|
if (type == "internal/counter") {
|
2016-11-02 15:22:45 -04:00
|
|
|
module.reset(new counter_module(bar, m_log, m_conf, module_name));
|
2016-11-25 07:55:15 -05:00
|
|
|
} else if (type == "internal/backlight") {
|
2016-11-02 15:22:45 -04:00
|
|
|
module.reset(new backlight_module(bar, m_log, m_conf, module_name));
|
2016-11-25 07:55:15 -05:00
|
|
|
} else if (type == "internal/battery") {
|
2016-11-02 15:22:45 -04:00
|
|
|
module.reset(new battery_module(bar, m_log, m_conf, module_name));
|
2016-11-25 07:55:15 -05:00
|
|
|
} else if (type == "internal/bspwm") {
|
2016-11-02 15:22:45 -04:00
|
|
|
module.reset(new bspwm_module(bar, m_log, m_conf, module_name));
|
2016-11-25 07:55:15 -05:00
|
|
|
} else if (type == "internal/cpu") {
|
2016-11-02 15:22:45 -04:00
|
|
|
module.reset(new cpu_module(bar, m_log, m_conf, module_name));
|
2016-11-25 07:55:15 -05:00
|
|
|
} else if (type == "internal/date") {
|
2016-11-02 15:22:45 -04:00
|
|
|
module.reset(new date_module(bar, m_log, m_conf, module_name));
|
2016-11-25 07:55:15 -05:00
|
|
|
} else if (type == "internal/fs") {
|
2016-11-13 00:09:51 -05:00
|
|
|
module.reset(new fs_module(bar, m_log, m_conf, module_name));
|
2016-11-25 07:55:15 -05:00
|
|
|
} else if (type == "internal/memory") {
|
2016-11-02 15:22:45 -04:00
|
|
|
module.reset(new memory_module(bar, m_log, m_conf, module_name));
|
2016-11-25 07:55:15 -05:00
|
|
|
} else if (type == "internal/i3") {
|
2016-11-02 15:22:45 -04:00
|
|
|
module.reset(new i3_module(bar, m_log, m_conf, module_name));
|
2016-11-25 07:55:15 -05:00
|
|
|
} else if (type == "internal/mpd") {
|
2016-11-02 15:22:45 -04:00
|
|
|
module.reset(new mpd_module(bar, m_log, m_conf, module_name));
|
2016-11-25 07:55:15 -05:00
|
|
|
} else if (type == "internal/volume") {
|
2016-11-02 15:22:45 -04:00
|
|
|
module.reset(new volume_module(bar, m_log, m_conf, module_name));
|
2016-11-25 07:55:15 -05:00
|
|
|
} else if (type == "internal/network") {
|
2016-11-02 15:22:45 -04:00
|
|
|
module.reset(new network_module(bar, m_log, m_conf, module_name));
|
2016-11-25 07:55:15 -05:00
|
|
|
} else if (type == "internal/temperature") {
|
2016-11-10 01:52:11 -05:00
|
|
|
module.reset(new temperature_module(bar, m_log, m_conf, module_name));
|
2016-11-25 07:55:15 -05:00
|
|
|
} else if (type == "internal/xbacklight") {
|
2016-11-18 22:03:18 -05:00
|
|
|
module.reset(new xbacklight_module(bar, m_log, m_conf, module_name));
|
2016-11-30 04:06:16 -05:00
|
|
|
} else if (type == "internal/xkeyboard") {
|
|
|
|
module.reset(new xkeyboard_module(bar, m_log, m_conf, module_name));
|
2016-11-25 07:55:15 -05:00
|
|
|
} else if (type == "internal/xwindow") {
|
2016-11-18 22:03:18 -05:00
|
|
|
module.reset(new xwindow_module(bar, m_log, m_conf, module_name));
|
2016-11-26 00:14:58 -05:00
|
|
|
} else if (type == "internal/xworkspaces") {
|
|
|
|
module.reset(new xworkspaces_module(bar, m_log, m_conf, module_name));
|
2016-11-25 07:55:15 -05:00
|
|
|
} else if (type == "custom/text") {
|
2016-11-02 15:22:45 -04:00
|
|
|
module.reset(new text_module(bar, m_log, m_conf, module_name));
|
2016-11-25 07:55:15 -05:00
|
|
|
} else if (type == "custom/script") {
|
2016-11-02 15:22:45 -04:00
|
|
|
module.reset(new script_module(bar, m_log, m_conf, module_name));
|
2016-11-25 07:55:15 -05:00
|
|
|
} else if (type == "custom/menu") {
|
2016-11-02 15:22:45 -04:00
|
|
|
module.reset(new menu_module(bar, m_log, m_conf, module_name));
|
2016-11-25 07:55:15 -05:00
|
|
|
} else if (type == "custom/ipc") {
|
|
|
|
if (!m_ipc) {
|
2016-11-18 12:37:52 -05:00
|
|
|
throw application_error("Inter-process messaging needs to be enabled");
|
2016-11-25 07:55:15 -05:00
|
|
|
}
|
2016-11-14 03:21:18 -05:00
|
|
|
module.reset(new ipc_module(bar, m_log, m_conf, module_name));
|
|
|
|
m_ipc->attach_callback(
|
2016-11-20 17:04:31 -05:00
|
|
|
bind(&ipc_module::on_message, static_cast<ipc_module*>(module.get()), placeholders::_1));
|
2016-11-25 07:55:15 -05:00
|
|
|
} else {
|
2016-11-02 15:22:45 -04:00
|
|
|
throw application_error("Unknown module: " + module_name);
|
2016-11-25 07:55:15 -05:00
|
|
|
}
|
2016-11-02 15:22:45 -04:00
|
|
|
|
2016-11-12 06:56:39 -05:00
|
|
|
module->set_update_cb(
|
2016-11-25 15:20:50 -05:00
|
|
|
bind(&eventloop::enqueue, m_eventloop.get(), eventloop::entry_t{static_cast<uint8_t>(event_type::UPDATE)}));
|
2016-11-12 06:56:39 -05:00
|
|
|
module->set_stop_cb(
|
2016-11-25 15:20:50 -05:00
|
|
|
bind(&eventloop::enqueue, m_eventloop.get(), eventloop::entry_t{static_cast<uint8_t>(event_type::CHECK)}));
|
2016-11-02 15:22:45 -04:00
|
|
|
module->setup();
|
|
|
|
|
|
|
|
m_eventloop->add_module(align, move(module));
|
2016-11-03 09:10:39 -04:00
|
|
|
} catch (const std::runtime_error& err) {
|
2016-11-24 13:24:47 -05:00
|
|
|
m_log.err("Disabling module \"%s\" (reason: %s)", module_name, err.what());
|
2016-11-02 15:22:45 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-11-25 15:20:50 -05:00
|
|
|
if (!m_eventloop->module_count()) {
|
2016-11-02 15:22:45 -04:00
|
|
|
throw application_error("No modules created");
|
2016-11-25 07:55:15 -05:00
|
|
|
}
|
2016-11-02 15:22:45 -04:00
|
|
|
}
|
|
|
|
|
2016-11-18 12:37:52 -05:00
|
|
|
/**
|
|
|
|
* Callback for received ipc actions
|
|
|
|
*/
|
|
|
|
void controller::on_ipc_action(const ipc_action& message) {
|
2016-11-25 15:20:50 -05:00
|
|
|
if (!m_eventloop) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2016-11-18 12:37:52 -05:00
|
|
|
string action = message.payload.substr(strlen(ipc_action::prefix));
|
|
|
|
|
|
|
|
if (action.empty()) {
|
|
|
|
m_log.err("Cannot enqueue empty IPC action");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2016-11-25 15:20:50 -05:00
|
|
|
eventloop::entry_t evt{static_cast<uint8_t>(event_type::INPUT)};
|
2016-11-18 12:37:52 -05:00
|
|
|
snprintf(evt.data, sizeof(evt.data), "%s", action.c_str());
|
|
|
|
|
|
|
|
m_log.info("Enqueuing IPC action: %s", action);
|
|
|
|
m_eventloop->enqueue(evt);
|
|
|
|
}
|
|
|
|
|
2016-11-02 15:22:45 -04:00
|
|
|
/**
|
|
|
|
* Callback for clicked bar actions
|
|
|
|
*/
|
2016-11-25 07:55:15 -05:00
|
|
|
void controller::on_mouse_event(const string& input) {
|
2016-11-25 15:20:50 -05:00
|
|
|
if (!m_eventloop) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
eventloop::entry_t evt{static_cast<uint8_t>(event_type::INPUT)};
|
2016-11-02 15:22:45 -04:00
|
|
|
|
|
|
|
if (input.length() > sizeof(evt.data)) {
|
2016-11-25 15:20:50 -05:00
|
|
|
return m_log.warn("Ignoring input event (size)");
|
|
|
|
}
|
|
|
|
|
|
|
|
snprintf(evt.data, sizeof(evt.data), "%s", input.c_str());
|
|
|
|
|
|
|
|
if (!m_eventloop->enqueue_delayed(evt)) {
|
|
|
|
m_log.trace_x("controller: Dispatcher busy");
|
2016-11-02 15:22:45 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2016-11-04 13:54:33 -04:00
|
|
|
* Callback for actions not handled internally by a module
|
2016-11-02 15:22:45 -04:00
|
|
|
*/
|
|
|
|
void controller::on_unrecognized_action(string input) {
|
|
|
|
try {
|
|
|
|
if (m_command) {
|
|
|
|
m_log.warn("Terminating previous shell command");
|
|
|
|
m_command->terminate();
|
|
|
|
}
|
|
|
|
|
|
|
|
m_log.info("Executing shell command: %s", input);
|
|
|
|
|
|
|
|
m_command = command_util::make_command(input);
|
|
|
|
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-11-04 13:54:33 -04:00
|
|
|
* Callback for module content update
|
2016-11-02 15:22:45 -04:00
|
|
|
*/
|
|
|
|
void controller::on_update() {
|
2016-11-25 15:20:50 -05:00
|
|
|
if (!m_bar) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
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};
|
2016-11-02 15:22:45 -04:00
|
|
|
|
2016-11-21 09:07:00 -05:00
|
|
|
string padding_left(bar.padding.left, ' ');
|
|
|
|
string padding_right(bar.padding.right, ' ');
|
2016-11-02 15:22:45 -04:00
|
|
|
|
2016-11-21 09:07:00 -05:00
|
|
|
auto margin_left = bar.module_margin.left;
|
|
|
|
auto margin_right = bar.module_margin.right;
|
2016-11-02 15:22:45 -04:00
|
|
|
|
|
|
|
for (const auto& block : m_eventloop->modules()) {
|
|
|
|
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) {
|
|
|
|
auto module_contents = module->contents();
|
|
|
|
|
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-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-11-25 07:55:15 -05:00
|
|
|
if (!(is_left && module == block.second.front())) {
|
2016-11-02 15:22:45 -04:00
|
|
|
block_contents += string(margin_left, ' ');
|
2016-11-25 07:55:15 -05:00
|
|
|
}
|
2016-11-02 15:22:45 -04:00
|
|
|
|
|
|
|
block_contents += module->contents();
|
|
|
|
|
2016-11-25 07:55:15 -05:00
|
|
|
if (!(is_right && module == block.second.back())) {
|
2016-11-02 15:22:45 -04:00
|
|
|
block_contents += string(margin_right, ' ');
|
2016-11-25 07:55:15 -05:00
|
|
|
}
|
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-11-25 07:55:15 -05:00
|
|
|
}
|
2016-11-02 15:22:45 -04:00
|
|
|
|
|
|
|
if (is_left) {
|
|
|
|
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, "}%{", " ");
|
|
|
|
}
|
|
|
|
|
|
|
|
if (m_writeback) {
|
|
|
|
std::cout << contents << std::endl;
|
2016-11-24 13:24:47 -05:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
try {
|
2016-11-02 15:22:45 -04:00
|
|
|
m_bar->parse(contents);
|
2016-11-24 13:24:47 -05:00
|
|
|
} catch (const exception& err) {
|
|
|
|
m_log.err("Failed to update bar contents (reason: %s)", err.what());
|
2016-11-02 15:22:45 -04:00
|
|
|
}
|
2016-11-04 13:54:33 -04:00
|
|
|
|
2016-11-24 13:24:47 -05:00
|
|
|
try {
|
|
|
|
if (!m_trayactivated) {
|
|
|
|
m_trayactivated = true;
|
|
|
|
m_bar->activate_tray();
|
|
|
|
}
|
|
|
|
} catch (const exception& err) {
|
|
|
|
m_log.err("Failed to active tray manager (reason: %s)", err.what());
|
2016-11-04 13:54:33 -04:00
|
|
|
}
|
2016-11-02 15:22:45 -04:00
|
|
|
}
|
|
|
|
|
2016-11-19 00:22:44 -05:00
|
|
|
POLYBAR_NS_END
|