polybar/src/components/controller.cpp

763 lines
21 KiB
C++
Raw Normal View History

#include "components/controller.hpp"
#include <csignal>
#include <utility>
2016-11-20 22:04:31 +00:00
#include "components/bar.hpp"
#include "components/builder.hpp"
2016-11-21 14:07:00 +00:00
#include "components/config.hpp"
2021-02-20 20:26:45 +00:00
#include "components/eventloop.hpp"
2016-11-21 14:07:00 +00:00
#include "components/logger.hpp"
#include "components/types.hpp"
#include "events/signal.hpp"
#include "events/signal_emitter.hpp"
#include "modules/meta/base.hpp"
#include "modules/meta/event_handler.hpp"
#include "modules/meta/factory.hpp"
2020-05-31 14:28:31 +00:00
#include "utils/actions.hpp"
2016-12-09 08:40:46 +00:00
#include "utils/inotify.hpp"
#include "utils/process.hpp"
2016-11-02 19:22:45 +00:00
#include "utils/string.hpp"
#include "utils/time.hpp"
2016-12-09 08:40:46 +00:00
#include "x11/connection.hpp"
2016-12-26 08:40:15 +00:00
#include "x11/extensions/all.hpp"
2016-11-19 05:22:44 +00:00
POLYBAR_NS
2016-11-02 19:22:45 +00:00
using namespace eventloop;
2016-12-09 08:02:47 +00:00
/**
* Build controller instance
2016-12-09 08:02:47 +00:00
*/
controller::make_type controller::make(bool has_ipc, loop& loop) {
return std::make_unique<controller>(
Use sockets for IPC (#2539) Deprecates not using `polybar-msg` for IPC. Fixes #2532 Closes #2465 Fixes #2504 * Create FIFO specific NamedPipeHandle subclass to PipeHandle * Prototype SocketHandle * Move mainloop up to main.cpp * Pass eventloop to ipc class * Deprecate sending ipc over the named pipe Unfortunately, we can only show the warning in the polybar log and not give the user any feedback because the pipe is one-way * Move eventloop into its own namespace * Prototype ipc socket handling * Remove handles from ipc_client Should be independent from eventloop logic * Remove ipc clients when finished * Add tests for ipc_client decoding * Add callback for complete ipc messages * Remove template param from mixins * Move signal handler to new callback system * Move poll handle to new callback system * Move FSEventHandle to new callback system * Move TimerHandle and AsyncHandle to new callback system * Move PipeHandle to new callback system * Implement socket functionality in new callback system * Correctly reset ipc named pipe handle * Let client close handles in error callback * Wrap client pipe and ipc::client in connection class * Better decoder log messages * Socket path logic * Fix CI warnings * Remove UVHandleGeneric * Fix error when socket folder already exists * Proof of concept message writeback * Restructure ipc files * polybar-msg: Use sockets * polybar-msg: Better syntax for actions * Fix memory leak with fifo After EOF, the pipe wasn't closed and EOF was called all the time, each time allocating a new pipe. * Make polybar-msg compile on its own * Rudimentary writeback for polybar-msg * Fix payload reference going out of scope. * Add IPC documentation * Cleanup polybar-msg code * Specify the v0 ipc message format * Close ipc connection after message * Fix ipc tests * Properly close ipc connections * Fix polybar-msg not working with action string * Write polybar-msg manpage * polybar-msg: Stop using exit() * ipc: Print log message with PID * Add tests for ipc util * polybar-msg: Print PID with success message * ipc: Propagate message errors * Rename ipc::client to ipc::decoder * Rename ipc.cpp to polybar-msg.cpp * ipc: Write encoder function and fix decoder bugs * ipc: Use message format for responses * ipc: Handle wrong message types * ipc: Write back error message if ipc message cannot be processed This only happens for commands and empty actions. Non-empty actions are not immediately executed, but deferred until the next loop iteration. * Remove TODO about deleting runtime directory The socket file is not deleted after socket.close() is called, only after libuv executes the close callback. So we can't just call rmdir because it will probably always fail. * CLeanup WriteRequest * Update manpage authors * Cleanup
2022-01-22 19:35:37 +00:00
connection::make(), signal_emitter::make(), logger::make(), config::make(), has_ipc, loop);
2016-12-09 08:02:47 +00:00
}
/**
* Construct controller
2016-12-09 08:02:47 +00:00
*/
controller::controller(
connection& conn, signal_emitter& emitter, const logger& logger, const config& config, bool has_ipc, loop& loop)
: m_connection(conn)
, m_sig(emitter)
, m_log(logger)
, m_conf(config)
Use sockets for IPC (#2539) Deprecates not using `polybar-msg` for IPC. Fixes #2532 Closes #2465 Fixes #2504 * Create FIFO specific NamedPipeHandle subclass to PipeHandle * Prototype SocketHandle * Move mainloop up to main.cpp * Pass eventloop to ipc class * Deprecate sending ipc over the named pipe Unfortunately, we can only show the warning in the polybar log and not give the user any feedback because the pipe is one-way * Move eventloop into its own namespace * Prototype ipc socket handling * Remove handles from ipc_client Should be independent from eventloop logic * Remove ipc clients when finished * Add tests for ipc_client decoding * Add callback for complete ipc messages * Remove template param from mixins * Move signal handler to new callback system * Move poll handle to new callback system * Move FSEventHandle to new callback system * Move TimerHandle and AsyncHandle to new callback system * Move PipeHandle to new callback system * Implement socket functionality in new callback system * Correctly reset ipc named pipe handle * Let client close handles in error callback * Wrap client pipe and ipc::client in connection class * Better decoder log messages * Socket path logic * Fix CI warnings * Remove UVHandleGeneric * Fix error when socket folder already exists * Proof of concept message writeback * Restructure ipc files * polybar-msg: Use sockets * polybar-msg: Better syntax for actions * Fix memory leak with fifo After EOF, the pipe wasn't closed and EOF was called all the time, each time allocating a new pipe. * Make polybar-msg compile on its own * Rudimentary writeback for polybar-msg * Fix payload reference going out of scope. * Add IPC documentation * Cleanup polybar-msg code * Specify the v0 ipc message format * Close ipc connection after message * Fix ipc tests * Properly close ipc connections * Fix polybar-msg not working with action string * Write polybar-msg manpage * polybar-msg: Stop using exit() * ipc: Print log message with PID * Add tests for ipc util * polybar-msg: Print PID with success message * ipc: Propagate message errors * Rename ipc::client to ipc::decoder * Rename ipc.cpp to polybar-msg.cpp * ipc: Write encoder function and fix decoder bugs * ipc: Use message format for responses * ipc: Handle wrong message types * ipc: Write back error message if ipc message cannot be processed This only happens for commands and empty actions. Non-empty actions are not immediately executed, but deferred until the next loop iteration. * Remove TODO about deleting runtime directory The socket file is not deleted after socket.close() is called, only after libuv executes the close callback. So we can't just call rmdir because it will probably always fail. * CLeanup WriteRequest * Update manpage authors * Cleanup
2022-01-22 19:35:37 +00:00
, m_loop(loop)
, m_bar(bar::make(m_loop))
, m_has_ipc(has_ipc) {
m_conf.ignore_key("settings", "throttle-input-for");
m_conf.ignore_key("settings", "throttle-output");
m_conf.ignore_key("settings", "throttle-output-for");
m_conf.ignore_key("settings", "eventqueue-swallow");
m_conf.ignore_key("settings", "eventqueue-swallow-time");
2016-11-20 22:04:31 +00:00
m_log.trace("controller: Setup user-defined modules");
size_t created_modules{0};
created_modules += setup_modules(alignment::LEFT);
created_modules += setup_modules(alignment::CENTER);
created_modules += setup_modules(alignment::RIGHT);
2016-12-01 07:41:49 +00:00
if (!created_modules) {
throw application_error("No modules created");
}
m_log.notice("Loaded %zd modules", created_modules);
2016-11-02 19:22:45 +00:00
}
/**
* Deconstruct controller
*/
controller::~controller() {
m_log.trace("controller: Detach signal receiver");
m_sig.detach(this);
m_log.trace("controller: Stop modules");
for (auto&& module : m_modules) {
auto module_name = module->name();
auto cleanup_ms = time_util::measure([&module] {
module->stop();
module->join();
module.reset();
});
m_log.info("Deconstruction of %s took %lu ms.", module_name, cleanup_ms);
}
}
/**
* Run the main loop
*/
bool controller::run(bool writeback, string snapshot_dst, bool confwatch) {
m_log.info("Starting application");
m_log.trace("controller: Main thread id = %i", concurrency_util::thread_id(this_thread::get_id()));
2016-11-02 19:22:45 +00:00
assert(!m_connection.connection_has_error());
2017-01-24 05:59:58 +00:00
m_writeback = writeback;
2017-01-24 05:59:58 +00:00
m_snapshot_dst = move(snapshot_dst);
m_sig.attach(this);
2016-12-14 04:42:46 +00:00
size_t started_modules{0};
for (const auto& module : m_modules) {
auto evt_handler = dynamic_cast<event_handler_interface*>(&*module);
if (evt_handler != nullptr) {
evt_handler->connect(m_connection);
}
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 19:22:45 +00:00
}
if (!started_modules) {
throw application_error("No modules started");
2016-11-02 19:22:45 +00:00
}
m_connection.flush();
read_events(confwatch);
2016-11-02 19:22:45 +00:00
m_log.notice("Termination signal received, shutting down...");
2016-11-02 19:22:45 +00:00
2021-09-11 13:58:18 +00:00
return !m_reload;
}
2016-11-02 19:22:45 +00:00
/**
* Enqueue input data
*/
2021-09-11 10:36:52 +00:00
void controller::trigger_action(string&& input_data) {
2021-09-11 13:39:22 +00:00
std::unique_lock<std::mutex> guard(m_notification_mutex);
m_log.trace("controller: Queueing input event '%s'", input_data);
m_notifications.inputdata.push(std::move(input_data));
trigger_notification();
2021-09-11 10:36:52 +00:00
}
void controller::trigger_quit(bool reload) {
2021-09-11 13:39:22 +00:00
std::unique_lock<std::mutex> guard(m_notification_mutex);
m_notifications.quit = true;
m_notifications.reload = m_notifications.reload || reload;
2021-09-11 13:58:18 +00:00
trigger_notification();
}
2016-11-02 19:22:45 +00:00
void controller::trigger_update(bool force) {
2021-09-11 13:39:22 +00:00
std::unique_lock<std::mutex> guard(m_notification_mutex);
m_notifications.update = true;
m_notifications.force_update = m_notifications.force_update || force;
trigger_notification();
}
2021-09-11 13:58:18 +00:00
void controller::trigger_notification() {
m_notifier->send();
2021-09-11 13:58:18 +00:00
}
2021-09-11 09:46:37 +00:00
void controller::stop(bool reload) {
2021-09-11 13:58:18 +00:00
update_reload(reload);
Use sockets for IPC (#2539) Deprecates not using `polybar-msg` for IPC. Fixes #2532 Closes #2465 Fixes #2504 * Create FIFO specific NamedPipeHandle subclass to PipeHandle * Prototype SocketHandle * Move mainloop up to main.cpp * Pass eventloop to ipc class * Deprecate sending ipc over the named pipe Unfortunately, we can only show the warning in the polybar log and not give the user any feedback because the pipe is one-way * Move eventloop into its own namespace * Prototype ipc socket handling * Remove handles from ipc_client Should be independent from eventloop logic * Remove ipc clients when finished * Add tests for ipc_client decoding * Add callback for complete ipc messages * Remove template param from mixins * Move signal handler to new callback system * Move poll handle to new callback system * Move FSEventHandle to new callback system * Move TimerHandle and AsyncHandle to new callback system * Move PipeHandle to new callback system * Implement socket functionality in new callback system * Correctly reset ipc named pipe handle * Let client close handles in error callback * Wrap client pipe and ipc::client in connection class * Better decoder log messages * Socket path logic * Fix CI warnings * Remove UVHandleGeneric * Fix error when socket folder already exists * Proof of concept message writeback * Restructure ipc files * polybar-msg: Use sockets * polybar-msg: Better syntax for actions * Fix memory leak with fifo After EOF, the pipe wasn't closed and EOF was called all the time, each time allocating a new pipe. * Make polybar-msg compile on its own * Rudimentary writeback for polybar-msg * Fix payload reference going out of scope. * Add IPC documentation * Cleanup polybar-msg code * Specify the v0 ipc message format * Close ipc connection after message * Fix ipc tests * Properly close ipc connections * Fix polybar-msg not working with action string * Write polybar-msg manpage * polybar-msg: Stop using exit() * ipc: Print log message with PID * Add tests for ipc util * polybar-msg: Print PID with success message * ipc: Propagate message errors * Rename ipc::client to ipc::decoder * Rename ipc.cpp to polybar-msg.cpp * ipc: Write encoder function and fix decoder bugs * ipc: Use message format for responses * ipc: Handle wrong message types * ipc: Write back error message if ipc message cannot be processed This only happens for commands and empty actions. Non-empty actions are not immediately executed, but deferred until the next loop iteration. * Remove TODO about deleting runtime directory The socket file is not deleted after socket.close() is called, only after libuv executes the close callback. So we can't just call rmdir because it will probably always fail. * CLeanup WriteRequest * Update manpage authors * Cleanup
2022-01-22 19:35:37 +00:00
m_loop.stop();
2021-09-11 09:46:37 +00:00
}
Use sockets for IPC (#2539) Deprecates not using `polybar-msg` for IPC. Fixes #2532 Closes #2465 Fixes #2504 * Create FIFO specific NamedPipeHandle subclass to PipeHandle * Prototype SocketHandle * Move mainloop up to main.cpp * Pass eventloop to ipc class * Deprecate sending ipc over the named pipe Unfortunately, we can only show the warning in the polybar log and not give the user any feedback because the pipe is one-way * Move eventloop into its own namespace * Prototype ipc socket handling * Remove handles from ipc_client Should be independent from eventloop logic * Remove ipc clients when finished * Add tests for ipc_client decoding * Add callback for complete ipc messages * Remove template param from mixins * Move signal handler to new callback system * Move poll handle to new callback system * Move FSEventHandle to new callback system * Move TimerHandle and AsyncHandle to new callback system * Move PipeHandle to new callback system * Implement socket functionality in new callback system * Correctly reset ipc named pipe handle * Let client close handles in error callback * Wrap client pipe and ipc::client in connection class * Better decoder log messages * Socket path logic * Fix CI warnings * Remove UVHandleGeneric * Fix error when socket folder already exists * Proof of concept message writeback * Restructure ipc files * polybar-msg: Use sockets * polybar-msg: Better syntax for actions * Fix memory leak with fifo After EOF, the pipe wasn't closed and EOF was called all the time, each time allocating a new pipe. * Make polybar-msg compile on its own * Rudimentary writeback for polybar-msg * Fix payload reference going out of scope. * Add IPC documentation * Cleanup polybar-msg code * Specify the v0 ipc message format * Close ipc connection after message * Fix ipc tests * Properly close ipc connections * Fix polybar-msg not working with action string * Write polybar-msg manpage * polybar-msg: Stop using exit() * ipc: Print log message with PID * Add tests for ipc util * polybar-msg: Print PID with success message * ipc: Propagate message errors * Rename ipc::client to ipc::decoder * Rename ipc.cpp to polybar-msg.cpp * ipc: Write encoder function and fix decoder bugs * ipc: Use message format for responses * ipc: Handle wrong message types * ipc: Write back error message if ipc message cannot be processed This only happens for commands and empty actions. Non-empty actions are not immediately executed, but deferred until the next loop iteration. * Remove TODO about deleting runtime directory The socket file is not deleted after socket.close() is called, only after libuv executes the close callback. So we can't just call rmdir because it will probably always fail. * CLeanup WriteRequest * Update manpage authors * Cleanup
2022-01-22 19:35:37 +00:00
void controller::conn_cb() {
2021-09-11 09:46:37 +00:00
int xcb_error = m_connection.connection_has_error();
if ((xcb_error = m_connection.connection_has_error()) != 0) {
2021-09-11 09:46:37 +00:00
m_log.err("X connection error, terminating... (what: %s)", m_connection.error_str(xcb_error));
stop(false);
return;
}
shared_ptr<xcb_generic_event_t> evt{};
while ((evt = m_connection.poll_for_event()) != 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()));
stop(false);
} catch (const exception& err) {
// IDs for events are defined in xproto.h
m_log.err("Error in X event loop while handling event %d: %s", evt->response_type, err.what());
2021-09-11 09:46:37 +00:00
}
}
if ((xcb_error = m_connection.connection_has_error()) != 0) {
m_log.err("X connection error, terminating... (what: %s)", m_connection.error_str(xcb_error));
stop(false);
return;
}
}
void controller::signal_handler(int signum) {
2021-09-11 12:10:02 +00:00
m_log.notice("Received signal(%d): %s", signum, strsignal(signum));
2021-09-11 09:46:37 +00:00
stop(signum == SIGUSR1);
}
void controller::create_config_watcher(const string& filename) {
auto fs_event_handle = m_loop.handle<FSEventHandle>();
fs_event_handle->start(
filename, 0, [this](const auto& e) { confwatch_handler(e.path); },
[this, &handle = *fs_event_handle](const auto& e) {
m_log.err("libuv error while watching included file for changes: %s", uv_strerror(e.status));
handle.close();
});
}
Use sockets for IPC (#2539) Deprecates not using `polybar-msg` for IPC. Fixes #2532 Closes #2465 Fixes #2504 * Create FIFO specific NamedPipeHandle subclass to PipeHandle * Prototype SocketHandle * Move mainloop up to main.cpp * Pass eventloop to ipc class * Deprecate sending ipc over the named pipe Unfortunately, we can only show the warning in the polybar log and not give the user any feedback because the pipe is one-way * Move eventloop into its own namespace * Prototype ipc socket handling * Remove handles from ipc_client Should be independent from eventloop logic * Remove ipc clients when finished * Add tests for ipc_client decoding * Add callback for complete ipc messages * Remove template param from mixins * Move signal handler to new callback system * Move poll handle to new callback system * Move FSEventHandle to new callback system * Move TimerHandle and AsyncHandle to new callback system * Move PipeHandle to new callback system * Implement socket functionality in new callback system * Correctly reset ipc named pipe handle * Let client close handles in error callback * Wrap client pipe and ipc::client in connection class * Better decoder log messages * Socket path logic * Fix CI warnings * Remove UVHandleGeneric * Fix error when socket folder already exists * Proof of concept message writeback * Restructure ipc files * polybar-msg: Use sockets * polybar-msg: Better syntax for actions * Fix memory leak with fifo After EOF, the pipe wasn't closed and EOF was called all the time, each time allocating a new pipe. * Make polybar-msg compile on its own * Rudimentary writeback for polybar-msg * Fix payload reference going out of scope. * Add IPC documentation * Cleanup polybar-msg code * Specify the v0 ipc message format * Close ipc connection after message * Fix ipc tests * Properly close ipc connections * Fix polybar-msg not working with action string * Write polybar-msg manpage * polybar-msg: Stop using exit() * ipc: Print log message with PID * Add tests for ipc util * polybar-msg: Print PID with success message * ipc: Propagate message errors * Rename ipc::client to ipc::decoder * Rename ipc.cpp to polybar-msg.cpp * ipc: Write encoder function and fix decoder bugs * ipc: Use message format for responses * ipc: Handle wrong message types * ipc: Write back error message if ipc message cannot be processed This only happens for commands and empty actions. Non-empty actions are not immediately executed, but deferred until the next loop iteration. * Remove TODO about deleting runtime directory The socket file is not deleted after socket.close() is called, only after libuv executes the close callback. So we can't just call rmdir because it will probably always fail. * CLeanup WriteRequest * Update manpage authors * Cleanup
2022-01-22 19:35:37 +00:00
void controller::confwatch_handler(const char* filename) {
2021-09-11 09:46:37 +00:00
m_log.notice("Watched config file changed %s", filename);
stop(true);
2021-02-20 20:26:45 +00:00
}
2021-09-11 10:19:00 +00:00
void controller::notifier_handler() {
2021-09-11 13:39:22 +00:00
notifications_t data{};
{
std::unique_lock<std::mutex> guard(m_notification_mutex);
std::swap(m_notifications, data);
}
if (data.quit) {
Use sockets for IPC (#2539) Deprecates not using `polybar-msg` for IPC. Fixes #2532 Closes #2465 Fixes #2504 * Create FIFO specific NamedPipeHandle subclass to PipeHandle * Prototype SocketHandle * Move mainloop up to main.cpp * Pass eventloop to ipc class * Deprecate sending ipc over the named pipe Unfortunately, we can only show the warning in the polybar log and not give the user any feedback because the pipe is one-way * Move eventloop into its own namespace * Prototype ipc socket handling * Remove handles from ipc_client Should be independent from eventloop logic * Remove ipc clients when finished * Add tests for ipc_client decoding * Add callback for complete ipc messages * Remove template param from mixins * Move signal handler to new callback system * Move poll handle to new callback system * Move FSEventHandle to new callback system * Move TimerHandle and AsyncHandle to new callback system * Move PipeHandle to new callback system * Implement socket functionality in new callback system * Correctly reset ipc named pipe handle * Let client close handles in error callback * Wrap client pipe and ipc::client in connection class * Better decoder log messages * Socket path logic * Fix CI warnings * Remove UVHandleGeneric * Fix error when socket folder already exists * Proof of concept message writeback * Restructure ipc files * polybar-msg: Use sockets * polybar-msg: Better syntax for actions * Fix memory leak with fifo After EOF, the pipe wasn't closed and EOF was called all the time, each time allocating a new pipe. * Make polybar-msg compile on its own * Rudimentary writeback for polybar-msg * Fix payload reference going out of scope. * Add IPC documentation * Cleanup polybar-msg code * Specify the v0 ipc message format * Close ipc connection after message * Fix ipc tests * Properly close ipc connections * Fix polybar-msg not working with action string * Write polybar-msg manpage * polybar-msg: Stop using exit() * ipc: Print log message with PID * Add tests for ipc util * polybar-msg: Print PID with success message * ipc: Propagate message errors * Rename ipc::client to ipc::decoder * Rename ipc.cpp to polybar-msg.cpp * ipc: Write encoder function and fix decoder bugs * ipc: Use message format for responses * ipc: Handle wrong message types * ipc: Write back error message if ipc message cannot be processed This only happens for commands and empty actions. Non-empty actions are not immediately executed, but deferred until the next loop iteration. * Remove TODO about deleting runtime directory The socket file is not deleted after socket.close() is called, only after libuv executes the close callback. So we can't just call rmdir because it will probably always fail. * CLeanup WriteRequest * Update manpage authors * Cleanup
2022-01-22 19:35:37 +00:00
stop(data.reload);
2021-09-11 10:36:52 +00:00
return;
}
while (!data.inputdata.empty()) {
auto inputdata = data.inputdata.front();
data.inputdata.pop();
m_log.trace("controller: Dequeueing inputdata: '%s'", inputdata);
process_inputdata(std::move(inputdata));
2021-09-11 10:19:00 +00:00
}
2021-09-11 13:39:22 +00:00
if (data.update) {
process_update(data.force_update);
}
2021-09-11 10:19:00 +00:00
}
2021-09-11 13:14:17 +00:00
void controller::screenshot_handler() {
m_sig.emit(signals::ui::request_snapshot{move(m_snapshot_dst)});
trigger_update(true);
}
/**
* Read events from configured file descriptors
*/
void controller::read_events(bool confwatch) {
m_log.info("Entering event loop (thread-id=%lu)", this_thread::get_id());
try {
auto x_poll_handle = m_loop.handle<PollHandle>(m_connection.get_file_descriptor());
x_poll_handle->start(
Use sockets for IPC (#2539) Deprecates not using `polybar-msg` for IPC. Fixes #2532 Closes #2465 Fixes #2504 * Create FIFO specific NamedPipeHandle subclass to PipeHandle * Prototype SocketHandle * Move mainloop up to main.cpp * Pass eventloop to ipc class * Deprecate sending ipc over the named pipe Unfortunately, we can only show the warning in the polybar log and not give the user any feedback because the pipe is one-way * Move eventloop into its own namespace * Prototype ipc socket handling * Remove handles from ipc_client Should be independent from eventloop logic * Remove ipc clients when finished * Add tests for ipc_client decoding * Add callback for complete ipc messages * Remove template param from mixins * Move signal handler to new callback system * Move poll handle to new callback system * Move FSEventHandle to new callback system * Move TimerHandle and AsyncHandle to new callback system * Move PipeHandle to new callback system * Implement socket functionality in new callback system * Correctly reset ipc named pipe handle * Let client close handles in error callback * Wrap client pipe and ipc::client in connection class * Better decoder log messages * Socket path logic * Fix CI warnings * Remove UVHandleGeneric * Fix error when socket folder already exists * Proof of concept message writeback * Restructure ipc files * polybar-msg: Use sockets * polybar-msg: Better syntax for actions * Fix memory leak with fifo After EOF, the pipe wasn't closed and EOF was called all the time, each time allocating a new pipe. * Make polybar-msg compile on its own * Rudimentary writeback for polybar-msg * Fix payload reference going out of scope. * Add IPC documentation * Cleanup polybar-msg code * Specify the v0 ipc message format * Close ipc connection after message * Fix ipc tests * Properly close ipc connections * Fix polybar-msg not working with action string * Write polybar-msg manpage * polybar-msg: Stop using exit() * ipc: Print log message with PID * Add tests for ipc util * polybar-msg: Print PID with success message * ipc: Propagate message errors * Rename ipc::client to ipc::decoder * Rename ipc.cpp to polybar-msg.cpp * ipc: Write encoder function and fix decoder bugs * ipc: Use message format for responses * ipc: Handle wrong message types * ipc: Write back error message if ipc message cannot be processed This only happens for commands and empty actions. Non-empty actions are not immediately executed, but deferred until the next loop iteration. * Remove TODO about deleting runtime directory The socket file is not deleted after socket.close() is called, only after libuv executes the close callback. So we can't just call rmdir because it will probably always fail. * CLeanup WriteRequest * Update manpage authors * Cleanup
2022-01-22 19:35:37 +00:00
UV_READABLE, [this](const auto&) { conn_cb(); },
[this](const auto& e) {
m_log.err("libuv error while polling X connection: "s + uv_strerror(e.status));
stop(false);
Use sockets for IPC (#2539) Deprecates not using `polybar-msg` for IPC. Fixes #2532 Closes #2465 Fixes #2504 * Create FIFO specific NamedPipeHandle subclass to PipeHandle * Prototype SocketHandle * Move mainloop up to main.cpp * Pass eventloop to ipc class * Deprecate sending ipc over the named pipe Unfortunately, we can only show the warning in the polybar log and not give the user any feedback because the pipe is one-way * Move eventloop into its own namespace * Prototype ipc socket handling * Remove handles from ipc_client Should be independent from eventloop logic * Remove ipc clients when finished * Add tests for ipc_client decoding * Add callback for complete ipc messages * Remove template param from mixins * Move signal handler to new callback system * Move poll handle to new callback system * Move FSEventHandle to new callback system * Move TimerHandle and AsyncHandle to new callback system * Move PipeHandle to new callback system * Implement socket functionality in new callback system * Correctly reset ipc named pipe handle * Let client close handles in error callback * Wrap client pipe and ipc::client in connection class * Better decoder log messages * Socket path logic * Fix CI warnings * Remove UVHandleGeneric * Fix error when socket folder already exists * Proof of concept message writeback * Restructure ipc files * polybar-msg: Use sockets * polybar-msg: Better syntax for actions * Fix memory leak with fifo After EOF, the pipe wasn't closed and EOF was called all the time, each time allocating a new pipe. * Make polybar-msg compile on its own * Rudimentary writeback for polybar-msg * Fix payload reference going out of scope. * Add IPC documentation * Cleanup polybar-msg code * Specify the v0 ipc message format * Close ipc connection after message * Fix ipc tests * Properly close ipc connections * Fix polybar-msg not working with action string * Write polybar-msg manpage * polybar-msg: Stop using exit() * ipc: Print log message with PID * Add tests for ipc util * polybar-msg: Print PID with success message * ipc: Propagate message errors * Rename ipc::client to ipc::decoder * Rename ipc.cpp to polybar-msg.cpp * ipc: Write encoder function and fix decoder bugs * ipc: Use message format for responses * ipc: Handle wrong message types * ipc: Write back error message if ipc message cannot be processed This only happens for commands and empty actions. Non-empty actions are not immediately executed, but deferred until the next loop iteration. * Remove TODO about deleting runtime directory The socket file is not deleted after socket.close() is called, only after libuv executes the close callback. So we can't just call rmdir because it will probably always fail. * CLeanup WriteRequest * Update manpage authors * Cleanup
2022-01-22 19:35:37 +00:00
});
2016-11-02 19:22:45 +00:00
auto x_prepare_handle = m_loop.handle<PrepareHandle>();
x_prepare_handle->start([this]() {
/*
* We have to also handle events in the prepare handle (which runs right
* before polling for IO) to process any already queued X events which
* wouldn't trigger the uv_poll handle.
*/
conn_cb();
m_connection.flush();
});
for (auto s : {SIGINT, SIGQUIT, SIGTERM, SIGUSR1, SIGALRM}) {
auto signal_handle = m_loop.handle<SignalHandle>();
signal_handle->start(s, [this](const auto& e) { signal_handler(e.signum); });
}
2016-11-02 19:22:45 +00:00
if (confwatch) {
create_config_watcher(m_conf.filepath());
// also watch the include-files for changes
for (auto& module_path : m_conf.get_included_files()) {
create_config_watcher(module_path);
}
}
2021-09-11 13:14:17 +00:00
if (!m_snapshot_dst.empty()) {
2021-09-12 13:53:14 +00:00
// Trigger a single screenshot after 3 seconds
auto timer_handle = m_loop.handle<TimerHandle>();
timer_handle->start(3000, 0, [this]() { screenshot_handler(); });
2021-09-11 13:14:17 +00:00
}
if (!m_writeback) {
m_bar->start(m_tray_module_name);
}
/*
* Immediately trigger and update so that the bar displays something.
*/
trigger_update(true);
Use sockets for IPC (#2539) Deprecates not using `polybar-msg` for IPC. Fixes #2532 Closes #2465 Fixes #2504 * Create FIFO specific NamedPipeHandle subclass to PipeHandle * Prototype SocketHandle * Move mainloop up to main.cpp * Pass eventloop to ipc class * Deprecate sending ipc over the named pipe Unfortunately, we can only show the warning in the polybar log and not give the user any feedback because the pipe is one-way * Move eventloop into its own namespace * Prototype ipc socket handling * Remove handles from ipc_client Should be independent from eventloop logic * Remove ipc clients when finished * Add tests for ipc_client decoding * Add callback for complete ipc messages * Remove template param from mixins * Move signal handler to new callback system * Move poll handle to new callback system * Move FSEventHandle to new callback system * Move TimerHandle and AsyncHandle to new callback system * Move PipeHandle to new callback system * Implement socket functionality in new callback system * Correctly reset ipc named pipe handle * Let client close handles in error callback * Wrap client pipe and ipc::client in connection class * Better decoder log messages * Socket path logic * Fix CI warnings * Remove UVHandleGeneric * Fix error when socket folder already exists * Proof of concept message writeback * Restructure ipc files * polybar-msg: Use sockets * polybar-msg: Better syntax for actions * Fix memory leak with fifo After EOF, the pipe wasn't closed and EOF was called all the time, each time allocating a new pipe. * Make polybar-msg compile on its own * Rudimentary writeback for polybar-msg * Fix payload reference going out of scope. * Add IPC documentation * Cleanup polybar-msg code * Specify the v0 ipc message format * Close ipc connection after message * Fix ipc tests * Properly close ipc connections * Fix polybar-msg not working with action string * Write polybar-msg manpage * polybar-msg: Stop using exit() * ipc: Print log message with PID * Add tests for ipc util * polybar-msg: Print PID with success message * ipc: Propagate message errors * Rename ipc::client to ipc::decoder * Rename ipc.cpp to polybar-msg.cpp * ipc: Write encoder function and fix decoder bugs * ipc: Use message format for responses * ipc: Handle wrong message types * ipc: Write back error message if ipc message cannot be processed This only happens for commands and empty actions. Non-empty actions are not immediately executed, but deferred until the next loop iteration. * Remove TODO about deleting runtime directory The socket file is not deleted after socket.close() is called, only after libuv executes the close callback. So we can't just call rmdir because it will probably always fail. * CLeanup WriteRequest * Update manpage authors * Cleanup
2022-01-22 19:35:37 +00:00
m_loop.run();
} catch (const exception& err) {
m_log.err("Fatal Error in eventloop: %s", err.what());
2021-09-11 09:46:37 +00:00
stop(false);
}
2021-09-11 09:46:37 +00:00
m_log.info("Eventloop finished");
}
/**
* Tries to match the given command to a legacy action string and sends the
* appropriate new action (and data) to the right module if possible.
*
2022-02-20 20:40:48 +00:00
* @returns true iff the given command matches a legacy action string and was
* successfully forwarded to a module
*/
2020-05-31 19:11:36 +00:00
bool controller::try_forward_legacy_action(const string& cmd) {
/*
* Maps legacy action names to a module type and the new action name in that module.
*
* We try to match the old action name as a prefix, and everything after it will also be added to the end of the new
* action string (for example "mpdseek+5" will be redirected to "seek.+5" in the first mpd module).
*
* The action will be delivered to the first module of that type so that it is consistent with existing behavior.
* If the module does not support the action or no matching module is found, the command is forwarded to the shell.
*
* TODO Remove when deprecated action names are removed
*/
2020-05-31 14:31:48 +00:00
// clang-format off
#define A_MAP(old, module_name, event) {old, {string(module_name::TYPE), string(module_name::event)}}
static const std::unordered_map<string, std::pair<string, const string>> legacy_actions{
2020-05-31 14:31:48 +00:00
A_MAP("datetoggle", date_module, EVENT_TOGGLE),
#if ENABLE_ALSA
2020-05-31 14:31:48 +00:00
A_MAP("volup", alsa_module, EVENT_INC),
A_MAP("voldown", alsa_module, EVENT_DEC),
A_MAP("volmute", alsa_module, EVENT_TOGGLE),
#endif
#if ENABLE_PULSEAUDIO
2020-05-31 14:31:48 +00:00
A_MAP("pa_volup", pulseaudio_module, EVENT_INC),
A_MAP("pa_voldown", pulseaudio_module, EVENT_DEC),
A_MAP("pa_volmute", pulseaudio_module, EVENT_TOGGLE),
#endif
2020-05-31 14:31:48 +00:00
A_MAP("xbacklight+", xbacklight_module, EVENT_INC),
A_MAP("xbacklight-", xbacklight_module, EVENT_DEC),
A_MAP("backlight+", backlight_module, EVENT_INC),
A_MAP("backlight-", backlight_module, EVENT_DEC),
#if ENABLE_XKEYBOARD
2020-05-31 14:31:48 +00:00
A_MAP("xkeyboard/switch", xkeyboard_module, EVENT_SWITCH),
#endif
#if ENABLE_MPD
2020-05-31 14:31:48 +00:00
A_MAP("mpdplay", mpd_module, EVENT_PLAY),
A_MAP("mpdpause", mpd_module, EVENT_PAUSE),
A_MAP("mpdstop", mpd_module, EVENT_STOP),
A_MAP("mpdprev", mpd_module, EVENT_PREV),
A_MAP("mpdnext", mpd_module, EVENT_NEXT),
A_MAP("mpdrepeat", mpd_module, EVENT_REPEAT),
A_MAP("mpdsingle", mpd_module, EVENT_SINGLE),
A_MAP("mpdrandom", mpd_module, EVENT_RANDOM),
A_MAP("mpdconsume", mpd_module, EVENT_CONSUME),
// Has data
A_MAP("mpdseek", mpd_module, EVENT_SEEK),
#endif
2020-05-31 14:31:48 +00:00
// Has data
A_MAP("xworkspaces-focus=", xworkspaces_module, EVENT_FOCUS),
A_MAP("xworkspaces-next", xworkspaces_module, EVENT_NEXT),
A_MAP("xworkspaces-prev", xworkspaces_module, EVENT_PREV),
// Has data
A_MAP("bspwm-deskfocus", bspwm_module, EVENT_FOCUS),
A_MAP("bspwm-desknext", bspwm_module, EVENT_NEXT),
A_MAP("bspwm-deskprev", bspwm_module, EVENT_PREV),
#if ENABLE_I3
2020-05-31 14:31:48 +00:00
// Has data
A_MAP("i3wm-wsfocus-", i3_module, EVENT_FOCUS),
A_MAP("i3wm-wsnext", i3_module, EVENT_NEXT),
A_MAP("i3wm-wsprev", i3_module, EVENT_PREV),
#endif
2020-05-31 14:31:48 +00:00
// Has data
A_MAP("menu-open-", menu_module, EVENT_OPEN),
A_MAP("menu-close", menu_module, EVENT_CLOSE),
};
#undef A_MAP
// clang-format on
// Check if any key in the map is a prefix for the `cmd`
for (const auto& entry : legacy_actions) {
const auto& key = entry.first;
if (cmd.compare(0, key.length(), key) == 0) {
string type = entry.second.first;
auto data = cmd.substr(key.length());
string action = entry.second.second;
// Search for the first module that matches the type for this legacy action
for (auto&& module : m_modules) {
if (module->type() == type) {
auto module_name = module->name_raw();
if (data.empty()) {
m_log.warn("The action '%s' is deprecated, use '#%s.%s' instead!", cmd, module_name, action);
} else {
m_log.warn("The action '%s' is deprecated, use '#%s.%s.%s' instead!", cmd, module_name, action, data);
}
m_log.warn("Consult the 'Actions' page in the polybar documentation for more information.");
2020-05-31 14:31:48 +00:00
m_log.info(
"Forwarding legacy action '%s' to module '%s' as '%s' with data '%s'", cmd, module_name, action, data);
if (!module->input(action, data)) {
m_log.err("Failed to forward deprecated action to %s module", type);
// Forward to shell if the module cannot accept the action to not break existing behavior.
return false;
}
// Only deliver to the first matching module.
return true;
}
}
}
}
/*
* If we couldn't find any matching legacy action, we return false and let
* the command be forwarded to the shell
*/
return false;
}
2020-11-25 09:16:26 +00:00
bool controller::forward_action(const actions_util::action& action_triple) {
string module_name = std::get<0>(action_triple);
string action = std::get<1>(action_triple);
string data = std::get<2>(action_triple);
m_log.info("Forwarding action to modules (module: '%s', action: '%s', data: '%s')", module_name, action, data);
int num_delivered = 0;
// Forwards the action to all modules that match the name
for (auto&& module : m_modules) {
if (module->name_raw() == module_name) {
if (!module->input(action, data)) {
m_log.err("The '%s' module does not support the '%s' action.", module_name, action);
}
num_delivered++;
}
}
if (num_delivered == 0) {
m_log.err("Could not forward action to module: No module named '%s' (action: '%s', data: '%s')", module_name,
action, data);
} else {
m_log.info("Delivered action to %d module%s", num_delivered, num_delivered > 1 ? "s" : "");
}
return true;
}
/**
* Process stored input data
*/
2021-09-11 13:39:22 +00:00
void controller::process_inputdata(string&& cmd) {
m_log.trace("controller: Processing inputdata: %s", cmd);
// Every command that starts with '#' is considered an action string.
if (cmd.front() == '#') {
try {
2020-11-25 09:16:26 +00:00
this->forward_action(actions_util::parse_action_string(cmd));
} catch (runtime_error& e) {
2020-11-25 09:16:26 +00:00
m_log.err("Invalid action string (action: %s, reason: %s)", cmd, e.what());
}
return;
}
if (this->try_forward_legacy_action(cmd)) {
return;
}
try {
// Run input as command if it's not an input for a module
m_log.info("Forwarding command to shell... (input: %s)", cmd);
m_log.info("Executing shell command: %s", cmd);
process_util::fork_detached([cmd] { process_util::exec_sh(cmd.c_str()); });
process_update(true);
} catch (const application_error& err) {
m_log.err("controller: Error while forwarding input to shell -> %s", err.what());
2016-12-01 07:41:49 +00:00
}
}
Use sockets for IPC (#2539) Deprecates not using `polybar-msg` for IPC. Fixes #2532 Closes #2465 Fixes #2504 * Create FIFO specific NamedPipeHandle subclass to PipeHandle * Prototype SocketHandle * Move mainloop up to main.cpp * Pass eventloop to ipc class * Deprecate sending ipc over the named pipe Unfortunately, we can only show the warning in the polybar log and not give the user any feedback because the pipe is one-way * Move eventloop into its own namespace * Prototype ipc socket handling * Remove handles from ipc_client Should be independent from eventloop logic * Remove ipc clients when finished * Add tests for ipc_client decoding * Add callback for complete ipc messages * Remove template param from mixins * Move signal handler to new callback system * Move poll handle to new callback system * Move FSEventHandle to new callback system * Move TimerHandle and AsyncHandle to new callback system * Move PipeHandle to new callback system * Implement socket functionality in new callback system * Correctly reset ipc named pipe handle * Let client close handles in error callback * Wrap client pipe and ipc::client in connection class * Better decoder log messages * Socket path logic * Fix CI warnings * Remove UVHandleGeneric * Fix error when socket folder already exists * Proof of concept message writeback * Restructure ipc files * polybar-msg: Use sockets * polybar-msg: Better syntax for actions * Fix memory leak with fifo After EOF, the pipe wasn't closed and EOF was called all the time, each time allocating a new pipe. * Make polybar-msg compile on its own * Rudimentary writeback for polybar-msg * Fix payload reference going out of scope. * Add IPC documentation * Cleanup polybar-msg code * Specify the v0 ipc message format * Close ipc connection after message * Fix ipc tests * Properly close ipc connections * Fix polybar-msg not working with action string * Write polybar-msg manpage * polybar-msg: Stop using exit() * ipc: Print log message with PID * Add tests for ipc util * polybar-msg: Print PID with success message * ipc: Propagate message errors * Rename ipc::client to ipc::decoder * Rename ipc.cpp to polybar-msg.cpp * ipc: Write encoder function and fix decoder bugs * ipc: Use message format for responses * ipc: Handle wrong message types * ipc: Write back error message if ipc message cannot be processed This only happens for commands and empty actions. Non-empty actions are not immediately executed, but deferred until the next loop iteration. * Remove TODO about deleting runtime directory The socket file is not deleted after socket.close() is called, only after libuv executes the close callback. So we can't just call rmdir because it will probably always fail. * CLeanup WriteRequest * Update manpage authors * Cleanup
2022-01-22 19:35:37 +00:00
/**
* Process eventqueue update event
*/
bool controller::process_update(bool force) {
2016-11-21 14:07:00 +00:00
const bar_settings& bar{m_bar->settings()};
2016-11-25 12:55:15 +00:00
string contents;
Add units support (POINT, PIXEL, SPACE) (#2578) * add units support (POINT, PIXEL, SPACE) for polybar - add a size_with_unit struct - add a geometry_format_values struct - move dpi initialisation from renderer.cpp to bar.cpp - add a string to size_with_unit converter - add point support (with pt) - add pixel support (with px) * Fix unit test compilation * clang-format * Better names The old names didn't really capture the purpose of the structs and function. space_type -> spacing_type space_size -> spacing_val size_type -> extent_type geometry -> extent_val geometry_format_values -> percentage_with_offset * Remove parse_size_with_unit No longer needed. The convert<spacing_val> function in config.cpp already does all the work for us and always setting the type to pixel was wrong. In addition, line-size should not be of type spacing_val but extent_val. * Cleanup I tried to address most of my comments on the old PR * Fix renderer width calculation We can't just blindly add the x difference to the width because for example the width should increase if x < width and the increase keeps x < width. Similarly, we can't just add the offset to the width. * Rename geom_format_to_pixels to percentage_with_offset_to_pixel * Cleanup * Apply suggested changes from Patrick on GitHub Co-authored-by: Patrick Ziegler <p.ziegler96@gmail.com> * Update src/components/bar.cpp Co-authored-by: Patrick Ziegler <p.ziegler96@gmail.com> * Update src/components/config.cpp Co-authored-by: Patrick Ziegler <p.ziegler96@gmail.com> * Update src/components/builder.cpp Co-authored-by: Patrick Ziegler <p.ziegler96@gmail.com> * Update src/components/builder.cpp Co-authored-by: Patrick Ziegler <p.ziegler96@gmail.com> * config: Use stod for parsing percentage * Use stof instead of strtof * units: Fix test edge cases * Remove unnecessary clang-format toggle * Use percentage_with_offset for margin-{top,bottom} * Support negative extent values * Rename unit to units and create a cpp file * Move percentage_with_offset_to_pixel unit test to units * Add unit tests for units_utils * Clarify when and how negative spacing/extent is allowed Negative spacing is never allowed and produces a config error. Extents allow negative values in theory, but only a few use-cases accept it. Only the extent value used for the `%{O}` tag and the offset value in percentage_with_offset can be negative. Everything else is capped below at 0. The final pixel value of percentage_with_offset also caps below at 0. * Fix parsing errors not being caught in config * Print a proper error message for uncaught exceptions * Cleanup module::get_output All changes preserve the existing semantics * Stop using remove_trailing_space in module::get_output Instead, we first check if the current tag is built, and only if it is, the spacing is prepended. * Remove unused imports * Restore old behavior If there are two tags and the second one isn't built (module::build returns false), the space in between them is removed. For example in the mpd module: format-online = <toggle> <label-song> foo If mpd is not running, the mpd module will return false when trying to build the `<label-song>` tag. If we don't remove the space between `<toggle>` and `<label-song>`, we end up with two spaces between `<toggle>` and `foo`. This change is to match the old behavior where at least one trailing space character was removed from the builder. * Add changelog entry * Remove unused setting * Use percentage with offset for tray-offset Co-authored-by: Jérôme BOULMIER <jerome.boulmier@outlook.fr> Co-authored-by: Joe Groocock <github@frebib.net>
2022-02-20 20:08:57 +00:00
string padding_left = builder::get_spacing_format_string(bar.padding.left);
string padding_right = builder::get_spacing_format_string(bar.padding.right);
string margin_left = builder::get_spacing_format_string(bar.module_margin.left);
string margin_right = builder::get_spacing_format_string(bar.module_margin.right);
2016-11-02 19:22:45 +00:00
builder build{bar};
build.node(bar.separator);
string separator{build.flush()};
for (const auto& block : m_blocks) {
2016-11-02 19:22:45 +00:00
string block_contents;
bool is_left = false;
bool is_center = false;
bool is_right = false;
2017-01-24 05:59:58 +00:00
bool is_first = true;
2016-11-02 19:22:45 +00:00
2016-11-25 12:55:15 +00:00
if (block.first == alignment::LEFT) {
2016-11-02 19:22:45 +00:00
is_left = true;
2016-11-25 12:55:15 +00:00
} else if (block.first == alignment::CENTER) {
2016-11-02 19:22:45 +00:00
is_center = true;
2016-11-25 12:55:15 +00:00
} else if (block.first == alignment::RIGHT) {
2016-11-02 19:22:45 +00:00
is_right = true;
2016-11-25 12:55:15 +00:00
}
2016-11-02 19:22:45 +00:00
for (const auto& module : block.second) {
if (!module->running() || !module->visible()) {
continue;
}
2016-11-02 19:22:45 +00:00
2017-01-24 05:59:58 +00:00
string module_contents;
try {
module_contents = module->contents();
} catch (const exception& err) {
m_log.err("Failed to get contents for \"%s\" (err: %s)", module->name(), err.what());
}
2016-11-25 12:55:15 +00:00
if (module_contents.empty()) {
2016-11-02 19:22:45 +00:00
continue;
2016-11-25 12:55:15 +00:00
}
2016-11-02 19:22:45 +00:00
if (!block_contents.empty() && !margin_right.empty()) {
block_contents += margin_right;
}
2016-11-25 12:55:15 +00:00
if (!block_contents.empty() && !separator.empty()) {
2016-11-02 19:22:45 +00:00
block_contents += separator;
2016-11-25 12:55:15 +00:00
}
2016-11-02 19:22:45 +00:00
2017-01-24 05:59:58 +00:00
if (!block_contents.empty() && !margin_left.empty() && !(is_left && is_first)) {
block_contents += margin_left;
2016-11-25 12:55:15 +00:00
}
2016-11-02 19:22:45 +00:00
2016-12-27 03:58:41 +00:00
block_contents.reserve(module_contents.size());
block_contents += module_contents;
2017-01-24 05:59:58 +00:00
is_first = false;
2016-11-02 19:22:45 +00:00
}
2016-11-25 12:55:15 +00:00
if (block_contents.empty()) {
2016-11-02 19:22:45 +00:00
continue;
} else if (is_left) {
2016-11-02 19:22:45 +00:00
contents += "%{l}";
contents += padding_left;
} else if (is_center) {
contents += "%{c}";
} else if (is_right) {
contents += "%{r}";
block_contents += padding_right;
}
contents += block_contents;
2016-11-02 19:22:45 +00:00
}
try {
if (!m_writeback) {
m_bar->parse(move(contents), force);
} else {
std::cout << contents << std::endl;
}
} catch (const exception& err) {
m_log.err("Failed to update bar contents (reason: %s)", err.what());
2016-11-04 17:54:33 +00:00
}
2016-12-03 21:54:58 +00:00
return true;
}
2021-09-11 13:58:18 +00:00
void controller::update_reload(bool reload) {
m_reload = m_reload || reload;
}
/**
* Creates module instances for all the modules in the given alignment block
*/
size_t controller::setup_modules(alignment align) {
string key;
switch (align) {
case alignment::LEFT:
key = "modules-left";
break;
case alignment::CENTER:
key = "modules-center";
break;
case alignment::RIGHT:
key = "modules-right";
break;
case alignment::NONE:
m_log.err("controller: Tried to setup modules for alignment NONE");
break;
}
string configured_modules;
if (!key.empty()) {
configured_modules = m_conf.get(m_conf.section(), key, ""s);
}
for (auto& module_name : string_util::split(configured_modules, ' ')) {
if (module_name.empty()) {
continue;
}
try {
auto type = m_conf.get("module/" + module_name, "type");
if (type == tray_module::TYPE) {
if (!m_tray_module_name.empty()) {
throw module_error("Multiple trays defined. Using tray `" + m_tray_module_name + "`");
}
m_tray_module_name = module_name;
}
Use sockets for IPC (#2539) Deprecates not using `polybar-msg` for IPC. Fixes #2532 Closes #2465 Fixes #2504 * Create FIFO specific NamedPipeHandle subclass to PipeHandle * Prototype SocketHandle * Move mainloop up to main.cpp * Pass eventloop to ipc class * Deprecate sending ipc over the named pipe Unfortunately, we can only show the warning in the polybar log and not give the user any feedback because the pipe is one-way * Move eventloop into its own namespace * Prototype ipc socket handling * Remove handles from ipc_client Should be independent from eventloop logic * Remove ipc clients when finished * Add tests for ipc_client decoding * Add callback for complete ipc messages * Remove template param from mixins * Move signal handler to new callback system * Move poll handle to new callback system * Move FSEventHandle to new callback system * Move TimerHandle and AsyncHandle to new callback system * Move PipeHandle to new callback system * Implement socket functionality in new callback system * Correctly reset ipc named pipe handle * Let client close handles in error callback * Wrap client pipe and ipc::client in connection class * Better decoder log messages * Socket path logic * Fix CI warnings * Remove UVHandleGeneric * Fix error when socket folder already exists * Proof of concept message writeback * Restructure ipc files * polybar-msg: Use sockets * polybar-msg: Better syntax for actions * Fix memory leak with fifo After EOF, the pipe wasn't closed and EOF was called all the time, each time allocating a new pipe. * Make polybar-msg compile on its own * Rudimentary writeback for polybar-msg * Fix payload reference going out of scope. * Add IPC documentation * Cleanup polybar-msg code * Specify the v0 ipc message format * Close ipc connection after message * Fix ipc tests * Properly close ipc connections * Fix polybar-msg not working with action string * Write polybar-msg manpage * polybar-msg: Stop using exit() * ipc: Print log message with PID * Add tests for ipc util * polybar-msg: Print PID with success message * ipc: Propagate message errors * Rename ipc::client to ipc::decoder * Rename ipc.cpp to polybar-msg.cpp * ipc: Write encoder function and fix decoder bugs * ipc: Use message format for responses * ipc: Handle wrong message types * ipc: Write back error message if ipc message cannot be processed This only happens for commands and empty actions. Non-empty actions are not immediately executed, but deferred until the next loop iteration. * Remove TODO about deleting runtime directory The socket file is not deleted after socket.close() is called, only after libuv executes the close callback. So we can't just call rmdir because it will probably always fail. * CLeanup WriteRequest * Update manpage authors * Cleanup
2022-01-22 19:35:37 +00:00
if (type == ipc_module::TYPE && !m_has_ipc) {
throw application_error("Inter-process messaging needs to be enabled");
}
m_log.notice("Loading module '%s' of type '%s'", module_name, type);
auto ptr = make_module(move(type), m_bar->settings(), module_name, m_log);
module_t module = shared_ptr<modules::module_interface>(ptr);
ptr = nullptr;
m_modules.push_back(module);
m_blocks[align].push_back(module);
} catch (const std::exception& err) {
m_log.err("Disabling module \"%s\" (reason: %s)", module_name, err.what());
}
}
return m_blocks[align].size();
}
/**
* Process broadcast events
*/
2017-01-12 15:34:14 +00:00
bool controller::on(const signals::eventqueue::notify_change&) {
trigger_update(false);
return true;
}
/**
* Process forced broadcast events
*/
2017-01-12 15:34:14 +00:00
bool controller::on(const signals::eventqueue::notify_forcechange&) {
trigger_update(true);
return true;
}
2016-12-23 21:19:42 +00:00
/**
* Process eventqueue reload event
*/
2017-01-12 15:34:14 +00:00
bool controller::on(const signals::eventqueue::exit_reload&) {
2021-09-11 10:36:52 +00:00
trigger_quit(true);
return true;
}
/**
* Process eventqueue check event
*/
2017-01-12 15:34:14 +00:00
bool controller::on(const signals::eventqueue::check_state&) {
for (const auto& module : m_modules) {
if (module->running()) {
return true;
}
}
m_log.warn("No running modules...");
2021-09-11 12:20:57 +00:00
trigger_quit(false);
return true;
}
/**
* Process ui button press event
*/
2017-01-12 15:34:14 +00:00
bool controller::on(const signals::ui::button_press& evt) {
string input{evt.cast()};
2016-12-14 04:42:46 +00:00
if (input.empty()) {
m_log.err("Cannot enqueue empty input");
return false;
}
2021-09-11 10:19:00 +00:00
trigger_action(move(input));
return true;
}
/**
* Process ipc action messages
*/
2017-01-12 15:34:14 +00:00
bool controller::on(const signals::ipc::action& evt) {
string action{evt.cast()};
2016-12-14 04:42:46 +00:00
if (action.empty()) {
m_log.err("Cannot enqueue empty ipc action");
2016-12-14 04:42:46 +00:00
return false;
2016-12-03 21:54:58 +00:00
}
2016-12-14 04:42:46 +00:00
m_log.info("Enqueuing ipc action: %s", action);
2021-09-11 10:19:00 +00:00
trigger_action(move(action));
return true;
}
/**
* Process ipc command messages
*/
2017-01-12 15:34:14 +00:00
bool controller::on(const signals::ipc::command& evt) {
string command{evt.cast()};
if (command.empty()) {
return false;
}
if (command == "quit") {
2021-09-11 10:36:52 +00:00
trigger_quit(false);
} else if (command == "restart") {
2021-09-11 10:36:52 +00:00
trigger_quit(true);
2017-04-21 16:15:18 +00:00
} else if (command == "hide") {
m_bar->hide();
} else if (command == "show") {
m_bar->show();
} else if (command == "toggle") {
m_bar->toggle();
} else {
m_log.warn("\"%s\" is not a valid ipc command", command);
Use sockets for IPC (#2539) Deprecates not using `polybar-msg` for IPC. Fixes #2532 Closes #2465 Fixes #2504 * Create FIFO specific NamedPipeHandle subclass to PipeHandle * Prototype SocketHandle * Move mainloop up to main.cpp * Pass eventloop to ipc class * Deprecate sending ipc over the named pipe Unfortunately, we can only show the warning in the polybar log and not give the user any feedback because the pipe is one-way * Move eventloop into its own namespace * Prototype ipc socket handling * Remove handles from ipc_client Should be independent from eventloop logic * Remove ipc clients when finished * Add tests for ipc_client decoding * Add callback for complete ipc messages * Remove template param from mixins * Move signal handler to new callback system * Move poll handle to new callback system * Move FSEventHandle to new callback system * Move TimerHandle and AsyncHandle to new callback system * Move PipeHandle to new callback system * Implement socket functionality in new callback system * Correctly reset ipc named pipe handle * Let client close handles in error callback * Wrap client pipe and ipc::client in connection class * Better decoder log messages * Socket path logic * Fix CI warnings * Remove UVHandleGeneric * Fix error when socket folder already exists * Proof of concept message writeback * Restructure ipc files * polybar-msg: Use sockets * polybar-msg: Better syntax for actions * Fix memory leak with fifo After EOF, the pipe wasn't closed and EOF was called all the time, each time allocating a new pipe. * Make polybar-msg compile on its own * Rudimentary writeback for polybar-msg * Fix payload reference going out of scope. * Add IPC documentation * Cleanup polybar-msg code * Specify the v0 ipc message format * Close ipc connection after message * Fix ipc tests * Properly close ipc connections * Fix polybar-msg not working with action string * Write polybar-msg manpage * polybar-msg: Stop using exit() * ipc: Print log message with PID * Add tests for ipc util * polybar-msg: Print PID with success message * ipc: Propagate message errors * Rename ipc::client to ipc::decoder * Rename ipc.cpp to polybar-msg.cpp * ipc: Write encoder function and fix decoder bugs * ipc: Use message format for responses * ipc: Handle wrong message types * ipc: Write back error message if ipc message cannot be processed This only happens for commands and empty actions. Non-empty actions are not immediately executed, but deferred until the next loop iteration. * Remove TODO about deleting runtime directory The socket file is not deleted after socket.close() is called, only after libuv executes the close callback. So we can't just call rmdir because it will probably always fail. * CLeanup WriteRequest * Update manpage authors * Cleanup
2022-01-22 19:35:37 +00:00
return false;
}
return true;
}
/**
* Process ipc hook messages
*/
2017-01-12 15:34:14 +00:00
bool controller::on(const signals::ipc::hook& evt) {
string hook{evt.cast()};
for (const auto& module : m_modules) {
if (!module->running()) {
continue;
}
auto ipc = std::dynamic_pointer_cast<ipc_module>(module);
if (ipc != nullptr) {
ipc->on_message(hook);
}
}
return true;
2016-11-02 19:22:45 +00:00
}
bool controller::on(const signals::ui::update_background&) {
trigger_update(true);
return false;
}
2016-11-19 05:22:44 +00:00
POLYBAR_NS_END