wip(refactor): Improve signal and event handling
This commit is contained in:
parent
d45fd76dcd
commit
08be86fbe1
@ -4,12 +4,8 @@
|
|||||||
#define BOOST_DI_CFG_DIAGNOSTICS_LEVEL 2
|
#define BOOST_DI_CFG_DIAGNOSTICS_LEVEL 2
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include <boost/di.hpp>
|
|
||||||
#include <cstring>
|
|
||||||
#include <map>
|
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <vector>
|
|
||||||
|
|
||||||
#include "config.hpp"
|
#include "config.hpp"
|
||||||
|
|
||||||
@ -41,7 +37,6 @@
|
|||||||
|
|
||||||
POLYBAR_NS
|
POLYBAR_NS
|
||||||
|
|
||||||
namespace di = boost::di;
|
|
||||||
namespace placeholders = std::placeholders;
|
namespace placeholders = std::placeholders;
|
||||||
|
|
||||||
using std::string;
|
using std::string;
|
||||||
@ -58,7 +53,6 @@ using std::make_unique;
|
|||||||
using std::make_shared;
|
using std::make_shared;
|
||||||
using std::make_pair;
|
using std::make_pair;
|
||||||
using std::array;
|
using std::array;
|
||||||
using std::map;
|
|
||||||
using std::vector;
|
using std::vector;
|
||||||
using std::to_string;
|
using std::to_string;
|
||||||
|
|
||||||
|
@ -2,12 +2,16 @@
|
|||||||
|
|
||||||
#include "common.hpp"
|
#include "common.hpp"
|
||||||
#include "components/config.hpp"
|
#include "components/config.hpp"
|
||||||
|
#include "components/screen.hpp"
|
||||||
#include "components/types.hpp"
|
#include "components/types.hpp"
|
||||||
#include "errors.hpp"
|
#include "errors.hpp"
|
||||||
|
#include "events/signal_emitter.hpp"
|
||||||
|
#include "events/signal_fwd.hpp"
|
||||||
#include "utils/concurrency.hpp"
|
#include "utils/concurrency.hpp"
|
||||||
#include "utils/throttle.hpp"
|
#include "utils/throttle.hpp"
|
||||||
#include "x11/connection.hpp"
|
#include "x11/connection.hpp"
|
||||||
#include "x11/events.hpp"
|
#include "x11/events.hpp"
|
||||||
|
#include "x11/tray_manager.hpp"
|
||||||
#include "x11/types.hpp"
|
#include "x11/types.hpp"
|
||||||
#include "x11/window.hpp"
|
#include "x11/window.hpp"
|
||||||
|
|
||||||
@ -21,20 +25,16 @@ class renderer;
|
|||||||
|
|
||||||
class bar : public xpp::event::sink<evt::button_press, evt::expose, evt::property_notify> {
|
class bar : public xpp::event::sink<evt::button_press, evt::expose, evt::property_notify> {
|
||||||
public:
|
public:
|
||||||
explicit bar(connection& conn, const config& config, const logger& logger, unique_ptr<screen> screen, unique_ptr<tray_manager> tray_manager);
|
explicit bar(connection& conn, signal_emitter& emitter, const config& config, const logger& logger,
|
||||||
~bar();
|
unique_ptr<screen> screen, unique_ptr<tray_manager> tray_manager);
|
||||||
|
|
||||||
void bootstrap(bool nodraw = false);
|
~bar();
|
||||||
void bootstrap_tray();
|
|
||||||
void activate_tray();
|
|
||||||
|
|
||||||
const bar_settings settings() const;
|
const bar_settings settings() const;
|
||||||
|
|
||||||
void parse(const string& data, bool force = false);
|
void parse(const string& data, bool force = false);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
void setup_monitor();
|
|
||||||
void configure_geom();
|
|
||||||
void restack_window();
|
void restack_window();
|
||||||
void reconfigure_pos();
|
void reconfigure_pos();
|
||||||
void reconfigure_struts();
|
void reconfigure_struts();
|
||||||
@ -47,22 +47,37 @@ class bar : public xpp::event::sink<evt::button_press, evt::expose, evt::propert
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
connection& m_connection;
|
connection& m_connection;
|
||||||
|
signal_emitter& m_sig;
|
||||||
const config& m_conf;
|
const config& m_conf;
|
||||||
const logger& m_log;
|
const logger& m_log;
|
||||||
unique_ptr<screen> m_screen;
|
unique_ptr<screen> m_screen;
|
||||||
unique_ptr<tray_manager> m_tray;
|
unique_ptr<tray_manager> m_tray;
|
||||||
unique_ptr<renderer> m_renderer;
|
unique_ptr<renderer> m_renderer;
|
||||||
|
|
||||||
xcb_window_t m_window;
|
|
||||||
bar_settings m_opts;
|
bar_settings m_opts;
|
||||||
|
|
||||||
string m_lastinput;
|
string m_lastinput;
|
||||||
|
|
||||||
std::mutex m_mutex;
|
std::mutex m_mutex;
|
||||||
|
|
||||||
event_timer m_buttonpress{};
|
event_timer m_buttonpress{0L, 5L};
|
||||||
};
|
};
|
||||||
|
|
||||||
di::injector<unique_ptr<bar>> configure_bar();
|
namespace {
|
||||||
|
/**
|
||||||
|
* Configure bar controller
|
||||||
|
*/
|
||||||
|
inline unique_ptr<bar> make_bar() {
|
||||||
|
// clang-format off
|
||||||
|
return factory_util::unique<bar>(
|
||||||
|
make_connection(),
|
||||||
|
make_signal_emitter(),
|
||||||
|
make_confreader(),
|
||||||
|
make_logger(),
|
||||||
|
make_screen(),
|
||||||
|
make_tray_manager());
|
||||||
|
// clang-format on
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
POLYBAR_NS_END
|
POLYBAR_NS_END
|
||||||
|
@ -1,5 +1,7 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include <map>
|
||||||
|
|
||||||
#include "common.hpp"
|
#include "common.hpp"
|
||||||
#include "components/config.hpp"
|
#include "components/config.hpp"
|
||||||
#include "components/types.hpp"
|
#include "components/types.hpp"
|
||||||
@ -7,6 +9,8 @@
|
|||||||
|
|
||||||
POLYBAR_NS
|
POLYBAR_NS
|
||||||
|
|
||||||
|
using std::map;
|
||||||
|
|
||||||
#define DEFAULT_SPACING -1
|
#define DEFAULT_SPACING -1
|
||||||
|
|
||||||
#ifndef BUILDER_SPACE_TOKEN
|
#ifndef BUILDER_SPACE_TOKEN
|
||||||
@ -28,7 +32,7 @@ class builder {
|
|||||||
explicit builder(const bar_settings bar) : m_bar(bar) {}
|
explicit builder(const bar_settings bar) : m_bar(bar) {}
|
||||||
|
|
||||||
string flush();
|
string flush();
|
||||||
void append(string text);
|
void append(const string& text);
|
||||||
void node(string str, bool add_space = false);
|
void node(string str, bool add_space = false);
|
||||||
void node(string str, int font_index, bool add_space = false);
|
void node(string str, int font_index, bool add_space = false);
|
||||||
void node(const label_t& label, bool add_space = false);
|
void node(const label_t& label, bool add_space = false);
|
||||||
|
@ -1,7 +1,10 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include <map>
|
||||||
|
|
||||||
#include "common.hpp"
|
#include "common.hpp"
|
||||||
#include "errors.hpp"
|
#include "errors.hpp"
|
||||||
|
#include "utils/factory.hpp"
|
||||||
|
|
||||||
POLYBAR_NS
|
POLYBAR_NS
|
||||||
|
|
||||||
@ -12,7 +15,7 @@ namespace command_line {
|
|||||||
class option;
|
class option;
|
||||||
using choices = vector<string>;
|
using choices = vector<string>;
|
||||||
using options = vector<option>;
|
using options = vector<option>;
|
||||||
using values = map<string, string>;
|
using values = std::map<string, string>;
|
||||||
|
|
||||||
// class definition : option {{{
|
// class definition : option {{{
|
||||||
|
|
||||||
@ -69,13 +72,8 @@ namespace {
|
|||||||
/**
|
/**
|
||||||
* Configure injection module
|
* Configure injection module
|
||||||
*/
|
*/
|
||||||
template <class T = cliparser>
|
inline unique_ptr<cliparser> make_command_line(string scriptname, const clioptions& opts) {
|
||||||
di::injector<T> configure_cliparser(string scriptname, const clioptions& opts) {
|
return factory_util::unique<cliparser>("Usage: " + scriptname + " bar_name [OPTION...]", opts);
|
||||||
// clang-format off
|
|
||||||
return di::make_injector(
|
|
||||||
di::bind<>().to("Usage: " + scriptname + " bar_name [OPTION...]"),
|
|
||||||
di::bind<>().to(opts));
|
|
||||||
// clang-format on
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -268,9 +268,9 @@ namespace {
|
|||||||
/**
|
/**
|
||||||
* Configure injection module
|
* Configure injection module
|
||||||
*/
|
*/
|
||||||
template <typename T = const config&>
|
inline const config& make_confreader() {
|
||||||
di::injector<T> configure_config() {
|
shared_ptr<config> instance = factory_util::singleton<config>(make_logger(), make_xresource_manager());
|
||||||
return di::make_injector(configure_logger(), configure_xresource_manager());
|
return static_cast<config&>(*instance);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3,11 +3,16 @@
|
|||||||
#include <csignal>
|
#include <csignal>
|
||||||
|
|
||||||
#include "common.hpp"
|
#include "common.hpp"
|
||||||
|
#include "components/bar.hpp"
|
||||||
#include "components/config.hpp"
|
#include "components/config.hpp"
|
||||||
#include "components/eventloop.hpp"
|
#include "components/eventloop.hpp"
|
||||||
#include "components/ipc.hpp"
|
#include "components/ipc.hpp"
|
||||||
#include "components/logger.hpp"
|
#include "components/logger.hpp"
|
||||||
|
#include "components/types.hpp"
|
||||||
#include "config.hpp"
|
#include "config.hpp"
|
||||||
|
#include "events/signal_emitter.hpp"
|
||||||
|
#include "events/signal_fwd.hpp"
|
||||||
|
#include "events/signal_receiver.hpp"
|
||||||
#include "utils/command.hpp"
|
#include "utils/command.hpp"
|
||||||
#include "utils/inotify.hpp"
|
#include "utils/inotify.hpp"
|
||||||
#include "x11/connection.hpp"
|
#include "x11/connection.hpp"
|
||||||
@ -18,65 +23,46 @@ POLYBAR_NS
|
|||||||
// fwd decl {{{
|
// fwd decl {{{
|
||||||
|
|
||||||
class bar;
|
class bar;
|
||||||
|
struct bar_settings;
|
||||||
|
|
||||||
// }}}
|
// }}}
|
||||||
|
|
||||||
using watch_t = inotify_util::watch_t;
|
using watch_t = inotify_util::watch_t;
|
||||||
|
|
||||||
class controller {
|
namespace sig_ev = signals::eventloop;
|
||||||
public:
|
namespace sig_ui = signals::ui;
|
||||||
explicit controller(connection& conn, const logger& logger, const config& config, unique_ptr<eventloop> eventloop,
|
namespace sig_ipc = signals::ipc;
|
||||||
unique_ptr<bar> bar, inotify_util::watch_t& confwatch)
|
|
||||||
: m_connection(conn)
|
|
||||||
, m_log(logger)
|
|
||||||
, m_conf(config)
|
|
||||||
, m_eventloop(forward<decltype(eventloop)>(eventloop))
|
|
||||||
, m_bar(forward<decltype(bar)>(bar))
|
|
||||||
, m_confwatch(confwatch) {}
|
|
||||||
|
|
||||||
|
class controller : public signal_receiver<SIGN_PRIORITY_CONTROLLER, sig_ev::process_update, sig_ev::process_input,
|
||||||
|
sig_ev::process_quit, sig_ui::button_press, sig_ipc::process_action, sig_ipc::process_command,
|
||||||
|
sig_ipc::process_hook> {
|
||||||
|
public:
|
||||||
|
explicit controller(connection& conn, signal_emitter& emitter, const logger& logger, const config& config,
|
||||||
|
unique_ptr<eventloop> eventloop, unique_ptr<bar> bar, unique_ptr<ipc> ipc, watch_t confwatch, bool writeback);
|
||||||
~controller();
|
~controller();
|
||||||
|
|
||||||
void bootstrap(bool writeback = false, bool dump_wmname = false);
|
void setup();
|
||||||
bool run();
|
bool run();
|
||||||
|
|
||||||
|
const bar_settings opts() const;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
void install_sigmask();
|
|
||||||
void uninstall_sigmask();
|
|
||||||
|
|
||||||
void install_confwatch();
|
|
||||||
void uninstall_confwatch();
|
|
||||||
|
|
||||||
void wait_for_signal();
|
void wait_for_signal();
|
||||||
void wait_for_xevent();
|
void wait_for_xevent();
|
||||||
void wait_for_eventloop();
|
void wait_for_eventloop();
|
||||||
void wait_for_configwatch();
|
void wait_for_configwatch();
|
||||||
|
|
||||||
void bootstrap_modules();
|
bool on(const sig_ev::process_update& evt);
|
||||||
|
bool on(const sig_ev::process_input& evt);
|
||||||
void on_ipc_action(const ipc_action& message);
|
bool on(const sig_ev::process_quit& evt);
|
||||||
void on_mouse_event(const string& input);
|
bool on(const sig_ui::button_press& evt);
|
||||||
void on_unrecognized_action(string input);
|
bool on(const sig_ipc::process_action& evt);
|
||||||
void on_update(bool force);
|
bool on(const sig_ipc::process_command& evt);
|
||||||
|
bool on(const sig_ipc::process_hook& evt);
|
||||||
private:
|
|
||||||
enum class thread_role {
|
|
||||||
EVENT_QUEUE,
|
|
||||||
EVENT_QUEUE_X,
|
|
||||||
IPC_LISTENER,
|
|
||||||
CONF_LISTENER,
|
|
||||||
};
|
|
||||||
|
|
||||||
bool is_thread_joinable(thread_role&& role) {
|
|
||||||
if (m_threads.find(role) == m_threads.end()) {
|
|
||||||
return false;
|
|
||||||
} else {
|
|
||||||
return m_threads[role].joinable();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
connection& m_connection;
|
connection& m_connection;
|
||||||
registry m_registry{m_connection};
|
signal_emitter& m_sig;
|
||||||
const logger& m_log;
|
const logger& m_log;
|
||||||
const config& m_conf;
|
const config& m_conf;
|
||||||
unique_ptr<eventloop> m_eventloop;
|
unique_ptr<eventloop> m_eventloop;
|
||||||
@ -86,18 +72,37 @@ class controller {
|
|||||||
stateflag m_running{false};
|
stateflag m_running{false};
|
||||||
stateflag m_reload{false};
|
stateflag m_reload{false};
|
||||||
stateflag m_waiting{false};
|
stateflag m_waiting{false};
|
||||||
stateflag m_trayactivated{false};
|
|
||||||
|
|
||||||
sigset_t m_blockmask;
|
|
||||||
sigset_t m_waitmask;
|
sigset_t m_waitmask;
|
||||||
map<thread_role, thread> m_threads;
|
vector<thread> m_threads;
|
||||||
|
|
||||||
inotify_util::watch_t& m_confwatch;
|
watch_t m_confwatch;
|
||||||
command_util::command_t m_command;
|
command_t m_command;
|
||||||
|
|
||||||
bool m_writeback{false};
|
bool m_writeback{false};
|
||||||
};
|
};
|
||||||
|
|
||||||
di::injector<unique_ptr<controller>> configure_controller(watch_t& confwatch);
|
namespace {
|
||||||
|
inline unique_ptr<controller> make_controller(watch_t&& confwatch, bool enableipc = false, bool writeback = false) {
|
||||||
|
unique_ptr<ipc> ipc;
|
||||||
|
|
||||||
|
if (enableipc) {
|
||||||
|
ipc = make_ipc();
|
||||||
|
}
|
||||||
|
|
||||||
|
// clang-format off
|
||||||
|
return factory_util::unique<controller>(
|
||||||
|
make_connection(),
|
||||||
|
make_signal_emitter(),
|
||||||
|
make_logger(),
|
||||||
|
make_confreader(),
|
||||||
|
make_eventloop(),
|
||||||
|
make_bar(),
|
||||||
|
move(ipc),
|
||||||
|
move(confwatch),
|
||||||
|
writeback);
|
||||||
|
// clang-format on
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
POLYBAR_NS_END
|
POLYBAR_NS_END
|
||||||
|
@ -5,104 +5,107 @@
|
|||||||
|
|
||||||
#include "common.hpp"
|
#include "common.hpp"
|
||||||
#include "components/logger.hpp"
|
#include "components/logger.hpp"
|
||||||
|
#include "events/signal_emitter.hpp"
|
||||||
|
#include "events/signal_fwd.hpp"
|
||||||
|
#include "events/signal_receiver.hpp"
|
||||||
#include "modules/meta/base.hpp"
|
#include "modules/meta/base.hpp"
|
||||||
|
|
||||||
POLYBAR_NS
|
POLYBAR_NS
|
||||||
|
|
||||||
|
using namespace signals::eventloop;
|
||||||
|
|
||||||
using module_t = unique_ptr<modules::module_interface>;
|
using module_t = unique_ptr<modules::module_interface>;
|
||||||
using modulemap_t = map<alignment, vector<module_t>>;
|
using modulemap_t = map<alignment, vector<module_t>>;
|
||||||
|
|
||||||
enum class event_type : uint8_t {
|
class eventloop : public signal_receiver<SIGN_PRIORITY_EVENTLOOP, process_quit, process_input, process_check,
|
||||||
|
enqueue_event, enqueue_quit, enqueue_update, enqueue_input, enqueue_check> {
|
||||||
|
public:
|
||||||
|
enum class event_type : uint8_t {
|
||||||
NONE = 0,
|
NONE = 0,
|
||||||
UPDATE,
|
UPDATE,
|
||||||
CHECK,
|
CHECK,
|
||||||
INPUT,
|
INPUT,
|
||||||
QUIT,
|
QUIT,
|
||||||
};
|
};
|
||||||
|
|
||||||
struct event {
|
struct event {
|
||||||
uint8_t type{0};
|
uint8_t type{static_cast<uint8_t>(event_type::NONE)};
|
||||||
char data[256]{'\0'};
|
bool flag{false};
|
||||||
};
|
};
|
||||||
|
|
||||||
struct quit_event {
|
struct input_data {
|
||||||
const uint8_t type{static_cast<uint8_t>(event_type::QUIT)};
|
char data[EVENT_SIZE];
|
||||||
bool reload{false};
|
};
|
||||||
};
|
|
||||||
|
|
||||||
struct update_event {
|
template <typename EventType>
|
||||||
const uint8_t type{static_cast<uint8_t>(event_type::UPDATE)};
|
using queue_t = moodycamel::BlockingConcurrentQueue<EventType>;
|
||||||
bool force{false};
|
|
||||||
};
|
|
||||||
|
|
||||||
struct input_event {
|
|
||||||
const uint8_t type{static_cast<uint8_t>(event_type::INPUT)};
|
|
||||||
char data[256]{'\0'};
|
|
||||||
};
|
|
||||||
|
|
||||||
class eventloop {
|
|
||||||
public:
|
|
||||||
/**
|
|
||||||
* Queue type
|
|
||||||
*/
|
|
||||||
using entry_t = event;
|
|
||||||
using queue_t = moodycamel::BlockingConcurrentQueue<entry_t>;
|
|
||||||
using duration_t = chrono::duration<double, std::milli>;
|
using duration_t = chrono::duration<double, std::milli>;
|
||||||
|
|
||||||
explicit eventloop(const logger& logger, const config& config);
|
public:
|
||||||
|
explicit eventloop(signal_emitter& emitter, const logger& logger, const config& config);
|
||||||
~eventloop();
|
~eventloop();
|
||||||
|
|
||||||
void start();
|
void start();
|
||||||
void wait();
|
|
||||||
void stop();
|
void stop();
|
||||||
|
|
||||||
bool enqueue(const entry_t& entry);
|
bool enqueue(event&& evt);
|
||||||
bool enqueue_delayed(const entry_t& entry);
|
bool enqueue(input_data&& evt);
|
||||||
|
|
||||||
void set_update_cb(callback<bool>&& cb);
|
|
||||||
void set_input_db(callback<string>&& cb);
|
|
||||||
|
|
||||||
void add_module(const alignment pos, module_t&& module);
|
void add_module(const alignment pos, module_t&& module);
|
||||||
const modulemap_t& modules() const;
|
const modulemap_t& modules() const;
|
||||||
size_t module_count() const;
|
size_t module_count() const;
|
||||||
|
|
||||||
static const eventloop::entry_t& make(update_event&& event, bool force = false) {
|
static auto make_quit_evt(bool reload = false) {
|
||||||
event.force = force;
|
return event{static_cast<uint8_t>(event_type::QUIT), reload};
|
||||||
return reinterpret_cast<const eventloop::entry_t&>(event);
|
|
||||||
}
|
}
|
||||||
|
static auto make_update_evt(bool force = false) {
|
||||||
static const eventloop::entry_t& make(quit_event&& event, bool reload = false) {
|
return event{static_cast<uint8_t>(event_type::UPDATE), force};
|
||||||
event.reload = reload;
|
|
||||||
return reinterpret_cast<const eventloop::entry_t&>(event);
|
|
||||||
}
|
}
|
||||||
|
static auto make_input_evt() {
|
||||||
static const eventloop::entry_t& make(input_event&& event, const string& data) {
|
return event{static_cast<uint8_t>(event_type::INPUT)};
|
||||||
snprintf(event.data, sizeof(event.data), "%s", data.c_str());
|
}
|
||||||
return reinterpret_cast<const eventloop::entry_t&>(event);
|
static auto make_input_data(string&& data) {
|
||||||
|
input_data d{};
|
||||||
|
memcpy(d.data, &data[0], sizeof(d.data));
|
||||||
|
return d;
|
||||||
|
}
|
||||||
|
static auto make_check_evt() {
|
||||||
|
return event{static_cast<uint8_t>(event_type::CHECK)};
|
||||||
}
|
}
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
void process_inputqueue();
|
||||||
void dispatch_modules();
|
void dispatch_modules();
|
||||||
void dispatch_queue_worker();
|
|
||||||
void dispatch_delayed_worker();
|
|
||||||
|
|
||||||
inline bool match_event(entry_t evt, event_type type);
|
inline bool compare_events(event evt, event evt2);
|
||||||
inline bool compare_events(entry_t evt, entry_t evt2);
|
inline bool compare_events(input_data data, input_data data1);
|
||||||
void forward_event(entry_t evt);
|
|
||||||
|
|
||||||
void on_update(const update_event& evt);
|
void forward_event(event evt);
|
||||||
void on_input(const input_event& evt);
|
|
||||||
void on_check();
|
bool on(const process_input& evt);
|
||||||
void on_quit(const quit_event& evt);
|
bool on(const process_check& evt);
|
||||||
|
bool on(const process_quit& evt);
|
||||||
|
|
||||||
|
bool on(const enqueue_event& evt);
|
||||||
|
bool on(const enqueue_quit& evt);
|
||||||
|
bool on(const enqueue_update& evt);
|
||||||
|
bool on(const enqueue_input& evt);
|
||||||
|
bool on(const enqueue_check& evt);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
signal_emitter& m_sig;
|
||||||
const logger& m_log;
|
const logger& m_log;
|
||||||
const config& m_conf;
|
const config& m_conf;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Event queue
|
* @brief Event queue
|
||||||
*/
|
*/
|
||||||
queue_t m_queue;
|
queue_t<event> m_queue;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Event queue
|
||||||
|
*/
|
||||||
|
queue_t<input_data> m_inputqueue;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Loaded modules
|
* @brief Loaded modules
|
||||||
@ -114,16 +117,6 @@ class eventloop {
|
|||||||
*/
|
*/
|
||||||
stateflag m_running;
|
stateflag m_running;
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Callback fired when receiving UPDATE events
|
|
||||||
*/
|
|
||||||
callback<bool> m_update_cb;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Callback fired for unprocessed INPUT events
|
|
||||||
*/
|
|
||||||
callback<string> m_unrecognized_input_cb;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Time to wait for subsequent events
|
* @brief Time to wait for subsequent events
|
||||||
*/
|
*/
|
||||||
@ -133,45 +126,11 @@ class eventloop {
|
|||||||
* @brief Maximum amount of subsequent events to swallow within timeframe
|
* @brief Maximum amount of subsequent events to swallow within timeframe
|
||||||
*/
|
*/
|
||||||
size_t m_swallow_limit{0};
|
size_t m_swallow_limit{0};
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Time until releasing the lock on the delayed enqueue channel
|
|
||||||
*/
|
|
||||||
duration_t m_delayed_time;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Lock used to control the condition variable
|
|
||||||
*/
|
|
||||||
std::mutex m_delayed_lock;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Condition variable used to manage notifications for delayed enqueues
|
|
||||||
*/
|
|
||||||
std::condition_variable m_delayed_cond;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Pending event on the delayed channel
|
|
||||||
*/
|
|
||||||
entry_t m_delayed_entry{0};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Queue worker thread
|
|
||||||
*/
|
|
||||||
thread m_queue_thread;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Delayed notifier thread
|
|
||||||
*/
|
|
||||||
thread m_delayed_thread;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
/**
|
inline unique_ptr<eventloop> make_eventloop() {
|
||||||
* Configure injection module
|
return make_unique<eventloop>(make_signal_emitter(), make_logger(), make_confreader());
|
||||||
*/
|
|
||||||
template <typename T = unique_ptr<eventloop>>
|
|
||||||
di::injector<T> configure_eventloop() {
|
|
||||||
return di::make_injector(configure_logger(), configure_config());
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
18
include/components/eventloop_fwd.hpp
Normal file
18
include/components/eventloop_fwd.hpp
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "common.hpp"
|
||||||
|
|
||||||
|
POLYBAR_NS
|
||||||
|
|
||||||
|
enum class event_type;
|
||||||
|
struct event;
|
||||||
|
struct quit_event;
|
||||||
|
struct update_event;
|
||||||
|
struct input_event;
|
||||||
|
|
||||||
|
class eventloop {
|
||||||
|
public:
|
||||||
|
using entry_t = event;
|
||||||
|
};
|
||||||
|
|
||||||
|
POLYBAR_NS_END
|
@ -2,8 +2,10 @@
|
|||||||
|
|
||||||
#include "common.hpp"
|
#include "common.hpp"
|
||||||
#include "components/logger.hpp"
|
#include "components/logger.hpp"
|
||||||
|
#include "events/signal_emitter.hpp"
|
||||||
#include "utils/concurrency.hpp"
|
#include "utils/concurrency.hpp"
|
||||||
#include "utils/functional.hpp"
|
#include "utils/functional.hpp"
|
||||||
|
#include "utils/factory.hpp"
|
||||||
|
|
||||||
POLYBAR_NS
|
POLYBAR_NS
|
||||||
|
|
||||||
@ -12,15 +14,15 @@ POLYBAR_NS
|
|||||||
*/
|
*/
|
||||||
struct ipc_command {
|
struct ipc_command {
|
||||||
static constexpr const char* prefix{"cmd:"};
|
static constexpr const char* prefix{"cmd:"};
|
||||||
string payload;
|
char payload[EVENT_SIZE]{'\0'};
|
||||||
};
|
};
|
||||||
struct ipc_hook {
|
struct ipc_hook {
|
||||||
static constexpr const char* prefix{"hook:"};
|
static constexpr const char* prefix{"hook:"};
|
||||||
string payload;
|
char payload[EVENT_SIZE]{'\0'};
|
||||||
};
|
};
|
||||||
struct ipc_action {
|
struct ipc_action {
|
||||||
static constexpr const char* prefix{"action:"};
|
static constexpr const char* prefix{"action:"};
|
||||||
string payload;
|
char payload[EVENT_SIZE]{'\0'};
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -32,40 +34,28 @@ struct ipc_action {
|
|||||||
*/
|
*/
|
||||||
class ipc {
|
class ipc {
|
||||||
public:
|
public:
|
||||||
explicit ipc(const logger& logger) : m_log(logger) {}
|
explicit ipc(signal_emitter& emitter, const logger& logger) : m_sig(emitter), m_log(logger) {}
|
||||||
~ipc();
|
~ipc();
|
||||||
|
|
||||||
void attach_callback(callback<const ipc_command&>&& cb);
|
|
||||||
void attach_callback(callback<const ipc_hook&>&& cb);
|
|
||||||
void attach_callback(callback<const ipc_action&>&& cb);
|
|
||||||
void receive_messages();
|
void receive_messages();
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
void parse(const string& payload) const;
|
void parse(const string& payload) const;
|
||||||
void delegate(const ipc_command& message) const;
|
|
||||||
void delegate(const ipc_hook& message) const;
|
|
||||||
void delegate(const ipc_action& message) const;
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
signal_emitter& m_sig;
|
||||||
const logger& m_log;
|
const logger& m_log;
|
||||||
|
|
||||||
vector<callback<const ipc_command&>> m_command_callbacks;
|
|
||||||
vector<callback<const ipc_hook&>> m_hook_callbacks;
|
|
||||||
vector<callback<const ipc_action&>> m_action_callbacks;
|
|
||||||
|
|
||||||
stateflag m_running{false};
|
|
||||||
|
|
||||||
string m_fifo;
|
string m_fifo;
|
||||||
int m_fd;
|
int m_fd;
|
||||||
|
stateflag m_running{false};
|
||||||
};
|
};
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
/**
|
/**
|
||||||
* Configure injection module
|
* Configure injection module
|
||||||
*/
|
*/
|
||||||
template <typename T = unique_ptr<ipc>>
|
inline unique_ptr<ipc> make_ipc() {
|
||||||
di::injector<T> configure_ipc() {
|
return factory_util::unique<ipc>(make_signal_emitter(), make_logger());
|
||||||
return di::make_injector(configure_logger());
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,13 +1,15 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <cstdio>
|
#include <cstdio>
|
||||||
|
#include <map>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
#include "common.hpp"
|
#include "common.hpp"
|
||||||
#include "utils/factory.hpp"
|
#include "utils/factory.hpp"
|
||||||
|
|
||||||
POLYBAR_NS
|
POLYBAR_NS
|
||||||
|
|
||||||
enum class loglevel {
|
enum class loglevel : uint8_t {
|
||||||
NONE = 0,
|
NONE = 0,
|
||||||
ERROR,
|
ERROR,
|
||||||
WARNING,
|
WARNING,
|
||||||
@ -25,34 +27,26 @@ class logger {
|
|||||||
void verbosity(loglevel level);
|
void verbosity(loglevel level);
|
||||||
void verbosity(string level);
|
void verbosity(string level);
|
||||||
|
|
||||||
/**
|
#ifdef DEBUG_LOGGER // {{{
|
||||||
* Output a trace message
|
|
||||||
*/
|
|
||||||
template <typename... Args>
|
template <typename... Args>
|
||||||
#ifdef DEBUG_LOGGER
|
|
||||||
void trace(string message, Args... args) const {
|
void trace(string message, Args... args) const {
|
||||||
output(loglevel::TRACE, message, args...);
|
output(loglevel::TRACE, message, args...);
|
||||||
}
|
}
|
||||||
#else
|
|
||||||
#ifdef VERBOSE_TRACELOG
|
#ifdef VERBOSE_TRACELOG
|
||||||
#undef VERBOSE_TRACELOG
|
|
||||||
#endif
|
|
||||||
void trace(string, Args...) const {
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Output extra verbose trace message
|
|
||||||
*/
|
|
||||||
template <typename... Args>
|
template <typename... Args>
|
||||||
#ifdef VERBOSE_TRACELOG
|
|
||||||
void trace_x(string message, Args... args) const {
|
void trace_x(string message, Args... args) const {
|
||||||
output(loglevel::TRACE, message, args...);
|
output(loglevel::TRACE, message, args...);
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
void trace_x(string, Args...) const {
|
template <typename... Args>
|
||||||
}
|
void trace_x(Args...) const {}
|
||||||
#endif
|
#endif
|
||||||
|
#else
|
||||||
|
template <typename... Args>
|
||||||
|
void trace(Args...) const {}
|
||||||
|
template <typename... Args>
|
||||||
|
void trace_x(Args...) const {}
|
||||||
|
#endif // }}}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Output an info message
|
* Output an info message
|
||||||
@ -97,70 +91,56 @@ class logger {
|
|||||||
*/
|
*/
|
||||||
template <typename... Args>
|
template <typename... Args>
|
||||||
void output(loglevel level, string format, Args... values) const {
|
void output(loglevel level, string format, Args... values) const {
|
||||||
if (level > m_level)
|
if (level > m_level) {
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
auto prefix = m_prefixes.find(level)->second;
|
#if defined(__clang__) // {{{
|
||||||
auto suffix = m_suffixes.find(level)->second;
|
|
||||||
|
|
||||||
// silence the compiler
|
|
||||||
#if defined(__clang__)
|
|
||||||
#pragma clang diagnostic push
|
#pragma clang diagnostic push
|
||||||
#pragma clang diagnostic ignored "-Wformat-security"
|
#pragma clang diagnostic ignored "-Wformat-security"
|
||||||
#elif defined(__GNUC__)
|
#elif defined(__GNUC__)
|
||||||
#pragma GCC diagnostic push
|
#pragma GCC diagnostic push
|
||||||
#pragma GCC diagnostic ignored "-Wformat-security"
|
#pragma GCC diagnostic ignored "-Wformat-security"
|
||||||
#endif
|
#endif // }}}
|
||||||
dprintf(m_fd, (prefix + format + suffix + "\n").c_str(), convert(values)...);
|
|
||||||
#if defined(__clang__)
|
dprintf(m_fd, (m_prefixes.at(level) + format + m_suffixes.at(level) + "\n").c_str(), convert(values)...);
|
||||||
|
|
||||||
|
#if defined(__clang__) // {{{
|
||||||
#pragma clang diagnostic pop
|
#pragma clang diagnostic pop
|
||||||
#elif defined(__GNUC__)
|
#elif defined(__GNUC__)
|
||||||
#pragma GCC diagnostic pop
|
#pragma GCC diagnostic pop
|
||||||
#endif
|
#endif // }}}
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
/**
|
/**
|
||||||
* Logger verbosity level
|
* Logger verbosity level
|
||||||
*/
|
*/
|
||||||
loglevel m_level = loglevel::TRACE;
|
loglevel m_level{loglevel::TRACE};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* File descriptor used when writing the log messages
|
* File descriptor used when writing the log messages
|
||||||
*/
|
*/
|
||||||
int m_fd = STDERR_FILENO;
|
int m_fd{STDERR_FILENO};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Loglevel specific prefixes
|
* Loglevel specific prefixes
|
||||||
*/
|
*/
|
||||||
// clang-format off
|
std::map<loglevel, string> m_prefixes;
|
||||||
map<loglevel, string> m_prefixes {
|
|
||||||
{loglevel::TRACE, "polybar|trace "},
|
|
||||||
{loglevel::INFO, "polybar|info "},
|
|
||||||
{loglevel::WARNING, "polybar|warn "},
|
|
||||||
{loglevel::ERROR, "polybar|error "},
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Loglevel specific suffixes
|
* Loglevel specific suffixes
|
||||||
*/
|
*/
|
||||||
map<loglevel, string> m_suffixes {
|
std::map<loglevel, string> m_suffixes;
|
||||||
{loglevel::TRACE, ""},
|
|
||||||
{loglevel::INFO, ""},
|
|
||||||
{loglevel::WARNING, ""},
|
|
||||||
{loglevel::ERROR, ""},
|
|
||||||
};
|
|
||||||
// clang-format on
|
|
||||||
};
|
};
|
||||||
|
|
||||||
namespace {
|
/**
|
||||||
/**
|
|
||||||
* Configure injection module
|
* Configure injection module
|
||||||
*/
|
*/
|
||||||
template <typename T = const logger&>
|
namespace {
|
||||||
di::injector<T> configure_logger(loglevel level = loglevel::NONE) {
|
inline const logger& make_logger(loglevel level = loglevel::NONE) {
|
||||||
auto instance = factory_util::generic_singleton<logger>(level);
|
auto instance = factory_util::singleton<const logger>(level);
|
||||||
return di::make_injector(di::bind<>().to(instance));
|
return static_cast<const logger&>(*instance);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -5,6 +5,7 @@
|
|||||||
|
|
||||||
POLYBAR_NS
|
POLYBAR_NS
|
||||||
|
|
||||||
|
class signal_emitter;
|
||||||
class logger;
|
class logger;
|
||||||
struct bar_settings;
|
struct bar_settings;
|
||||||
enum class attribute : uint8_t;
|
enum class attribute : uint8_t;
|
||||||
@ -17,7 +18,7 @@ DEFINE_CHILD_ERROR(unclosed_actionblocks, parser_error);
|
|||||||
|
|
||||||
class parser {
|
class parser {
|
||||||
public:
|
public:
|
||||||
explicit parser(const logger& logger, const bar_settings& bar);
|
explicit parser(signal_emitter& emitter, const logger& logger, const bar_settings& bar);
|
||||||
void operator()(string data);
|
void operator()(string data);
|
||||||
void codeblock(string data);
|
void codeblock(string data);
|
||||||
size_t text(string data);
|
size_t text(string data);
|
||||||
@ -30,6 +31,7 @@ class parser {
|
|||||||
string parse_action_cmd(const string& data);
|
string parse_action_cmd(const string& data);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
signal_emitter& m_sig;
|
||||||
const logger& m_log;
|
const logger& m_log;
|
||||||
const bar_settings& m_bar;
|
const bar_settings& m_bar;
|
||||||
vector<int> m_actions;
|
vector<int> m_actions;
|
||||||
|
@ -1,7 +1,13 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "common.hpp"
|
#include "common.hpp"
|
||||||
|
#include "components/logger.hpp"
|
||||||
#include "components/types.hpp"
|
#include "components/types.hpp"
|
||||||
|
#include "events/signal_emitter.hpp"
|
||||||
|
#include "events/signal_fwd.hpp"
|
||||||
|
#include "events/signal_receiver.hpp"
|
||||||
|
#include "x11/connection.hpp"
|
||||||
|
#include "x11/fonts.hpp"
|
||||||
#include "x11/types.hpp"
|
#include "x11/types.hpp"
|
||||||
|
|
||||||
POLYBAR_NS
|
POLYBAR_NS
|
||||||
@ -10,12 +16,17 @@ class connection;
|
|||||||
class font_manager;
|
class font_manager;
|
||||||
class logger;
|
class logger;
|
||||||
|
|
||||||
class renderer {
|
using namespace signals::parser;
|
||||||
|
|
||||||
|
class renderer
|
||||||
|
: public signal_receiver<SIGN_PRIORITY_RENDERER, change_background, change_foreground, change_underline,
|
||||||
|
change_overline, change_font, change_alignment, offset_pixel, attribute_set, attribute_unset,
|
||||||
|
attribute_toggle, action_begin, action_end, write_text_ascii, write_text_unicode, write_text_string> {
|
||||||
public:
|
public:
|
||||||
enum class gc : uint8_t { BG, FG, OL, UL, BT, BB, BL, BR };
|
enum class gc : uint8_t { BG, FG, OL, UL, BT, BB, BL, BR };
|
||||||
|
|
||||||
explicit renderer(connection& conn, const logger& logger, unique_ptr<font_manager> font_manager,
|
explicit renderer(connection& conn, signal_emitter& emitter, const logger& logger,
|
||||||
const bar_settings& bar, const vector<string>& fonts);
|
unique_ptr<font_manager> font_manager, const bar_settings& bar, const vector<string>& fonts);
|
||||||
~renderer();
|
~renderer();
|
||||||
|
|
||||||
xcb_window_t window() const;
|
xcb_window_t window() const;
|
||||||
@ -52,6 +63,22 @@ class renderer {
|
|||||||
int16_t shift_content(int16_t x, const int16_t shift_x);
|
int16_t shift_content(int16_t x, const int16_t shift_x);
|
||||||
int16_t shift_content(const int16_t shift_x);
|
int16_t shift_content(const int16_t shift_x);
|
||||||
|
|
||||||
|
bool on(const change_background& evt);
|
||||||
|
bool on(const change_foreground& evt);
|
||||||
|
bool on(const change_underline& evt);
|
||||||
|
bool on(const change_overline& evt);
|
||||||
|
bool on(const change_font& evt);
|
||||||
|
bool on(const change_alignment& evt);
|
||||||
|
bool on(const offset_pixel& evt);
|
||||||
|
bool on(const attribute_set& evt);
|
||||||
|
bool on(const attribute_unset& evt);
|
||||||
|
bool on(const attribute_toggle& evt);
|
||||||
|
bool on(const action_begin& evt);
|
||||||
|
bool on(const action_end& evt);
|
||||||
|
bool on(const write_text_ascii& evt);
|
||||||
|
bool on(const write_text_unicode& evt);
|
||||||
|
bool on(const write_text_string& evt);
|
||||||
|
|
||||||
#ifdef DEBUG_HINTS
|
#ifdef DEBUG_HINTS
|
||||||
vector<xcb_window_t> m_debughints;
|
vector<xcb_window_t> m_debughints;
|
||||||
void debug_hints();
|
void debug_hints();
|
||||||
@ -65,13 +92,13 @@ class renderer {
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
connection& m_connection;
|
connection& m_connection;
|
||||||
|
signal_emitter& m_sig;
|
||||||
const logger& m_log;
|
const logger& m_log;
|
||||||
unique_ptr<font_manager> m_fontmanager;
|
unique_ptr<font_manager> m_fontmanager;
|
||||||
|
|
||||||
const bar_settings& m_bar;
|
const bar_settings& m_bar;
|
||||||
|
|
||||||
xcb_rectangle_t m_rect{0, 0, 0U, 0U};
|
xcb_rectangle_t m_rect{0, 0, 0U, 0U};
|
||||||
|
|
||||||
xcb_rectangle_t m_cleared{0, 0, 0U, 0U};
|
xcb_rectangle_t m_cleared{0, 0, 0U, 0U};
|
||||||
reserve_area m_cleararea{};
|
reserve_area m_cleararea{};
|
||||||
|
|
||||||
@ -95,6 +122,21 @@ class renderer {
|
|||||||
xcb_font_t m_gcfont{XCB_NONE};
|
xcb_font_t m_gcfont{XCB_NONE};
|
||||||
};
|
};
|
||||||
|
|
||||||
di::injector<unique_ptr<renderer>> configure_renderer(const bar_settings& bar, const vector<string>& fonts);
|
namespace {
|
||||||
|
/**
|
||||||
|
* Configure injection module
|
||||||
|
*/
|
||||||
|
inline unique_ptr<renderer> make_renderer(const bar_settings& bar, const vector<string>& fonts) {
|
||||||
|
// clang-format off
|
||||||
|
return factory_util::unique<renderer>(
|
||||||
|
make_connection(),
|
||||||
|
make_signal_emitter(),
|
||||||
|
make_logger(),
|
||||||
|
make_font_manager(),
|
||||||
|
bar,
|
||||||
|
fonts);
|
||||||
|
// clang-format on
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
POLYBAR_NS_END
|
POLYBAR_NS_END
|
||||||
|
@ -1,7 +1,10 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "common.hpp"
|
#include "common.hpp"
|
||||||
|
#include "components/config.hpp"
|
||||||
|
#include "components/logger.hpp"
|
||||||
#include "components/types.hpp"
|
#include "components/types.hpp"
|
||||||
|
#include "events/signal_emitter.hpp"
|
||||||
#include "x11/events.hpp"
|
#include "x11/events.hpp"
|
||||||
#include "x11/window.hpp"
|
#include "x11/window.hpp"
|
||||||
|
|
||||||
@ -11,10 +14,11 @@ POLYBAR_NS
|
|||||||
class config;
|
class config;
|
||||||
class logger;
|
class logger;
|
||||||
class connection;
|
class connection;
|
||||||
|
class signal_emitter;
|
||||||
|
|
||||||
class screen : public xpp::event::sink<evt::randr_screen_change_notify> {
|
class screen : public xpp::event::sink<evt::randr_screen_change_notify> {
|
||||||
public:
|
public:
|
||||||
explicit screen(connection& conn, const logger& logger, const config& conf);
|
explicit screen(connection& conn, signal_emitter& emitter, const logger& logger, const config& conf);
|
||||||
~screen();
|
~screen();
|
||||||
|
|
||||||
struct size size() const {
|
struct size size() const {
|
||||||
@ -30,6 +34,7 @@ class screen : public xpp::event::sink<evt::randr_screen_change_notify> {
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
connection& m_connection;
|
connection& m_connection;
|
||||||
|
signal_emitter& m_sig;
|
||||||
const logger& m_log;
|
const logger& m_log;
|
||||||
const config& m_conf;
|
const config& m_conf;
|
||||||
|
|
||||||
@ -37,10 +42,20 @@ class screen : public xpp::event::sink<evt::randr_screen_change_notify> {
|
|||||||
xcb_window_t m_proxy{XCB_NONE};
|
xcb_window_t m_proxy{XCB_NONE};
|
||||||
|
|
||||||
vector<monitor_t> m_monitors;
|
vector<monitor_t> m_monitors;
|
||||||
struct size m_size{0U, 0U};
|
struct size m_size {
|
||||||
|
0U, 0U
|
||||||
|
};
|
||||||
bool m_sigraised{false};
|
bool m_sigraised{false};
|
||||||
};
|
};
|
||||||
|
|
||||||
di::injector<unique_ptr<screen>> configure_screen();
|
namespace {
|
||||||
|
/**
|
||||||
|
* Configure injection module
|
||||||
|
*/
|
||||||
|
inline unique_ptr<screen> make_screen() {
|
||||||
|
return factory_util::unique<screen>(
|
||||||
|
make_connection(), make_signal_emitter(), make_logger(), make_confreader());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
POLYBAR_NS_END
|
POLYBAR_NS_END
|
||||||
|
@ -1,68 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
|
|
||||||
#include "common.hpp"
|
|
||||||
|
|
||||||
#include "components/eventloop.hpp"
|
|
||||||
#include "utils/functional.hpp"
|
|
||||||
|
|
||||||
POLYBAR_NS
|
|
||||||
|
|
||||||
// fwd decl {{{
|
|
||||||
|
|
||||||
enum class mousebtn : uint8_t;
|
|
||||||
enum class syntaxtag : uint8_t;
|
|
||||||
enum class alignment : uint8_t;
|
|
||||||
enum class attribute : uint8_t;
|
|
||||||
|
|
||||||
// }}}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @TODO: Allow multiple signal handlers
|
|
||||||
* @TODO: Encapsulate signals
|
|
||||||
*/
|
|
||||||
namespace g_signals {
|
|
||||||
/**
|
|
||||||
* Helper used to create no-op "callbacks"
|
|
||||||
*/
|
|
||||||
template <typename... T>
|
|
||||||
static callback<T...> noop = [](T...) {};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Signals used to communicate with the event loop
|
|
||||||
*/
|
|
||||||
namespace event {
|
|
||||||
extern callback<const eventloop::entry_t&> enqueue;
|
|
||||||
extern callback<const eventloop::entry_t&> enqueue_delayed;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Signals used to communicate with the bar window
|
|
||||||
*/
|
|
||||||
namespace bar {
|
|
||||||
extern callback<string> action_click;
|
|
||||||
extern callback<const bool> visibility_change;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Signals used to communicate with the input parser
|
|
||||||
*/
|
|
||||||
namespace parser {
|
|
||||||
extern callback<const uint32_t> background_change;
|
|
||||||
extern callback<const uint32_t> foreground_change;
|
|
||||||
extern callback<const uint32_t> underline_change;
|
|
||||||
extern callback<const uint32_t> overline_change;
|
|
||||||
extern callback<const alignment> alignment_change;
|
|
||||||
extern callback<const attribute> attribute_set;
|
|
||||||
extern callback<const attribute> attribute_unset;
|
|
||||||
extern callback<const attribute> attribute_toggle;
|
|
||||||
extern callback<const int8_t> font_change;
|
|
||||||
extern callback<const int16_t> pixel_offset;
|
|
||||||
extern callback<const mousebtn, const string> action_block_open;
|
|
||||||
extern callback<const mousebtn> action_block_close;
|
|
||||||
extern callback<const uint16_t> ascii_text_write;
|
|
||||||
extern callback<const uint16_t> unicode_text_write;
|
|
||||||
extern callback<const char*, const size_t> string_write;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
POLYBAR_NS_END
|
|
@ -1,5 +1,7 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
|
||||||
#include "common.hpp"
|
#include "common.hpp"
|
||||||
#include "x11/color.hpp"
|
#include "x11/color.hpp"
|
||||||
#include "x11/randr.hpp"
|
#include "x11/randr.hpp"
|
||||||
@ -80,8 +82,8 @@ struct action {
|
|||||||
|
|
||||||
struct action_block : public action {
|
struct action_block : public action {
|
||||||
alignment align{alignment::NONE};
|
alignment align{alignment::NONE};
|
||||||
double start_x{0.0};
|
volatile double start_x{0.0};
|
||||||
double end_x{0.0};
|
volatile double end_x{0.0};
|
||||||
bool active{true};
|
bool active{true};
|
||||||
|
|
||||||
uint16_t width() const {
|
uint16_t width() const {
|
||||||
@ -90,6 +92,11 @@ struct action_block : public action {
|
|||||||
};
|
};
|
||||||
|
|
||||||
struct bar_settings {
|
struct bar_settings {
|
||||||
|
explicit bar_settings() = default;
|
||||||
|
bar_settings(const bar_settings& other) = default;
|
||||||
|
|
||||||
|
xcb_window_t window;
|
||||||
|
|
||||||
monitor_t monitor;
|
monitor_t monitor;
|
||||||
edge origin{edge::TOP};
|
edge origin{edge::TOP};
|
||||||
struct size size {
|
struct size size {
|
||||||
@ -109,7 +116,7 @@ struct bar_settings {
|
|||||||
line_settings underline;
|
line_settings underline;
|
||||||
line_settings overline;
|
line_settings overline;
|
||||||
|
|
||||||
map<edge, border_settings> borders;
|
std::unordered_map<edge, border_settings> borders;
|
||||||
|
|
||||||
uint8_t spacing{1U};
|
uint8_t spacing{1U};
|
||||||
string separator;
|
string separator;
|
||||||
@ -128,13 +135,20 @@ struct bar_settings {
|
|||||||
rect.x = pos.x;
|
rect.x = pos.x;
|
||||||
rect.y = pos.y;
|
rect.y = pos.y;
|
||||||
}
|
}
|
||||||
|
if (borders.find(edge::TOP) != borders.end()) {
|
||||||
rect.y += borders.at(edge::TOP).size;
|
rect.y += borders.at(edge::TOP).size;
|
||||||
rect.height -= borders.at(edge::TOP).size;
|
rect.height -= borders.at(edge::TOP).size;
|
||||||
|
}
|
||||||
|
if (borders.find(edge::BOTTOM) != borders.end()) {
|
||||||
rect.height -= borders.at(edge::BOTTOM).size;
|
rect.height -= borders.at(edge::BOTTOM).size;
|
||||||
|
}
|
||||||
|
if (borders.find(edge::LEFT) != borders.end()) {
|
||||||
rect.x += borders.at(edge::LEFT).size;
|
rect.x += borders.at(edge::LEFT).size;
|
||||||
rect.width -= borders.at(edge::LEFT).size;
|
rect.width -= borders.at(edge::LEFT).size;
|
||||||
|
}
|
||||||
|
if (borders.find(edge::RIGHT) != borders.end()) {
|
||||||
rect.width -= borders.at(edge::RIGHT).size;
|
rect.width -= borders.at(edge::RIGHT).size;
|
||||||
|
}
|
||||||
return rect;
|
return rect;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -29,6 +29,15 @@
|
|||||||
#cmakedefine VERBOSE_TRACELOG
|
#cmakedefine VERBOSE_TRACELOG
|
||||||
#cmakedefine DEBUG_HINTS
|
#cmakedefine DEBUG_HINTS
|
||||||
|
|
||||||
|
static const size_t EVENT_SIZE{64U};
|
||||||
|
|
||||||
|
static const int SIGN_PRIORITY_EVENTLOOP{1};
|
||||||
|
static const int SIGN_PRIORITY_CONTROLLER{2};
|
||||||
|
static const int SIGN_PRIORITY_SCREEN{3};
|
||||||
|
static const int SIGN_PRIORITY_BAR{4};
|
||||||
|
static const int SIGN_PRIORITY_RENDERER{5};
|
||||||
|
static const int SIGN_PRIORITY_TRAY{6};
|
||||||
|
|
||||||
static const int SINK_PRIORITY_BAR{1};
|
static const int SINK_PRIORITY_BAR{1};
|
||||||
static const int SINK_PRIORITY_SCREEN{2};
|
static const int SINK_PRIORITY_SCREEN{2};
|
||||||
static const int SINK_PRIORITY_TRAY{3};
|
static const int SINK_PRIORITY_TRAY{3};
|
||||||
|
@ -1,5 +1,7 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include <map>
|
||||||
|
|
||||||
#include "common.hpp"
|
#include "common.hpp"
|
||||||
#include "drawtypes/label.hpp"
|
#include "drawtypes/label.hpp"
|
||||||
#include "utils/mixins.hpp"
|
#include "utils/mixins.hpp"
|
||||||
@ -15,7 +17,7 @@ namespace drawtypes {
|
|||||||
operator bool();
|
operator bool();
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
map<string, icon_t> m_icons;
|
std::map<string, icon_t> m_icons;
|
||||||
};
|
};
|
||||||
|
|
||||||
using iconset_t = shared_ptr<iconset>;
|
using iconset_t = shared_ptr<iconset>;
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <cerrno>
|
#include <cerrno>
|
||||||
|
#include <cstring>
|
||||||
|
|
||||||
#include "common.hpp"
|
#include "common.hpp"
|
||||||
|
|
||||||
|
135
include/events/signal.hpp
Normal file
135
include/events/signal.hpp
Normal file
@ -0,0 +1,135 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "common.hpp"
|
||||||
|
|
||||||
|
#include "components/eventloop.hpp"
|
||||||
|
#include "components/ipc.hpp"
|
||||||
|
#include "components/types.hpp"
|
||||||
|
#include "utils/functional.hpp"
|
||||||
|
|
||||||
|
POLYBAR_NS
|
||||||
|
|
||||||
|
// fwd decl {{{
|
||||||
|
|
||||||
|
enum class mousebtn : uint8_t;
|
||||||
|
enum class syntaxtag : uint8_t;
|
||||||
|
enum class alignment : uint8_t;
|
||||||
|
enum class attribute : uint8_t;
|
||||||
|
|
||||||
|
// }}}
|
||||||
|
|
||||||
|
#define DEFINE_SIGNAL(id, name) \
|
||||||
|
struct name : public detail::base_signal<name, id> { \
|
||||||
|
using base_type::base_type; \
|
||||||
|
}
|
||||||
|
|
||||||
|
#define DEFINE_VALUE_SIGNAL(id, name, type) \
|
||||||
|
struct name : public detail::value_signal<name, id, type> { \
|
||||||
|
using base_type::base_type; \
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace signals {
|
||||||
|
namespace detail {
|
||||||
|
// definition : signal {{{
|
||||||
|
|
||||||
|
class signal {
|
||||||
|
public:
|
||||||
|
explicit signal() = default;
|
||||||
|
virtual ~signal() {}
|
||||||
|
virtual size_t size() const = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
// }}}
|
||||||
|
// definition : base_signal {{{
|
||||||
|
|
||||||
|
template <typename Derived, uint8_t Id>
|
||||||
|
class base_signal : public signal {
|
||||||
|
public:
|
||||||
|
using base_type = base_signal<Derived, Id>;
|
||||||
|
|
||||||
|
explicit base_signal() = default;
|
||||||
|
|
||||||
|
virtual ~base_signal() {}
|
||||||
|
|
||||||
|
static uint8_t id() {
|
||||||
|
return Id;
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual size_t size() const override {
|
||||||
|
return sizeof(Derived);
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
// }}}
|
||||||
|
// definition : value_signal {{{
|
||||||
|
|
||||||
|
template <typename Derived, uint8_t Id, typename ValueType>
|
||||||
|
class value_signal : public base_signal<Derived, Id> {
|
||||||
|
public:
|
||||||
|
using base_type = value_signal<Derived, Id, ValueType>;
|
||||||
|
using value_type = ValueType;
|
||||||
|
|
||||||
|
explicit value_signal() {}
|
||||||
|
explicit value_signal(ValueType&& data) {
|
||||||
|
memcpy(m_data, &data, sizeof(data));
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual ~value_signal() {}
|
||||||
|
|
||||||
|
const ValueType* operator()() const {
|
||||||
|
return reinterpret_cast<const ValueType*>(&m_data);
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
char m_data[sizeof(ValueType)];
|
||||||
|
};
|
||||||
|
|
||||||
|
// }}}
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace eventloop {
|
||||||
|
using eventloop_t = polybar::eventloop;
|
||||||
|
|
||||||
|
DEFINE_VALUE_SIGNAL(1, process_quit, eventloop_t::event);
|
||||||
|
DEFINE_VALUE_SIGNAL(2, process_update, eventloop_t::event);
|
||||||
|
DEFINE_VALUE_SIGNAL(3, process_input, eventloop_t::input_data);
|
||||||
|
DEFINE_VALUE_SIGNAL(4, process_check, eventloop_t::event);
|
||||||
|
|
||||||
|
DEFINE_VALUE_SIGNAL(5, enqueue_event, eventloop_t::event);
|
||||||
|
DEFINE_VALUE_SIGNAL(6, enqueue_quit, eventloop_t::event);
|
||||||
|
DEFINE_VALUE_SIGNAL(7, enqueue_update, eventloop_t::event);
|
||||||
|
DEFINE_VALUE_SIGNAL(8, enqueue_input, eventloop_t::input_data);
|
||||||
|
DEFINE_VALUE_SIGNAL(9, enqueue_check, eventloop_t::event);
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace ipc {
|
||||||
|
DEFINE_VALUE_SIGNAL(20, process_command, ipc_command);
|
||||||
|
DEFINE_VALUE_SIGNAL(21, process_hook, ipc_hook);
|
||||||
|
DEFINE_VALUE_SIGNAL(22, process_action, ipc_action);
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace ui {
|
||||||
|
DEFINE_VALUE_SIGNAL(50, button_press, string);
|
||||||
|
DEFINE_VALUE_SIGNAL(51, visibility_change, bool);
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace parser {
|
||||||
|
DEFINE_VALUE_SIGNAL(70, change_background, uint32_t);
|
||||||
|
DEFINE_VALUE_SIGNAL(71, change_foreground, uint32_t);
|
||||||
|
DEFINE_VALUE_SIGNAL(72, change_underline, uint32_t);
|
||||||
|
DEFINE_VALUE_SIGNAL(73, change_overline, uint32_t);
|
||||||
|
DEFINE_VALUE_SIGNAL(74, change_font, int8_t);
|
||||||
|
DEFINE_VALUE_SIGNAL(75, change_alignment, alignment);
|
||||||
|
DEFINE_VALUE_SIGNAL(76, offset_pixel, int16_t);
|
||||||
|
DEFINE_VALUE_SIGNAL(77, attribute_set, attribute);
|
||||||
|
DEFINE_VALUE_SIGNAL(78, attribute_unset, attribute);
|
||||||
|
DEFINE_VALUE_SIGNAL(79, attribute_toggle, attribute);
|
||||||
|
DEFINE_VALUE_SIGNAL(80, action_begin, action);
|
||||||
|
DEFINE_VALUE_SIGNAL(81, action_end, mousebtn);
|
||||||
|
DEFINE_VALUE_SIGNAL(82, write_text_ascii, uint16_t);
|
||||||
|
DEFINE_VALUE_SIGNAL(83, write_text_unicode, uint16_t);
|
||||||
|
DEFINE_VALUE_SIGNAL(84, write_text_string, string);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
POLYBAR_NS_END
|
112
include/events/signal_emitter.hpp
Normal file
112
include/events/signal_emitter.hpp
Normal file
@ -0,0 +1,112 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "common.hpp"
|
||||||
|
#include "events/signal_receiver.hpp"
|
||||||
|
#include "utils/factory.hpp"
|
||||||
|
#include "utils/mixins.hpp"
|
||||||
|
|
||||||
|
POLYBAR_NS
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Holds all signal receivers attached to the emitter
|
||||||
|
*/
|
||||||
|
extern signal_receivers_t g_signal_receivers;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Wrapper used to delegate emitted signals
|
||||||
|
* to attached signal receivers
|
||||||
|
*/
|
||||||
|
class signal_emitter {
|
||||||
|
public:
|
||||||
|
explicit signal_emitter() = default;
|
||||||
|
virtual ~signal_emitter() {}
|
||||||
|
|
||||||
|
template <typename Signal>
|
||||||
|
bool emit(const Signal& sig) {
|
||||||
|
try {
|
||||||
|
for (auto&& item : g_signal_receivers.at(id<Signal>())) {
|
||||||
|
if (item.second->on(sig)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (...) {
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename Signal, typename Next, typename... Signals>
|
||||||
|
bool emit(const Signal& sig) const {
|
||||||
|
return emit<Signal>(sig) || emit<Next, Signals...>(sig);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <uint8_t Priority, typename Signal, typename... Signals>
|
||||||
|
void attach(signal_receiver<Priority, Signal, Signals...>* s) {
|
||||||
|
attach<signal_receiver<Priority, Signal, Signals...>, Signal, Signals...>(s);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <uint8_t Priority, typename Signal, typename... Signals>
|
||||||
|
void detach(signal_receiver<Priority, Signal, Signals...>* s) {
|
||||||
|
detach<signal_receiver<Priority, Signal, Signals...>, Signal, Signals...>(s);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected:
|
||||||
|
template <typename Signal>
|
||||||
|
uint8_t id() const {
|
||||||
|
return Signal::id();
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename Receiver, typename Signal>
|
||||||
|
void attach(Receiver* s) {
|
||||||
|
attach(s, id<Signal>());
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename Receiver, typename Signal, typename Next, typename... Signals>
|
||||||
|
void attach(Receiver* s) {
|
||||||
|
attach(s, id<Signal>());
|
||||||
|
attach<Receiver, Next, Signals...>(s);
|
||||||
|
}
|
||||||
|
|
||||||
|
void attach(signal_receiver_interface* s, uint8_t id) {
|
||||||
|
g_signal_receivers[id].emplace(s->priority(), s);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename Receiver, typename Signal>
|
||||||
|
void detach(Receiver* s) {
|
||||||
|
detach(s, id<Signal>());
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename Receiver, typename Signal, typename Next, typename... Signals>
|
||||||
|
void detach(Receiver* s) {
|
||||||
|
detach(s, id<Signal>());
|
||||||
|
detach<Receiver, Next, Signals...>(s);
|
||||||
|
}
|
||||||
|
|
||||||
|
void detach(signal_receiver_interface* d, uint8_t id) {
|
||||||
|
try {
|
||||||
|
auto& prio_map = g_signal_receivers.at(id);
|
||||||
|
const auto& prio_sink_pair = prio_map.equal_range(d->priority());
|
||||||
|
|
||||||
|
for (auto it = prio_sink_pair.first; it != prio_sink_pair.second;) {
|
||||||
|
if (d == it->second) {
|
||||||
|
it = prio_map.erase(it);
|
||||||
|
} else {
|
||||||
|
++it;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (...) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
/**
|
||||||
|
* Configure injection module
|
||||||
|
*/
|
||||||
|
inline signal_emitter& make_signal_emitter() {
|
||||||
|
auto instance = factory_util::singleton<signal_emitter>();
|
||||||
|
return static_cast<signal_emitter&>(*instance);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
POLYBAR_NS_END
|
48
include/events/signal_fwd.hpp
Normal file
48
include/events/signal_fwd.hpp
Normal file
@ -0,0 +1,48 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "common.hpp"
|
||||||
|
|
||||||
|
POLYBAR_NS
|
||||||
|
|
||||||
|
namespace signals {
|
||||||
|
namespace eventloop {
|
||||||
|
struct process_quit;
|
||||||
|
struct process_update;
|
||||||
|
struct process_input;
|
||||||
|
struct process_check;
|
||||||
|
|
||||||
|
struct enqueue_event;
|
||||||
|
struct enqueue_quit;
|
||||||
|
struct enqueue_update;
|
||||||
|
struct enqueue_input;
|
||||||
|
struct enqueue_check;
|
||||||
|
}
|
||||||
|
namespace ipc {
|
||||||
|
struct process_command;
|
||||||
|
struct process_hook;
|
||||||
|
struct process_action;
|
||||||
|
}
|
||||||
|
namespace ui {
|
||||||
|
struct button_press;
|
||||||
|
struct visibility_change;
|
||||||
|
}
|
||||||
|
namespace parser {
|
||||||
|
struct change_background;
|
||||||
|
struct change_foreground;
|
||||||
|
struct change_underline;
|
||||||
|
struct change_overline;
|
||||||
|
struct change_font;
|
||||||
|
struct change_alignment;
|
||||||
|
struct offset_pixel;
|
||||||
|
struct attribute_set;
|
||||||
|
struct attribute_unset;
|
||||||
|
struct attribute_toggle;
|
||||||
|
struct action_begin;
|
||||||
|
struct action_end;
|
||||||
|
struct write_text_ascii;
|
||||||
|
struct write_text_unicode;
|
||||||
|
struct write_text_string;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
POLYBAR_NS_END
|
50
include/events/signal_receiver.hpp
Normal file
50
include/events/signal_receiver.hpp
Normal file
@ -0,0 +1,50 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <map>
|
||||||
|
#include <unordered_map>
|
||||||
|
|
||||||
|
#include "common.hpp"
|
||||||
|
|
||||||
|
POLYBAR_NS
|
||||||
|
|
||||||
|
class signal_receiver_interface {
|
||||||
|
public:
|
||||||
|
using prio = unsigned int;
|
||||||
|
using prio_map = std::multimap<prio, signal_receiver_interface*>;
|
||||||
|
virtual ~signal_receiver_interface() {}
|
||||||
|
virtual prio priority() const = 0;
|
||||||
|
template <typename Signal>
|
||||||
|
bool on(const Signal& signal);
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename Signal>
|
||||||
|
class signal_receiver_impl {
|
||||||
|
public:
|
||||||
|
virtual ~signal_receiver_impl() {}
|
||||||
|
virtual bool on(const Signal&) = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename Signal>
|
||||||
|
bool signal_receiver_interface::on(const Signal& s) {
|
||||||
|
auto event_sink = dynamic_cast<signal_receiver_impl<Signal>*>(this);
|
||||||
|
|
||||||
|
if (event_sink != nullptr && event_sink->on(s)) {
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
template <uint8_t Priority, typename Signal, typename... Signals>
|
||||||
|
class signal_receiver : public signal_receiver_interface,
|
||||||
|
public signal_receiver_impl<Signal>,
|
||||||
|
public signal_receiver_impl<Signals>... {
|
||||||
|
public:
|
||||||
|
prio priority() const {
|
||||||
|
return Priority;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
using signal_receivers_t = std::unordered_map<uint8_t, signal_receiver_interface::prio_map>;
|
||||||
|
|
||||||
|
POLYBAR_NS_END
|
@ -4,6 +4,7 @@
|
|||||||
#include <chrono>
|
#include <chrono>
|
||||||
#include <condition_variable>
|
#include <condition_variable>
|
||||||
#include <mutex>
|
#include <mutex>
|
||||||
|
#include <map>
|
||||||
|
|
||||||
#include "common.hpp"
|
#include "common.hpp"
|
||||||
#include "components/config.hpp"
|
#include "components/config.hpp"
|
||||||
@ -19,6 +20,7 @@ POLYBAR_NS
|
|||||||
|
|
||||||
namespace chrono = std::chrono;
|
namespace chrono = std::chrono;
|
||||||
using namespace std::chrono_literals;
|
using namespace std::chrono_literals;
|
||||||
|
using std::map;
|
||||||
|
|
||||||
#define DEFAULT_FORMAT "format"
|
#define DEFAULT_FORMAT "format"
|
||||||
|
|
||||||
|
96
include/modules/meta/factory.hpp
Normal file
96
include/modules/meta/factory.hpp
Normal file
@ -0,0 +1,96 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "common.hpp"
|
||||||
|
|
||||||
|
#include "modules/backlight.hpp"
|
||||||
|
#include "modules/battery.hpp"
|
||||||
|
#include "modules/bspwm.hpp"
|
||||||
|
#include "modules/counter.hpp"
|
||||||
|
#include "modules/cpu.hpp"
|
||||||
|
#include "modules/date.hpp"
|
||||||
|
#include "modules/fs.hpp"
|
||||||
|
#include "modules/ipc.hpp"
|
||||||
|
#include "modules/memory.hpp"
|
||||||
|
#include "modules/menu.hpp"
|
||||||
|
#include "modules/meta/base.hpp"
|
||||||
|
#include "modules/script.hpp"
|
||||||
|
#include "modules/temperature.hpp"
|
||||||
|
#include "modules/text.hpp"
|
||||||
|
#include "modules/xbacklight.hpp"
|
||||||
|
#include "modules/xwindow.hpp"
|
||||||
|
#include "modules/xworkspaces.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
|
||||||
|
#if WITH_XKB
|
||||||
|
#include "modules/xkeyboard.hpp"
|
||||||
|
#endif
|
||||||
|
#if not(ENABLE_I3 && ENABLE_MPD && ENABLE_NETWORK && ENABLE_ALSA && WITH_XKB)
|
||||||
|
#include "modules/unsupported.hpp"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
POLYBAR_NS
|
||||||
|
|
||||||
|
using namespace modules;
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
template <typename... Args>
|
||||||
|
module_interface* make_module(string&& name, Args&&... args) {
|
||||||
|
if (name == "internal/counter") {
|
||||||
|
return new counter_module(forward<Args>(args)...);
|
||||||
|
} else if (name == "internal/backlight") {
|
||||||
|
return new backlight_module(forward<Args>(args)...);
|
||||||
|
} else if (name == "internal/battery") {
|
||||||
|
return new battery_module(forward<Args>(args)...);
|
||||||
|
} else if (name == "internal/bspwm") {
|
||||||
|
return new bspwm_module(forward<Args>(args)...);
|
||||||
|
} else if (name == "internal/cpu") {
|
||||||
|
return new cpu_module(forward<Args>(args)...);
|
||||||
|
} else if (name == "internal/date") {
|
||||||
|
return new date_module(forward<Args>(args)...);
|
||||||
|
} else if (name == "internal/fs") {
|
||||||
|
return new fs_module(forward<Args>(args)...);
|
||||||
|
} else if (name == "internal/memory") {
|
||||||
|
return new memory_module(forward<Args>(args)...);
|
||||||
|
} else if (name == "internal/i3") {
|
||||||
|
return new i3_module(forward<Args>(args)...);
|
||||||
|
} else if (name == "internal/mpd") {
|
||||||
|
return new mpd_module(forward<Args>(args)...);
|
||||||
|
} else if (name == "internal/volume") {
|
||||||
|
return new volume_module(forward<Args>(args)...);
|
||||||
|
} else if (name == "internal/network") {
|
||||||
|
return new network_module(forward<Args>(args)...);
|
||||||
|
} else if (name == "internal/temperature") {
|
||||||
|
return new temperature_module(forward<Args>(args)...);
|
||||||
|
} else if (name == "internal/xbacklight") {
|
||||||
|
return new xbacklight_module(forward<Args>(args)...);
|
||||||
|
} else if (name == "internal/xkeyboard") {
|
||||||
|
return new xkeyboard_module(forward<Args>(args)...);
|
||||||
|
} else if (name == "internal/xwindow") {
|
||||||
|
return new xwindow_module(forward<Args>(args)...);
|
||||||
|
} else if (name == "internal/xworkspaces") {
|
||||||
|
return new xworkspaces_module(forward<Args>(args)...);
|
||||||
|
} else if (name == "custom/text") {
|
||||||
|
return new text_module(forward<Args>(args)...);
|
||||||
|
} else if (name == "custom/script") {
|
||||||
|
return new script_module(forward<Args>(args)...);
|
||||||
|
} else if (name == "custom/menu") {
|
||||||
|
return new menu_module(forward<Args>(args)...);
|
||||||
|
} else if (name == "custom/ipc") {
|
||||||
|
return new ipc_module(forward<Args>(args)...);
|
||||||
|
} else {
|
||||||
|
throw application_error("Unknown module: " + name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
POLYBAR_NS_END
|
@ -30,7 +30,7 @@ namespace modules {
|
|||||||
static constexpr const char* TAG_OUTPUT{"<output>"};
|
static constexpr const char* TAG_OUTPUT{"<output>"};
|
||||||
static constexpr const char* TAG_LABEL{"<label>"};
|
static constexpr const char* TAG_LABEL{"<label>"};
|
||||||
|
|
||||||
command_util::command_t m_command;
|
unique_ptr<command> m_command;
|
||||||
|
|
||||||
string m_exec;
|
string m_exec;
|
||||||
bool m_tail{false};
|
bool m_tail{false};
|
||||||
|
@ -25,7 +25,7 @@ namespace modules {
|
|||||||
*/
|
*/
|
||||||
class xbacklight_module : public static_module<xbacklight_module>, public xpp::event::sink<evt::randr_notify> {
|
class xbacklight_module : public static_module<xbacklight_module>, public xpp::event::sink<evt::randr_notify> {
|
||||||
public:
|
public:
|
||||||
xbacklight_module(const bar_settings& bar, const logger& logger, const config& config, string name);
|
explicit xbacklight_module(const bar_settings& bar, const logger& logger, const config& config, string name);
|
||||||
|
|
||||||
void setup();
|
void setup();
|
||||||
void teardown();
|
void teardown();
|
||||||
@ -39,24 +39,23 @@ namespace modules {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
static constexpr auto TAG_LABEL = "<label>";
|
static constexpr const char* TAG_LABEL{"<label>"};
|
||||||
static constexpr auto TAG_BAR = "<bar>";
|
static constexpr const char* TAG_BAR{"<bar>"};
|
||||||
static constexpr auto TAG_RAMP = "<ramp>";
|
static constexpr const char* TAG_RAMP{"<ramp>"};
|
||||||
|
|
||||||
static constexpr auto EVENT_SCROLLUP = "xbacklight+";
|
static constexpr const char* EVENT_SCROLLUP{"xbacklight+"};
|
||||||
static constexpr auto EVENT_SCROLLDOWN = "xbacklight-";
|
static constexpr const char* EVENT_SCROLLDOWN{"xbacklight-"};
|
||||||
|
|
||||||
connection& m_connection;
|
connection& m_connection;
|
||||||
monitor_t m_output;
|
monitor_t m_output;
|
||||||
xcb_window_t m_proxy;
|
xcb_window_t m_proxy;
|
||||||
event_timer m_randrnotify{};
|
|
||||||
|
|
||||||
ramp_t m_ramp;
|
ramp_t m_ramp;
|
||||||
label_t m_label;
|
label_t m_label;
|
||||||
progressbar_t m_progressbar;
|
progressbar_t m_progressbar;
|
||||||
|
|
||||||
bool m_scroll = true;
|
bool m_scroll{true};
|
||||||
int m_percentage = 0;
|
int m_percentage{0};
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -19,7 +19,7 @@ namespace modules {
|
|||||||
class xkeyboard_module : public static_module<xkeyboard_module>,
|
class xkeyboard_module : public static_module<xkeyboard_module>,
|
||||||
public xpp::event::sink<evt::xkb_new_keyboard_notify, evt::xkb_state_notify, evt::xkb_indicator_state_notify> {
|
public xpp::event::sink<evt::xkb_new_keyboard_notify, evt::xkb_state_notify, evt::xkb_indicator_state_notify> {
|
||||||
public:
|
public:
|
||||||
xkeyboard_module(const bar_settings& bar, const logger& logger, const config& config, string name);
|
explicit xkeyboard_module(const bar_settings& bar, const logger& logger, const config& config, string name);
|
||||||
|
|
||||||
void setup();
|
void setup();
|
||||||
void teardown();
|
void teardown();
|
||||||
|
@ -32,7 +32,7 @@ namespace modules {
|
|||||||
*/
|
*/
|
||||||
class xwindow_module : public static_module<xwindow_module>, public xpp::event::sink<evt::property_notify> {
|
class xwindow_module : public static_module<xwindow_module>, public xpp::event::sink<evt::property_notify> {
|
||||||
public:
|
public:
|
||||||
xwindow_module(const bar_settings&, const logger&, const config&, string);
|
explicit xwindow_module(const bar_settings&, const logger&, const config&, string);
|
||||||
|
|
||||||
void setup();
|
void setup();
|
||||||
void teardown();
|
void teardown();
|
||||||
|
@ -49,7 +49,7 @@ namespace modules {
|
|||||||
*/
|
*/
|
||||||
class xworkspaces_module : public static_module<xworkspaces_module>, public xpp::event::sink<evt::property_notify> {
|
class xworkspaces_module : public static_module<xworkspaces_module>, public xpp::event::sink<evt::property_notify> {
|
||||||
public:
|
public:
|
||||||
xworkspaces_module(const bar_settings& bar, const logger& logger, const config& config, string name);
|
explicit xworkspaces_module(const bar_settings& bar, const logger& logger, const config& config, string name);
|
||||||
|
|
||||||
void setup();
|
void setup();
|
||||||
void teardown();
|
void teardown();
|
||||||
|
@ -2,6 +2,7 @@
|
|||||||
|
|
||||||
#include "common.hpp"
|
#include "common.hpp"
|
||||||
#include "components/logger.hpp"
|
#include "components/logger.hpp"
|
||||||
|
#include "errors.hpp"
|
||||||
#include "utils/concurrency.hpp"
|
#include "utils/concurrency.hpp"
|
||||||
#include "utils/functional.hpp"
|
#include "utils/functional.hpp"
|
||||||
|
|
||||||
@ -73,15 +74,13 @@ namespace command_util {
|
|||||||
concurrency_util::spin_lock m_pipelock;
|
concurrency_util::spin_lock m_pipelock;
|
||||||
};
|
};
|
||||||
|
|
||||||
using command_t = unique_ptr<command>;
|
|
||||||
|
|
||||||
template <typename... Args>
|
template <typename... Args>
|
||||||
command_t make_command(Args&&... args) {
|
unique_ptr<command> make_command(Args&&... args) {
|
||||||
return make_unique<command>(configure_logger().create<const logger&>(), forward<Args>(args)...);
|
return make_unique<command>(make_logger(), forward<Args>(args)...);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
using command = command_util::command;
|
using command = command_util::command;
|
||||||
using command_t = command_util::command_t;
|
using command_t = unique_ptr<command>;
|
||||||
|
|
||||||
POLYBAR_NS_END
|
POLYBAR_NS_END
|
||||||
|
@ -20,14 +20,19 @@ namespace factory_util {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
template <class InstanceType, class... Deps>
|
template <typename T, typename... Deps>
|
||||||
unique_ptr<InstanceType> generic_instance(Deps... deps) {
|
unique_ptr<T> unique(Deps&&... deps) {
|
||||||
return make_unique<InstanceType>(deps...);
|
return make_unique<T>(forward<Deps>(deps)...);
|
||||||
}
|
}
|
||||||
|
|
||||||
template <class InstanceType, class... Deps>
|
template <typename T, typename... Deps>
|
||||||
shared_ptr<InstanceType> generic_singleton(Deps... deps) {
|
shared_ptr<T> shared(Deps&&... deps) {
|
||||||
static auto instance = make_shared<InstanceType>(deps...);
|
return make_shared<T>(forward<Deps>(deps)...);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class T, class... Deps>
|
||||||
|
shared_ptr<T> singleton(Deps&&... deps) {
|
||||||
|
static auto instance = make_shared<T>(forward<Deps>(deps)...);
|
||||||
return instance;
|
return instance;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,7 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include <map>
|
||||||
|
|
||||||
#include <X11/Xft/Xft.h>
|
#include <X11/Xft/Xft.h>
|
||||||
|
|
||||||
#include "common.hpp"
|
#include "common.hpp"
|
||||||
@ -26,7 +28,7 @@ class color {
|
|||||||
string m_source;
|
string m_source;
|
||||||
};
|
};
|
||||||
|
|
||||||
extern map<string, class color> g_colorstore;
|
extern std::map<string, class color> g_colorstore;
|
||||||
extern color g_colorempty;
|
extern color g_colorempty;
|
||||||
extern color g_colorblack;
|
extern color g_colorblack;
|
||||||
extern color g_colorwhite;
|
extern color g_colorwhite;
|
||||||
|
@ -8,9 +8,11 @@
|
|||||||
#include <xpp/xpp.hpp>
|
#include <xpp/xpp.hpp>
|
||||||
|
|
||||||
#include "common.hpp"
|
#include "common.hpp"
|
||||||
|
#include "utils/factory.hpp"
|
||||||
#include "x11/extensions.hpp"
|
#include "x11/extensions.hpp"
|
||||||
#include "x11/registry.hpp"
|
#include "x11/registry.hpp"
|
||||||
#include "x11/types.hpp"
|
#include "x11/types.hpp"
|
||||||
|
#include "x11/xutils.hpp"
|
||||||
|
|
||||||
POLYBAR_NS
|
POLYBAR_NS
|
||||||
|
|
||||||
@ -18,8 +20,7 @@ using xpp_connection = xpp::connection<XPP_EXTENSION_LIST>;
|
|||||||
|
|
||||||
class connection : public xpp_connection {
|
class connection : public xpp_connection {
|
||||||
public:
|
public:
|
||||||
explicit connection() {}
|
explicit connection(xcb_connection_t* conn) : connection(conn, 0) {}
|
||||||
explicit connection(xcb_connection_t* conn) : xpp_connection(conn) {}
|
|
||||||
explicit connection(xcb_connection_t* conn, int connection_fd)
|
explicit connection(xcb_connection_t* conn, int connection_fd)
|
||||||
: xpp_connection(conn), m_connection_fd(connection_fd) {}
|
: xpp_connection(conn), m_connection_fd(connection_fd) {}
|
||||||
|
|
||||||
@ -54,7 +55,6 @@ class connection : public xpp_connection {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void preload_atoms();
|
void preload_atoms();
|
||||||
|
|
||||||
void query_extensions();
|
void query_extensions();
|
||||||
|
|
||||||
string id(xcb_window_t w) const;
|
string id(xcb_window_t w) const;
|
||||||
@ -98,6 +98,14 @@ class connection : public xpp_connection {
|
|||||||
int m_connection_fd{0};
|
int m_connection_fd{0};
|
||||||
};
|
};
|
||||||
|
|
||||||
di::injector<connection&> configure_connection();
|
namespace {
|
||||||
|
/**
|
||||||
|
* Configure injection module
|
||||||
|
*/
|
||||||
|
inline connection& make_connection() {
|
||||||
|
auto instance = factory_util::singleton<connection>(xutils::get_connection(), xutils::get_connection_fd());
|
||||||
|
return static_cast<connection&>(*instance);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
POLYBAR_NS_END
|
POLYBAR_NS_END
|
||||||
|
@ -78,6 +78,6 @@ class font_manager {
|
|||||||
XftDraw* m_xftdraw{nullptr};
|
XftDraw* m_xftdraw{nullptr};
|
||||||
};
|
};
|
||||||
|
|
||||||
di::injector<unique_ptr<font_manager>> configure_font_manager();
|
unique_ptr<font_manager> make_font_manager();
|
||||||
|
|
||||||
POLYBAR_NS_END
|
POLYBAR_NS_END
|
||||||
|
49
include/x11/tray_client.hpp
Normal file
49
include/x11/tray_client.hpp
Normal file
@ -0,0 +1,49 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <xcb/xcb.h>
|
||||||
|
|
||||||
|
#include "common.hpp"
|
||||||
|
#include "utils/concurrency.hpp"
|
||||||
|
|
||||||
|
POLYBAR_NS
|
||||||
|
|
||||||
|
// fwd declarations
|
||||||
|
class connection;
|
||||||
|
struct xembed_data;
|
||||||
|
|
||||||
|
class tray_client {
|
||||||
|
public:
|
||||||
|
explicit tray_client(connection& conn, xcb_window_t win, uint16_t w, uint16_t h);
|
||||||
|
tray_client(const tray_client& c) = default;
|
||||||
|
tray_client& operator=(tray_client& c) = default;
|
||||||
|
|
||||||
|
~tray_client();
|
||||||
|
|
||||||
|
uint16_t width() const;
|
||||||
|
uint16_t height() const;
|
||||||
|
void clear_window() const;
|
||||||
|
|
||||||
|
bool match(const xcb_window_t& win) const;
|
||||||
|
bool mapped() const;
|
||||||
|
void mapped(bool state);
|
||||||
|
|
||||||
|
xcb_window_t window() const;
|
||||||
|
xembed_data* xembed() const;
|
||||||
|
|
||||||
|
void ensure_state() const;
|
||||||
|
void reconfigure(int16_t x, int16_t y) const;
|
||||||
|
void configure_notify(int16_t x, int16_t y) const;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
connection& m_connection;
|
||||||
|
xcb_window_t m_window{0};
|
||||||
|
|
||||||
|
shared_ptr<xembed_data> m_xembed;
|
||||||
|
bool m_mapped{false};
|
||||||
|
|
||||||
|
uint16_t m_width;
|
||||||
|
uint16_t m_height;
|
||||||
|
}
|
||||||
|
;
|
||||||
|
|
||||||
|
POLYBAR_NS_END
|
@ -6,8 +6,14 @@
|
|||||||
#include "common.hpp"
|
#include "common.hpp"
|
||||||
#include "components/logger.hpp"
|
#include "components/logger.hpp"
|
||||||
#include "components/types.hpp"
|
#include "components/types.hpp"
|
||||||
|
#include "events/signal_emitter.hpp"
|
||||||
|
#include "events/signal_fwd.hpp"
|
||||||
#include "utils/concurrency.hpp"
|
#include "utils/concurrency.hpp"
|
||||||
|
#include "x11/atoms.hpp"
|
||||||
|
#include "x11/connection.hpp"
|
||||||
#include "x11/events.hpp"
|
#include "x11/events.hpp"
|
||||||
|
#include "x11/graphics.hpp"
|
||||||
|
#include "x11/tray_client.hpp"
|
||||||
|
|
||||||
#define _NET_SYSTEM_TRAY_ORIENTATION_HORZ 0
|
#define _NET_SYSTEM_TRAY_ORIENTATION_HORZ 0
|
||||||
#define _NET_SYSTEM_TRAY_ORIENTATION_VERT 1
|
#define _NET_SYSTEM_TRAY_ORIENTATION_VERT 1
|
||||||
@ -23,24 +29,19 @@ POLYBAR_NS
|
|||||||
|
|
||||||
namespace chrono = std::chrono;
|
namespace chrono = std::chrono;
|
||||||
using namespace std::chrono_literals;
|
using namespace std::chrono_literals;
|
||||||
|
using namespace signals::eventloop;
|
||||||
|
using namespace signals::ui;
|
||||||
|
|
||||||
// fwd declarations
|
// fwd declarations
|
||||||
class connection;
|
class connection;
|
||||||
struct xembed_data;
|
struct xembed_data;
|
||||||
|
|
||||||
namespace graphics_util {
|
|
||||||
struct root_pixmap;
|
|
||||||
}
|
|
||||||
|
|
||||||
using root_pixmap = graphics_util::root_pixmap;
|
|
||||||
|
|
||||||
// class definition : settings {{{
|
|
||||||
|
|
||||||
struct tray_settings {
|
struct tray_settings {
|
||||||
tray_settings() = default;
|
tray_settings() = default;
|
||||||
tray_settings& operator=(const tray_settings& o) = default;
|
tray_settings& operator=(const tray_settings& o) = default;
|
||||||
|
|
||||||
alignment align{alignment::NONE};
|
alignment align{alignment::NONE};
|
||||||
|
int16_t running{false};
|
||||||
int16_t orig_x{0};
|
int16_t orig_x{0};
|
||||||
int16_t orig_y{0};
|
int16_t orig_y{0};
|
||||||
int16_t configured_x{0};
|
int16_t configured_x{0};
|
||||||
@ -59,55 +60,18 @@ struct tray_settings {
|
|||||||
bool detached{false};
|
bool detached{false};
|
||||||
};
|
};
|
||||||
|
|
||||||
// }}}
|
|
||||||
// class definition : tray_client {{{
|
|
||||||
|
|
||||||
class tray_client {
|
|
||||||
public:
|
|
||||||
explicit tray_client(connection& conn, xcb_window_t win, uint16_t w, uint16_t h);
|
|
||||||
|
|
||||||
~tray_client();
|
|
||||||
|
|
||||||
uint16_t width() const;
|
|
||||||
uint16_t height() const;
|
|
||||||
void clear_window() const;
|
|
||||||
|
|
||||||
bool match(const xcb_window_t& win) const;
|
|
||||||
bool mapped() const;
|
|
||||||
void mapped(bool state);
|
|
||||||
|
|
||||||
xcb_window_t window() const;
|
|
||||||
xembed_data* xembed() const;
|
|
||||||
|
|
||||||
void ensure_state() const;
|
|
||||||
void reconfigure(int16_t x, int16_t y) const;
|
|
||||||
void configure_notify(int16_t x, int16_t y) const;
|
|
||||||
|
|
||||||
protected:
|
|
||||||
connection& m_connection;
|
|
||||||
xcb_window_t m_window{0};
|
|
||||||
|
|
||||||
shared_ptr<xembed_data> m_xembed;
|
|
||||||
stateflag m_mapped{false};
|
|
||||||
|
|
||||||
uint16_t m_width;
|
|
||||||
uint16_t m_height;
|
|
||||||
};
|
|
||||||
|
|
||||||
// }}}
|
|
||||||
// class definition : tray_manager {{{
|
|
||||||
|
|
||||||
class tray_manager : public xpp::event::sink<evt::expose, evt::visibility_notify, evt::client_message,
|
class tray_manager : public xpp::event::sink<evt::expose, evt::visibility_notify, evt::client_message,
|
||||||
evt::configure_request, evt::resize_request, evt::selection_clear, evt::property_notify,
|
evt::configure_request, evt::resize_request, evt::selection_clear, evt::property_notify,
|
||||||
evt::reparent_notify, evt::destroy_notify, evt::map_notify, evt::unmap_notify> {
|
evt::reparent_notify, evt::destroy_notify, evt::map_notify, evt::unmap_notify>,
|
||||||
|
public signal_receiver<SIGN_PRIORITY_TRAY, visibility_change> {
|
||||||
public:
|
public:
|
||||||
explicit tray_manager(connection& conn, const logger& logger);
|
explicit tray_manager(connection& conn, signal_emitter& emitter, const logger& logger);
|
||||||
|
|
||||||
~tray_manager();
|
~tray_manager();
|
||||||
|
|
||||||
const tray_settings settings() const;
|
const tray_settings settings() const;
|
||||||
|
|
||||||
void bootstrap(tray_settings settings);
|
void setup(const bar_settings& bar_opts);
|
||||||
void activate();
|
void activate();
|
||||||
void activate_delayed(chrono::duration<double, std::milli> delay = 1s);
|
void activate_delayed(chrono::duration<double, std::milli> delay = 1s);
|
||||||
void deactivate(bool clear_selection = true);
|
void deactivate(bool clear_selection = true);
|
||||||
@ -124,8 +88,8 @@ class tray_manager : public xpp::event::sink<evt::expose, evt::visibility_notify
|
|||||||
void create_window();
|
void create_window();
|
||||||
void create_bg(bool realloc = false);
|
void create_bg(bool realloc = false);
|
||||||
void restack_window();
|
void restack_window();
|
||||||
void set_wmhints();
|
void set_wm_hints();
|
||||||
void set_traycolors();
|
void set_tray_colors();
|
||||||
|
|
||||||
void acquire_selection();
|
void acquire_selection();
|
||||||
void notify_clients();
|
void notify_clients();
|
||||||
@ -134,8 +98,6 @@ class tray_manager : public xpp::event::sink<evt::expose, evt::visibility_notify
|
|||||||
void track_selection_owner(xcb_window_t owner);
|
void track_selection_owner(xcb_window_t owner);
|
||||||
void process_docking_request(xcb_window_t win);
|
void process_docking_request(xcb_window_t win);
|
||||||
|
|
||||||
void bar_visibility_change(bool visible);
|
|
||||||
|
|
||||||
int16_t calculate_x(uint16_t width) const;
|
int16_t calculate_x(uint16_t width) const;
|
||||||
int16_t calculate_y() const;
|
int16_t calculate_y() const;
|
||||||
uint16_t calculate_w() const;
|
uint16_t calculate_w() const;
|
||||||
@ -144,9 +106,11 @@ class tray_manager : public xpp::event::sink<evt::expose, evt::visibility_notify
|
|||||||
int16_t calculate_client_x(const xcb_window_t& win);
|
int16_t calculate_client_x(const xcb_window_t& win);
|
||||||
int16_t calculate_client_y();
|
int16_t calculate_client_y();
|
||||||
|
|
||||||
|
bool is_embedded(const xcb_window_t& win) const;
|
||||||
shared_ptr<tray_client> find_client(const xcb_window_t& win) const;
|
shared_ptr<tray_client> find_client(const xcb_window_t& win) const;
|
||||||
void remove_client(shared_ptr<tray_client>& client, bool reconfigure = true);
|
void remove_client(shared_ptr<tray_client>& client, bool reconfigure = true);
|
||||||
int mapped_clients() const;
|
void remove_client(xcb_window_t window, bool reconfigure = true);
|
||||||
|
size_t mapped_clients() const;
|
||||||
|
|
||||||
void handle(const evt::expose& evt);
|
void handle(const evt::expose& evt);
|
||||||
void handle(const evt::visibility_notify& evt);
|
void handle(const evt::visibility_notify& evt);
|
||||||
@ -160,8 +124,11 @@ class tray_manager : public xpp::event::sink<evt::expose, evt::visibility_notify
|
|||||||
void handle(const evt::map_notify& evt);
|
void handle(const evt::map_notify& evt);
|
||||||
void handle(const evt::unmap_notify& evt);
|
void handle(const evt::unmap_notify& evt);
|
||||||
|
|
||||||
|
bool on(const visibility_change& evt);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
connection& m_connection;
|
connection& m_connection;
|
||||||
|
signal_emitter& m_sig;
|
||||||
const logger& m_log;
|
const logger& m_log;
|
||||||
vector<shared_ptr<tray_client>> m_clients;
|
vector<shared_ptr<tray_client>> m_clients;
|
||||||
|
|
||||||
@ -169,7 +136,7 @@ class tray_manager : public xpp::event::sink<evt::expose, evt::visibility_notify
|
|||||||
|
|
||||||
xcb_gcontext_t m_gc{0};
|
xcb_gcontext_t m_gc{0};
|
||||||
xcb_pixmap_t m_pixmap{0};
|
xcb_pixmap_t m_pixmap{0};
|
||||||
root_pixmap m_rootpixmap;
|
graphics_util::root_pixmap m_rootpixmap;
|
||||||
uint16_t m_prevwidth{0};
|
uint16_t m_prevwidth{0};
|
||||||
uint16_t m_prevheight{0};
|
uint16_t m_prevheight{0};
|
||||||
|
|
||||||
@ -189,15 +156,12 @@ class tray_manager : public xpp::event::sink<evt::expose, evt::visibility_notify
|
|||||||
std::mutex m_mtx;
|
std::mutex m_mtx;
|
||||||
};
|
};
|
||||||
|
|
||||||
// }}}
|
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
/**
|
/**
|
||||||
* Configure injection module
|
* Configure injection module
|
||||||
*/
|
*/
|
||||||
template <class T = unique_ptr<tray_manager>>
|
inline unique_ptr<tray_manager> make_tray_manager() {
|
||||||
di::injector<T> configure_tray_manager() {
|
return factory_util::unique<tray_manager>(make_connection(), make_signal_emitter(), make_logger());
|
||||||
return di::make_injector(configure_logger(), configure_connection());
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -7,15 +7,12 @@
|
|||||||
POLYBAR_NS
|
POLYBAR_NS
|
||||||
|
|
||||||
namespace wm_util {
|
namespace wm_util {
|
||||||
void set_wmname(xcb_connection_t* conn, xcb_window_t win, const string& wm_name, const string& wm_class);
|
void set_wm_name(xcb_connection_t* conn, xcb_window_t win, const string& wm_name, const string& wm_class);
|
||||||
void set_wmprotocols(xcb_connection_t* conn, xcb_window_t win, vector<xcb_atom_t> flags);
|
void set_wm_protocols(xcb_connection_t* conn, xcb_window_t win, vector<xcb_atom_t> flags);
|
||||||
void set_windowtype(xcb_connection_t* conn, xcb_window_t win, vector<xcb_atom_t> types);
|
void set_wm_window_type(xcb_connection_t* conn, xcb_window_t win, vector<xcb_atom_t> types);
|
||||||
void set_wmstate(xcb_connection_t* conn, xcb_window_t win, vector<xcb_atom_t> states);
|
void set_wm_state(xcb_connection_t* conn, xcb_window_t win, vector<xcb_atom_t> states);
|
||||||
void set_wmpid(xcb_connection_t* conn, xcb_window_t win, pid_t pid);
|
void set_wm_pid(xcb_connection_t* conn, xcb_window_t win, pid_t pid);
|
||||||
void set_wmdesktop(xcb_connection_t* conn, xcb_window_t win, uint32_t desktop = -1u);
|
void set_wm_desktop(xcb_connection_t* conn, xcb_window_t win, uint32_t desktop = -1u);
|
||||||
|
|
||||||
void set_trayorientation(xcb_connection_t* conn, xcb_window_t win, uint32_t orientation);
|
|
||||||
void set_trayvisual(xcb_connection_t* conn, xcb_window_t win, xcb_visualid_t visual);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
POLYBAR_NS_END
|
POLYBAR_NS_END
|
||||||
|
@ -1,5 +1,7 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include <map>
|
||||||
|
|
||||||
#include "config.hpp"
|
#include "config.hpp"
|
||||||
|
|
||||||
#if not WITH_XKB
|
#if not WITH_XKB
|
||||||
@ -24,6 +26,8 @@
|
|||||||
|
|
||||||
POLYBAR_NS
|
POLYBAR_NS
|
||||||
|
|
||||||
|
using std::map;
|
||||||
|
|
||||||
// fwd
|
// fwd
|
||||||
class connection;
|
class connection;
|
||||||
|
|
||||||
|
@ -22,6 +22,6 @@ class xresource_manager {
|
|||||||
XrmDatabase m_db;
|
XrmDatabase m_db;
|
||||||
};
|
};
|
||||||
|
|
||||||
di::injector<const xresource_manager&> configure_xresource_manager();
|
const xresource_manager& make_xresource_manager();
|
||||||
|
|
||||||
POLYBAR_NS_END
|
POLYBAR_NS_END
|
||||||
|
@ -16,9 +16,6 @@ namespace xutils {
|
|||||||
xcb_connection_t* get_connection();
|
xcb_connection_t* get_connection();
|
||||||
int get_connection_fd();
|
int get_connection_fd();
|
||||||
|
|
||||||
uint32_t event_timer_ms(const config& conf, const xcb_button_press_event_t&);
|
|
||||||
uint32_t event_timer_ms(const config& conf, const xcb_randr_notify_event_t&);
|
|
||||||
|
|
||||||
void pack_values(uint32_t mask, const uint32_t* src, uint32_t* dest);
|
void pack_values(uint32_t mask, const uint32_t* src, uint32_t* dest);
|
||||||
void pack_values(uint32_t mask, const xcb_params_cw_t* src, uint32_t* dest);
|
void pack_values(uint32_t mask, const xcb_params_cw_t* src, uint32_t* dest);
|
||||||
void pack_values(uint32_t mask, const xcb_params_gc_t* src, uint32_t* dest);
|
void pack_values(uint32_t mask, const xcb_params_gc_t* src, uint32_t* dest);
|
||||||
|
@ -1,20 +1,24 @@
|
|||||||
#include <xcb/xcb_icccm.h>
|
#include <xcb/xcb_icccm.h>
|
||||||
|
#include <algorithm>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
#include "components/bar.hpp"
|
#include "components/bar.hpp"
|
||||||
|
#include "components/command_line.hpp"
|
||||||
|
#include "components/config.hpp"
|
||||||
|
#include "components/eventloop.hpp"
|
||||||
#include "components/parser.hpp"
|
#include "components/parser.hpp"
|
||||||
#include "components/renderer.hpp"
|
#include "components/renderer.hpp"
|
||||||
#include "components/screen.hpp"
|
#include "components/screen.hpp"
|
||||||
#include "components/signals.hpp"
|
#include "events/signal.hpp"
|
||||||
|
#include "events/signal_emitter.hpp"
|
||||||
#include "utils/bspwm.hpp"
|
#include "utils/bspwm.hpp"
|
||||||
#include "utils/color.hpp"
|
#include "utils/color.hpp"
|
||||||
#include "utils/math.hpp"
|
#include "utils/math.hpp"
|
||||||
#include "utils/string.hpp"
|
#include "utils/string.hpp"
|
||||||
#include "x11/atoms.hpp"
|
#include "x11/atoms.hpp"
|
||||||
#include "x11/connection.hpp"
|
#include "x11/connection.hpp"
|
||||||
#include "x11/ewmh.hpp"
|
|
||||||
#include "x11/fonts.hpp"
|
#include "x11/fonts.hpp"
|
||||||
#include "x11/graphics.hpp"
|
#include "x11/tray_manager.hpp"
|
||||||
#include "x11/tray.hpp"
|
|
||||||
#include "x11/wm.hpp"
|
#include "x11/wm.hpp"
|
||||||
#include "x11/xutils.hpp"
|
#include "x11/xutils.hpp"
|
||||||
|
|
||||||
@ -24,59 +28,51 @@
|
|||||||
|
|
||||||
POLYBAR_NS
|
POLYBAR_NS
|
||||||
|
|
||||||
namespace ph = std::placeholders;
|
using namespace signals::ui;
|
||||||
|
using namespace wm_util;
|
||||||
/**
|
|
||||||
* Configure injection module
|
|
||||||
*/
|
|
||||||
di::injector<unique_ptr<bar>> configure_bar() {
|
|
||||||
// clang-format off
|
|
||||||
return di::make_injector(
|
|
||||||
configure_connection(),
|
|
||||||
configure_config(),
|
|
||||||
configure_logger(),
|
|
||||||
configure_screen(),
|
|
||||||
configure_tray_manager());
|
|
||||||
// clang-format on
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Construct bar instance
|
* Construct bar instance
|
||||||
*/
|
|
||||||
bar::bar(connection& conn, const config& config, const logger& logger, unique_ptr<screen> screen,
|
|
||||||
unique_ptr<tray_manager> tray_manager)
|
|
||||||
: m_connection(conn), m_conf(config), m_log(logger), m_screen(move(screen)), m_tray(move(tray_manager)) {}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Cleanup signal handlers and destroy the bar window
|
|
||||||
*/
|
|
||||||
bar::~bar() {
|
|
||||||
std::lock_guard<std::mutex> guard(m_mutex);
|
|
||||||
m_connection.detach_sink(this, SINK_PRIORITY_BAR);
|
|
||||||
m_tray.reset();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Create required components
|
|
||||||
*
|
*
|
||||||
* This is done outside the constructor due to boost::di noexcept
|
* TODO: Break out all tray handling
|
||||||
*/
|
*/
|
||||||
void bar::bootstrap(bool nodraw) {
|
bar::bar(connection& conn, signal_emitter& emitter, const config& config, const logger& logger,
|
||||||
auto bs = m_conf.bar_section();
|
unique_ptr<screen> screen, unique_ptr<tray_manager> tray_manager)
|
||||||
|
: m_connection(conn)
|
||||||
|
, m_sig(emitter)
|
||||||
|
, m_conf(config)
|
||||||
|
, m_log(logger)
|
||||||
|
, m_screen(move(screen))
|
||||||
|
, m_tray(move(tray_manager)) {
|
||||||
|
string bs{m_conf.bar_section()};
|
||||||
|
|
||||||
setup_monitor();
|
// Get available RandR outputs
|
||||||
|
auto monitor_name = m_conf.get<string>(bs, "monitor", "");
|
||||||
|
auto monitor_strictmode = m_conf.get<bool>(bs, "monitor-strict", false);
|
||||||
|
auto monitors = randr_util::get_monitors(m_connection, m_connection.screen()->root, monitor_strictmode);
|
||||||
|
|
||||||
m_log.trace("bar: Load config values");
|
if (monitors.empty()) {
|
||||||
{
|
throw application_error("No monitors found");
|
||||||
m_opts.locale = m_conf.get<string>(bs, "locale", "");
|
} else if (monitor_name.empty()) {
|
||||||
m_opts.separator = string_util::trim(m_conf.get<string>(bs, "separator", ""), '"');
|
monitor_name = monitors[0]->name;
|
||||||
m_opts.wmname = m_conf.get<string>(bs, "wm-name", "polybar-" + bs.substr(4) + "_" + m_opts.monitor->name);
|
m_log.warn("No monitor specified, using \"%s\"", monitor_name);
|
||||||
m_opts.wmname = string_util::replace(m_opts.wmname, " ", "-");
|
|
||||||
|
|
||||||
if (m_conf.get<bool>(bs, "bottom", false)) {
|
|
||||||
m_opts.origin = edge::BOTTOM;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Match against the defined monitor name
|
||||||
|
for (auto&& monitor : monitors) {
|
||||||
|
if (monitor->match(monitor_name, monitor_strictmode)) {
|
||||||
|
m_opts.monitor = move(monitor);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!m_opts.monitor) {
|
||||||
|
throw application_error("Monitor \"" + monitor_name + "\" not found or disconnected");
|
||||||
|
}
|
||||||
|
|
||||||
|
m_log.trace("bar: Loaded monitor %s (%ix%i+%i+%i)", m_opts.monitor->name, m_opts.monitor->w, m_opts.monitor->h,
|
||||||
|
m_opts.monitor->x, m_opts.monitor->y);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
m_opts.override_redirect = m_conf.get<bool>(bs, "dock");
|
m_opts.override_redirect = m_conf.get<bool>(bs, "dock");
|
||||||
m_conf.warn_deprecated(bs, "dock", "override-redirect");
|
m_conf.warn_deprecated(bs, "dock", "override-redirect");
|
||||||
@ -84,107 +80,131 @@ void bar::bootstrap(bool nodraw) {
|
|||||||
m_opts.override_redirect = m_conf.get<bool>(bs, "override-redirect", m_opts.override_redirect);
|
m_opts.override_redirect = m_conf.get<bool>(bs, "override-redirect", m_opts.override_redirect);
|
||||||
}
|
}
|
||||||
|
|
||||||
GET_CONFIG_VALUE(bs, m_opts.spacing, "spacing");
|
// Build WM_NAME
|
||||||
GET_CONFIG_VALUE(bs, m_opts.padding.left, "padding-left");
|
m_opts.wmname = m_conf.get<string>(bs, "wm-name", "polybar-" + bs.substr(4) + "_" + m_opts.monitor->name);
|
||||||
GET_CONFIG_VALUE(bs, m_opts.padding.right, "padding-right");
|
m_opts.wmname = string_util::replace(m_opts.wmname, " ", "-");
|
||||||
GET_CONFIG_VALUE(bs, m_opts.module_margin.left, "module-margin-left");
|
|
||||||
GET_CONFIG_VALUE(bs, m_opts.module_margin.right, "module-margin-right");
|
|
||||||
|
|
||||||
|
// Load configuration values
|
||||||
|
m_opts.origin = m_conf.get<bool>(bs, "bottom", false) ? edge::BOTTOM : edge::TOP;
|
||||||
|
m_opts.spacing = m_conf.get<decltype(m_opts.spacing)>(bs, "spacing", m_opts.spacing);
|
||||||
|
m_opts.padding.left = m_conf.get<decltype(m_opts.padding.left)>(bs, "padding-left", m_opts.padding.left);
|
||||||
|
m_opts.padding.right = m_conf.get<decltype(m_opts.padding.right)>(bs, "padding-right", m_opts.padding.right);
|
||||||
|
m_opts.module_margin.left =
|
||||||
|
m_conf.get<decltype(m_opts.module_margin.left)>(bs, "module-margin-left", m_opts.module_margin.left);
|
||||||
|
m_opts.module_margin.right =
|
||||||
|
m_conf.get<decltype(m_opts.module_margin.right)>(bs, "module-margin-right", m_opts.module_margin.right);
|
||||||
|
m_opts.separator = string_util::trim(m_conf.get<string>(bs, "separator", ""), '"');
|
||||||
|
m_opts.locale = m_conf.get<string>(bs, "locale", "");
|
||||||
|
|
||||||
|
// Load values used to adjust the struts atom
|
||||||
m_opts.strut.top = m_conf.get<int>("global/wm", "margin-top", 0);
|
m_opts.strut.top = m_conf.get<int>("global/wm", "margin-top", 0);
|
||||||
m_opts.strut.bottom = m_conf.get<int>("global/wm", "margin-bottom", 0);
|
m_opts.strut.bottom = m_conf.get<int>("global/wm", "margin-bottom", 0);
|
||||||
|
|
||||||
m_buttonpress.offset = xutils::event_timer_ms(m_conf, xcb_button_press_event_t{});
|
// Load commands used for fallback click handlers
|
||||||
|
vector<action> actions;
|
||||||
|
actions.emplace_back(action{mousebtn::LEFT, m_conf.get<string>(bs, "click-left", "")});
|
||||||
|
actions.emplace_back(action{mousebtn::MIDDLE, m_conf.get<string>(bs, "click-middle", "")});
|
||||||
|
actions.emplace_back(action{mousebtn::RIGHT, m_conf.get<string>(bs, "click-right", "")});
|
||||||
|
actions.emplace_back(action{mousebtn::SCROLL_UP, m_conf.get<string>(bs, "scroll-up", "")});
|
||||||
|
actions.emplace_back(action{mousebtn::SCROLL_DOWN, m_conf.get<string>(bs, "scroll-down", "")});
|
||||||
|
|
||||||
// Get fallback click handlers
|
for (auto&& act : actions) {
|
||||||
auto click_left = m_conf.get<string>(bs, "click-left", "");
|
if (!act.command.empty()) {
|
||||||
auto click_middle = m_conf.get<string>(bs, "click-middle", "");
|
m_opts.actions.emplace_back(action{act.button, act.command});
|
||||||
auto click_right = m_conf.get<string>(bs, "click-right", "");
|
|
||||||
auto scroll_up = m_conf.get<string>(bs, "scroll-up", "");
|
|
||||||
auto scroll_down = m_conf.get<string>(bs, "scroll-down", "");
|
|
||||||
|
|
||||||
if (!click_left.empty()) {
|
|
||||||
m_opts.actions.emplace_back(action{mousebtn::LEFT, move(click_left)});
|
|
||||||
}
|
|
||||||
if (!click_middle.empty()) {
|
|
||||||
m_opts.actions.emplace_back(action{mousebtn::MIDDLE, move(click_middle)});
|
|
||||||
}
|
|
||||||
if (!click_right.empty()) {
|
|
||||||
m_opts.actions.emplace_back(action{mousebtn::RIGHT, move(click_right)});
|
|
||||||
}
|
|
||||||
if (!scroll_up.empty()) {
|
|
||||||
m_opts.actions.emplace_back(action{mousebtn::SCROLL_UP, move(scroll_up)});
|
|
||||||
}
|
|
||||||
if (!scroll_down.empty()) {
|
|
||||||
m_opts.actions.emplace_back(action{mousebtn::SCROLL_DOWN, move(scroll_down)});
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
m_log.trace("bar: Load color values");
|
// Load foreground/background
|
||||||
{
|
m_opts.background = color::parse(m_conf.get<string>(bs, "background", color_util::hex<uint16_t>(m_opts.background)));
|
||||||
m_opts.background =
|
m_opts.foreground = color::parse(m_conf.get<string>(bs, "foreground", color_util::hex<uint16_t>(m_opts.foreground)));
|
||||||
color::parse(m_conf.get<string>(bs, "background", color_util::hex<uint16_t>(m_opts.background)));
|
|
||||||
m_opts.foreground =
|
|
||||||
color::parse(m_conf.get<string>(bs, "foreground", color_util::hex<uint16_t>(m_opts.foreground)));
|
|
||||||
|
|
||||||
auto linecolor = color::parse(m_conf.get<string>(bs, "linecolor", "#f00"));
|
|
||||||
auto lineheight = m_conf.get<int>(bs, "lineheight", 0);
|
|
||||||
|
|
||||||
|
// Load over-/underline color and size (warn about deprecated params if used)
|
||||||
m_conf.warn_deprecated(bs, "linecolor", "{underline,overline}-color");
|
m_conf.warn_deprecated(bs, "linecolor", "{underline,overline}-color");
|
||||||
m_conf.warn_deprecated(bs, "lineheight", "{underline,overline}-size");
|
m_conf.warn_deprecated(bs, "lineheight", "{underline,overline}-size");
|
||||||
|
|
||||||
try {
|
auto linecolor = color::parse(m_conf.get<string>(bs, "linecolor", "#f00"));
|
||||||
|
auto lineheight = m_conf.get<int>(bs, "lineheight", 0);
|
||||||
m_opts.overline.size = m_conf.get<int16_t>(bs, "overline-size", lineheight);
|
m_opts.overline.size = m_conf.get<int16_t>(bs, "overline-size", lineheight);
|
||||||
m_opts.overline.color = color::parse(m_conf.get<string>(bs, "overline-color"));
|
m_opts.overline.color = color::parse(m_conf.get<string>(bs, "overline-color", linecolor));
|
||||||
} catch (const key_error& err) {
|
|
||||||
m_opts.overline.color = linecolor;
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
m_opts.underline.size = m_conf.get<uint16_t>(bs, "underline-size", lineheight);
|
m_opts.underline.size = m_conf.get<uint16_t>(bs, "underline-size", lineheight);
|
||||||
m_opts.underline.color = color::parse(m_conf.get<string>(bs, "underline-color"));
|
m_opts.underline.color = color::parse(m_conf.get<string>(bs, "underline-color", linecolor));
|
||||||
} catch (const key_error& err) {
|
|
||||||
m_opts.underline.color = linecolor;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
m_log.trace("bar: Load border values");
|
// Load border settings
|
||||||
{
|
|
||||||
auto bsize = m_conf.get<int>(bs, "border-size", 0);
|
auto bsize = m_conf.get<int>(bs, "border-size", 0);
|
||||||
auto bcolor = m_conf.get<string>(bs, "border-color", "#00000000");
|
auto bcolor = m_conf.get<string>(bs, "border-color", "#00000000");
|
||||||
|
|
||||||
m_opts.borders.emplace(edge::TOP, border_settings{});
|
m_opts.borders.emplace(edge::TOP, border_settings{});
|
||||||
m_opts.borders[edge::TOP].size = m_conf.get<int>(bs, "border-top", bsize);
|
m_opts.borders[edge::TOP].size = m_conf.get<int>(bs, "border-top", bsize);
|
||||||
m_opts.borders[edge::TOP].color = color::parse(m_conf.get<string>(bs, "border-top-color", bcolor));
|
m_opts.borders[edge::TOP].color = color::parse(m_conf.get<string>(bs, "border-top-color", bcolor));
|
||||||
|
|
||||||
m_opts.borders.emplace(edge::BOTTOM, border_settings{});
|
m_opts.borders.emplace(edge::BOTTOM, border_settings{});
|
||||||
m_opts.borders[edge::BOTTOM].size = m_conf.get<int>(bs, "border-bottom", bsize);
|
m_opts.borders[edge::BOTTOM].size = m_conf.get<int>(bs, "border-bottom", bsize);
|
||||||
m_opts.borders[edge::BOTTOM].color = color::parse(m_conf.get<string>(bs, "border-bottom-color", bcolor));
|
m_opts.borders[edge::BOTTOM].color = color::parse(m_conf.get<string>(bs, "border-bottom-color", bcolor));
|
||||||
|
|
||||||
m_opts.borders.emplace(edge::LEFT, border_settings{});
|
m_opts.borders.emplace(edge::LEFT, border_settings{});
|
||||||
m_opts.borders[edge::LEFT].size = m_conf.get<int>(bs, "border-left", bsize);
|
m_opts.borders[edge::LEFT].size = m_conf.get<int>(bs, "border-left", bsize);
|
||||||
m_opts.borders[edge::LEFT].color = color::parse(m_conf.get<string>(bs, "border-left-color", bcolor));
|
m_opts.borders[edge::LEFT].color = color::parse(m_conf.get<string>(bs, "border-left-color", bcolor));
|
||||||
|
|
||||||
m_opts.borders.emplace(edge::RIGHT, border_settings{});
|
m_opts.borders.emplace(edge::RIGHT, border_settings{});
|
||||||
m_opts.borders[edge::RIGHT].size = m_conf.get<int>(bs, "border-right", bsize);
|
m_opts.borders[edge::RIGHT].size = m_conf.get<int>(bs, "border-right", bsize);
|
||||||
m_opts.borders[edge::RIGHT].color = color::parse(m_conf.get<string>(bs, "border-right-color", bcolor));
|
m_opts.borders[edge::RIGHT].color = color::parse(m_conf.get<string>(bs, "border-right-color", bcolor));
|
||||||
|
|
||||||
|
// Load geometry values
|
||||||
|
auto w = m_conf.get<string>(m_conf.bar_section(), "width", "100%");
|
||||||
|
auto h = m_conf.get<string>(m_conf.bar_section(), "height", "24");
|
||||||
|
auto offsetx = m_conf.get<string>(m_conf.bar_section(), "offset-x", "");
|
||||||
|
auto offsety = m_conf.get<string>(m_conf.bar_section(), "offset-y", "");
|
||||||
|
|
||||||
|
if ((m_opts.size.w = atoi(w.c_str())) && w.find('%') != string::npos) {
|
||||||
|
m_opts.size.w = math_util::percentage_to_value<int>(m_opts.size.w, m_opts.monitor->w);
|
||||||
|
}
|
||||||
|
if ((m_opts.size.h = atoi(h.c_str())) && h.find('%') != string::npos) {
|
||||||
|
m_opts.size.h = math_util::percentage_to_value<int>(m_opts.size.h, m_opts.monitor->h);
|
||||||
|
}
|
||||||
|
if ((m_opts.offset.x = atoi(offsetx.c_str())) != 0 && offsetx.find('%') != string::npos) {
|
||||||
|
m_opts.offset.x = math_util::percentage_to_value<int>(m_opts.offset.x, m_opts.monitor->w);
|
||||||
|
}
|
||||||
|
if ((m_opts.offset.y = atoi(offsety.c_str())) != 0 && offsety.find('%') != string::npos) {
|
||||||
|
m_opts.offset.y = math_util::percentage_to_value<int>(m_opts.offset.y, m_opts.monitor->h);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (nodraw) {
|
// Apply offsets
|
||||||
m_log.trace("bar: Abort bootstrap routine (reason: nodraw)");
|
m_opts.pos.x = m_opts.offset.x + m_opts.monitor->x;
|
||||||
m_tray.reset();
|
m_opts.pos.y = m_opts.offset.y + m_opts.monitor->y;
|
||||||
return;
|
m_opts.size.h += m_opts.borders[edge::TOP].size;
|
||||||
|
m_opts.size.h += m_opts.borders[edge::BOTTOM].size;
|
||||||
|
|
||||||
|
if (m_opts.origin == edge::BOTTOM) {
|
||||||
|
m_opts.pos.y = m_opts.monitor->y + m_opts.monitor->h - m_opts.size.h - m_opts.offset.y;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (m_opts.size.w <= 0 || m_opts.size.w > m_opts.monitor->w) {
|
||||||
|
throw application_error("Resulting bar width is out of bounds");
|
||||||
|
} else if (m_opts.size.h <= 0 || m_opts.size.h > m_opts.monitor->h) {
|
||||||
|
throw application_error("Resulting bar height is out of bounds");
|
||||||
|
}
|
||||||
|
|
||||||
|
m_opts.size.w = math_util::cap<int>(m_opts.size.w, 0, m_opts.monitor->w);
|
||||||
|
m_opts.size.h = math_util::cap<int>(m_opts.size.h, 0, m_opts.monitor->h);
|
||||||
|
|
||||||
|
m_opts.center.y = m_opts.size.h;
|
||||||
|
m_opts.center.y -= m_opts.borders[edge::BOTTOM].size;
|
||||||
|
m_opts.center.y /= 2;
|
||||||
|
m_opts.center.y += m_opts.borders[edge::TOP].size;
|
||||||
|
|
||||||
|
m_opts.center.x = m_opts.size.w;
|
||||||
|
m_opts.center.x -= m_opts.borders[edge::RIGHT].size;
|
||||||
|
m_opts.center.x /= 2;
|
||||||
|
m_opts.center.x += m_opts.borders[edge::LEFT].size;
|
||||||
|
|
||||||
|
m_log.trace("bar: Create renderer");
|
||||||
|
auto fonts = m_conf.get_list<string>(m_conf.bar_section(), "font", {});
|
||||||
|
m_renderer = make_renderer(m_opts, move(fonts));
|
||||||
|
|
||||||
m_log.trace("bar: Attaching sink to registry");
|
m_log.trace("bar: Attaching sink to registry");
|
||||||
m_connection.attach_sink(this, SINK_PRIORITY_BAR);
|
m_connection.attach_sink(this, SINK_PRIORITY_BAR);
|
||||||
|
|
||||||
configure_geom();
|
m_log.info("Bar geometry: %ix%i+%i+%i", m_opts.size.w, m_opts.size.h, m_opts.pos.x, m_opts.pos.y);
|
||||||
|
m_opts.window = m_renderer->window();
|
||||||
m_renderer = configure_renderer(m_opts, m_conf.get_list<string>(bs, "font", {})).create<unique_ptr<renderer>>();
|
|
||||||
m_window = m_renderer->window();
|
|
||||||
|
|
||||||
m_log.info("Bar window: %s", m_connection.id(m_window));
|
|
||||||
|
|
||||||
|
m_log.info("Bar window: %s", m_connection.id(m_opts.window));
|
||||||
restack_window();
|
restack_window();
|
||||||
|
|
||||||
m_log.trace("bar: Reconfigure window");
|
m_log.trace("bar: Reconfigure window");
|
||||||
@ -192,190 +212,29 @@ void bar::bootstrap(bool nodraw) {
|
|||||||
reconfigure_wm_hints();
|
reconfigure_wm_hints();
|
||||||
|
|
||||||
m_log.trace("bar: Map window");
|
m_log.trace("bar: Map window");
|
||||||
m_connection.map_window_checked(m_window);
|
m_connection.map_window_checked(m_opts.window);
|
||||||
|
|
||||||
// Reconfigure window position after mapping (required by Openbox)
|
// Reconfigure window position after mapping (required by Openbox)
|
||||||
// Required by Openbox
|
// Required by Openbox
|
||||||
reconfigure_pos();
|
reconfigure_pos();
|
||||||
|
|
||||||
m_log.trace("bar: Attach parser signal handlers");
|
|
||||||
g_signals::parser::background_change = bind(&renderer::set_background, m_renderer.get(), ph::_1);
|
|
||||||
g_signals::parser::foreground_change = bind(&renderer::set_foreground, m_renderer.get(), ph::_1);
|
|
||||||
g_signals::parser::underline_change = bind(&renderer::set_underline, m_renderer.get(), ph::_1);
|
|
||||||
g_signals::parser::overline_change = bind(&renderer::set_overline, m_renderer.get(), ph::_1);
|
|
||||||
g_signals::parser::pixel_offset = bind(&renderer::fill_shift, m_renderer.get(), ph::_1);
|
|
||||||
g_signals::parser::alignment_change = bind(&renderer::set_alignment, m_renderer.get(), ph::_1);
|
|
||||||
g_signals::parser::attribute_set = bind(&renderer::set_attribute, m_renderer.get(), ph::_1, true);
|
|
||||||
g_signals::parser::attribute_unset = bind(&renderer::set_attribute, m_renderer.get(), ph::_1, false);
|
|
||||||
g_signals::parser::attribute_toggle = bind(&renderer::toggle_attribute, m_renderer.get(), ph::_1);
|
|
||||||
g_signals::parser::action_block_open = bind(&renderer::begin_action, m_renderer.get(), ph::_1, ph::_2);
|
|
||||||
g_signals::parser::action_block_close = bind(&renderer::end_action, m_renderer.get(), ph::_1);
|
|
||||||
g_signals::parser::font_change = bind(&renderer::set_fontindex, m_renderer.get(), ph::_1);
|
|
||||||
g_signals::parser::ascii_text_write = bind(&renderer::draw_character, m_renderer.get(), ph::_1);
|
|
||||||
g_signals::parser::unicode_text_write = bind(&renderer::draw_character, m_renderer.get(), ph::_1);
|
|
||||||
g_signals::parser::string_write = bind(&renderer::draw_textstring, m_renderer.get(), ph::_1, ph::_2);
|
|
||||||
|
|
||||||
try {
|
|
||||||
m_log.trace("bar: Drawing empty bar");
|
m_log.trace("bar: Drawing empty bar");
|
||||||
m_renderer->begin();
|
m_renderer->begin();
|
||||||
m_renderer->fill_background();
|
m_renderer->fill_background();
|
||||||
m_renderer->end();
|
m_renderer->end();
|
||||||
} catch (const exception& err) {
|
|
||||||
throw application_error("Failed to output empty bar window (reason: " + string{err.what()} + ")");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Setup tray manager
|
|
||||||
*/
|
|
||||||
void bar::bootstrap_tray() {
|
|
||||||
if (!m_tray) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
tray_settings settings;
|
|
||||||
|
|
||||||
auto bs = m_conf.bar_section();
|
|
||||||
auto tray_position = m_conf.get<string>(bs, "tray-position", "");
|
|
||||||
|
|
||||||
if (tray_position == "left") {
|
|
||||||
settings.align = alignment::LEFT;
|
|
||||||
} else if (tray_position == "right") {
|
|
||||||
settings.align = alignment::RIGHT;
|
|
||||||
} else if (tray_position == "center") {
|
|
||||||
settings.align = alignment::CENTER;
|
|
||||||
} else {
|
|
||||||
settings.align = alignment::NONE;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (settings.align == alignment::NONE) {
|
|
||||||
m_log.warn("Disabling tray manager (reason: disabled in config)");
|
|
||||||
m_tray.reset();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
settings.detached = m_conf.get<bool>(bs, "tray-detached", false);
|
|
||||||
|
|
||||||
settings.height = m_opts.size.h;
|
|
||||||
settings.height -= m_opts.borders.at(edge::BOTTOM).size;
|
|
||||||
settings.height -= m_opts.borders.at(edge::TOP).size;
|
|
||||||
settings.height_fill = settings.height;
|
|
||||||
|
|
||||||
if (settings.height % 2 != 0) {
|
|
||||||
settings.height--;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto maxsize = m_conf.get<int>(bs, "tray-maxsize", 16);
|
|
||||||
if (settings.height > maxsize) {
|
|
||||||
settings.spacing += (settings.height - maxsize) / 2;
|
|
||||||
settings.height = maxsize;
|
|
||||||
}
|
|
||||||
|
|
||||||
settings.width_max = m_opts.size.w;
|
|
||||||
settings.width = settings.height;
|
|
||||||
settings.orig_y = m_opts.pos.y + m_opts.borders.at(edge::TOP).size;
|
|
||||||
|
|
||||||
// Apply user-defined scaling
|
|
||||||
auto scale = m_conf.get<float>(bs, "tray-scale", 1.0f);
|
|
||||||
settings.width *= scale;
|
|
||||||
settings.height_fill *= scale;
|
|
||||||
|
|
||||||
auto inner_area = m_opts.inner_area(true);
|
|
||||||
|
|
||||||
switch (settings.align) {
|
|
||||||
case alignment::NONE:
|
|
||||||
break;
|
|
||||||
case alignment::LEFT:
|
|
||||||
settings.orig_x = inner_area.x;
|
|
||||||
break;
|
|
||||||
case alignment::CENTER:
|
|
||||||
settings.orig_x = inner_area.x + inner_area.width / 2 - settings.width / 2;
|
|
||||||
break;
|
|
||||||
case alignment::RIGHT:
|
|
||||||
settings.orig_x = inner_area.x + inner_area.width;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Set user-defined background color
|
|
||||||
if (!(settings.transparent = m_conf.get<bool>(bs, "tray-transparent", settings.transparent))) {
|
|
||||||
auto bg = m_conf.get<string>(bs, "tray-background", "");
|
|
||||||
|
|
||||||
if (bg.length() > 7) {
|
|
||||||
m_log.warn("Alpha support for the systray is limited. See the wiki for more details.");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!bg.empty()) {
|
|
||||||
settings.background = color::parse(bg, g_colorempty);
|
|
||||||
} else {
|
|
||||||
settings.background = m_opts.background;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (color_util::alpha_channel(settings.background) == 0) {
|
|
||||||
settings.transparent = true;
|
|
||||||
settings.background = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Add user-defined padding
|
|
||||||
settings.spacing += m_conf.get<int>(bs, "tray-padding", 0);
|
|
||||||
|
|
||||||
// Add user-defiend offset
|
|
||||||
auto offset_x_def = m_conf.get<string>(bs, "tray-offset-x", "");
|
|
||||||
auto offset_y_def = m_conf.get<string>(bs, "tray-offset-y", "");
|
|
||||||
|
|
||||||
auto offset_x = atoi(offset_x_def.c_str());
|
|
||||||
auto offset_y = atoi(offset_y_def.c_str());
|
|
||||||
|
|
||||||
if (offset_x != 0 && offset_x_def.find('%') != string::npos) {
|
|
||||||
if (settings.detached) {
|
|
||||||
offset_x = math_util::percentage_to_value<int>(offset_x, m_opts.monitor->w);
|
|
||||||
} else {
|
|
||||||
offset_x = math_util::percentage_to_value<int>(offset_x, inner_area.width);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (offset_y != 0 && offset_y_def.find('%') != string::npos) {
|
|
||||||
if (settings.detached) {
|
|
||||||
offset_y = math_util::percentage_to_value<int>(offset_y, m_opts.monitor->h);
|
|
||||||
} else {
|
|
||||||
offset_y = math_util::percentage_to_value<int>(offset_y, inner_area.height);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
settings.orig_x += offset_x;
|
|
||||||
settings.orig_y += offset_y;
|
|
||||||
|
|
||||||
// Put the tray next to the bar in the window stack
|
|
||||||
settings.sibling = m_window;
|
|
||||||
|
|
||||||
try {
|
|
||||||
m_log.trace("bar: Setup tray manager");
|
m_log.trace("bar: Setup tray manager");
|
||||||
m_tray->bootstrap(settings);
|
m_tray->setup(static_cast<const bar_settings&>(m_opts));
|
||||||
} catch (const exception& err) {
|
|
||||||
m_log.err(err.what());
|
broadcast_visibility();
|
||||||
m_log.warn("Failed to setup tray, disabling...");
|
|
||||||
m_tray.reset();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Activate tray manager
|
* Cleanup signal handlers and destroy the bar window
|
||||||
*/
|
*/
|
||||||
void bar::activate_tray() {
|
bar::~bar() {
|
||||||
if (!m_tray) {
|
std::lock_guard<std::mutex> guard(m_mutex);
|
||||||
return;
|
m_connection.detach_sink(this, SINK_PRIORITY_BAR);
|
||||||
}
|
|
||||||
|
|
||||||
m_log.trace("bar: Activate tray manager");
|
|
||||||
|
|
||||||
try {
|
|
||||||
broadcast_visibility();
|
|
||||||
m_tray->activate();
|
|
||||||
} catch (const exception& err) {
|
|
||||||
m_log.err(err.what());
|
|
||||||
m_log.err("Failed to activate tray manager, disabling...");
|
|
||||||
m_tray.reset();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -404,6 +263,7 @@ void bar::parse(const string& data, bool force) {
|
|||||||
|
|
||||||
m_lastinput = data;
|
m_lastinput = data;
|
||||||
|
|
||||||
|
m_log.info("Redrawing bar window");
|
||||||
m_renderer->begin();
|
m_renderer->begin();
|
||||||
|
|
||||||
if (m_tray && !m_tray->settings().detached && m_tray->settings().configured_slots) {
|
if (m_tray && !m_tray->settings().detached && m_tray->settings().configured_slots) {
|
||||||
@ -417,8 +277,10 @@ void bar::parse(const string& data, bool force) {
|
|||||||
m_renderer->fill_background();
|
m_renderer->fill_background();
|
||||||
|
|
||||||
try {
|
try {
|
||||||
parser parser{m_log, m_opts};
|
if (!data.empty()) {
|
||||||
|
parser parser{m_sig, m_log, m_opts};
|
||||||
parser(data);
|
parser(data);
|
||||||
|
}
|
||||||
} catch (const parser_error& err) {
|
} catch (const parser_error& err) {
|
||||||
m_log.err("Failed to parse contents (reason: %s)", err.what());
|
m_log.err("Failed to parse contents (reason: %s)", err.what());
|
||||||
}
|
}
|
||||||
@ -426,108 +288,6 @@ void bar::parse(const string& data, bool force) {
|
|||||||
m_renderer->end();
|
m_renderer->end();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Configure geometry values
|
|
||||||
*/
|
|
||||||
void bar::configure_geom() {
|
|
||||||
m_log.trace("bar: Configure window geometry");
|
|
||||||
|
|
||||||
auto w = m_conf.get<string>(m_conf.bar_section(), "width", "100%");
|
|
||||||
auto h = m_conf.get<string>(m_conf.bar_section(), "height", "24");
|
|
||||||
|
|
||||||
auto offsetx = m_conf.get<string>(m_conf.bar_section(), "offset-x", "");
|
|
||||||
auto offsety = m_conf.get<string>(m_conf.bar_section(), "offset-y", "");
|
|
||||||
|
|
||||||
// look for user-defined width
|
|
||||||
if ((m_opts.size.w = atoi(w.c_str())) && w.find('%') != string::npos) {
|
|
||||||
m_opts.size.w = math_util::percentage_to_value<int>(m_opts.size.w, m_opts.monitor->w);
|
|
||||||
}
|
|
||||||
|
|
||||||
// look for user-defined height
|
|
||||||
if ((m_opts.size.h = atoi(h.c_str())) && h.find('%') != string::npos) {
|
|
||||||
m_opts.size.h = math_util::percentage_to_value<int>(m_opts.size.h, m_opts.monitor->h);
|
|
||||||
}
|
|
||||||
|
|
||||||
// look for user-defined offset-x
|
|
||||||
if ((m_opts.offset.x = atoi(offsetx.c_str())) != 0 && offsetx.find('%') != string::npos) {
|
|
||||||
m_opts.offset.x = math_util::percentage_to_value<int>(m_opts.offset.x, m_opts.monitor->w);
|
|
||||||
}
|
|
||||||
|
|
||||||
// look for user-defined offset-y
|
|
||||||
if ((m_opts.offset.y = atoi(offsety.c_str())) != 0 && offsety.find('%') != string::npos) {
|
|
||||||
m_opts.offset.y = math_util::percentage_to_value<int>(m_opts.offset.y, m_opts.monitor->h);
|
|
||||||
}
|
|
||||||
|
|
||||||
// apply offsets
|
|
||||||
m_opts.pos.x = m_opts.offset.x + m_opts.monitor->x;
|
|
||||||
m_opts.pos.y = m_opts.offset.y + m_opts.monitor->y;
|
|
||||||
|
|
||||||
// apply borders
|
|
||||||
m_opts.size.h += m_opts.borders[edge::TOP].size;
|
|
||||||
m_opts.size.h += m_opts.borders[edge::BOTTOM].size;
|
|
||||||
|
|
||||||
if (m_opts.origin == edge::BOTTOM) {
|
|
||||||
m_opts.pos.y = m_opts.monitor->y + m_opts.monitor->h - m_opts.size.h - m_opts.offset.y;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (m_opts.size.w <= 0 || m_opts.size.w > m_opts.monitor->w) {
|
|
||||||
throw application_error("Resulting bar width is out of bounds");
|
|
||||||
}
|
|
||||||
if (m_opts.size.h <= 0 || m_opts.size.h > m_opts.monitor->h) {
|
|
||||||
throw application_error("Resulting bar height is out of bounds");
|
|
||||||
}
|
|
||||||
|
|
||||||
m_opts.size.w = math_util::cap<int>(m_opts.size.w, 0, m_opts.monitor->w);
|
|
||||||
m_opts.size.h = math_util::cap<int>(m_opts.size.h, 0, m_opts.monitor->h);
|
|
||||||
|
|
||||||
m_opts.center.y = m_opts.size.h;
|
|
||||||
m_opts.center.y -= m_opts.borders[edge::BOTTOM].size;
|
|
||||||
m_opts.center.y /= 2;
|
|
||||||
m_opts.center.y += m_opts.borders[edge::TOP].size;
|
|
||||||
|
|
||||||
m_opts.center.x = m_opts.size.w;
|
|
||||||
m_opts.center.x -= m_opts.borders[edge::RIGHT].size;
|
|
||||||
m_opts.center.x /= 2;
|
|
||||||
m_opts.center.x += m_opts.borders[edge::LEFT].size;
|
|
||||||
|
|
||||||
m_log.info("Bar geometry: %ix%i+%i+%i", m_opts.size.w, m_opts.size.h, m_opts.pos.x, m_opts.pos.y);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Create monitor object
|
|
||||||
*/
|
|
||||||
void bar::setup_monitor() {
|
|
||||||
m_log.trace("bar: Create monitor from matching X RandR output");
|
|
||||||
|
|
||||||
auto strict = m_conf.get<bool>(m_conf.bar_section(), "monitor-strict", false);
|
|
||||||
auto monitors = randr_util::get_monitors(m_connection, m_screen->root(), strict);
|
|
||||||
|
|
||||||
if (monitors.empty()) {
|
|
||||||
throw application_error("No monitors found");
|
|
||||||
}
|
|
||||||
|
|
||||||
auto name = m_conf.get<string>(m_conf.bar_section(), "monitor", "");
|
|
||||||
|
|
||||||
if (name.empty()) {
|
|
||||||
name = monitors[0]->name;
|
|
||||||
m_log.warn("No monitor specified, using \"%s\"", name);
|
|
||||||
}
|
|
||||||
|
|
||||||
for (auto&& monitor : monitors) {
|
|
||||||
if (monitor->match(name, strict)) {
|
|
||||||
m_opts.monitor = move(monitor);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!m_opts.monitor) {
|
|
||||||
throw application_error("Monitor \"" + name + "\" not found or disconnected");
|
|
||||||
}
|
|
||||||
|
|
||||||
const auto& m = m_opts.monitor;
|
|
||||||
m_log.trace("bar: Loaded monitor %s (%ix%i+%i+%i)", m->name, m->w, m->h, m->x, m->y);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Move the bar window above defined sibling
|
* Move the bar window above defined sibling
|
||||||
* in the X window stack
|
* in the X window stack
|
||||||
@ -544,10 +304,10 @@ void bar::restack_window() {
|
|||||||
auto restacked = false;
|
auto restacked = false;
|
||||||
|
|
||||||
if (wm_restack == "bspwm") {
|
if (wm_restack == "bspwm") {
|
||||||
restacked = bspwm_util::restack_above_root(m_connection, m_opts.monitor, m_window);
|
restacked = bspwm_util::restack_above_root(m_connection, m_opts.monitor, m_opts.window);
|
||||||
#if ENABLE_I3
|
#if ENABLE_I3
|
||||||
} else if (wm_restack == "i3" && m_opts.override_redirect) {
|
} else if (wm_restack == "i3" && m_opts.override_redirect) {
|
||||||
restacked = i3_util::restack_above_root(m_connection, m_opts.monitor, m_window);
|
restacked = i3_util::restack_above_root(m_connection, m_opts.monitor, m_opts.window);
|
||||||
} else if (wm_restack == "i3" && !m_opts.override_redirect) {
|
} else if (wm_restack == "i3" && !m_opts.override_redirect) {
|
||||||
m_log.warn("Ignoring restack of i3 window (not needed when `override-redirect = false`)");
|
m_log.warn("Ignoring restack of i3 window (not needed when `override-redirect = false`)");
|
||||||
wm_restack.clear();
|
wm_restack.clear();
|
||||||
@ -568,7 +328,7 @@ void bar::restack_window() {
|
|||||||
* Reconfigure window position
|
* Reconfigure window position
|
||||||
*/
|
*/
|
||||||
void bar::reconfigure_pos() {
|
void bar::reconfigure_pos() {
|
||||||
window win{m_connection, m_window};
|
window win{m_connection, m_opts.window};
|
||||||
win.reconfigure_pos(m_opts.pos.x, m_opts.pos.y);
|
win.reconfigure_pos(m_opts.pos.x, m_opts.pos.y);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -592,7 +352,7 @@ void bar::reconfigure_struts() {
|
|||||||
h += m_opts.monitor->y;
|
h += m_opts.monitor->y;
|
||||||
}
|
}
|
||||||
|
|
||||||
window win{m_connection, m_window};
|
window win{m_connection, m_opts.window};
|
||||||
win.reconfigure_struts(w, h, m_opts.pos.x, m_opts.origin == edge::BOTTOM);
|
win.reconfigure_struts(w, h, m_opts.pos.x, m_opts.origin == edge::BOTTOM);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -601,42 +361,34 @@ void bar::reconfigure_struts() {
|
|||||||
*/
|
*/
|
||||||
void bar::reconfigure_wm_hints() {
|
void bar::reconfigure_wm_hints() {
|
||||||
m_log.trace("bar: Set window WM_NAME");
|
m_log.trace("bar: Set window WM_NAME");
|
||||||
xcb_icccm_set_wm_name(m_connection, m_window, XCB_ATOM_STRING, 8, m_opts.wmname.size(), m_opts.wmname.c_str());
|
xcb_icccm_set_wm_name(m_connection, m_opts.window, XCB_ATOM_STRING, 8, m_opts.wmname.size(), m_opts.wmname.c_str());
|
||||||
xcb_icccm_set_wm_class(m_connection, m_window, 15, "polybar\0Polybar");
|
xcb_icccm_set_wm_class(m_connection, m_opts.window, 15, "polybar\0Polybar");
|
||||||
|
|
||||||
m_log.trace("bar: Set window _NET_WM_WINDOW_TYPE");
|
m_log.trace("bar: Set window _NET_Wm_opts.window_TYPE");
|
||||||
wm_util::set_windowtype(m_connection, m_window, {_NET_WM_WINDOW_TYPE_DOCK});
|
set_wm_window_type(m_connection, m_opts.window, {_NET_WM_WINDOW_TYPE_DOCK});
|
||||||
|
|
||||||
m_log.trace("bar: Set window _NET_WM_STATE");
|
m_log.trace("bar: Set window _NET_WM_STATE");
|
||||||
wm_util::set_wmstate(m_connection, m_window, {_NET_WM_STATE_STICKY, _NET_WM_STATE_ABOVE});
|
set_wm_state(m_connection, m_opts.window, {_NET_WM_STATE_STICKY, _NET_WM_STATE_ABOVE});
|
||||||
|
|
||||||
m_log.trace("bar: Set window _NET_WM_DESKTOP");
|
m_log.trace("bar: Set window _NET_WM_DESKTOP");
|
||||||
wm_util::set_wmdesktop(m_connection, m_window, 0xFFFFFFFF);
|
set_wm_desktop(m_connection, m_opts.window, 0xFFFFFFFF);
|
||||||
|
|
||||||
m_log.trace("bar: Set window _NET_WM_PID");
|
m_log.trace("bar: Set window _NET_WM_PID");
|
||||||
wm_util::set_wmpid(m_connection, m_window, getpid());
|
set_wm_pid(m_connection, m_opts.window, getpid());
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Broadcast current map state
|
* Broadcast current map state
|
||||||
*/
|
*/
|
||||||
void bar::broadcast_visibility() {
|
void bar::broadcast_visibility() {
|
||||||
if (!g_signals::bar::visibility_change) {
|
auto attr = m_connection.get_window_attributes(m_opts.window);
|
||||||
return m_log.trace("bar: no callback handler set for bar visibility change");
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
auto attr = m_connection.get_window_attributes(m_window);
|
|
||||||
|
|
||||||
if (attr->map_state == XCB_MAP_STATE_UNVIEWABLE) {
|
if (attr->map_state == XCB_MAP_STATE_UNVIEWABLE) {
|
||||||
g_signals::bar::visibility_change(false);
|
m_sig.emit(visibility_change{move(false)});
|
||||||
} else if (attr->map_state == XCB_MAP_STATE_UNMAPPED) {
|
} else if (attr->map_state == XCB_MAP_STATE_UNMAPPED) {
|
||||||
g_signals::bar::visibility_change(false);
|
m_sig.emit(visibility_change{move(false)});
|
||||||
} else {
|
} else {
|
||||||
g_signals::bar::visibility_change(true);
|
m_sig.emit(visibility_change{move(true)});
|
||||||
}
|
|
||||||
} catch (const exception& err) {
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -669,29 +421,17 @@ void bar::handle(const evt::button_press& evt) {
|
|||||||
continue;
|
continue;
|
||||||
} else if (action.end_x < evt->event_x) {
|
} else if (action.end_x < evt->event_x) {
|
||||||
continue;
|
continue;
|
||||||
}
|
} else {
|
||||||
|
|
||||||
m_log.trace("Found matching input area");
|
m_log.trace("Found matching input area");
|
||||||
m_log.trace_x("action.command = %s", action.command);
|
m_sig.emit(button_press{string{action.command}});
|
||||||
m_log.trace_x("action.button = %i", evt->detail);
|
|
||||||
m_log.trace_x("action.start_x = %i", action.start_x);
|
|
||||||
m_log.trace_x("action.end_x = %i", action.end_x);
|
|
||||||
|
|
||||||
if (g_signals::bar::action_click) {
|
|
||||||
g_signals::bar::action_click(action.command);
|
|
||||||
}
|
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
for (auto&& action : m_opts.actions) {
|
for (auto&& action : m_opts.actions) {
|
||||||
if (action.button == button && !action.command.empty()) {
|
if (action.button == button && !action.command.empty()) {
|
||||||
m_log.trace("Triggering fallback click handler: %s", action.command);
|
m_log.trace("Triggering fallback click handler: %s", action.command);
|
||||||
|
m_sig.emit(button_press{string{action.command}});
|
||||||
if (g_signals::bar::action_click) {
|
|
||||||
g_signals::bar::action_click(action.command);
|
|
||||||
}
|
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -705,7 +445,11 @@ void bar::handle(const evt::button_press& evt) {
|
|||||||
* Used to redraw the bar
|
* Used to redraw the bar
|
||||||
*/
|
*/
|
||||||
void bar::handle(const evt::expose& evt) {
|
void bar::handle(const evt::expose& evt) {
|
||||||
if (evt->window == m_window && evt->count == 0) {
|
if (evt->window == m_opts.window && evt->count == 0) {
|
||||||
|
if (m_tray->settings().running) {
|
||||||
|
broadcast_visibility();
|
||||||
|
}
|
||||||
|
|
||||||
m_log.trace("bar: Received expose event");
|
m_log.trace("bar: Received expose event");
|
||||||
m_renderer->flush(false);
|
m_renderer->flush(false);
|
||||||
}
|
}
|
||||||
@ -729,7 +473,7 @@ void bar::handle(const evt::property_notify& evt) {
|
|||||||
m_log.trace_x("bar: property_notify(%s)", atom_name);
|
m_log.trace_x("bar: property_notify(%s)", atom_name);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if (evt->window == m_window && evt->atom == WM_STATE) {
|
if (evt->window == m_opts.window && evt->atom == WM_STATE) {
|
||||||
broadcast_visibility();
|
broadcast_visibility();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -54,7 +54,7 @@ string builder::flush() {
|
|||||||
/**
|
/**
|
||||||
* Insert raw text string
|
* Insert raw text string
|
||||||
*/
|
*/
|
||||||
void builder::append(string text) {
|
void builder::append(const string& text) {
|
||||||
m_output += text;
|
m_output += text;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -4,6 +4,7 @@
|
|||||||
#include <utility>
|
#include <utility>
|
||||||
|
|
||||||
#include "components/config.hpp"
|
#include "components/config.hpp"
|
||||||
|
#include "components/logger.hpp"
|
||||||
#include "utils/env.hpp"
|
#include "utils/env.hpp"
|
||||||
#include "utils/file.hpp"
|
#include "utils/file.hpp"
|
||||||
|
|
||||||
|
@ -1,114 +1,59 @@
|
|||||||
#include <chrono>
|
#include "components/controller.hpp"
|
||||||
#include <mutex>
|
#include "common.hpp"
|
||||||
|
|
||||||
#include "components/bar.hpp"
|
#include "components/bar.hpp"
|
||||||
#include "components/config.hpp"
|
#include "components/config.hpp"
|
||||||
#include "components/controller.hpp"
|
|
||||||
#include "components/eventloop.hpp"
|
#include "components/eventloop.hpp"
|
||||||
#include "components/ipc.hpp"
|
#include "components/ipc.hpp"
|
||||||
#include "components/logger.hpp"
|
#include "components/logger.hpp"
|
||||||
#include "components/signals.hpp"
|
#include "events/signal.hpp"
|
||||||
#include "modules/backlight.hpp"
|
#include "modules/meta/factory.hpp"
|
||||||
#include "modules/battery.hpp"
|
#include "utils/factory.hpp"
|
||||||
#include "modules/bspwm.hpp"
|
|
||||||
#include "modules/counter.hpp"
|
|
||||||
#include "modules/cpu.hpp"
|
|
||||||
#include "modules/date.hpp"
|
|
||||||
#include "modules/fs.hpp"
|
|
||||||
#include "modules/ipc.hpp"
|
|
||||||
#include "modules/memory.hpp"
|
|
||||||
#include "modules/menu.hpp"
|
|
||||||
#include "modules/script.hpp"
|
|
||||||
#include "modules/temperature.hpp"
|
|
||||||
#include "modules/text.hpp"
|
|
||||||
#include "modules/xbacklight.hpp"
|
|
||||||
#include "modules/xwindow.hpp"
|
|
||||||
#include "modules/xworkspaces.hpp"
|
|
||||||
#include "utils/process.hpp"
|
#include "utils/process.hpp"
|
||||||
#include "utils/string.hpp"
|
#include "utils/string.hpp"
|
||||||
|
#include "x11/xutils.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
|
|
||||||
#if WITH_XKB
|
|
||||||
#include "modules/xkeyboard.hpp"
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if not(ENABLE_I3 && ENABLE_MPD && ENABLE_NETWORK && ENABLE_ALSA && WITH_XKB)
|
|
||||||
#include "modules/unsupported.hpp"
|
|
||||||
#endif
|
|
||||||
|
|
||||||
POLYBAR_NS
|
POLYBAR_NS
|
||||||
|
|
||||||
using namespace modules;
|
using namespace modules;
|
||||||
|
|
||||||
namespace chrono = std::chrono;
|
controller::controller(connection& conn, signal_emitter& emitter, const logger& logger, const config& config,
|
||||||
|
unique_ptr<eventloop> eventloop, unique_ptr<bar> bar, unique_ptr<ipc> ipc, watch_t confwatch, bool writeback)
|
||||||
|
: m_connection(conn)
|
||||||
|
, m_sig(emitter)
|
||||||
|
, m_log(logger)
|
||||||
|
, m_conf(config)
|
||||||
|
, m_eventloop(move(eventloop))
|
||||||
|
, m_bar(move(bar))
|
||||||
|
, m_ipc(move(ipc))
|
||||||
|
, m_confwatch(move(confwatch))
|
||||||
|
, m_writeback(writeback) {}
|
||||||
|
|
||||||
/**
|
|
||||||
* 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
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Stop modules and cleanup X components,
|
|
||||||
* threads and spawned processes
|
|
||||||
*/
|
|
||||||
controller::~controller() {
|
controller::~controller() {
|
||||||
pthread_sigmask(SIG_UNBLOCK, &m_blockmask, nullptr);
|
|
||||||
|
|
||||||
sigset_t sig;
|
|
||||||
sigemptyset(&sig);
|
|
||||||
sigaddset(&sig, SIGALRM);
|
|
||||||
pthread_sigmask(SIG_BLOCK, &sig, nullptr);
|
|
||||||
|
|
||||||
if (m_command) {
|
|
||||||
m_log.info("Terminating running shell command");
|
|
||||||
m_command.reset();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (m_bar) {
|
|
||||||
m_log.info("Deconstructing bar");
|
|
||||||
m_bar.reset();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (m_ipc) {
|
|
||||||
m_log.info("Deconstructing ipc");
|
|
||||||
m_ipc.reset();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (m_eventloop) {
|
if (m_eventloop) {
|
||||||
m_log.info("Deconstructing eventloop");
|
m_log.info("Deconstructing eventloop");
|
||||||
m_eventloop.reset();
|
m_eventloop.reset();
|
||||||
}
|
}
|
||||||
|
if (m_command) {
|
||||||
|
m_log.info("Terminating running shell command");
|
||||||
|
m_command.reset();
|
||||||
|
}
|
||||||
|
if (m_bar) {
|
||||||
|
m_log.info("Deconstructing bar");
|
||||||
|
m_bar.reset();
|
||||||
|
}
|
||||||
|
if (m_ipc) {
|
||||||
|
m_log.info("Deconstructing ipc");
|
||||||
|
m_ipc.reset();
|
||||||
|
}
|
||||||
if (!m_writeback) {
|
if (!m_writeback) {
|
||||||
m_log.info("Interrupting X event loop");
|
m_log.info("Interrupting X event loop");
|
||||||
m_connection.send_dummy_event(m_connection.root());
|
m_connection.send_dummy_event(m_connection.root());
|
||||||
}
|
}
|
||||||
|
|
||||||
m_log.info("Joining active threads");
|
m_log.info("Joining active threads");
|
||||||
for (auto&& th : m_threads) {
|
for (auto&& thread_ : m_threads) {
|
||||||
if (th.second.joinable()) {
|
if (thread_.joinable()) {
|
||||||
th.second.join();
|
thread_.join();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -117,90 +62,82 @@ controller::~controller() {
|
|||||||
;
|
;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
m_sig.detach(this);
|
||||||
m_connection.flush();
|
m_connection.flush();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
void controller::setup() {
|
||||||
* Initialize components and setup X environment
|
string bs{m_conf.bar_section()};
|
||||||
*/
|
|
||||||
void controller::bootstrap(bool writeback, bool dump_wmname) {
|
|
||||||
// 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");
|
|
||||||
}
|
|
||||||
|
|
||||||
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();
|
|
||||||
|
|
||||||
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)>();
|
|
||||||
m_ipc->attach_callback(bind(&controller::on_ipc_action, this, placeholders::_1));
|
|
||||||
} else {
|
|
||||||
m_log.info("Inter-process messaging disabled");
|
|
||||||
}
|
|
||||||
|
|
||||||
// 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");
|
|
||||||
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);
|
|
||||||
|
|
||||||
m_log.trace("controller: Setup bar");
|
|
||||||
m_bar->bootstrap(m_writeback || dump_wmname);
|
|
||||||
m_bar->bootstrap_tray();
|
|
||||||
|
|
||||||
if (dump_wmname) {
|
|
||||||
std::cout << m_bar->settings().wmname << std::endl;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
m_log.trace("controller: Attach eventloop update callback");
|
|
||||||
m_eventloop->set_update_cb(bind(&controller::on_update, this, placeholders::_1));
|
|
||||||
|
|
||||||
if (!m_writeback) {
|
|
||||||
m_log.trace("controller: Attach eventloop input callback");
|
|
||||||
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");
|
m_log.trace("controller: Setup user-defined modules");
|
||||||
bootstrap_modules();
|
|
||||||
|
for (int i = 0; i < 3; i++) {
|
||||||
|
alignment align = static_cast<alignment>(i + 1);
|
||||||
|
string confkey;
|
||||||
|
|
||||||
|
if (align == alignment::LEFT) {
|
||||||
|
confkey = "modules-left";
|
||||||
|
} else if (align == alignment::CENTER) {
|
||||||
|
confkey = "modules-center";
|
||||||
|
} else if (align == alignment::RIGHT) {
|
||||||
|
confkey = "modules-right";
|
||||||
|
}
|
||||||
|
|
||||||
|
for (auto& module_name : string_util::split(m_conf.get<string>(bs, confkey, ""), ' ')) {
|
||||||
|
if (module_name.empty()) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
auto type = m_conf.get<string>("module/" + module_name, "type");
|
||||||
|
if (type == "custom/ipc" && !m_ipc) {
|
||||||
|
throw application_error("Inter-process messaging needs to be enabled");
|
||||||
|
}
|
||||||
|
|
||||||
|
unique_ptr<module_interface> module{make_module(move(type), m_bar->settings(), m_log, m_conf, module_name)};
|
||||||
|
|
||||||
|
module->set_update_cb([&] {
|
||||||
|
if (m_eventloop && m_running) {
|
||||||
|
m_sig.emit(enqueue_update{eventloop_t::make_update_evt(false)});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
module->set_stop_cb([&] {
|
||||||
|
if (m_eventloop && m_running) {
|
||||||
|
m_sig.emit(enqueue_check{eventloop::make_check_evt()});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
module->setup();
|
||||||
|
|
||||||
|
m_eventloop->add_module(align, move(module));
|
||||||
|
} catch (const std::runtime_error& err) {
|
||||||
|
m_log.err("Disabling module \"%s\" (reason: %s)", module_name, err.what());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!m_eventloop->module_count()) {
|
||||||
|
throw application_error("No modules created");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Launch the controller
|
|
||||||
*/
|
|
||||||
bool controller::run() {
|
bool controller::run() {
|
||||||
assert(!m_connection.connection_has_error());
|
assert(!m_connection.connection_has_error());
|
||||||
|
m_sig.attach(this);
|
||||||
|
|
||||||
m_log.info("Starting application");
|
m_log.info("Starting application");
|
||||||
m_running = true;
|
m_running = true;
|
||||||
|
|
||||||
if (m_confwatch && !m_writeback) {
|
if (m_confwatch && !m_writeback) {
|
||||||
m_threads[thread_role::CONF_LISTENER] = thread(&controller::wait_for_configwatch, this);
|
m_threads.emplace_back(thread(&controller::wait_for_configwatch, this));
|
||||||
}
|
}
|
||||||
|
if (m_ipc) {
|
||||||
// Start ipc receiver if its enabled
|
m_threads.emplace_back(thread(&ipc::receive_messages, m_ipc.get()));
|
||||||
if (m_conf.get<bool>(m_conf.bar_section(), "enable-ipc", false)) {
|
|
||||||
m_threads[thread_role::IPC_LISTENER] = thread(&ipc::receive_messages, m_ipc.get());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Listen for X events in separate thread
|
|
||||||
if (!m_writeback) {
|
if (!m_writeback) {
|
||||||
m_threads[thread_role::EVENT_QUEUE_X] = thread(&controller::wait_for_xevent, this);
|
m_threads.emplace_back(thread(&controller::wait_for_xevent, this));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Start event loop
|
|
||||||
if (m_eventloop) {
|
if (m_eventloop) {
|
||||||
m_threads[thread_role::EVENT_QUEUE] = thread(&controller::wait_for_eventloop, this);
|
m_threads.emplace_back(thread(&controller::wait_for_eventloop, this));
|
||||||
}
|
}
|
||||||
|
|
||||||
m_log.trace("controller: Wait for signal");
|
m_log.trace("controller: Wait for signal");
|
||||||
@ -226,11 +163,13 @@ bool controller::run() {
|
|||||||
m_log.warn("Termination signal received, shutting down...");
|
m_log.warn("Termination signal received, shutting down...");
|
||||||
m_log.trace("controller: Caught signal %d", caught_signal);
|
m_log.trace("controller: Caught signal %d", caught_signal);
|
||||||
|
|
||||||
|
// Signal the eventloop, in case it's still running
|
||||||
|
m_eventloop->enqueue(eventloop::make_quit_evt(false));
|
||||||
|
|
||||||
if (m_eventloop) {
|
if (m_eventloop) {
|
||||||
m_log.trace("controller: Stopping event loop");
|
m_log.trace("controller: Stopping event loop");
|
||||||
m_eventloop->stop();
|
m_eventloop->stop();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!m_writeback && m_confwatch) {
|
if (!m_writeback && m_confwatch) {
|
||||||
m_log.trace("controller: Removing config watch");
|
m_log.trace("controller: Removing config watch");
|
||||||
m_confwatch->remove(true);
|
m_confwatch->remove(true);
|
||||||
@ -239,9 +178,10 @@ bool controller::run() {
|
|||||||
return !m_running && !m_reload;
|
return !m_running && !m_reload;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
const bar_settings controller::opts() const {
|
||||||
* Listen for changes to the config file
|
return m_bar->settings();
|
||||||
*/
|
}
|
||||||
|
|
||||||
void controller::wait_for_configwatch() {
|
void controller::wait_for_configwatch() {
|
||||||
try {
|
try {
|
||||||
m_log.trace("controller: Attach config watch");
|
m_log.trace("controller: Attach config watch");
|
||||||
@ -259,19 +199,14 @@ void controller::wait_for_configwatch() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Wait for X events and forward them to
|
|
||||||
* the event registry
|
|
||||||
*/
|
|
||||||
void controller::wait_for_xevent() {
|
void controller::wait_for_xevent() {
|
||||||
m_log.trace("controller: Listen for X events");
|
m_log.trace("controller: Listen for X events");
|
||||||
|
|
||||||
m_connection.flush();
|
m_connection.flush();
|
||||||
|
|
||||||
shared_ptr<xcb_generic_event_t> evt;
|
|
||||||
while (m_running) {
|
while (m_running) {
|
||||||
try {
|
try {
|
||||||
if ((evt = m_connection.wait_for_event()) != nullptr && m_running) {
|
auto evt = m_connection.wait_for_event();
|
||||||
|
if (evt && m_running) {
|
||||||
m_connection.dispatch_event(evt);
|
m_connection.dispatch_event(evt);
|
||||||
}
|
}
|
||||||
} catch (xpp::connection_error& err) {
|
} catch (xpp::connection_error& err) {
|
||||||
@ -279,7 +214,6 @@ void controller::wait_for_xevent() {
|
|||||||
} catch (const exception& err) {
|
} catch (const exception& err) {
|
||||||
m_log.err("Error in X event loop: %s", err.what());
|
m_log.err("Error in X event loop: %s", err.what());
|
||||||
}
|
}
|
||||||
|
|
||||||
if (m_connection.connection_has_error()) {
|
if (m_connection.connection_has_error()) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -290,14 +224,10 @@ void controller::wait_for_xevent() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Start event loop and wait for it to finish
|
|
||||||
*/
|
|
||||||
void controller::wait_for_eventloop() {
|
void controller::wait_for_eventloop() {
|
||||||
m_eventloop->start();
|
m_eventloop->start();
|
||||||
m_eventloop->wait();
|
|
||||||
|
|
||||||
this_thread::sleep_for(250ms);
|
this_thread::sleep_for(std::chrono::milliseconds{250});
|
||||||
|
|
||||||
if (m_running) {
|
if (m_running) {
|
||||||
m_log.trace("controller: eventloop ended, raising SIGALRM");
|
m_log.trace("controller: eventloop ended, raising SIGALRM");
|
||||||
@ -305,178 +235,16 @@ void controller::wait_for_eventloop() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
bool controller::on(const sig_ev::process_update& evt) {
|
||||||
* 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, ""), ' ')) {
|
|
||||||
if (module_name.empty()) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
auto type = m_conf.get<string>("module/" + module_name, "type");
|
|
||||||
module_t module;
|
|
||||||
|
|
||||||
if (type == "internal/counter") {
|
|
||||||
module.reset(new counter_module(bar, m_log, m_conf, module_name));
|
|
||||||
} else if (type == "internal/backlight") {
|
|
||||||
module.reset(new backlight_module(bar, m_log, m_conf, module_name));
|
|
||||||
} else if (type == "internal/battery") {
|
|
||||||
module.reset(new battery_module(bar, m_log, m_conf, module_name));
|
|
||||||
} else if (type == "internal/bspwm") {
|
|
||||||
module.reset(new bspwm_module(bar, m_log, m_conf, module_name));
|
|
||||||
} else if (type == "internal/cpu") {
|
|
||||||
module.reset(new cpu_module(bar, m_log, m_conf, module_name));
|
|
||||||
} else if (type == "internal/date") {
|
|
||||||
module.reset(new date_module(bar, m_log, m_conf, module_name));
|
|
||||||
} else if (type == "internal/fs") {
|
|
||||||
module.reset(new fs_module(bar, m_log, m_conf, module_name));
|
|
||||||
} else if (type == "internal/memory") {
|
|
||||||
module.reset(new memory_module(bar, m_log, m_conf, module_name));
|
|
||||||
} else if (type == "internal/i3") {
|
|
||||||
module.reset(new i3_module(bar, m_log, m_conf, module_name));
|
|
||||||
} else if (type == "internal/mpd") {
|
|
||||||
module.reset(new mpd_module(bar, m_log, m_conf, module_name));
|
|
||||||
} else if (type == "internal/volume") {
|
|
||||||
module.reset(new volume_module(bar, m_log, m_conf, module_name));
|
|
||||||
} else if (type == "internal/network") {
|
|
||||||
module.reset(new network_module(bar, m_log, m_conf, module_name));
|
|
||||||
} else if (type == "internal/temperature") {
|
|
||||||
module.reset(new temperature_module(bar, m_log, m_conf, module_name));
|
|
||||||
} else if (type == "internal/xbacklight") {
|
|
||||||
module.reset(new xbacklight_module(bar, m_log, m_conf, module_name));
|
|
||||||
} else if (type == "internal/xkeyboard") {
|
|
||||||
module.reset(new xkeyboard_module(bar, m_log, m_conf, module_name));
|
|
||||||
} else if (type == "internal/xwindow") {
|
|
||||||
module.reset(new xwindow_module(bar, m_log, m_conf, module_name));
|
|
||||||
} else if (type == "internal/xworkspaces") {
|
|
||||||
module.reset(new xworkspaces_module(bar, m_log, m_conf, module_name));
|
|
||||||
} else if (type == "custom/text") {
|
|
||||||
module.reset(new text_module(bar, m_log, m_conf, module_name));
|
|
||||||
} else if (type == "custom/script") {
|
|
||||||
module.reset(new script_module(bar, m_log, m_conf, module_name));
|
|
||||||
} else if (type == "custom/menu") {
|
|
||||||
module.reset(new menu_module(bar, m_log, m_conf, module_name));
|
|
||||||
} else if (type == "custom/ipc") {
|
|
||||||
if (!m_ipc) {
|
|
||||||
throw application_error("Inter-process messaging needs to be enabled");
|
|
||||||
}
|
|
||||||
module.reset(new ipc_module(bar, m_log, m_conf, module_name));
|
|
||||||
m_ipc->attach_callback(
|
|
||||||
bind(&ipc_module::on_message, static_cast<ipc_module*>(module.get()), placeholders::_1));
|
|
||||||
} else {
|
|
||||||
throw application_error("Unknown module: " + module_name);
|
|
||||||
}
|
|
||||||
|
|
||||||
module->set_update_cb(
|
|
||||||
bind(&eventloop::enqueue, m_eventloop.get(), eventloop::entry_t{static_cast<uint8_t>(event_type::UPDATE)}));
|
|
||||||
module->set_stop_cb(
|
|
||||||
bind(&eventloop::enqueue, m_eventloop.get(), eventloop::entry_t{static_cast<uint8_t>(event_type::CHECK)}));
|
|
||||||
module->setup();
|
|
||||||
|
|
||||||
m_eventloop->add_module(align, move(module));
|
|
||||||
} catch (const std::runtime_error& err) {
|
|
||||||
m_log.err("Disabling module \"%s\" (reason: %s)", module_name, err.what());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!m_eventloop->module_count()) {
|
|
||||||
throw application_error("No modules created");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Callback for received ipc actions
|
|
||||||
*/
|
|
||||||
void controller::on_ipc_action(const ipc_action& message) {
|
|
||||||
if (!m_eventloop) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
string action = message.payload.substr(strlen(ipc_action::prefix));
|
|
||||||
|
|
||||||
if (action.size() >= sizeof(input_event::data)) {
|
|
||||||
m_log.warn("Ignoring input event (size)");
|
|
||||||
} else if (action.empty()) {
|
|
||||||
m_log.err("Cannot enqueue empty IPC action");
|
|
||||||
} else {
|
|
||||||
m_log.info("Enqueuing IPC action: %s", action);
|
|
||||||
m_eventloop->enqueue(eventloop::make(input_event{}, action));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Callback for clicked bar actions
|
|
||||||
*/
|
|
||||||
void controller::on_mouse_event(const string& input) {
|
|
||||||
if (!m_eventloop) {
|
|
||||||
return;
|
|
||||||
} else if (input.length() >= sizeof(input_event::data)) {
|
|
||||||
m_log.warn("Ignoring input event (size)");
|
|
||||||
} else if (!m_eventloop->enqueue_delayed(eventloop::make(input_event{}, input))) {
|
|
||||||
m_log.trace_x("controller: Dispatcher busy");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Callback for actions not handled internally by a module
|
|
||||||
*/
|
|
||||||
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());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Callback for module content update
|
|
||||||
*/
|
|
||||||
void controller::on_update(bool force) {
|
|
||||||
if (!m_bar) {
|
if (!m_bar) {
|
||||||
return;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
const bar_settings& bar{m_bar->settings()};
|
const bar_settings& bar{m_bar->settings()};
|
||||||
|
|
||||||
string contents;
|
string contents;
|
||||||
string separator{bar.separator};
|
string separator{bar.separator};
|
||||||
|
|
||||||
string padding_left(bar.padding.left, ' ');
|
string padding_left(bar.padding.left, ' ');
|
||||||
string padding_right(bar.padding.right, ' ');
|
string padding_right(bar.padding.right, ' ');
|
||||||
|
|
||||||
auto margin_left = bar.module_margin.left;
|
auto margin_left = bar.module_margin.left;
|
||||||
auto margin_right = bar.module_margin.right;
|
auto margin_right = bar.module_margin.right;
|
||||||
|
|
||||||
@ -518,9 +286,7 @@ void controller::on_update(bool force) {
|
|||||||
|
|
||||||
if (block_contents.empty()) {
|
if (block_contents.empty()) {
|
||||||
continue;
|
continue;
|
||||||
}
|
} else if (is_left) {
|
||||||
|
|
||||||
if (is_left) {
|
|
||||||
contents += "%{l}";
|
contents += "%{l}";
|
||||||
contents += padding_left;
|
contents += padding_left;
|
||||||
} else if (is_center) {
|
} else if (is_center) {
|
||||||
@ -542,25 +308,110 @@ void controller::on_update(bool force) {
|
|||||||
contents += string_util::replace_all(block_contents, "}%{", " ");
|
contents += string_util::replace_all(block_contents, "}%{", " ");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (m_writeback) {
|
try {
|
||||||
|
if (!m_writeback) {
|
||||||
|
m_bar->parse(contents, evt());
|
||||||
|
} else {
|
||||||
std::cout << contents << std::endl;
|
std::cout << contents << std::endl;
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
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());
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
m_bar->parse(contents, force);
|
|
||||||
} catch (const exception& err) {
|
} catch (const exception& err) {
|
||||||
m_log.err("Failed to update bar contents (reason: %s)", err.what());
|
m_log.err("Failed to update bar contents (reason: %s)", err.what());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool controller::on(const sig_ev::process_input& evt) {
|
||||||
|
try {
|
||||||
|
string input{(*evt()).data};
|
||||||
|
|
||||||
|
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());
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool controller::on(const sig_ev::process_quit&) {
|
||||||
|
kill(getpid(), SIGUSR1);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool controller::on(const sig_ui::button_press& evt) {
|
||||||
|
if (!m_eventloop) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
string input{*evt()};
|
||||||
|
|
||||||
|
if (input.length() >= sizeof(eventloop::input_data)) {
|
||||||
|
m_log.warn("Ignoring input event (size)");
|
||||||
|
} else if (!m_sig.emit(enqueue_input{eventloop::make_input_data(move(input))})) {
|
||||||
|
m_log.trace_x("controller: Dispatcher busy");
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool controller::on(const sig_ipc::process_action& evt) {
|
||||||
|
ipc_action a{*evt()};
|
||||||
|
string action{a.payload};
|
||||||
|
action.erase(0, strlen(ipc_action::prefix));
|
||||||
|
|
||||||
|
if (action.size() >= sizeof(eventloop::input_data)) {
|
||||||
|
m_log.warn("Ignoring input event (size)");
|
||||||
|
} else if (action.empty()) {
|
||||||
|
m_log.err("Cannot enqueue empty ipc action");
|
||||||
|
} else {
|
||||||
|
m_log.info("Enqueuing ipc action: %s", action);
|
||||||
|
m_eventloop->enqueue(eventloop::make_input_evt());
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool controller::on(const sig_ipc::process_command& evt) {
|
||||||
|
ipc_command c{*evt()};
|
||||||
|
string command{c.payload};
|
||||||
|
command.erase(0, strlen(ipc_command::prefix));
|
||||||
|
|
||||||
|
if (command.empty()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (command == "quit") {
|
||||||
|
m_eventloop->enqueue(eventloop::make_quit_evt(false));
|
||||||
|
} else if (command == "restart") {
|
||||||
|
m_eventloop->enqueue(eventloop::make_quit_evt(true));
|
||||||
|
} else {
|
||||||
|
m_log.warn("\"%s\" is not a valid ipc command", command);
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool controller::on(const sig_ipc::process_hook& evt) {
|
||||||
|
const ipc_hook hook{*evt()};
|
||||||
|
|
||||||
|
for (const auto& block : m_eventloop->modules()) {
|
||||||
|
for (const auto& module : block.second) {
|
||||||
|
auto ipc = dynamic_cast<ipc_module*>(module.get());
|
||||||
|
if (ipc != nullptr) {
|
||||||
|
ipc->on_message(hook);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
POLYBAR_NS_END
|
POLYBAR_NS_END
|
||||||
|
@ -1,8 +1,8 @@
|
|||||||
#include <csignal>
|
#include <csignal>
|
||||||
|
|
||||||
#include "components/eventloop.hpp"
|
#include "components/eventloop.hpp"
|
||||||
#include "components/signals.hpp"
|
|
||||||
#include "components/types.hpp"
|
#include "components/types.hpp"
|
||||||
|
#include "events/signal.hpp"
|
||||||
#include "utils/string.hpp"
|
#include "utils/string.hpp"
|
||||||
#include "utils/time.hpp"
|
#include "utils/time.hpp"
|
||||||
#include "x11/color.hpp"
|
#include "x11/color.hpp"
|
||||||
@ -12,31 +12,18 @@ POLYBAR_NS
|
|||||||
/**
|
/**
|
||||||
* Construct eventloop instance
|
* Construct eventloop instance
|
||||||
*/
|
*/
|
||||||
eventloop::eventloop(const logger& logger, const config& config) : m_log(logger), m_conf(config) {
|
eventloop::eventloop(signal_emitter& emitter, const logger& logger, const config& config)
|
||||||
m_delayed_time = duration_t{m_conf.get<double>("settings", "eventloop-delayed-time", 25)};
|
: m_sig(emitter), m_log(logger), m_conf(config) {
|
||||||
m_swallow_time = duration_t{m_conf.get<double>("settings", "eventloop-swallow-time", 10)};
|
m_swallow_time = duration_t{m_conf.get<double>("settings", "eventloop-swallow-time", 10)};
|
||||||
m_swallow_limit = m_conf.get<size_t>("settings", "eventloop-swallow", 5U);
|
m_swallow_limit = m_conf.get<size_t>("settings", "eventloop-swallow", 5U);
|
||||||
|
m_sig.attach(this);
|
||||||
g_signals::event::enqueue = bind(&eventloop::enqueue, this, placeholders::_1);
|
|
||||||
g_signals::event::enqueue_delayed = bind(&eventloop::enqueue_delayed, this, placeholders::_1);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Deconstruct eventloop
|
* Deconstruct eventloop
|
||||||
*/
|
*/
|
||||||
eventloop::~eventloop() {
|
eventloop::~eventloop() {
|
||||||
g_signals::event::enqueue = g_signals::noop<const eventloop::entry_t&>;
|
m_sig.detach(this);
|
||||||
g_signals::event::enqueue_delayed = g_signals::noop<const eventloop::entry_t&>;
|
|
||||||
|
|
||||||
m_update_cb = nullptr;
|
|
||||||
m_unrecognized_input_cb = nullptr;
|
|
||||||
|
|
||||||
if (m_delayed_thread.joinable()) {
|
|
||||||
m_delayed_thread.join();
|
|
||||||
}
|
|
||||||
if (m_queue_thread.joinable()) {
|
|
||||||
m_queue_thread.join();
|
|
||||||
}
|
|
||||||
|
|
||||||
for (auto&& block : m_modules) {
|
for (auto&& block : m_modules) {
|
||||||
for (auto&& module : block.second) {
|
for (auto&& module : block.second) {
|
||||||
@ -45,7 +32,7 @@ eventloop::~eventloop() {
|
|||||||
module->stop();
|
module->stop();
|
||||||
module.reset();
|
module.reset();
|
||||||
});
|
});
|
||||||
m_log.trace("eventloop: Deconstruction of %s took %lu microsec.", module_name, cleanup_ms);
|
m_log.info("eventloop: Deconstruction of %s took %lu microsec.", module_name, cleanup_ms);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -56,19 +43,61 @@ eventloop::~eventloop() {
|
|||||||
void eventloop::start() {
|
void eventloop::start() {
|
||||||
m_log.info("Starting event loop");
|
m_log.info("Starting event loop");
|
||||||
m_running = true;
|
m_running = true;
|
||||||
|
|
||||||
dispatch_modules();
|
dispatch_modules();
|
||||||
|
|
||||||
m_queue_thread = thread(&eventloop::dispatch_queue_worker, this);
|
while (m_running) {
|
||||||
m_delayed_thread = thread(&eventloop::dispatch_delayed_worker, this);
|
event evt, next;
|
||||||
|
input_data data;
|
||||||
|
|
||||||
|
m_queue.wait_dequeue(evt);
|
||||||
|
|
||||||
|
if (!m_running) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (evt.type == static_cast<uint8_t>(event_type::INPUT)) {
|
||||||
|
while (m_running && m_inputqueue.try_dequeue(data)) {
|
||||||
|
m_sig.emit(process_input{move(data)});
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
size_t swallowed{0};
|
||||||
|
while (swallowed++ < m_swallow_limit && m_queue.wait_dequeue_timed(next, m_swallow_time)) {
|
||||||
|
if (next.type == static_cast<uint8_t>(event_type::QUIT)) {
|
||||||
|
evt = next;
|
||||||
|
break;
|
||||||
|
|
||||||
|
} else if (next.type == static_cast<uint8_t>(event_type::INPUT)) {
|
||||||
|
evt = next;
|
||||||
|
break;
|
||||||
|
|
||||||
|
} else if (!compare_events(evt, next)) {
|
||||||
|
enqueue(move(next));
|
||||||
|
break;
|
||||||
|
|
||||||
|
} else {
|
||||||
|
m_log.trace_x("eventloop: Swallowing event within timeframe");
|
||||||
|
evt = next;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (evt.type == static_cast<uint8_t>(event_type::INPUT)) {
|
||||||
|
while (m_inputqueue.try_dequeue(data)) {
|
||||||
|
m_sig.emit(process_input{move(data)});
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
forward_event(evt);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
m_log.info("Queue worker done");
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
void eventloop::process_inputqueue() {
|
||||||
* Wait for worker threads to end
|
input_data data{};
|
||||||
*/
|
|
||||||
void eventloop::wait() {
|
while (m_inputqueue.try_dequeue(data)) {
|
||||||
if (m_queue_thread.joinable()) {
|
m_sig.emit(process_input{move(data)});
|
||||||
m_queue_thread.join();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -78,61 +107,33 @@ void eventloop::wait() {
|
|||||||
void eventloop::stop() {
|
void eventloop::stop() {
|
||||||
m_log.info("Stopping event loop");
|
m_log.info("Stopping event loop");
|
||||||
m_running = false;
|
m_running = false;
|
||||||
|
m_sig.emit(enqueue_quit{make_quit_evt(false)});
|
||||||
if (m_delayed_thread.joinable()) {
|
|
||||||
m_delayed_cond.notify_one();
|
|
||||||
}
|
|
||||||
|
|
||||||
enqueue({static_cast<uint8_t>(event_type::QUIT)});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Enqueue event
|
* Enqueue event
|
||||||
*/
|
*/
|
||||||
bool eventloop::enqueue(const entry_t& entry) {
|
bool eventloop::enqueue(event&& evt) {
|
||||||
if (m_queue.enqueue(entry)) {
|
uint8_t type{static_cast<uint8_t>(evt.type)};
|
||||||
|
|
||||||
|
if (!m_queue.enqueue(move(evt))) {
|
||||||
|
m_log.warn("Failed to enqueue event (%d)", static_cast<uint8_t>(type));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
|
||||||
m_log.warn("Failed to enqueue event (%d)", entry.type);
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Delay enqueue by given time
|
* Enqueue input event
|
||||||
*/
|
*/
|
||||||
bool eventloop::enqueue_delayed(const entry_t& entry) {
|
bool eventloop::enqueue(input_data&& evt) {
|
||||||
if (!m_delayed_lock.try_lock()) {
|
if (!m_inputqueue.enqueue(move(evt))) {
|
||||||
|
m_log.warn("Failed to enqueue input_data");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::unique_lock<std::mutex> guard(m_delayed_lock, std::adopt_lock);
|
|
||||||
|
|
||||||
if (m_delayed_entry.type != 0) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
m_delayed_entry = entry;
|
|
||||||
|
|
||||||
if (m_queue.enqueue(entry)) {
|
|
||||||
return true;
|
return true;
|
||||||
}
|
|
||||||
|
|
||||||
m_delayed_entry.type = 0;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Set callback handler for UPDATE events
|
|
||||||
*/
|
|
||||||
void eventloop::set_update_cb(callback<bool>&& cb) {
|
|
||||||
m_update_cb = forward<decltype(cb)>(cb);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Set callback handler for raw INPUT events
|
|
||||||
*/
|
|
||||||
void eventloop::set_input_db(callback<string>&& cb) {
|
|
||||||
m_unrecognized_input_cb = forward<decltype(cb)>(cb);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -184,165 +185,101 @@ void eventloop::dispatch_modules() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Dispatch queue worker thread
|
|
||||||
*/
|
|
||||||
void eventloop::dispatch_queue_worker() {
|
|
||||||
while (m_running) {
|
|
||||||
entry_t evt, next{static_cast<uint8_t>(event_type::NONE)};
|
|
||||||
m_queue.wait_dequeue(evt);
|
|
||||||
|
|
||||||
if (!m_running) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (m_delayed_entry.type != 0 && compare_events(evt, m_delayed_entry)) {
|
|
||||||
m_delayed_cond.notify_one();
|
|
||||||
}
|
|
||||||
|
|
||||||
size_t swallowed{0};
|
|
||||||
while (swallowed++ < m_swallow_limit && m_queue.wait_dequeue_timed(next, m_swallow_time)) {
|
|
||||||
if (match_event(next, event_type::QUIT)) {
|
|
||||||
evt = next;
|
|
||||||
break;
|
|
||||||
} else if (!compare_events(evt, next)) {
|
|
||||||
enqueue(move(next));
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
m_log.trace_x("eventloop: Swallowing event within timeframe");
|
|
||||||
evt = next;
|
|
||||||
}
|
|
||||||
|
|
||||||
forward_event(evt);
|
|
||||||
}
|
|
||||||
|
|
||||||
m_log.info("Queue worker done");
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Dispatch delayed worker thread
|
|
||||||
*/
|
|
||||||
void eventloop::dispatch_delayed_worker() {
|
|
||||||
while (true) {
|
|
||||||
// wait for notification
|
|
||||||
while (m_running && m_delayed_entry.type != 0) {
|
|
||||||
std::unique_lock<std::mutex> guard(m_delayed_lock);
|
|
||||||
m_delayed_cond.wait(guard, [&] { return m_delayed_entry.type != 0 || !m_running; });
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!m_running) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
this_thread::sleep_for(m_delayed_time);
|
|
||||||
m_delayed_entry.type = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
m_log.info("Delayed worker done");
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Test if event matches given type
|
|
||||||
*/
|
|
||||||
inline bool eventloop::match_event(entry_t evt, event_type type) {
|
|
||||||
return static_cast<uint8_t>(type) == evt.type;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Compare given events
|
* Compare given events
|
||||||
*/
|
*/
|
||||||
inline bool eventloop::compare_events(entry_t evt, entry_t evt2) {
|
inline bool eventloop::compare_events(event evt, event evt2) {
|
||||||
if (evt.type != evt2.type) {
|
return evt.type != evt2.type;
|
||||||
return false;
|
}
|
||||||
} else if (match_event(evt, event_type::INPUT)) {
|
|
||||||
return evt.data[0] == evt2.data[0] && strncmp(evt.data, evt2.data, strlen(evt.data)) == 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
inline bool eventloop::compare_events(input_data data, input_data data2) {
|
||||||
|
return data.data[0] == data2.data[0] && strncmp(data.data, data2.data, strlen(data.data)) == 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Forward event to handler based on type
|
* Forward event to handler based on type
|
||||||
*/
|
*/
|
||||||
void eventloop::forward_event(entry_t evt) {
|
void eventloop::forward_event(event evt) {
|
||||||
if (evt.type == static_cast<uint8_t>(event_type::UPDATE)) {
|
if (evt.type == static_cast<uint8_t>(event_type::QUIT)) {
|
||||||
on_update(reinterpret_cast<const update_event&>(evt));
|
m_sig.emit(process_quit{reinterpret_cast<event&&>(evt)});
|
||||||
} else if (evt.type == static_cast<uint8_t>(event_type::INPUT)) {
|
} else if (evt.type == static_cast<uint8_t>(event_type::UPDATE)) {
|
||||||
on_input(reinterpret_cast<const input_event&>(evt));
|
m_sig.emit(process_update{reinterpret_cast<event&&>(evt)});
|
||||||
} else if (evt.type == static_cast<uint8_t>(event_type::CHECK)) {
|
} else if (evt.type == static_cast<uint8_t>(event_type::CHECK)) {
|
||||||
on_check();
|
m_sig.emit(process_check{reinterpret_cast<event&&>(evt)});
|
||||||
} else if (evt.type == static_cast<uint8_t>(event_type::QUIT)) {
|
|
||||||
on_quit(reinterpret_cast<const quit_event&>(evt));
|
|
||||||
} else {
|
} else {
|
||||||
m_log.warn("Unknown event type for enqueued event (%d)", evt.type);
|
m_log.warn("Unknown event type for enqueued event (%d)", evt.type);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
bool eventloop::on(const process_input& evt) {
|
||||||
* Handler for enqueued UPDATE events
|
string input{(*evt()).data};
|
||||||
*/
|
|
||||||
void eventloop::on_update(const update_event& evt) {
|
|
||||||
m_log.trace("eventloop: Received UPDATE event");
|
|
||||||
|
|
||||||
if (m_update_cb) {
|
|
||||||
m_update_cb(evt.force);
|
|
||||||
} else {
|
|
||||||
m_log.warn("No callback to handle update");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Handler for enqueued INPUT events
|
|
||||||
*/
|
|
||||||
void eventloop::on_input(const input_event& evt) {
|
|
||||||
m_log.trace("eventloop: Received INPUT event");
|
|
||||||
|
|
||||||
for (auto&& block : m_modules) {
|
for (auto&& block : m_modules) {
|
||||||
for (auto&& module : block.second) {
|
for (auto&& module : block.second) {
|
||||||
if (!module->receive_events()) {
|
if (module->receive_events() && module->handle_event(input)) {
|
||||||
continue;
|
return true;
|
||||||
}
|
|
||||||
if (module->handle_event(evt.data)) {
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (m_unrecognized_input_cb) {
|
m_log.warn("Input event \"%s\" was rejected by all modules, passing to shell...", input);
|
||||||
m_unrecognized_input_cb(evt.data);
|
|
||||||
} else {
|
return false;
|
||||||
m_log.warn("No callback to handle unrecognized input");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
bool eventloop::on(const process_check&) {
|
||||||
* Handler for enqueued CHECK events
|
|
||||||
*/
|
|
||||||
void eventloop::on_check() {
|
|
||||||
for (const auto& block : m_modules) {
|
for (const auto& block : m_modules) {
|
||||||
for (const auto& module : block.second) {
|
for (const auto& module : block.second) {
|
||||||
if (m_running && module->running()) {
|
if (m_running && module->running()) {
|
||||||
return;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
m_log.warn("No running modules...");
|
m_log.warn("No running modules...");
|
||||||
|
enqueue(make_quit_evt(false));
|
||||||
stop();
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
bool eventloop::on(const process_quit& evt) {
|
||||||
* Handler for enqueued QUIT events
|
assert((*evt()).type == static_cast<uint8_t>(event_type::QUIT));
|
||||||
*/
|
const event quit{static_cast<const event>(*evt())};
|
||||||
void eventloop::on_quit(const quit_event& evt) {
|
m_log.info("Processing QUIT event (reload=%i)", quit.flag);
|
||||||
m_log.trace("eventloop: Received QUIT event");
|
|
||||||
m_running = false;
|
m_running = false;
|
||||||
|
return !quit.flag; // break emit chain if reload flag isn't set
|
||||||
|
}
|
||||||
|
|
||||||
if (evt.reload) {
|
bool eventloop::on(const enqueue_event& evt) {
|
||||||
kill(getpid(), SIGUSR1);
|
m_log.trace("eventloop: enqueuing event (type=%i)", (*evt()).type);
|
||||||
|
return enqueue(static_cast<event>(*evt()));
|
||||||
|
}
|
||||||
|
|
||||||
|
bool eventloop::on(const enqueue_quit& evt) {
|
||||||
|
assert((*evt()).type == static_cast<uint8_t>(event_type::QUIT));
|
||||||
|
if (m_running) {
|
||||||
|
const event quit{reinterpret_cast<const event&>(*evt())};
|
||||||
|
m_log.info("Enqueuing QUIT event (reload=%i)", quit.flag);
|
||||||
|
return enqueue(static_cast<event>(*evt()));
|
||||||
}
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool eventloop::on(const enqueue_update& evt) {
|
||||||
|
event update{reinterpret_cast<const event&>(*evt())};
|
||||||
|
assert(update.type == static_cast<uint8_t>(event_type::UPDATE));
|
||||||
|
m_log.trace("eventloop: enqueuing UPDATE event (force=%i)", update.flag);
|
||||||
|
return enqueue(move(update));
|
||||||
|
}
|
||||||
|
|
||||||
|
bool eventloop::on(const enqueue_input& evt) {
|
||||||
|
m_log.trace("eventloop: enqueuing INPUT event");
|
||||||
|
return enqueue(input_data{(*evt())}) && enqueue(make_input_evt());
|
||||||
|
}
|
||||||
|
|
||||||
|
bool eventloop::on(const enqueue_check& evt) {
|
||||||
|
event check{reinterpret_cast<const event&>(*evt())};
|
||||||
|
assert(check.type == static_cast<uint8_t>(event_type::CHECK));
|
||||||
|
m_log.trace("eventloop: enqueuing CHECK event");
|
||||||
|
return enqueue(move(check));
|
||||||
}
|
}
|
||||||
|
|
||||||
POLYBAR_NS_END
|
POLYBAR_NS_END
|
||||||
|
@ -4,12 +4,16 @@
|
|||||||
|
|
||||||
#include "components/ipc.hpp"
|
#include "components/ipc.hpp"
|
||||||
#include "config.hpp"
|
#include "config.hpp"
|
||||||
|
#include "events/signal.hpp"
|
||||||
|
#include "events/signal_emitter.hpp"
|
||||||
#include "utils/file.hpp"
|
#include "utils/file.hpp"
|
||||||
#include "utils/io.hpp"
|
#include "utils/io.hpp"
|
||||||
#include "utils/string.hpp"
|
#include "utils/string.hpp"
|
||||||
|
|
||||||
POLYBAR_NS
|
POLYBAR_NS
|
||||||
|
|
||||||
|
using namespace signals::ipc;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Interrupt the blocked listener and
|
* Interrupt the blocked listener and
|
||||||
* remove the file handler
|
* remove the file handler
|
||||||
@ -28,27 +32,6 @@ ipc::~ipc() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Register listener callback for ipc_command messages
|
|
||||||
*/
|
|
||||||
void ipc::attach_callback(callback<const ipc_command&>&& cb) {
|
|
||||||
m_command_callbacks.emplace_back(cb);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Register listener callback for ipc_hook messages
|
|
||||||
*/
|
|
||||||
void ipc::attach_callback(callback<const ipc_hook&>&& cb) {
|
|
||||||
m_hook_callbacks.emplace_back(cb);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Register listener callback for ipc_action messages
|
|
||||||
*/
|
|
||||||
void ipc::attach_callback(callback<const ipc_action&>&& cb) {
|
|
||||||
m_action_callbacks.emplace_back(cb);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Start listening for event messages
|
* Start listening for event messages
|
||||||
*/
|
*/
|
||||||
@ -76,53 +59,20 @@ void ipc::parse(const string& payload) const {
|
|||||||
if (payload.empty()) {
|
if (payload.empty()) {
|
||||||
return;
|
return;
|
||||||
} else if (payload.find(ipc_command::prefix) == 0) {
|
} else if (payload.find(ipc_command::prefix) == 0) {
|
||||||
delegate(ipc_command{payload});
|
ipc_command msg{};
|
||||||
|
memcpy(msg.payload, &payload[0], payload.size());
|
||||||
|
m_sig.emit(process_command{move(msg)});
|
||||||
} else if (payload.find(ipc_hook::prefix) == 0) {
|
} else if (payload.find(ipc_hook::prefix) == 0) {
|
||||||
delegate(ipc_hook{payload});
|
ipc_hook msg{};
|
||||||
|
memcpy(msg.payload, &payload[0], payload.size());
|
||||||
|
m_sig.emit(process_hook{move(msg)});
|
||||||
} else if (payload.find(ipc_action::prefix) == 0) {
|
} else if (payload.find(ipc_action::prefix) == 0) {
|
||||||
delegate(ipc_action{payload});
|
ipc_action msg{};
|
||||||
|
memcpy(msg.payload, &payload[0], payload.size());
|
||||||
|
m_sig.emit(process_action{move(msg)});
|
||||||
} else {
|
} else {
|
||||||
m_log.warn("Received unknown ipc message: (payload=%s)", payload);
|
m_log.warn("Received unknown ipc message: (payload=%s)", payload);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Send ipc message to attached listeners
|
|
||||||
*/
|
|
||||||
void ipc::delegate(const ipc_command& message) const {
|
|
||||||
if (!m_command_callbacks.empty()) {
|
|
||||||
for (auto&& callback : m_command_callbacks) {
|
|
||||||
callback(message);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
m_log.warn("Unhandled message (payload=%s)", message.payload);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Send ipc message to attached listeners
|
|
||||||
*/
|
|
||||||
void ipc::delegate(const ipc_hook& message) const {
|
|
||||||
if (!m_hook_callbacks.empty()) {
|
|
||||||
for (auto&& callback : m_hook_callbacks) {
|
|
||||||
callback(message);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
m_log.warn("Unhandled message (payload=%s)", message.payload);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Send ipc message to attached listeners
|
|
||||||
*/
|
|
||||||
void ipc::delegate(const ipc_action& message) const {
|
|
||||||
if (!m_action_callbacks.empty()) {
|
|
||||||
for (auto&& callback : m_action_callbacks) {
|
|
||||||
callback(message);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
m_log.warn("Unhandled message (payload=%s)", message.payload);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
POLYBAR_NS_END
|
POLYBAR_NS_END
|
||||||
|
@ -1,7 +1,5 @@
|
|||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
|
||||||
#include <utility>
|
|
||||||
|
|
||||||
#include "components/logger.hpp"
|
#include "components/logger.hpp"
|
||||||
#include "errors.hpp"
|
#include "errors.hpp"
|
||||||
#include "utils/string.hpp"
|
#include "utils/string.hpp"
|
||||||
@ -12,8 +10,8 @@ POLYBAR_NS
|
|||||||
* Construct logger
|
* Construct logger
|
||||||
*/
|
*/
|
||||||
logger::logger(loglevel level) : m_level(level) {
|
logger::logger(loglevel level) : m_level(level) {
|
||||||
if (isatty(m_fd)) {
|
|
||||||
// clang-format off
|
// clang-format off
|
||||||
|
if (isatty(m_fd)) {
|
||||||
m_prefixes[loglevel::TRACE] = "\r\033[0;90m- ";
|
m_prefixes[loglevel::TRACE] = "\r\033[0;90m- ";
|
||||||
m_prefixes[loglevel::INFO] = "\r\033[1;32m* \033[0m";
|
m_prefixes[loglevel::INFO] = "\r\033[1;32m* \033[0m";
|
||||||
m_prefixes[loglevel::WARNING] = "\r\033[1;33mwarn: \033[0m";
|
m_prefixes[loglevel::WARNING] = "\r\033[1;33mwarn: \033[0m";
|
||||||
@ -22,8 +20,17 @@ logger::logger(loglevel level) : m_level(level) {
|
|||||||
m_suffixes[loglevel::INFO] = "\033[0m";
|
m_suffixes[loglevel::INFO] = "\033[0m";
|
||||||
m_suffixes[loglevel::WARNING] = "\033[0m";
|
m_suffixes[loglevel::WARNING] = "\033[0m";
|
||||||
m_suffixes[loglevel::ERROR] = "\033[0m";
|
m_suffixes[loglevel::ERROR] = "\033[0m";
|
||||||
// clang-format on
|
} else {
|
||||||
|
m_prefixes.emplace(make_pair(loglevel::TRACE, "polybar|trace "));
|
||||||
|
m_prefixes.emplace(make_pair(loglevel::INFO, "polybar|infoe "));
|
||||||
|
m_prefixes.emplace(make_pair(loglevel::WARNING, "polybar|warne "));
|
||||||
|
m_prefixes.emplace(make_pair(loglevel::ERROR, "polybar|error "));
|
||||||
|
m_suffixes.emplace(make_pair(loglevel::TRACE, ""));
|
||||||
|
m_suffixes.emplace(make_pair(loglevel::INFO, ""));
|
||||||
|
m_suffixes.emplace(make_pair(loglevel::WARNING, ""));
|
||||||
|
m_suffixes.emplace(make_pair(loglevel::ERROR, ""));
|
||||||
}
|
}
|
||||||
|
// clang-format on
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -2,33 +2,21 @@
|
|||||||
|
|
||||||
#include "components/logger.hpp"
|
#include "components/logger.hpp"
|
||||||
#include "components/parser.hpp"
|
#include "components/parser.hpp"
|
||||||
#include "components/signals.hpp"
|
|
||||||
#include "components/types.hpp"
|
#include "components/types.hpp"
|
||||||
|
#include "events/signal.hpp"
|
||||||
|
#include "events/signal_emitter.hpp"
|
||||||
#include "utils/math.hpp"
|
#include "utils/math.hpp"
|
||||||
#include "utils/string.hpp"
|
#include "utils/string.hpp"
|
||||||
|
|
||||||
POLYBAR_NS
|
POLYBAR_NS
|
||||||
|
|
||||||
|
using namespace signals::parser;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Construct parser instance
|
* Construct parser instance
|
||||||
*/
|
*/
|
||||||
parser::parser(const logger& logger, const bar_settings& bar) : m_log(logger), m_bar(bar) {
|
parser::parser(signal_emitter& emitter, const logger& logger, const bar_settings& bar)
|
||||||
assert(g_signals::parser::background_change != nullptr);
|
: m_sig(emitter), m_log(logger), m_bar(bar) {}
|
||||||
assert(g_signals::parser::foreground_change != nullptr);
|
|
||||||
assert(g_signals::parser::underline_change != nullptr);
|
|
||||||
assert(g_signals::parser::overline_change != nullptr);
|
|
||||||
assert(g_signals::parser::alignment_change != nullptr);
|
|
||||||
assert(g_signals::parser::attribute_set != nullptr);
|
|
||||||
assert(g_signals::parser::attribute_unset != nullptr);
|
|
||||||
assert(g_signals::parser::attribute_toggle != nullptr);
|
|
||||||
assert(g_signals::parser::font_change != nullptr);
|
|
||||||
assert(g_signals::parser::pixel_offset != nullptr);
|
|
||||||
assert(g_signals::parser::action_block_open != nullptr);
|
|
||||||
assert(g_signals::parser::action_block_close != nullptr);
|
|
||||||
assert(g_signals::parser::ascii_text_write != nullptr);
|
|
||||||
assert(g_signals::parser::unicode_text_write != nullptr);
|
|
||||||
assert(g_signals::parser::string_write != nullptr);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Process input string
|
* Process input string
|
||||||
@ -82,61 +70,61 @@ void parser::codeblock(string data) {
|
|||||||
|
|
||||||
switch (tag) {
|
switch (tag) {
|
||||||
case 'B':
|
case 'B':
|
||||||
g_signals::parser::background_change(parse_color(value, m_bar.background));
|
m_sig.emit(change_background{parse_color(value, m_bar.background)});
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 'F':
|
case 'F':
|
||||||
g_signals::parser::foreground_change(parse_color(value, m_bar.foreground));
|
m_sig.emit(change_foreground{parse_color(value, m_bar.foreground)});
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 'T':
|
case 'T':
|
||||||
g_signals::parser::font_change(parse_fontindex(value));
|
m_sig.emit(change_font{parse_fontindex(value)});
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 'U':
|
case 'U':
|
||||||
g_signals::parser::underline_change(parse_color(value, m_bar.underline.color));
|
m_sig.emit(change_underline{parse_color(value, m_bar.underline.color)});
|
||||||
g_signals::parser::overline_change(parse_color(value, m_bar.overline.color));
|
m_sig.emit(change_overline{parse_color(value, m_bar.overline.color)});
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 'u':
|
case 'u':
|
||||||
g_signals::parser::underline_change(parse_color(value, m_bar.underline.color));
|
m_sig.emit(change_underline{parse_color(value, m_bar.underline.color)});
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 'o':
|
case 'o':
|
||||||
g_signals::parser::overline_change(parse_color(value, m_bar.overline.color));
|
m_sig.emit(change_overline{parse_color(value, m_bar.overline.color)});
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 'R':
|
case 'R':
|
||||||
g_signals::parser::background_change(m_bar.foreground);
|
m_sig.emit(change_background{parse_color(value, m_bar.foreground)});
|
||||||
g_signals::parser::foreground_change(m_bar.background);
|
m_sig.emit(change_foreground{parse_color(value, m_bar.background)});
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 'O':
|
case 'O':
|
||||||
g_signals::parser::pixel_offset(atoi(value.c_str()));
|
m_sig.emit(offset_pixel{static_cast<int16_t>(std::atoi(value.c_str()))});
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 'l':
|
case 'l':
|
||||||
g_signals::parser::alignment_change(alignment::LEFT);
|
m_sig.emit(change_alignment{alignment::LEFT});
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 'c':
|
case 'c':
|
||||||
g_signals::parser::alignment_change(alignment::CENTER);
|
m_sig.emit(change_alignment{alignment::CENTER});
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 'r':
|
case 'r':
|
||||||
g_signals::parser::alignment_change(alignment::RIGHT);
|
m_sig.emit(change_alignment{alignment::RIGHT});
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case '+':
|
case '+':
|
||||||
g_signals::parser::attribute_set(parse_attr(value[0]));
|
m_sig.emit(attribute_set{parse_attr(value[0])});
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case '-':
|
case '-':
|
||||||
g_signals::parser::attribute_unset(parse_attr(value[0]));
|
m_sig.emit(attribute_unset{parse_attr(value[0])});
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case '!':
|
case '!':
|
||||||
g_signals::parser::attribute_toggle(parse_attr(value[0]));
|
m_sig.emit(attribute_toggle{parse_attr(value[0])});
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 'A':
|
case 'A':
|
||||||
@ -145,7 +133,7 @@ void parser::codeblock(string data) {
|
|||||||
mousebtn btn = parse_action_btn(data);
|
mousebtn btn = parse_action_btn(data);
|
||||||
m_actions.push_back(static_cast<int>(btn));
|
m_actions.push_back(static_cast<int>(btn));
|
||||||
|
|
||||||
g_signals::parser::action_block_open(btn, value);
|
m_sig.emit(action_begin{action{btn, value}});
|
||||||
|
|
||||||
// make sure we strip the correct length (btn+wrapping colons)
|
// make sure we strip the correct length (btn+wrapping colons)
|
||||||
if (value[0] != ':') {
|
if (value[0] != ':') {
|
||||||
@ -153,7 +141,7 @@ void parser::codeblock(string data) {
|
|||||||
}
|
}
|
||||||
value += "::";
|
value += "::";
|
||||||
} else if (!m_actions.empty()) {
|
} else if (!m_actions.empty()) {
|
||||||
g_signals::parser::action_block_close(parse_action_btn(value));
|
m_sig.emit(action_end{parse_action_btn(value)});
|
||||||
m_actions.pop_back();
|
m_actions.pop_back();
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
@ -172,7 +160,7 @@ void parser::codeblock(string data) {
|
|||||||
* Process text contents
|
* Process text contents
|
||||||
*/
|
*/
|
||||||
size_t parser::text(string data) {
|
size_t parser::text(string data) {
|
||||||
uint8_t* utf = (uint8_t*)data.c_str();
|
uint8_t* utf = reinterpret_cast<uint8_t*>(const_cast<char*>(data.c_str()));
|
||||||
|
|
||||||
if (utf[0] < 0x80) {
|
if (utf[0] < 0x80) {
|
||||||
// grab all consecutive ascii chars
|
// grab all consecutive ascii chars
|
||||||
@ -184,25 +172,26 @@ size_t parser::text(string data) {
|
|||||||
while (utf[n] != '\0' && utf[++n] < 0x80) {
|
while (utf[n] != '\0' && utf[++n] < 0x80) {
|
||||||
;
|
;
|
||||||
}
|
}
|
||||||
g_signals::parser::string_write(data.substr(0, n).c_str(), n);
|
m_sig.emit(write_text_string{data.substr(0, n)});
|
||||||
return n;
|
return n;
|
||||||
} else if ((utf[0] & 0xe0) == 0xc0) { // 2 byte utf-8 sequence
|
} else if ((utf[0] & 0xe0) == 0xc0) { // 2 byte utf-8 sequence
|
||||||
g_signals::parser::unicode_text_write((utf[0] & 0x1f) << 6 | (utf[1] & 0x3f));
|
m_sig.emit(write_text_unicode{static_cast<uint16_t>((utf[0] & 0x1f) << 6 | (utf[1] & 0x3f))});
|
||||||
return 2;
|
return 2;
|
||||||
} else if ((utf[0] & 0xf0) == 0xe0) { // 3 byte utf-8 sequence
|
} else if ((utf[0] & 0xf0) == 0xe0) { // 3 byte utf-8 sequence
|
||||||
g_signals::parser::unicode_text_write((utf[0] & 0xf) << 12 | (utf[1] & 0x3f) << 6 | (utf[2] & 0x3f));
|
m_sig.emit(
|
||||||
|
write_text_unicode{static_cast<uint16_t>((utf[0] & 0xf) << 12 | (utf[1] & 0x3f) << 6 | (utf[2] & 0x3f))});
|
||||||
return 3;
|
return 3;
|
||||||
} else if ((utf[0] & 0xf8) == 0xf0) { // 4 byte utf-8 sequence
|
} else if ((utf[0] & 0xf8) == 0xf0) { // 4 byte utf-8 sequence
|
||||||
g_signals::parser::unicode_text_write(0xfffd);
|
m_sig.emit(write_text_unicode{static_cast<uint16_t>(0xfffd)});
|
||||||
return 4;
|
return 4;
|
||||||
} else if ((utf[0] & 0xfc) == 0xf8) { // 5 byte utf-8 sequence
|
} else if ((utf[0] & 0xfc) == 0xf8) { // 5 byte utf-8 sequence
|
||||||
g_signals::parser::unicode_text_write(0xfffd);
|
m_sig.emit(write_text_unicode{static_cast<uint16_t>(0xfffd)});
|
||||||
return 5;
|
return 5;
|
||||||
} else if ((utf[0] & 0xfe) == 0xfc) { // 6 byte utf-8 sequence
|
} else if ((utf[0] & 0xfe) == 0xfc) { // 6 byte utf-8 sequence
|
||||||
g_signals::parser::unicode_text_write(0xfffd);
|
m_sig.emit(write_text_unicode{static_cast<uint16_t>(0xfffd)});
|
||||||
return 6;
|
return 6;
|
||||||
} else { // invalid utf-8 sequence
|
} else { // invalid utf-8 sequence
|
||||||
g_signals::parser::ascii_text_write(utf[0]);
|
m_sig.emit(write_text_ascii{utf[0]});
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2,6 +2,9 @@
|
|||||||
#include "components/logger.hpp"
|
#include "components/logger.hpp"
|
||||||
#include "components/types.hpp"
|
#include "components/types.hpp"
|
||||||
#include "errors.hpp"
|
#include "errors.hpp"
|
||||||
|
#include "events/signal.hpp"
|
||||||
|
#include "events/signal_emitter.hpp"
|
||||||
|
#include "events/signal.hpp"
|
||||||
#include "x11/connection.hpp"
|
#include "x11/connection.hpp"
|
||||||
#include "x11/draw.hpp"
|
#include "x11/draw.hpp"
|
||||||
#include "x11/fonts.hpp"
|
#include "x11/fonts.hpp"
|
||||||
@ -12,30 +15,19 @@
|
|||||||
|
|
||||||
POLYBAR_NS
|
POLYBAR_NS
|
||||||
|
|
||||||
/**
|
|
||||||
* Configure injection module
|
|
||||||
*/
|
|
||||||
di::injector<unique_ptr<renderer>> configure_renderer(const bar_settings& bar, const vector<string>& fonts) {
|
|
||||||
// clang-format off
|
|
||||||
return di::make_injector(
|
|
||||||
di::bind<>().to(bar),
|
|
||||||
di::bind<>().to(fonts),
|
|
||||||
configure_connection(),
|
|
||||||
configure_logger(),
|
|
||||||
configure_font_manager());
|
|
||||||
// clang-format on
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Construct renderer instance
|
* Construct renderer instance
|
||||||
*/
|
*/
|
||||||
renderer::renderer(connection& conn, const logger& logger, unique_ptr<font_manager> font_manager,
|
renderer::renderer(connection& conn, signal_emitter& emitter, const logger& logger,
|
||||||
const bar_settings& bar, const vector<string>& fonts)
|
unique_ptr<font_manager> font_manager, const bar_settings& bar, const vector<string>& fonts)
|
||||||
: m_connection(conn)
|
: m_connection(conn)
|
||||||
|
, m_sig(emitter)
|
||||||
, m_log(logger)
|
, m_log(logger)
|
||||||
, m_fontmanager(forward<decltype(font_manager)>(font_manager))
|
, m_fontmanager(forward<decltype(font_manager)>(font_manager))
|
||||||
, m_bar(bar)
|
, m_bar(forward<const bar_settings&>(bar))
|
||||||
, m_rect(bar.inner_area()) {
|
, m_rect(m_bar.inner_area()) {
|
||||||
|
m_sig.attach(this);
|
||||||
|
|
||||||
m_log.trace("renderer: Get TrueColor visual");
|
m_log.trace("renderer: Get TrueColor visual");
|
||||||
m_visual = m_connection.visual_type(m_connection.screen(), 32).get();
|
m_visual = m_connection.visual_type(m_connection.screen(), 32).get();
|
||||||
|
|
||||||
@ -127,11 +119,9 @@ renderer::renderer(connection& conn, const logger& logger, unique_ptr<font_manag
|
|||||||
if (!fonts_loaded && !fonts.empty()) {
|
if (!fonts_loaded && !fonts.empty()) {
|
||||||
m_log.warn("Unable to load fonts, using fallback font \"fixed\"");
|
m_log.warn("Unable to load fonts, using fallback font \"fixed\"");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!fonts_loaded && !m_fontmanager->load("fixed")) {
|
if (!fonts_loaded && !m_fontmanager->load("fixed")) {
|
||||||
throw application_error("Unable to load fonts");
|
throw application_error("Unable to load fonts");
|
||||||
}
|
}
|
||||||
|
|
||||||
m_fontmanager->allocate_color(m_bar.foreground, true);
|
m_fontmanager->allocate_color(m_bar.foreground, true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -140,6 +130,8 @@ renderer::renderer(connection& conn, const logger& logger, unique_ptr<font_manag
|
|||||||
* Deconstruct instance
|
* Deconstruct instance
|
||||||
*/
|
*/
|
||||||
renderer::~renderer() {
|
renderer::~renderer() {
|
||||||
|
m_sig.detach(this);
|
||||||
|
|
||||||
if (m_window != XCB_NONE) {
|
if (m_window != XCB_NONE) {
|
||||||
m_connection.destroy_window(m_window);
|
m_connection.destroy_window(m_window);
|
||||||
}
|
}
|
||||||
@ -183,7 +175,7 @@ void renderer::end() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Redraw window contents
|
* Flush pixmap contents onto the target window
|
||||||
*/
|
*/
|
||||||
void renderer::flush(bool clear) {
|
void renderer::flush(bool clear) {
|
||||||
const xcb_rectangle_t& r = m_rect;
|
const xcb_rectangle_t& r = m_rect;
|
||||||
@ -291,110 +283,14 @@ void renderer::reserve_space(edge side, uint16_t w) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Change value of background gc
|
* Check if given attribute is enabled
|
||||||
*/
|
|
||||||
void renderer::set_background(const uint32_t color) {
|
|
||||||
if (m_colors[gc::BG] == color) {
|
|
||||||
return m_log.trace_x("renderer: ignoring unchanged background color(#%08x)", color);
|
|
||||||
}
|
|
||||||
m_log.trace_x("renderer: set_background(#%08x)", color);
|
|
||||||
m_connection.change_gc(m_gcontexts.at(gc::BG), XCB_GC_FOREGROUND, &color);
|
|
||||||
m_colors[gc::BG] = color;
|
|
||||||
shift_content(0);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Change value of foreground gc
|
|
||||||
*/
|
|
||||||
void renderer::set_foreground(const uint32_t color) {
|
|
||||||
if (m_colors[gc::FG] == color) {
|
|
||||||
return m_log.trace_x("renderer: ignoring unchanged foreground color(#%08x)", color);
|
|
||||||
}
|
|
||||||
m_log.trace_x("renderer: set_foreground(#%08x)", color);
|
|
||||||
m_connection.change_gc(m_gcontexts.at(gc::FG), XCB_GC_FOREGROUND, &color);
|
|
||||||
m_fontmanager->allocate_color(color);
|
|
||||||
m_colors[gc::FG] = color;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Change value of underline gc
|
|
||||||
*/
|
|
||||||
void renderer::set_underline(const uint32_t color) {
|
|
||||||
if (m_colors[gc::UL] == color) {
|
|
||||||
return m_log.trace_x("renderer: ignoring unchanged underline color(#%08x)", color);
|
|
||||||
}
|
|
||||||
m_log.trace_x("renderer: set_underline(#%08x)", color);
|
|
||||||
m_connection.change_gc(m_gcontexts.at(gc::UL), XCB_GC_FOREGROUND, &color);
|
|
||||||
m_colors[gc::UL] = color;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Change value of overline gc
|
|
||||||
*/
|
|
||||||
void renderer::set_overline(const uint32_t color) {
|
|
||||||
if (m_colors[gc::OL] == color) {
|
|
||||||
return m_log.trace_x("renderer: ignoring unchanged overline color(#%08x)", color);
|
|
||||||
}
|
|
||||||
m_log.trace_x("renderer: set_overline(#%08x)", color);
|
|
||||||
m_connection.change_gc(m_gcontexts.at(gc::OL), XCB_GC_FOREGROUND, &color);
|
|
||||||
m_colors[gc::OL] = color;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Change preferred font index used when matching glyphs
|
|
||||||
*/
|
|
||||||
void renderer::set_fontindex(const int8_t font) {
|
|
||||||
if (m_fontindex == font) {
|
|
||||||
return m_log.trace_x("renderer: ignoring unchanged font index(%i)", static_cast<int8_t>(font));
|
|
||||||
}
|
|
||||||
m_log.trace_x("renderer: set_fontindex(%i)", static_cast<int8_t>(font));
|
|
||||||
m_fontmanager->set_preferred_font(font);
|
|
||||||
m_fontindex = font;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Change current alignment
|
|
||||||
*/
|
|
||||||
void renderer::set_alignment(const alignment align) {
|
|
||||||
if (align == m_alignment) {
|
|
||||||
return m_log.trace_x("renderer: ignoring unchanged alignment(%i)", static_cast<uint8_t>(align));
|
|
||||||
}
|
|
||||||
|
|
||||||
m_log.trace_x("renderer: set_alignment(%i)", static_cast<uint8_t>(align));
|
|
||||||
m_alignment = align;
|
|
||||||
m_currentx = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Enable/remove attribute
|
|
||||||
*/
|
|
||||||
void renderer::set_attribute(const attribute attr, bool state) {
|
|
||||||
m_log.trace_x("renderer: set_attribute(%i, %i)", static_cast<uint8_t>(attr), state);
|
|
||||||
|
|
||||||
if (state) {
|
|
||||||
m_attributes |= 1U << static_cast<uint8_t>(attr);
|
|
||||||
} else {
|
|
||||||
m_attributes &= ~(1U << static_cast<uint8_t>(attr));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Toggle attribute
|
|
||||||
*/
|
|
||||||
void renderer::toggle_attribute(const attribute attr) {
|
|
||||||
m_log.trace_x("renderer: toggle_attribute(%i)", static_cast<uint8_t>(attr));
|
|
||||||
m_attributes ^= 1U << static_cast<uint8_t>(attr);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Check if the given attribute is set
|
|
||||||
*/
|
*/
|
||||||
bool renderer::check_attribute(const attribute attr) {
|
bool renderer::check_attribute(const attribute attr) {
|
||||||
return (m_attributes >> static_cast<uint8_t>(attr)) & 1U;
|
return (m_attributes >> static_cast<uint8_t>(attr)) & 1U;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Fill background area
|
* Fill background color
|
||||||
*/
|
*/
|
||||||
void renderer::fill_background() {
|
void renderer::fill_background() {
|
||||||
m_log.trace_x("renderer: fill_background");
|
m_log.trace_x("renderer: fill_background");
|
||||||
@ -402,7 +298,7 @@ void renderer::fill_background() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Fill overline area
|
* Fill overline color
|
||||||
*/
|
*/
|
||||||
void renderer::fill_overline(int16_t x, uint16_t w) {
|
void renderer::fill_overline(int16_t x, uint16_t w) {
|
||||||
if (!check_attribute(attribute::OVERLINE)) {
|
if (!check_attribute(attribute::OVERLINE)) {
|
||||||
@ -415,7 +311,7 @@ void renderer::fill_overline(int16_t x, uint16_t w) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Fill underline area
|
* Fill underline color
|
||||||
*/
|
*/
|
||||||
void renderer::fill_underline(int16_t x, uint16_t w) {
|
void renderer::fill_underline(int16_t x, uint16_t w) {
|
||||||
if (!check_attribute(attribute::UNDERLINE)) {
|
if (!check_attribute(attribute::UNDERLINE)) {
|
||||||
@ -429,7 +325,7 @@ void renderer::fill_underline(int16_t x, uint16_t w) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Shift filled area by given pixels
|
* @see shift_content
|
||||||
*/
|
*/
|
||||||
void renderer::fill_shift(const int16_t px) {
|
void renderer::fill_shift(const int16_t px) {
|
||||||
shift_content(px);
|
shift_content(px);
|
||||||
@ -469,7 +365,7 @@ void renderer::draw_character(uint16_t character) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Draw character glyphs
|
* Draw consecutive character glyphs
|
||||||
*/
|
*/
|
||||||
void renderer::draw_textstring(const char* text, size_t len) {
|
void renderer::draw_textstring(const char* text, size_t len) {
|
||||||
m_log.trace_x("renderer: draw_textstring(\"%s\")", text);
|
m_log.trace_x("renderer: draw_textstring(\"%s\")", text);
|
||||||
@ -493,7 +389,6 @@ void renderer::draw_textstring(const char* text, size_t len) {
|
|||||||
chars.emplace_back(text[++n]);
|
chars.emplace_back(text[++n]);
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: cache
|
|
||||||
auto width = m_fontmanager->char_width(font, chars[0]) * chars.size();
|
auto width = m_fontmanager->char_width(font, chars[0]) * chars.size();
|
||||||
auto x = shift_content(width);
|
auto x = shift_content(width);
|
||||||
auto y = m_rect.height / 2 + font->height / 2 - font->descent + font->offset_y;
|
auto y = m_rect.height / 2 + font->height / 2 - font->descent + font->offset_y;
|
||||||
@ -517,70 +412,14 @@ void renderer::draw_textstring(const char* text, size_t len) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create new action block at the current position
|
* Get completed action blocks
|
||||||
*/
|
|
||||||
void renderer::begin_action(const mousebtn btn, const string& cmd) {
|
|
||||||
action_block action{};
|
|
||||||
action.button = btn;
|
|
||||||
action.align = m_alignment;
|
|
||||||
action.start_x = m_currentx;
|
|
||||||
action.command = string_util::replace_all(cmd, ":", "\\:");
|
|
||||||
action.active = true;
|
|
||||||
if (action.button == mousebtn::NONE) {
|
|
||||||
action.button = mousebtn::LEFT;
|
|
||||||
}
|
|
||||||
m_log.trace_x("renderer: begin_action(%i, %s)", static_cast<uint8_t>(action.button), cmd.c_str());
|
|
||||||
m_actions.emplace_back(action);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* End action block at the current position
|
|
||||||
*/
|
|
||||||
void renderer::end_action(const mousebtn btn) {
|
|
||||||
int16_t clickable_width{0};
|
|
||||||
|
|
||||||
for (auto action = m_actions.rbegin(); action != m_actions.rend(); action++) {
|
|
||||||
if (!action->active || action->align != m_alignment || action->button != btn) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
action->active = false;
|
|
||||||
|
|
||||||
switch (action->align) {
|
|
||||||
case alignment::NONE:
|
|
||||||
break;
|
|
||||||
case alignment::LEFT:
|
|
||||||
action->end_x = m_currentx;
|
|
||||||
break;
|
|
||||||
case alignment::CENTER:
|
|
||||||
clickable_width = m_currentx - action->start_x;
|
|
||||||
action->start_x = m_rect.width / 2 - clickable_width / 2 + action->start_x / 2;
|
|
||||||
action->end_x = action->start_x + clickable_width;
|
|
||||||
break;
|
|
||||||
case alignment::RIGHT:
|
|
||||||
action->start_x = m_rect.width - m_currentx + action->start_x;
|
|
||||||
action->end_x = m_rect.width;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
action->start_x += m_bar.pos.x + m_rect.x;
|
|
||||||
action->end_x += m_bar.pos.x + m_rect.x;
|
|
||||||
|
|
||||||
m_log.trace_x("renderer: end_action(%i, %s, %i)", static_cast<uint8_t>(btn), action->command, action->width());
|
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get all action blocks
|
|
||||||
*/
|
*/
|
||||||
const vector<action_block> renderer::get_actions() {
|
const vector<action_block> renderer::get_actions() {
|
||||||
return m_actions;
|
return m_actions;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Shift contents by given pixel value
|
* Shift pixmap content by given value
|
||||||
*/
|
*/
|
||||||
int16_t renderer::shift_content(int16_t x, const int16_t shift_x) {
|
int16_t renderer::shift_content(int16_t x, const int16_t shift_x) {
|
||||||
m_log.trace_x("renderer: shift_content(%i)", shift_x);
|
m_log.trace_x("renderer: shift_content(%i)", shift_x);
|
||||||
@ -628,7 +467,7 @@ int16_t renderer::shift_content(int16_t x, const int16_t shift_x) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Shift contents by given pixel value
|
* @see shift_content
|
||||||
*/
|
*/
|
||||||
int16_t renderer::shift_content(const int16_t shift_x) {
|
int16_t renderer::shift_content(const int16_t shift_x) {
|
||||||
return shift_content(m_currentx, shift_x);
|
return shift_content(m_currentx, shift_x);
|
||||||
@ -636,7 +475,7 @@ int16_t renderer::shift_content(const int16_t shift_x) {
|
|||||||
|
|
||||||
#ifdef DEBUG_HINTS
|
#ifdef DEBUG_HINTS
|
||||||
/**
|
/**
|
||||||
* Draw debugging hints onto the output window
|
* Draw boxes at the location of each created action block
|
||||||
*/
|
*/
|
||||||
void renderer::debug_hints() {
|
void renderer::debug_hints() {
|
||||||
uint16_t border_width{1};
|
uint16_t border_width{1};
|
||||||
@ -685,4 +524,185 @@ void renderer::debug_hints() {
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
bool renderer::on(const change_background& evt) {
|
||||||
|
uint32_t color{*evt()};
|
||||||
|
|
||||||
|
if (m_colors[gc::BG] == color) {
|
||||||
|
m_log.trace_x("renderer: ignoring unchanged background color(#%08x)", color);
|
||||||
|
} else {
|
||||||
|
m_log.trace_x("renderer: set_background(#%08x)", color);
|
||||||
|
m_connection.change_gc(m_gcontexts.at(gc::BG), XCB_GC_FOREGROUND, &color);
|
||||||
|
m_colors[gc::BG] = color;
|
||||||
|
shift_content(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool renderer::on(const change_foreground& evt) {
|
||||||
|
uint32_t color{*evt()};
|
||||||
|
|
||||||
|
if (m_colors[gc::FG] == color) {
|
||||||
|
m_log.trace_x("renderer: ignoring unchanged foreground color(#%08x)", color);
|
||||||
|
} else {
|
||||||
|
m_log.trace_x("renderer: set_foreground(#%08x)", color);
|
||||||
|
m_connection.change_gc(m_gcontexts.at(gc::FG), XCB_GC_FOREGROUND, &color);
|
||||||
|
m_fontmanager->allocate_color(color);
|
||||||
|
m_colors[gc::FG] = color;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool renderer::on(const change_underline& evt) {
|
||||||
|
uint32_t color{*evt()};
|
||||||
|
|
||||||
|
if (m_colors[gc::UL] == color) {
|
||||||
|
m_log.trace_x("renderer: ignoring unchanged underline color(#%08x)", color);
|
||||||
|
} else {
|
||||||
|
m_log.trace_x("renderer: set_underline(#%08x)", color);
|
||||||
|
m_connection.change_gc(m_gcontexts.at(gc::UL), XCB_GC_FOREGROUND, &color);
|
||||||
|
m_colors[gc::UL] = color;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool renderer::on(const change_overline& evt) {
|
||||||
|
uint32_t color{*evt()};
|
||||||
|
|
||||||
|
if (m_colors[gc::OL] == color) {
|
||||||
|
m_log.trace_x("renderer: ignoring unchanged overline color(#%08x)", color);
|
||||||
|
} else {
|
||||||
|
m_log.trace_x("renderer: set_overline(#%08x)", color);
|
||||||
|
m_connection.change_gc(m_gcontexts.at(gc::OL), XCB_GC_FOREGROUND, &color);
|
||||||
|
m_colors[gc::OL] = color;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool renderer::on(const change_font& evt) {
|
||||||
|
int8_t font{*evt()};
|
||||||
|
|
||||||
|
if (m_fontindex == font) {
|
||||||
|
m_log.trace_x("renderer: ignoring unchanged font index(%i)", static_cast<int8_t>(font));
|
||||||
|
} else {
|
||||||
|
m_log.trace_x("renderer: set_fontindex(%i)", static_cast<int8_t>(font));
|
||||||
|
m_fontmanager->set_preferred_font(font);
|
||||||
|
m_fontindex = font;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool renderer::on(const change_alignment& evt) {
|
||||||
|
alignment align{*evt()};
|
||||||
|
|
||||||
|
if (align == m_alignment) {
|
||||||
|
m_log.trace_x("renderer: ignoring unchanged alignment(%i)", static_cast<uint8_t>(align));
|
||||||
|
} else {
|
||||||
|
m_log.trace_x("renderer: set_alignment(%i)", static_cast<uint8_t>(align));
|
||||||
|
m_alignment = align;
|
||||||
|
m_currentx = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool renderer::on(const offset_pixel& evt) {
|
||||||
|
shift_content(*evt());
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool renderer::on(const attribute_set& evt) {
|
||||||
|
m_log.trace_x("renderer: attribute_set(%i, %i)", static_cast<uint8_t>(*evt()), true);
|
||||||
|
m_attributes |= 1U << static_cast<uint8_t>(*evt());
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool renderer::on(const attribute_unset& evt) {
|
||||||
|
m_log.trace_x("renderer: attribute_unset(%i, %i)", static_cast<uint8_t>(*evt()), true);
|
||||||
|
m_attributes &= ~(1U << static_cast<uint8_t>(*evt()));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool renderer::on(const attribute_toggle& evt) {
|
||||||
|
m_log.trace_x("renderer: attribute_toggle(%i)", static_cast<uint8_t>(*evt()));
|
||||||
|
m_attributes ^= 1U << static_cast<uint8_t>(*evt());
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool renderer::on(const action_begin& evt) {
|
||||||
|
action a{*evt()};
|
||||||
|
action_block action{};
|
||||||
|
action.button = a.button;
|
||||||
|
action.align = m_alignment;
|
||||||
|
action.start_x = m_currentx;
|
||||||
|
action.command = string_util::replace_all(a.command, ":", "\\:");
|
||||||
|
action.active = true;
|
||||||
|
|
||||||
|
if (action.button == mousebtn::NONE) {
|
||||||
|
action.button = mousebtn::LEFT;
|
||||||
|
}
|
||||||
|
|
||||||
|
m_log.trace_x("renderer: action_begin(%i, %s)", static_cast<uint8_t>(a.button), a.command.c_str());
|
||||||
|
m_actions.emplace_back(action);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool renderer::on(const action_end& evt) {
|
||||||
|
mousebtn btn{*evt()};
|
||||||
|
int16_t clickable_width{0};
|
||||||
|
|
||||||
|
for (auto action = m_actions.rbegin(); action != m_actions.rend(); action++) {
|
||||||
|
if (!action->active || action->align != m_alignment || action->button != btn) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
action->active = false;
|
||||||
|
|
||||||
|
switch (action->align) {
|
||||||
|
case alignment::NONE:
|
||||||
|
break;
|
||||||
|
case alignment::LEFT:
|
||||||
|
action->end_x = m_currentx;
|
||||||
|
break;
|
||||||
|
case alignment::CENTER:
|
||||||
|
clickable_width = m_currentx - action->start_x;
|
||||||
|
action->start_x = m_rect.width / 2 - clickable_width / 2 + action->start_x / 2;
|
||||||
|
action->end_x = action->start_x + clickable_width;
|
||||||
|
break;
|
||||||
|
case alignment::RIGHT:
|
||||||
|
action->start_x = m_rect.width - m_currentx + action->start_x;
|
||||||
|
action->end_x = m_rect.width;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
action->start_x += m_bar.pos.x + m_rect.x;
|
||||||
|
action->end_x += m_bar.pos.x + m_rect.x;
|
||||||
|
|
||||||
|
m_log.trace_x("renderer: action_end(%i, %s, %i)", static_cast<uint8_t>(btn), action->command, action->width());
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool renderer::on(const write_text_ascii& evt) {
|
||||||
|
draw_character(*evt());
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool renderer::on(const write_text_unicode& evt) {
|
||||||
|
draw_character(*evt());
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool renderer::on(const write_text_string& evt) {
|
||||||
|
string text{*evt()};
|
||||||
|
draw_textstring(text.c_str(), text.size());
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
POLYBAR_NS_END
|
POLYBAR_NS_END
|
||||||
|
@ -5,33 +5,28 @@
|
|||||||
#include "components/eventloop.hpp"
|
#include "components/eventloop.hpp"
|
||||||
#include "components/logger.hpp"
|
#include "components/logger.hpp"
|
||||||
#include "components/screen.hpp"
|
#include "components/screen.hpp"
|
||||||
#include "components/signals.hpp"
|
|
||||||
#include "components/types.hpp"
|
#include "components/types.hpp"
|
||||||
|
#include "events/signal.hpp"
|
||||||
|
#include "events/signal_emitter.hpp"
|
||||||
#include "x11/connection.hpp"
|
#include "x11/connection.hpp"
|
||||||
#include "x11/randr.hpp"
|
#include "x11/randr.hpp"
|
||||||
#include "x11/winspec.hpp"
|
#include "x11/winspec.hpp"
|
||||||
|
|
||||||
POLYBAR_NS
|
POLYBAR_NS
|
||||||
|
|
||||||
/**
|
using namespace signals::eventloop;
|
||||||
* Configure injection module
|
|
||||||
*/
|
|
||||||
di::injector<unique_ptr<screen>> configure_screen() {
|
|
||||||
return di::make_injector(configure_connection(), configure_logger(), configure_config());
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Construct screen instance
|
* Construct screen instance
|
||||||
*/
|
*/
|
||||||
screen::screen(connection& conn, const logger& logger, const config& conf)
|
screen::screen(connection& conn, signal_emitter& emitter, const logger& logger, const config& conf)
|
||||||
: m_connection(conn)
|
: m_connection(conn)
|
||||||
|
, m_sig(emitter)
|
||||||
, m_log(logger)
|
, m_log(logger)
|
||||||
, m_conf(conf)
|
, m_conf(conf)
|
||||||
, m_root(conn.root())
|
, m_root(conn.root())
|
||||||
, m_monitors(randr_util::get_monitors(m_connection, m_root, true))
|
, m_monitors(randr_util::get_monitors(m_connection, m_root, true))
|
||||||
, m_size({conn.screen()->width_in_pixels, conn.screen()->height_in_pixels}) {
|
, m_size({conn.screen()->width_in_pixels, conn.screen()->height_in_pixels}) {
|
||||||
assert(g_signals::event::enqueue != nullptr);
|
|
||||||
|
|
||||||
// Check if the reloading has been disabled by the user
|
// Check if the reloading has been disabled by the user
|
||||||
if (!m_conf.get<bool>("settings", "screenchange-reload", false)) {
|
if (!m_conf.get<bool>("settings", "screenchange-reload", false)) {
|
||||||
return;
|
return;
|
||||||
@ -105,8 +100,8 @@ void screen::handle(const evt::randr_screen_change_notify& evt) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
m_log.warn("randr_screen_change_notify (%ux%u)... reloading", evt->width, evt->height);
|
m_log.warn("randr_screen_change_notify (%ux%u)... reloading", evt->width, evt->height);
|
||||||
|
m_sig.emit(process_quit{eventloop::make_quit_evt(true)});
|
||||||
m_sigraised = true;
|
m_sigraised = true;
|
||||||
g_signals::event::enqueue(eventloop::make(quit_event{}, true));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
POLYBAR_NS_END
|
POLYBAR_NS_END
|
||||||
|
@ -1,45 +0,0 @@
|
|||||||
#include "components/signals.hpp"
|
|
||||||
#include "components/types.hpp"
|
|
||||||
|
|
||||||
POLYBAR_NS
|
|
||||||
|
|
||||||
namespace g_signals {
|
|
||||||
/**
|
|
||||||
* Signals used to communicate with the event loop
|
|
||||||
*/
|
|
||||||
namespace event {
|
|
||||||
callback<const eventloop::entry_t&> enqueue{noop<const eventloop::entry_t&>};
|
|
||||||
callback<const eventloop::entry_t&> enqueue_delayed{noop<const eventloop::entry_t&>};
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Signals used to communicate with the bar window
|
|
||||||
*/
|
|
||||||
namespace bar {
|
|
||||||
callback<const string> action_click{noop<const string>};
|
|
||||||
callback<const bool> visibility_change{noop<const bool>};
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Signals used to communicate with the input parser
|
|
||||||
*/
|
|
||||||
namespace parser {
|
|
||||||
callback<const uint32_t> background_change{noop<const uint32_t>};
|
|
||||||
callback<const uint32_t> foreground_change{noop<const uint32_t>};
|
|
||||||
callback<const uint32_t> underline_change{noop<const uint32_t>};
|
|
||||||
callback<const uint32_t> overline_change{noop<const uint32_t>};
|
|
||||||
callback<const alignment> alignment_change{noop<const alignment>};
|
|
||||||
callback<const attribute> attribute_set{noop<const attribute>};
|
|
||||||
callback<const attribute> attribute_unset{noop<const attribute>};
|
|
||||||
callback<const attribute> attribute_toggle{noop<const attribute>};
|
|
||||||
callback<const int8_t> font_change{noop<const int8_t>};
|
|
||||||
callback<const int16_t> pixel_offset{noop<const int16_t>};
|
|
||||||
callback<const mousebtn, const string> action_block_open{noop<const mousebtn, const string>};
|
|
||||||
callback<const mousebtn> action_block_close{noop<const mousebtn>};
|
|
||||||
callback<const uint16_t> ascii_text_write{noop<const uint16_t>};
|
|
||||||
callback<const uint16_t> unicode_text_write{noop<const uint16_t>};
|
|
||||||
callback<const char*, const size_t> string_write{noop<const char*, const size_t>};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
POLYBAR_NS_END
|
|
@ -61,7 +61,7 @@ namespace drawtypes {
|
|||||||
|
|
||||||
auto framerate = conf.get<int>(section, name + "-framerate", 1000);
|
auto framerate = conf.get<int>(section, name + "-framerate", 1000);
|
||||||
|
|
||||||
return make_shared<animation>(move(vec), framerate);
|
return factory_util::shared<animation>(move(vec), framerate);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -19,7 +19,7 @@ namespace drawtypes {
|
|||||||
std::back_insert_iterator<decltype(tokens)> back_it(tokens);
|
std::back_insert_iterator<decltype(tokens)> back_it(tokens);
|
||||||
std::copy(m_tokens.begin(), m_tokens.end(), back_it);
|
std::copy(m_tokens.begin(), m_tokens.end(), back_it);
|
||||||
}
|
}
|
||||||
return make_shared<label>(m_text, m_foreground, m_background, m_underline, m_overline, m_font, m_padding, m_margin,
|
return factory_util::shared<label>(m_text, m_foreground, m_background, m_underline, m_overline, m_font, m_padding, m_margin,
|
||||||
m_maxlen, m_ellipsis, move(tokens));
|
m_maxlen, m_ellipsis, move(tokens));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -145,7 +145,7 @@ namespace drawtypes {
|
|||||||
auto value = conf.get<int>(section, key, 0);
|
auto value = conf.get<int>(section, key, 0);
|
||||||
auto left = conf.get<int>(section, key + "-left", value);
|
auto left = conf.get<int>(section, key + "-left", value);
|
||||||
auto right = conf.get<int>(section, key + "-right", value);
|
auto right = conf.get<int>(section, key + "-right", value);
|
||||||
return side_values {static_cast<uint16_t>(left), static_cast<uint16_t>(right)};
|
return side_values{static_cast<uint16_t>(left), static_cast<uint16_t>(right)};
|
||||||
};
|
};
|
||||||
|
|
||||||
padding = get_left_right(name + "-padding");
|
padding = get_left_right(name + "-padding");
|
||||||
|
@ -45,7 +45,7 @@ namespace drawtypes {
|
|||||||
vec.emplace_back(move(icon));
|
vec.emplace_back(move(icon));
|
||||||
}
|
}
|
||||||
|
|
||||||
return make_shared<ramp>(move(vec));
|
return factory_util::shared<ramp>(move(vec));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
8
src/events/signal_emitter.cpp
Normal file
8
src/events/signal_emitter.cpp
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
#include "events/signal_emitter.hpp"
|
||||||
|
#include "events/signal_receiver.hpp"
|
||||||
|
|
||||||
|
POLYBAR_NS
|
||||||
|
|
||||||
|
signal_receivers_t g_signal_receivers;
|
||||||
|
|
||||||
|
POLYBAR_NS_END
|
1
src/events/signal_receiver.cpp
Normal file
1
src/events/signal_receiver.cpp
Normal file
@ -0,0 +1 @@
|
|||||||
|
#include "events/signal_receiver.hpp"
|
84
src/main.cpp
84
src/main.cpp
@ -2,7 +2,6 @@
|
|||||||
|
|
||||||
#include "common.hpp"
|
#include "common.hpp"
|
||||||
|
|
||||||
#include "components/bar.hpp"
|
|
||||||
#include "components/command_line.hpp"
|
#include "components/command_line.hpp"
|
||||||
#include "components/config.hpp"
|
#include "components/config.hpp"
|
||||||
#include "components/controller.hpp"
|
#include "components/controller.hpp"
|
||||||
@ -11,7 +10,6 @@
|
|||||||
#include "utils/env.hpp"
|
#include "utils/env.hpp"
|
||||||
#include "utils/inotify.hpp"
|
#include "utils/inotify.hpp"
|
||||||
#include "utils/process.hpp"
|
#include "utils/process.hpp"
|
||||||
#include "x11/ewmh.hpp"
|
|
||||||
#include "x11/xutils.hpp"
|
#include "x11/xutils.hpp"
|
||||||
|
|
||||||
using namespace polybar;
|
using namespace polybar;
|
||||||
@ -34,55 +32,69 @@ int main(int argc, char** argv) {
|
|||||||
};
|
};
|
||||||
// clang-format on
|
// clang-format on
|
||||||
|
|
||||||
logger& logger{configure_logger<decltype(logger)>(loglevel::WARNING).create<decltype(logger)>()};
|
|
||||||
|
|
||||||
uint8_t exit_code{EXIT_SUCCESS};
|
uint8_t exit_code{EXIT_SUCCESS};
|
||||||
bool reload{false};
|
bool reload{false};
|
||||||
|
|
||||||
|
logger& logger{const_cast<class logger&>(make_logger(loglevel::WARNING))};
|
||||||
|
|
||||||
try {
|
try {
|
||||||
//==================================================
|
//==================================================
|
||||||
// Connect to X server
|
// Connect to X server
|
||||||
//==================================================
|
//==================================================
|
||||||
XInitThreads();
|
XInitThreads();
|
||||||
|
xcb_connection_t* xcbconn{nullptr};
|
||||||
|
|
||||||
if (!xutils::get_connection()) {
|
if ((xcbconn = xutils::get_connection()) == nullptr) {
|
||||||
logger.err("A connection to X could not be established... ");
|
logger.err("A connection to X could not be established... ");
|
||||||
throw exit_failure{};
|
throw exit_failure{};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
connection{xcbconn}.preload_atoms();
|
||||||
|
connection{xcbconn}.query_extensions();
|
||||||
|
|
||||||
|
//==================================================
|
||||||
|
// Block all signals by default
|
||||||
|
//==================================================
|
||||||
|
sigset_t blockmask;
|
||||||
|
sigfillset(&blockmask);
|
||||||
|
|
||||||
|
if (pthread_sigmask(SIG_BLOCK, &blockmask, nullptr) == -1) {
|
||||||
|
throw system_error("Failed to block signals");
|
||||||
|
}
|
||||||
|
|
||||||
//==================================================
|
//==================================================
|
||||||
// Parse command line arguments
|
// Parse command line arguments
|
||||||
//==================================================
|
//==================================================
|
||||||
string scriptname{argv[0]};
|
string scriptname{argv[0]};
|
||||||
vector<string> args(argv + 1, argv + argc);
|
vector<string> args(argv + 1, argv + argc);
|
||||||
|
|
||||||
cliparser cli{configure_cliparser<decltype(cli)>(scriptname, opts).create<decltype(cli)>()};
|
unique_ptr<cliparser> cli{make_command_line(scriptname, opts)};
|
||||||
cli.process_input(args);
|
cli->process_input(args);
|
||||||
|
|
||||||
if (cli.has("quiet")) {
|
if (cli->has("quiet")) {
|
||||||
logger.verbosity(loglevel::ERROR);
|
logger.verbosity(loglevel::ERROR);
|
||||||
} else if (cli.has("log")) {
|
} else if (cli->has("log")) {
|
||||||
logger.verbosity(cli.get("log"));
|
logger.verbosity(cli->get("log"));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (cli.has("help")) {
|
if (cli->has("help")) {
|
||||||
cli.usage();
|
cli->usage();
|
||||||
throw exit_success{};
|
throw exit_success{};
|
||||||
} else if (cli.has("version")) {
|
} else if (cli->has("version")) {
|
||||||
print_build_info(version_details(args));
|
print_build_info(version_details(args));
|
||||||
throw exit_success{};
|
throw exit_success{};
|
||||||
} else if (args.empty() || args[0][0] == '-') {
|
} else if (args.empty() || args[0][0] == '-') {
|
||||||
cli.usage();
|
cli->usage();
|
||||||
throw exit_failure{};
|
throw exit_failure{};
|
||||||
}
|
}
|
||||||
|
|
||||||
//==================================================
|
//==================================================
|
||||||
// Load user configuration
|
// Load user configuration
|
||||||
//==================================================
|
//==================================================
|
||||||
config& conf{configure_config<decltype(conf)>().create<decltype(conf)>()};
|
config& conf{const_cast<config&>(make_confreader())};
|
||||||
|
|
||||||
if (cli.has("config")) {
|
if (cli->has("config")) {
|
||||||
conf.load(cli.get("config"), args[0]);
|
conf.load(cli->get("config"), args[0]);
|
||||||
} else if (env_util::has("XDG_CONFIG_HOME")) {
|
} else if (env_util::has("XDG_CONFIG_HOME")) {
|
||||||
conf.load(env_util::get("XDG_CONFIG_HOME") + "/polybar/config", args[0]);
|
conf.load(env_util::get("XDG_CONFIG_HOME") + "/polybar/config", args[0]);
|
||||||
} else if (env_util::has("HOME")) {
|
} else if (env_util::has("HOME")) {
|
||||||
@ -94,37 +106,43 @@ int main(int argc, char** argv) {
|
|||||||
//==================================================
|
//==================================================
|
||||||
// Dump requested data
|
// Dump requested data
|
||||||
//==================================================
|
//==================================================
|
||||||
if (cli.has("dump")) {
|
if (cli->has("dump")) {
|
||||||
std::cout << conf.get<string>(conf.bar_section(), cli.get("dump")) << std::endl;
|
std::cout << conf.get<string>(conf.bar_section(), cli->get("dump")) << std::endl;
|
||||||
throw exit_success{};
|
throw exit_success{};
|
||||||
}
|
}
|
||||||
|
|
||||||
//==================================================
|
//==================================================
|
||||||
// Create config watch if we should track changes
|
// Create controller and run application
|
||||||
//==================================================
|
//==================================================
|
||||||
inotify_util::watch_t watch;
|
unique_ptr<controller> ctrl;
|
||||||
|
bool enable_ipc{conf.get<bool>(conf.bar_section(), "enable-ipc", false)};
|
||||||
|
watch_t confwatch;
|
||||||
|
|
||||||
if (cli.has("reload")) {
|
if (cli->has("print-wmname")) {
|
||||||
watch = inotify_util::make_watch(conf.filepath());
|
enable_ipc = false;
|
||||||
|
} else if (cli->has("reload")) {
|
||||||
|
inotify_util::make_watch(conf.filepath());
|
||||||
}
|
}
|
||||||
|
|
||||||
//==================================================
|
ctrl = make_controller(move(confwatch), enable_ipc, cli->has("stdout"));
|
||||||
// Create controller
|
|
||||||
//==================================================
|
|
||||||
auto ctrl = configure_controller(watch).create<unique_ptr<controller>>();
|
|
||||||
|
|
||||||
ctrl->bootstrap(cli.has("stdout"), cli.has("print-wmname"));
|
if (cli->has("print-wmname")) {
|
||||||
|
std::cout << ctrl->opts().wmname << std::endl;
|
||||||
if (cli.has("print-wmname")) {
|
|
||||||
throw exit_success{};
|
throw exit_success{};
|
||||||
}
|
}
|
||||||
|
|
||||||
//==================================================
|
ctrl->setup();
|
||||||
// Run application
|
|
||||||
//==================================================
|
|
||||||
if (!ctrl->run()) {
|
if (!ctrl->run()) {
|
||||||
reload = true;
|
reload = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//==================================================
|
||||||
|
// Unblock signals
|
||||||
|
//==================================================
|
||||||
|
if (pthread_sigmask(SIG_UNBLOCK, &blockmask, nullptr) == -1) {
|
||||||
|
throw system_error("Failed to unblock signals");
|
||||||
|
}
|
||||||
} catch (const exit_success& term) {
|
} catch (const exit_success& term) {
|
||||||
exit_code = EXIT_SUCCESS;
|
exit_code = EXIT_SUCCESS;
|
||||||
} catch (const exit_failure& term) {
|
} catch (const exit_failure& term) {
|
||||||
|
@ -118,13 +118,13 @@ namespace modules {
|
|||||||
m_modelabels.emplace(mode::NODE_PRIVATE, load_optional_label(m_conf, name(), "label-private"));
|
m_modelabels.emplace(mode::NODE_PRIVATE, load_optional_label(m_conf, name(), "label-private"));
|
||||||
}
|
}
|
||||||
|
|
||||||
m_icons = make_shared<iconset>();
|
m_icons = factory_util::shared<iconset>();
|
||||||
m_icons->add(DEFAULT_ICON, make_shared<label>(m_conf.get<string>(name(), DEFAULT_ICON, "")));
|
m_icons->add(DEFAULT_ICON, factory_util::shared<label>(m_conf.get<string>(name(), DEFAULT_ICON, "")));
|
||||||
|
|
||||||
for (const auto& workspace : m_conf.get_list<string>(name(), "ws-icon", {})) {
|
for (const auto& workspace : m_conf.get_list<string>(name(), "ws-icon", {})) {
|
||||||
auto vec = string_util::split(workspace, ';');
|
auto vec = string_util::split(workspace, ';');
|
||||||
if (vec.size() == 2) {
|
if (vec.size() == 2) {
|
||||||
m_icons->add(vec[0], make_shared<label>(vec[1]));
|
m_icons->add(vec[0], factory_util::shared<label>(vec[1]));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -55,13 +55,13 @@ namespace modules {
|
|||||||
m_modelabel = load_optional_label(m_conf, name(), "label-mode", "%mode%");
|
m_modelabel = load_optional_label(m_conf, name(), "label-mode", "%mode%");
|
||||||
}
|
}
|
||||||
|
|
||||||
m_icons = make_shared<iconset>();
|
m_icons = factory_util::shared<iconset>();
|
||||||
m_icons->add(DEFAULT_WS_ICON, make_shared<label>(m_conf.get<string>(name(), DEFAULT_WS_ICON, "")));
|
m_icons->add(DEFAULT_WS_ICON, factory_util::shared<label>(m_conf.get<string>(name(), DEFAULT_WS_ICON, "")));
|
||||||
|
|
||||||
for (const auto& workspace : m_conf.get_list<string>(name(), "ws-icon", {})) {
|
for (const auto& workspace : m_conf.get_list<string>(name(), "ws-icon", {})) {
|
||||||
auto vec = string_util::split(workspace, ';');
|
auto vec = string_util::split(workspace, ';');
|
||||||
if (vec.size() == 2) {
|
if (vec.size() == 2) {
|
||||||
m_icons->add(vec[0], make_shared<label>(vec[1]));
|
m_icons->add(vec[0], factory_util::shared<label>(vec[1]));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -30,7 +30,7 @@ namespace modules {
|
|||||||
|
|
||||||
m_formatter->add(FORMAT_OFFLINE, "", {TAG_LABEL_OFFLINE});
|
m_formatter->add(FORMAT_OFFLINE, "", {TAG_LABEL_OFFLINE});
|
||||||
|
|
||||||
m_icons = make_shared<iconset>();
|
m_icons = factory_util::shared<iconset>();
|
||||||
|
|
||||||
if (m_formatter->has(TAG_ICON_PLAY) || m_formatter->has(TAG_TOGGLE) || m_formatter->has(TAG_TOGGLE_STOP)) {
|
if (m_formatter->has(TAG_ICON_PLAY) || m_formatter->has(TAG_TOGGLE) || m_formatter->has(TAG_TOGGLE_STOP)) {
|
||||||
m_icons->add("play", load_icon(m_conf, name(), TAG_ICON_PLAY));
|
m_icons->add("play", load_icon(m_conf, name(), TAG_ICON_PLAY));
|
||||||
|
@ -21,7 +21,7 @@ namespace modules {
|
|||||||
*/
|
*/
|
||||||
xbacklight_module::xbacklight_module(const bar_settings& bar, const logger& logger, const config& config, string name)
|
xbacklight_module::xbacklight_module(const bar_settings& bar, const logger& logger, const config& config, string name)
|
||||||
: static_module<xbacklight_module>(bar, logger, config, name)
|
: static_module<xbacklight_module>(bar, logger, config, name)
|
||||||
, m_connection(configure_connection().create<connection&>()) {}
|
, m_connection(make_connection()) {}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Bootstrap the module by grabbing all required components
|
* Bootstrap the module by grabbing all required components
|
||||||
@ -60,9 +60,6 @@ namespace modules {
|
|||||||
throw module_error("Failed to create event proxy");
|
throw module_error("Failed to create event proxy");
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get the throttle time
|
|
||||||
m_randrnotify.offset = xutils::event_timer_ms(m_conf, xcb_randr_notify_event_t{});
|
|
||||||
|
|
||||||
// Connect with the event registry and make sure we get
|
// Connect with the event registry and make sure we get
|
||||||
// notified when a RandR output property gets modified
|
// notified when a RandR output property gets modified
|
||||||
m_connection.attach_sink(this, SINK_PRIORITY_MODULE);
|
m_connection.attach_sink(this, SINK_PRIORITY_MODULE);
|
||||||
@ -106,8 +103,6 @@ namespace modules {
|
|||||||
return;
|
return;
|
||||||
} else if (evt->u.op.atom != m_output->backlight.atom) {
|
} else if (evt->u.op.atom != m_output->backlight.atom) {
|
||||||
return;
|
return;
|
||||||
} else if (m_randrnotify.deny(evt->u.op.timestamp)) {
|
|
||||||
return m_log.trace_x("%s: Ignoring randr notify (throttled)...", name());
|
|
||||||
} else {
|
} else {
|
||||||
update();
|
update();
|
||||||
}
|
}
|
||||||
@ -142,8 +137,8 @@ namespace modules {
|
|||||||
// with the cmd handlers
|
// with the cmd handlers
|
||||||
string output{module::get_output()};
|
string output{module::get_output()};
|
||||||
|
|
||||||
m_builder->cmd(mousebtn::SCROLL_UP, EVENT_SCROLLUP, m_scroll && m_percentage < 100);
|
m_builder->cmd(mousebtn::SCROLL_UP, string{EVENT_SCROLLUP}, m_scroll && m_percentage < 100);
|
||||||
m_builder->cmd(mousebtn::SCROLL_DOWN, EVENT_SCROLLDOWN, m_scroll && m_percentage > 0);
|
m_builder->cmd(mousebtn::SCROLL_DOWN, string{EVENT_SCROLLDOWN}, m_scroll && m_percentage > 0);
|
||||||
|
|
||||||
m_builder->append(output);
|
m_builder->append(output);
|
||||||
|
|
||||||
|
@ -18,7 +18,7 @@ namespace modules {
|
|||||||
*/
|
*/
|
||||||
xkeyboard_module::xkeyboard_module(const bar_settings& bar, const logger& logger, const config& config, string name)
|
xkeyboard_module::xkeyboard_module(const bar_settings& bar, const logger& logger, const config& config, string name)
|
||||||
: static_module<xkeyboard_module>(bar, logger, config, name)
|
: static_module<xkeyboard_module>(bar, logger, config, name)
|
||||||
, m_connection(configure_connection().create<connection&>()) {}
|
, m_connection(make_connection()) {}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Bootstrap the module
|
* Bootstrap the module
|
||||||
|
@ -18,7 +18,7 @@ namespace modules {
|
|||||||
* currently active to enable title tracking
|
* currently active to enable title tracking
|
||||||
*/
|
*/
|
||||||
active_window::active_window(xcb_window_t win)
|
active_window::active_window(xcb_window_t win)
|
||||||
: m_connection(configure_connection().create<decltype(m_connection)>()), m_window(m_connection, win) {
|
: m_connection(make_connection()), m_window(m_connection, win) {
|
||||||
try {
|
try {
|
||||||
m_window.change_event_mask(XCB_EVENT_MASK_PROPERTY_CHANGE);
|
m_window.change_event_mask(XCB_EVENT_MASK_PROPERTY_CHANGE);
|
||||||
} catch (const xpp::x::error::window& err) {
|
} catch (const xpp::x::error::window& err) {
|
||||||
@ -66,7 +66,7 @@ namespace modules {
|
|||||||
*/
|
*/
|
||||||
xwindow_module::xwindow_module(const bar_settings& bar, const logger& logger, const config& config, string name)
|
xwindow_module::xwindow_module(const bar_settings& bar, const logger& logger, const config& config, string name)
|
||||||
: static_module<xwindow_module>(bar, logger, config, name)
|
: static_module<xwindow_module>(bar, logger, config, name)
|
||||||
, m_connection(configure_connection().create<connection&>()) {}
|
, m_connection(make_connection()) {}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Bootstrap the module
|
* Bootstrap the module
|
||||||
|
@ -22,7 +22,7 @@ namespace modules {
|
|||||||
xworkspaces_module::xworkspaces_module(
|
xworkspaces_module::xworkspaces_module(
|
||||||
const bar_settings& bar, const logger& logger, const config& config, string name)
|
const bar_settings& bar, const logger& logger, const config& config, string name)
|
||||||
: static_module<xworkspaces_module>(bar, logger, config, name)
|
: static_module<xworkspaces_module>(bar, logger, config, name)
|
||||||
, m_connection(configure_connection().create<connection&>()) {}
|
, m_connection(make_connection()) {}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Bootstrap the module
|
* Bootstrap the module
|
||||||
@ -73,13 +73,13 @@ namespace modules {
|
|||||||
// clang-format on
|
// clang-format on
|
||||||
}
|
}
|
||||||
|
|
||||||
m_icons = make_shared<iconset>();
|
m_icons = factory_util::shared<iconset>();
|
||||||
m_icons->add(DEFAULT_ICON, make_shared<label>(m_conf.get<string>(name(), DEFAULT_ICON, "")));
|
m_icons->add(DEFAULT_ICON, factory_util::shared<label>(m_conf.get<string>(name(), DEFAULT_ICON, "")));
|
||||||
|
|
||||||
for (const auto& workspace : m_conf.get_list<string>(name(), "icon", {})) {
|
for (const auto& workspace : m_conf.get_list<string>(name(), "icon", {})) {
|
||||||
auto vec = string_util::split(workspace, ';');
|
auto vec = string_util::split(workspace, ';');
|
||||||
if (vec.size() == 2) {
|
if (vec.size() == 2) {
|
||||||
m_icons->add(vec[0], make_shared<label>(vec[1]));
|
m_icons->add(vec[0], factory_util::shared<label>(vec[1]));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -105,14 +105,13 @@ namespace inotify_util {
|
|||||||
return m_path;
|
return m_path;
|
||||||
}
|
}
|
||||||
|
|
||||||
watch_t make_watch(string path) {
|
|
||||||
di::injector<watch_t> injector = di::make_injector(di::bind<>().to(path));
|
|
||||||
return injector.create<watch_t>();
|
|
||||||
}
|
|
||||||
|
|
||||||
bool match(const event_t* evt, int mask) {
|
bool match(const event_t* evt, int mask) {
|
||||||
return (evt->mask & mask) == mask;
|
return (evt->mask & mask) == mask;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
watch_t make_watch(string path) {
|
||||||
|
return watch_t{new watch_t::element_type{path}};
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
POLYBAR_NS_END
|
POLYBAR_NS_END
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
#include <iomanip>
|
#include <iomanip>
|
||||||
#include <utility>
|
#include <utility>
|
||||||
|
#include <map>
|
||||||
|
|
||||||
#include "errors.hpp"
|
#include "errors.hpp"
|
||||||
#include "utils/color.hpp"
|
#include "utils/color.hpp"
|
||||||
@ -8,7 +9,7 @@
|
|||||||
|
|
||||||
POLYBAR_NS
|
POLYBAR_NS
|
||||||
|
|
||||||
map<string, color> g_colorstore;
|
std::map<string, color> g_colorstore;
|
||||||
color g_colorempty{"#00000000"};
|
color g_colorempty{"#00000000"};
|
||||||
color g_colorblack{"#ff000000"};
|
color g_colorblack{"#ff000000"};
|
||||||
color g_colorwhite{"#ffffffff"};
|
color g_colorwhite{"#ffffffff"};
|
||||||
|
@ -8,14 +8,6 @@
|
|||||||
|
|
||||||
POLYBAR_NS
|
POLYBAR_NS
|
||||||
|
|
||||||
/**
|
|
||||||
* Configure injection module
|
|
||||||
*/
|
|
||||||
di::injector<connection&> configure_connection() {
|
|
||||||
return di::make_injector(di::bind<>().to(
|
|
||||||
factory_util::generic_singleton<connection>(xutils::get_connection(), xutils::get_connection_fd())));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Preload required xcb atoms
|
* Preload required xcb atoms
|
||||||
*/
|
*/
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
#include <X11/Xlib-xcb.h>
|
#include <X11/Xlib-xcb.h>
|
||||||
|
|
||||||
#include "utils/color.hpp"
|
#include "utils/color.hpp"
|
||||||
|
#include "utils/factory.hpp"
|
||||||
#include "utils/memory.hpp"
|
#include "utils/memory.hpp"
|
||||||
#include "x11/connection.hpp"
|
#include "x11/connection.hpp"
|
||||||
#include "x11/fonts.hpp"
|
#include "x11/fonts.hpp"
|
||||||
@ -12,8 +13,8 @@ POLYBAR_NS
|
|||||||
/**
|
/**
|
||||||
* Configure injection module
|
* Configure injection module
|
||||||
*/
|
*/
|
||||||
di::injector<unique_ptr<font_manager>> configure_font_manager() {
|
unique_ptr<font_manager> make_font_manager() {
|
||||||
return di::make_injector(configure_connection(), configure_logger());
|
return factory_util::unique<font_manager>(make_connection(), make_logger());
|
||||||
}
|
}
|
||||||
|
|
||||||
array<char, XFT_MAXCHARS> xft_widths;
|
array<char, XFT_MAXCHARS> xft_widths;
|
||||||
|
122
src/x11/tray_client.cpp
Normal file
122
src/x11/tray_client.cpp
Normal file
@ -0,0 +1,122 @@
|
|||||||
|
#include <xcb/xcb.h>
|
||||||
|
#include <xcb/xcb_aux.h>
|
||||||
|
|
||||||
|
#include "utils/memory.hpp"
|
||||||
|
#include "x11/connection.hpp"
|
||||||
|
#include "x11/tray_client.hpp"
|
||||||
|
#include "x11/xembed.hpp"
|
||||||
|
#include "x11/xutils.hpp"
|
||||||
|
|
||||||
|
POLYBAR_NS
|
||||||
|
|
||||||
|
tray_client::tray_client(connection& conn, xcb_window_t win, uint16_t w, uint16_t h)
|
||||||
|
: m_connection(conn), m_window(win), m_width(w), m_height(h) {
|
||||||
|
m_xembed = memory_util::make_malloc_ptr<xembed_data>();
|
||||||
|
m_xembed->version = XEMBED_VERSION;
|
||||||
|
m_xembed->flags = XEMBED_MAPPED;
|
||||||
|
}
|
||||||
|
|
||||||
|
tray_client::~tray_client() {
|
||||||
|
xembed::unembed(m_connection, window(), m_connection.root());
|
||||||
|
}
|
||||||
|
|
||||||
|
uint16_t tray_client::width() const {
|
||||||
|
return m_width;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint16_t tray_client::height() const {
|
||||||
|
return m_height;
|
||||||
|
}
|
||||||
|
|
||||||
|
void tray_client::clear_window() const {
|
||||||
|
try {
|
||||||
|
m_connection.clear_area_checked(1, window(), 0, 0, width(), height());
|
||||||
|
} catch (const xpp::x::error::window& err) {
|
||||||
|
// ignore
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Match given window against client window
|
||||||
|
*/
|
||||||
|
bool tray_client::match(const xcb_window_t& win) const {
|
||||||
|
return win == m_window;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get client window mapped state
|
||||||
|
*/
|
||||||
|
bool tray_client::mapped() const {
|
||||||
|
return m_mapped;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set client window mapped state
|
||||||
|
*/
|
||||||
|
void tray_client::mapped(bool state) {
|
||||||
|
m_mapped = state;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get client window
|
||||||
|
*/
|
||||||
|
xcb_window_t tray_client::window() const {
|
||||||
|
return m_window;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get xembed data pointer
|
||||||
|
*/
|
||||||
|
xembed_data* tray_client::xembed() const {
|
||||||
|
return m_xembed.get();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Make sure that the window mapping state is correct
|
||||||
|
*/
|
||||||
|
void tray_client::ensure_state() const {
|
||||||
|
if (!mapped() && ((xembed()->flags & XEMBED_MAPPED) == XEMBED_MAPPED)) {
|
||||||
|
m_connection.map_window_checked(window());
|
||||||
|
} else if (mapped() && ((xembed()->flags & XEMBED_MAPPED) != XEMBED_MAPPED)) {
|
||||||
|
m_connection.unmap_window_checked(window());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Configure window size
|
||||||
|
*/
|
||||||
|
void tray_client::reconfigure(int16_t x, int16_t y) const {
|
||||||
|
uint32_t configure_mask = 0;
|
||||||
|
uint32_t configure_values[7];
|
||||||
|
xcb_params_configure_window_t configure_params;
|
||||||
|
|
||||||
|
XCB_AUX_ADD_PARAM(&configure_mask, &configure_params, width, m_width);
|
||||||
|
XCB_AUX_ADD_PARAM(&configure_mask, &configure_params, height, m_height);
|
||||||
|
XCB_AUX_ADD_PARAM(&configure_mask, &configure_params, x, x);
|
||||||
|
XCB_AUX_ADD_PARAM(&configure_mask, &configure_params, y, y);
|
||||||
|
|
||||||
|
xutils::pack_values(configure_mask, &configure_params, configure_values);
|
||||||
|
m_connection.configure_window_checked(window(), configure_mask, configure_values);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Respond to client resize requests
|
||||||
|
*/
|
||||||
|
void tray_client::configure_notify(int16_t x, int16_t y) const {
|
||||||
|
auto notify = memory_util::make_malloc_ptr<xcb_configure_notify_event_t>(32);
|
||||||
|
notify->response_type = XCB_CONFIGURE_NOTIFY;
|
||||||
|
notify->event = m_window;
|
||||||
|
notify->window = m_window;
|
||||||
|
notify->override_redirect = false;
|
||||||
|
notify->above_sibling = 0;
|
||||||
|
notify->x = x;
|
||||||
|
notify->y = y;
|
||||||
|
notify->width = m_width;
|
||||||
|
notify->height = m_height;
|
||||||
|
notify->border_width = 0;
|
||||||
|
|
||||||
|
const char* data = reinterpret_cast<const char*>(notify.get());
|
||||||
|
m_connection.send_event_checked(false, m_window, XCB_EVENT_MASK_STRUCTURE_NOTIFY, data);
|
||||||
|
}
|
||||||
|
|
||||||
|
POLYBAR_NS_END
|
@ -2,20 +2,22 @@
|
|||||||
#include <xcb/xcb_image.h>
|
#include <xcb/xcb_image.h>
|
||||||
#include <thread>
|
#include <thread>
|
||||||
|
|
||||||
#include "components/signals.hpp"
|
#include "components/config.hpp"
|
||||||
|
#include "components/eventloop.hpp"
|
||||||
#include "components/types.hpp"
|
#include "components/types.hpp"
|
||||||
#include "errors.hpp"
|
#include "errors.hpp"
|
||||||
|
#include "events/signal.hpp"
|
||||||
#include "utils/color.hpp"
|
#include "utils/color.hpp"
|
||||||
#include "utils/factory.hpp"
|
#include "utils/factory.hpp"
|
||||||
|
#include "utils/math.hpp"
|
||||||
#include "utils/memory.hpp"
|
#include "utils/memory.hpp"
|
||||||
#include "utils/process.hpp"
|
#include "utils/process.hpp"
|
||||||
#include "x11/atoms.hpp"
|
#include "x11/atoms.hpp"
|
||||||
#include "x11/color.hpp"
|
#include "x11/color.hpp"
|
||||||
#include "x11/connection.hpp"
|
#include "x11/connection.hpp"
|
||||||
#include "x11/draw.hpp"
|
#include "x11/draw.hpp"
|
||||||
#include "x11/ewmh.hpp"
|
|
||||||
#include "x11/graphics.hpp"
|
#include "x11/graphics.hpp"
|
||||||
#include "x11/tray.hpp"
|
#include "x11/tray_manager.hpp"
|
||||||
#include "x11/window.hpp"
|
#include "x11/window.hpp"
|
||||||
#include "x11/winspec.hpp"
|
#include "x11/winspec.hpp"
|
||||||
#include "x11/wm.hpp"
|
#include "x11/wm.hpp"
|
||||||
@ -39,135 +41,136 @@
|
|||||||
|
|
||||||
POLYBAR_NS
|
POLYBAR_NS
|
||||||
|
|
||||||
// implementation : tray_client {{{
|
using namespace wm_util;
|
||||||
|
|
||||||
tray_client::tray_client(connection& conn, xcb_window_t win, uint16_t w, uint16_t h)
|
tray_manager::tray_manager(connection& conn, signal_emitter& emitter, const logger& logger)
|
||||||
: m_connection(conn), m_window(win), m_width(w), m_height(h) {
|
: m_connection(conn), m_sig(emitter), m_log(logger) {}
|
||||||
m_xembed = memory_util::make_malloc_ptr<xembed_data>();
|
|
||||||
m_xembed->version = XEMBED_VERSION;
|
|
||||||
m_xembed->flags = XEMBED_MAPPED;
|
|
||||||
}
|
|
||||||
|
|
||||||
tray_client::~tray_client() {
|
|
||||||
xembed::unembed(m_connection, window(), m_connection.root());
|
|
||||||
}
|
|
||||||
|
|
||||||
uint16_t tray_client::width() const {
|
|
||||||
return m_width;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint16_t tray_client::height() const {
|
|
||||||
return m_height;
|
|
||||||
}
|
|
||||||
|
|
||||||
void tray_client::clear_window() const {
|
|
||||||
try {
|
|
||||||
m_connection.clear_area_checked(1, window(), 0, 0, width(), height());
|
|
||||||
} catch (const xpp::x::error::window& err) {
|
|
||||||
// ignore
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Match given window against client window
|
|
||||||
*/
|
|
||||||
bool tray_client::match(const xcb_window_t& win) const {
|
|
||||||
return win == m_window;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get client window mapped state
|
|
||||||
*/
|
|
||||||
bool tray_client::mapped() const {
|
|
||||||
return m_mapped;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Set client window mapped state
|
|
||||||
*/
|
|
||||||
void tray_client::mapped(bool state) {
|
|
||||||
m_mapped = state;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get client window
|
|
||||||
*/
|
|
||||||
xcb_window_t tray_client::window() const {
|
|
||||||
return m_window;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get xembed data pointer
|
|
||||||
*/
|
|
||||||
xembed_data* tray_client::xembed() const {
|
|
||||||
return m_xembed.get();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Make sure that the window mapping state is correct
|
|
||||||
*/
|
|
||||||
void tray_client::ensure_state() const {
|
|
||||||
if (!mapped() && ((xembed()->flags & XEMBED_MAPPED) == XEMBED_MAPPED)) {
|
|
||||||
m_connection.map_window_checked(window());
|
|
||||||
} else if (mapped() && ((xembed()->flags & XEMBED_MAPPED) != XEMBED_MAPPED)) {
|
|
||||||
m_connection.unmap_window_checked(window());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Configure window size
|
|
||||||
*/
|
|
||||||
void tray_client::reconfigure(int16_t x, int16_t y) const {
|
|
||||||
uint32_t configure_mask = 0;
|
|
||||||
uint32_t configure_values[7];
|
|
||||||
xcb_params_configure_window_t configure_params;
|
|
||||||
|
|
||||||
XCB_AUX_ADD_PARAM(&configure_mask, &configure_params, width, m_width);
|
|
||||||
XCB_AUX_ADD_PARAM(&configure_mask, &configure_params, height, m_height);
|
|
||||||
XCB_AUX_ADD_PARAM(&configure_mask, &configure_params, x, x);
|
|
||||||
XCB_AUX_ADD_PARAM(&configure_mask, &configure_params, y, y);
|
|
||||||
|
|
||||||
xutils::pack_values(configure_mask, &configure_params, configure_values);
|
|
||||||
m_connection.configure_window_checked(window(), configure_mask, configure_values);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Respond to client resize requests
|
|
||||||
*/
|
|
||||||
void tray_client::configure_notify(int16_t x, int16_t y) const {
|
|
||||||
auto notify = memory_util::make_malloc_ptr<xcb_configure_notify_event_t>(32);
|
|
||||||
notify->response_type = XCB_CONFIGURE_NOTIFY;
|
|
||||||
notify->event = m_window;
|
|
||||||
notify->window = m_window;
|
|
||||||
notify->override_redirect = false;
|
|
||||||
notify->above_sibling = 0;
|
|
||||||
notify->x = x;
|
|
||||||
notify->y = y;
|
|
||||||
notify->width = m_width;
|
|
||||||
notify->height = m_height;
|
|
||||||
notify->border_width = 0;
|
|
||||||
|
|
||||||
const char* data = reinterpret_cast<const char*>(notify.get());
|
|
||||||
m_connection.send_event_checked(false, m_window, XCB_EVENT_MASK_STRUCTURE_NOTIFY, data);
|
|
||||||
}
|
|
||||||
|
|
||||||
// }}}
|
|
||||||
// implementation : tray_manager {{{
|
|
||||||
|
|
||||||
tray_manager::tray_manager(connection& conn, const logger& logger) : m_connection(conn), m_log(logger) {
|
|
||||||
m_connection.attach_sink(this, SINK_PRIORITY_TRAY);
|
|
||||||
}
|
|
||||||
|
|
||||||
tray_manager::~tray_manager() {
|
tray_manager::~tray_manager() {
|
||||||
m_connection.detach_sink(this, SINK_PRIORITY_TRAY);
|
|
||||||
|
|
||||||
if (m_delaythread.joinable()) {
|
if (m_delaythread.joinable()) {
|
||||||
m_delaythread.join();
|
m_delaythread.join();
|
||||||
}
|
}
|
||||||
|
|
||||||
deactivate();
|
deactivate();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void tray_manager::setup(const bar_settings& bar_opts) {
|
||||||
|
auto conf = make_confreader();
|
||||||
|
auto bs = conf.bar_section();
|
||||||
|
auto tray_position = conf.get<string>(bs, "tray-position", "");
|
||||||
|
|
||||||
|
if (tray_position == "left") {
|
||||||
|
m_opts.align = alignment::LEFT;
|
||||||
|
} else if (tray_position == "right") {
|
||||||
|
m_opts.align = alignment::RIGHT;
|
||||||
|
} else if (tray_position == "center") {
|
||||||
|
m_opts.align = alignment::CENTER;
|
||||||
|
} else {
|
||||||
|
m_opts.align = alignment::NONE;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (m_opts.align == alignment::NONE) {
|
||||||
|
m_log.warn("Disabling tray manager (reason: position not set or invalid)");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
m_opts.detached = conf.get<bool>(bs, "tray-detached", false);
|
||||||
|
m_opts.height = bar_opts.size.h;
|
||||||
|
m_opts.height -= bar_opts.borders.at(edge::BOTTOM).size;
|
||||||
|
m_opts.height -= bar_opts.borders.at(edge::TOP).size;
|
||||||
|
m_opts.height_fill = m_opts.height;
|
||||||
|
|
||||||
|
if (m_opts.height % 2 != 0) {
|
||||||
|
m_opts.height--;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto maxsize = conf.get<int>(bs, "tray-maxsize", 16);
|
||||||
|
if (m_opts.height > maxsize) {
|
||||||
|
m_opts.spacing += (m_opts.height - maxsize) / 2;
|
||||||
|
m_opts.height = maxsize;
|
||||||
|
}
|
||||||
|
|
||||||
|
m_opts.width_max = bar_opts.size.w;
|
||||||
|
m_opts.width = m_opts.height;
|
||||||
|
m_opts.orig_y = bar_opts.pos.y + bar_opts.borders.at(edge::TOP).size;
|
||||||
|
|
||||||
|
// Apply user-defined scaling
|
||||||
|
auto scale = conf.get<float>(bs, "tray-scale", 1.0);
|
||||||
|
m_opts.width *= scale;
|
||||||
|
m_opts.height_fill *= scale;
|
||||||
|
|
||||||
|
auto inner_area = bar_opts.inner_area(true);
|
||||||
|
|
||||||
|
switch (m_opts.align) {
|
||||||
|
case alignment::NONE:
|
||||||
|
break;
|
||||||
|
case alignment::LEFT:
|
||||||
|
m_opts.orig_x = inner_area.x;
|
||||||
|
break;
|
||||||
|
case alignment::CENTER:
|
||||||
|
m_opts.orig_x = inner_area.x + inner_area.width / 2 - m_opts.width / 2;
|
||||||
|
break;
|
||||||
|
case alignment::RIGHT:
|
||||||
|
m_opts.orig_x = inner_area.x + inner_area.width;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set user-defined background color
|
||||||
|
if (!(m_opts.transparent = conf.get<bool>(bs, "tray-transparent", m_opts.transparent))) {
|
||||||
|
auto bg = conf.get<string>(bs, "tray-background", "");
|
||||||
|
|
||||||
|
if (bg.length() > 7) {
|
||||||
|
m_log.warn("Alpha support for the systray is limited. See the wiki for more details.");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!bg.empty()) {
|
||||||
|
m_opts.background = color::parse(bg, g_colorempty);
|
||||||
|
} else {
|
||||||
|
m_opts.background = bar_opts.background;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (color_util::alpha_channel(m_opts.background) == 0) {
|
||||||
|
m_opts.transparent = true;
|
||||||
|
m_opts.background = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add user-defined padding
|
||||||
|
m_opts.spacing += conf.get<int>(bs, "tray-padding", 0);
|
||||||
|
|
||||||
|
// Add user-defiend offset
|
||||||
|
auto offset_x_def = conf.get<string>(bs, "tray-offset-x", "");
|
||||||
|
auto offset_y_def = conf.get<string>(bs, "tray-offset-y", "");
|
||||||
|
|
||||||
|
auto offset_x = atoi(offset_x_def.c_str());
|
||||||
|
auto offset_y = atoi(offset_y_def.c_str());
|
||||||
|
|
||||||
|
if (offset_x != 0 && offset_x_def.find('%') != string::npos) {
|
||||||
|
if (m_opts.detached) {
|
||||||
|
offset_x = math_util::percentage_to_value<int>(offset_x, bar_opts.monitor->w);
|
||||||
|
} else {
|
||||||
|
offset_x = math_util::percentage_to_value<int>(offset_x, inner_area.width);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (offset_y != 0 && offset_y_def.find('%') != string::npos) {
|
||||||
|
if (m_opts.detached) {
|
||||||
|
offset_y = math_util::percentage_to_value<int>(offset_y, bar_opts.monitor->h);
|
||||||
|
} else {
|
||||||
|
offset_y = math_util::percentage_to_value<int>(offset_y, inner_area.height);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
m_opts.orig_x += offset_x;
|
||||||
|
m_opts.orig_y += offset_y;
|
||||||
|
|
||||||
|
// Put the tray next to the bar in the window stack
|
||||||
|
m_opts.sibling = bar_opts.window;
|
||||||
|
|
||||||
|
// Activate the tray manager
|
||||||
|
query_atom();
|
||||||
|
activate();
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the settings container
|
* Get the settings container
|
||||||
*/
|
*/
|
||||||
@ -175,17 +178,6 @@ const tray_settings tray_manager::settings() const {
|
|||||||
return m_opts;
|
return m_opts;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Initialize data
|
|
||||||
*/
|
|
||||||
void tray_manager::bootstrap(tray_settings settings) {
|
|
||||||
m_opts = settings;
|
|
||||||
query_atom();
|
|
||||||
|
|
||||||
// Listen for visibility change events on the bar window
|
|
||||||
g_signals::bar::visibility_change = bind(&tray_manager::bar_visibility_change, this, placeholders::_1);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Activate systray management
|
* Activate systray management
|
||||||
*/
|
*/
|
||||||
@ -196,13 +188,17 @@ void tray_manager::activate() {
|
|||||||
|
|
||||||
m_log.info("Activating tray manager");
|
m_log.info("Activating tray manager");
|
||||||
m_activated = true;
|
m_activated = true;
|
||||||
|
m_opts.running = true;
|
||||||
|
|
||||||
|
m_sig.attach(this);
|
||||||
|
m_connection.attach_sink(this, SINK_PRIORITY_TRAY);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
create_window();
|
create_window();
|
||||||
create_bg();
|
create_bg();
|
||||||
restack_window();
|
restack_window();
|
||||||
set_wmhints();
|
set_wm_hints();
|
||||||
set_traycolors();
|
set_tray_colors();
|
||||||
} catch (const exception& err) {
|
} catch (const exception& err) {
|
||||||
m_log.err(err.what());
|
m_log.err(err.what());
|
||||||
m_log.err("Cannot activate tray manager... failed to setup window");
|
m_log.err("Cannot activate tray manager... failed to setup window");
|
||||||
@ -210,6 +206,10 @@ void tray_manager::activate() {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Make sure we receive notificatins when the root pixmap changes
|
||||||
|
m_connection.ensure_event_mask(m_connection.root(), XCB_EVENT_MASK_PROPERTY_CHANGE);
|
||||||
|
m_connection.flush();
|
||||||
|
|
||||||
// Attempt to get control of the systray selection then
|
// Attempt to get control of the systray selection then
|
||||||
// notify clients waiting for a manager.
|
// notify clients waiting for a manager.
|
||||||
acquire_selection();
|
acquire_selection();
|
||||||
@ -221,8 +221,6 @@ void tray_manager::activate() {
|
|||||||
if (m_othermanager != XCB_NONE && m_othermanager != m_tray) {
|
if (m_othermanager != XCB_NONE && m_othermanager != m_tray) {
|
||||||
notify_clients_delayed();
|
notify_clients_delayed();
|
||||||
}
|
}
|
||||||
|
|
||||||
m_connection.flush();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -235,14 +233,10 @@ void tray_manager::deactivate(bool clear_selection) {
|
|||||||
|
|
||||||
m_log.info("Deactivating tray manager");
|
m_log.info("Deactivating tray manager");
|
||||||
m_activated = false;
|
m_activated = false;
|
||||||
|
m_opts.running = false;
|
||||||
|
|
||||||
if (!m_opts.detached) {
|
m_sig.detach(this);
|
||||||
g_signals::event::enqueue(eventloop::make(update_event{}, true));
|
m_connection.detach_sink(this, SINK_PRIORITY_TRAY);
|
||||||
}
|
|
||||||
|
|
||||||
if (g_signals::bar::visibility_change) {
|
|
||||||
g_signals::bar::visibility_change = nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!m_connection.connection_has_error() && clear_selection && m_acquired_selection) {
|
if (!m_connection.connection_has_error() && clear_selection && m_acquired_selection) {
|
||||||
m_log.trace("tray: Unset selection owner");
|
m_log.trace("tray: Unset selection owner");
|
||||||
@ -256,11 +250,9 @@ void tray_manager::deactivate(bool clear_selection) {
|
|||||||
m_log.trace("tray: Destroy window");
|
m_log.trace("tray: Destroy window");
|
||||||
m_connection.destroy_window(m_tray);
|
m_connection.destroy_window(m_tray);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (m_pixmap) {
|
if (m_pixmap) {
|
||||||
m_connection.free_pixmap(m_pixmap);
|
m_connection.free_pixmap(m_pixmap);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (m_gc) {
|
if (m_gc) {
|
||||||
m_connection.free_gc(m_pixmap);
|
m_connection.free_gc(m_pixmap);
|
||||||
}
|
}
|
||||||
@ -281,6 +273,8 @@ void tray_manager::deactivate(bool clear_selection) {
|
|||||||
m_restacked = false;
|
m_restacked = false;
|
||||||
|
|
||||||
m_connection.flush();
|
m_connection.flush();
|
||||||
|
|
||||||
|
m_sig.emit(process_update{eventloop::make_update_evt(true)});
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -313,15 +307,13 @@ void tray_manager::reconfigure() {
|
|||||||
|
|
||||||
m_opts.configured_slots = mapped_clients();
|
m_opts.configured_slots = mapped_clients();
|
||||||
|
|
||||||
if (!m_opts.detached) {
|
|
||||||
g_signals::event::enqueue(eventloop::make(update_event{}, true));
|
|
||||||
}
|
|
||||||
|
|
||||||
guard.unlock();
|
guard.unlock();
|
||||||
|
|
||||||
refresh_window();
|
refresh_window();
|
||||||
|
|
||||||
m_connection.flush();
|
m_connection.flush();
|
||||||
|
|
||||||
|
m_sig.emit(process_update{eventloop::make_update_evt(true)});
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -336,7 +328,7 @@ void tray_manager::reconfigure_window() {
|
|||||||
|
|
||||||
auto clients = mapped_clients();
|
auto clients = mapped_clients();
|
||||||
|
|
||||||
if (!clients && m_mapped && !m_hidden) {
|
if (!clients && m_mapped) {
|
||||||
m_log.trace("tray: Reconfigure window / unmap");
|
m_log.trace("tray: Reconfigure window / unmap");
|
||||||
m_connection.unmap_window_checked(m_tray);
|
m_connection.unmap_window_checked(m_tray);
|
||||||
} else if (clients && !m_mapped && !m_hidden) {
|
} else if (clients && !m_mapped && !m_hidden) {
|
||||||
@ -352,19 +344,18 @@ void tray_manager::reconfigure_window() {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// configure window
|
if (width > 0) {
|
||||||
|
m_log.trace("tray: New window values, width=%d, x=%d", width, x);
|
||||||
|
|
||||||
uint32_t mask = 0;
|
uint32_t mask = 0;
|
||||||
uint32_t values[7];
|
uint32_t values[7];
|
||||||
xcb_params_configure_window_t params;
|
xcb_params_configure_window_t params;
|
||||||
|
|
||||||
m_log.trace("tray: New window values, width=%d, x=%d", width, x);
|
|
||||||
|
|
||||||
XCB_AUX_ADD_PARAM(&mask, ¶ms, width, width);
|
XCB_AUX_ADD_PARAM(&mask, ¶ms, width, width);
|
||||||
XCB_AUX_ADD_PARAM(&mask, ¶ms, x, x);
|
XCB_AUX_ADD_PARAM(&mask, ¶ms, x, x);
|
||||||
|
|
||||||
xutils::pack_values(mask, ¶ms, values);
|
xutils::pack_values(mask, ¶ms, values);
|
||||||
|
|
||||||
m_connection.configure_window_checked(m_tray, mask, values);
|
m_connection.configure_window_checked(m_tray, mask, values);
|
||||||
|
}
|
||||||
|
|
||||||
m_opts.configured_w = width;
|
m_opts.configured_w = width;
|
||||||
m_opts.configured_x = x;
|
m_opts.configured_x = x;
|
||||||
@ -413,9 +404,7 @@ void tray_manager::reconfigure_bg(bool realloc) {
|
|||||||
|
|
||||||
if (realloc && !get_root_pixmap(m_connection, &m_rootpixmap)) {
|
if (realloc && !get_root_pixmap(m_connection, &m_rootpixmap)) {
|
||||||
return m_log.err("Failed to get root pixmap for tray background (realloc=%i)", realloc);
|
return m_log.err("Failed to get root pixmap for tray background (realloc=%i)", realloc);
|
||||||
}
|
} else if (realloc) {
|
||||||
|
|
||||||
if (realloc) {
|
|
||||||
// clang-format off
|
// clang-format off
|
||||||
m_log.info("Tray root pixmap (rootpmap=%s, geom=%dx%d+%d+%d, tray=%s, pmap=%s, gc=%s)",
|
m_log.info("Tray root pixmap (rootpmap=%s, geom=%dx%d+%d+%d, tray=%s, pmap=%s, gc=%s)",
|
||||||
m_connection.id(m_rootpixmap.pixmap),
|
m_connection.id(m_rootpixmap.pixmap),
|
||||||
@ -434,9 +423,8 @@ void tray_manager::reconfigure_bg(bool realloc) {
|
|||||||
|
|
||||||
auto x = calculate_x(w);
|
auto x = calculate_x(w);
|
||||||
auto y = calculate_y();
|
auto y = calculate_y();
|
||||||
|
auto px = math_util::max(0, m_rootpixmap.x + x);
|
||||||
auto px = m_rootpixmap.x + x;
|
auto py = math_util::max(0, m_rootpixmap.y + y);
|
||||||
auto py = m_rootpixmap.y + y;
|
|
||||||
|
|
||||||
// Make sure we don't try to copy void content
|
// Make sure we don't try to copy void content
|
||||||
if (px + w > m_rootpixmap.width) {
|
if (px + w > m_rootpixmap.width) {
|
||||||
@ -477,16 +465,12 @@ void tray_manager::reconfigure_bg(bool realloc) {
|
|||||||
* Refresh the bar window by clearing it along with each client window
|
* Refresh the bar window by clearing it along with each client window
|
||||||
*/
|
*/
|
||||||
void tray_manager::refresh_window() {
|
void tray_manager::refresh_window() {
|
||||||
if (!m_mtx.try_lock()) {
|
if (!m_activated || !m_mapped || !m_mtx.try_lock()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::lock_guard<std::mutex> lock(m_mtx, std::adopt_lock);
|
std::lock_guard<std::mutex> lock(m_mtx, std::adopt_lock);
|
||||||
|
|
||||||
if (!m_activated || !m_mapped) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
m_log.trace("tray: Refreshing window");
|
m_log.trace("tray: Refreshing window");
|
||||||
|
|
||||||
auto width = calculate_w();
|
auto width = calculate_w();
|
||||||
@ -503,6 +487,12 @@ void tray_manager::refresh_window() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
m_connection.flush();
|
m_connection.flush();
|
||||||
|
|
||||||
|
if (!mapped_clients()) {
|
||||||
|
m_opts.configured_w = 0;
|
||||||
|
} else {
|
||||||
|
m_opts.configured_w = width;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -547,7 +537,7 @@ void tray_manager::create_window() {
|
|||||||
win << cw_params_border_pixel(m_opts.background);
|
win << cw_params_border_pixel(m_opts.background);
|
||||||
}
|
}
|
||||||
|
|
||||||
m_tray = win << cw_flush();
|
m_tray = win << cw_flush(true);
|
||||||
m_log.info("Tray window: %s", m_connection.id(m_tray));
|
m_log.info("Tray window: %s", m_connection.id(m_tray));
|
||||||
|
|
||||||
xutils::compton_shadow_exclude(m_connection, m_tray);
|
xutils::compton_shadow_exclude(m_connection, m_tray);
|
||||||
@ -560,16 +550,13 @@ void tray_manager::create_bg(bool realloc) {
|
|||||||
if (!m_opts.transparent) {
|
if (!m_opts.transparent) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!realloc && m_pixmap && m_gc && m_rootpixmap.pixmap) {
|
if (!realloc && m_pixmap && m_gc && m_rootpixmap.pixmap) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (realloc && m_pixmap) {
|
if (realloc && m_pixmap) {
|
||||||
m_connection.free_pixmap(m_pixmap);
|
m_connection.free_pixmap(m_pixmap);
|
||||||
m_pixmap = 0;
|
m_pixmap = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (realloc && m_gc) {
|
if (realloc && m_gc) {
|
||||||
m_connection.free_gc(m_gc);
|
m_connection.free_gc(m_gc);
|
||||||
m_gc = 0;
|
m_gc = 0;
|
||||||
@ -608,6 +595,7 @@ void tray_manager::restack_window() {
|
|||||||
|
|
||||||
XCB_AUX_ADD_PARAM(&mask, ¶ms, sibling, m_opts.sibling);
|
XCB_AUX_ADD_PARAM(&mask, ¶ms, sibling, m_opts.sibling);
|
||||||
XCB_AUX_ADD_PARAM(&mask, ¶ms, stack_mode, XCB_STACK_MODE_ABOVE);
|
XCB_AUX_ADD_PARAM(&mask, ¶ms, stack_mode, XCB_STACK_MODE_ABOVE);
|
||||||
|
|
||||||
xutils::pack_values(mask, ¶ms, values);
|
xutils::pack_values(mask, ¶ms, values);
|
||||||
m_connection.configure_window_checked(m_tray, mask, values);
|
m_connection.configure_window_checked(m_tray, mask, values);
|
||||||
m_restacked = true;
|
m_restacked = true;
|
||||||
@ -620,34 +608,39 @@ void tray_manager::restack_window() {
|
|||||||
/**
|
/**
|
||||||
* Set window WM hints
|
* Set window WM hints
|
||||||
*/
|
*/
|
||||||
void tray_manager::set_wmhints() {
|
void tray_manager::set_wm_hints() {
|
||||||
|
const uint32_t visual{m_connection.screen()->root_visual};
|
||||||
|
const uint32_t orientation{_NET_SYSTEM_TRAY_ORIENTATION_HORZ};
|
||||||
|
|
||||||
m_log.trace("tray: Set window WM_NAME / WM_CLASS", m_connection.id(m_tray));
|
m_log.trace("tray: Set window WM_NAME / WM_CLASS", m_connection.id(m_tray));
|
||||||
xcb_icccm_set_wm_name(m_connection, m_tray, XCB_ATOM_STRING, 8, 19, TRAY_WM_NAME);
|
xcb_icccm_set_wm_name(m_connection, m_tray, XCB_ATOM_STRING, 8, 19, TRAY_WM_NAME);
|
||||||
xcb_icccm_set_wm_class(m_connection, m_tray, 12, TRAY_WM_CLASS);
|
xcb_icccm_set_wm_class(m_connection, m_tray, 12, TRAY_WM_CLASS);
|
||||||
|
|
||||||
m_log.trace("tray: Set window WM_PROTOCOLS");
|
m_log.trace("tray: Set window WM_PROTOCOLS");
|
||||||
wm_util::set_wmprotocols(m_connection, m_tray, {WM_DELETE_WINDOW, WM_TAKE_FOCUS});
|
set_wm_protocols(m_connection, m_tray, {WM_DELETE_WINDOW, WM_TAKE_FOCUS});
|
||||||
|
|
||||||
m_log.trace("tray: Set window _NET_WM_WINDOW_TYPE");
|
m_log.trace("tray: Set window _NET_WM_WINDOW_TYPE");
|
||||||
wm_util::set_windowtype(m_connection, m_tray, {_NET_WM_WINDOW_TYPE_DOCK, _NET_WM_WINDOW_TYPE_NORMAL});
|
set_wm_window_type(m_connection, m_tray, {_NET_WM_WINDOW_TYPE_DOCK, _NET_WM_WINDOW_TYPE_NORMAL});
|
||||||
|
|
||||||
m_log.trace("tray: Set window _NET_WM_STATE");
|
m_log.trace("tray: Set window _NET_WM_STATE");
|
||||||
wm_util::set_wmstate(m_connection, m_tray, {_NET_WM_STATE_SKIP_TASKBAR});
|
set_wm_state(m_connection, m_tray, {_NET_WM_STATE_SKIP_TASKBAR});
|
||||||
|
|
||||||
m_log.trace("tray: Set window _NET_WM_PID");
|
m_log.trace("tray: Set window _NET_WM_PID");
|
||||||
wm_util::set_wmpid(m_connection, m_tray, getpid());
|
set_wm_pid(m_connection, m_tray, getpid());
|
||||||
|
|
||||||
m_log.trace("tray: Set window _NET_SYSTEM_TRAY_ORIENTATION");
|
|
||||||
wm_util::set_trayorientation(m_connection, m_tray, _NET_SYSTEM_TRAY_ORIENTATION_HORZ);
|
|
||||||
|
|
||||||
m_log.trace("tray: Set window _NET_SYSTEM_TRAY_VISUAL");
|
m_log.trace("tray: Set window _NET_SYSTEM_TRAY_VISUAL");
|
||||||
wm_util::set_trayvisual(m_connection, m_tray, m_connection.screen()->root_visual);
|
xcb_change_property(
|
||||||
|
m_connection, XCB_PROP_MODE_REPLACE, m_tray, _NET_SYSTEM_TRAY_VISUAL, XCB_ATOM_VISUALID, 32, 1, &visual);
|
||||||
|
|
||||||
|
m_log.trace("tray: Set window _NET_SYSTEM_TRAY_ORIENTATION");
|
||||||
|
xcb_change_property(m_connection, XCB_PROP_MODE_REPLACE, m_tray, _NET_SYSTEM_TRAY_ORIENTATION,
|
||||||
|
_NET_SYSTEM_TRAY_ORIENTATION, 32, 1, &orientation);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set color atom used by clients when determing icon theme
|
* Set color atom used by clients when determing icon theme
|
||||||
*/
|
*/
|
||||||
void tray_manager::set_traycolors() {
|
void tray_manager::set_tray_colors() {
|
||||||
m_log.trace("tray: Set _NET_SYSTEM_TRAY_COLORS to %x", m_opts.background);
|
m_log.trace("tray: Set _NET_SYSTEM_TRAY_COLORS to %x", m_opts.background);
|
||||||
|
|
||||||
auto r = color_util::red_channel(m_opts.background);
|
auto r = color_util::red_channel(m_opts.background);
|
||||||
@ -669,15 +662,14 @@ void tray_manager::set_traycolors() {
|
|||||||
* Acquire the systray selection
|
* Acquire the systray selection
|
||||||
*/
|
*/
|
||||||
void tray_manager::acquire_selection() {
|
void tray_manager::acquire_selection() {
|
||||||
xcb_window_t owner{m_connection.get_selection_owner_unchecked(m_atom)->owner};
|
auto reply = m_connection.get_selection_owner_unchecked(m_atom);
|
||||||
|
auto owner = reply.owner<xcb_window_t>();
|
||||||
|
|
||||||
if (owner == m_tray) {
|
if (owner == m_tray) {
|
||||||
m_log.info("tray: Already managing the systray selection");
|
m_log.info("tray: Already managing the systray selection");
|
||||||
return;
|
|
||||||
} else if ((m_othermanager = owner) != XCB_NONE) {
|
} else if ((m_othermanager = owner) != XCB_NONE) {
|
||||||
m_log.info("Replacing selection manager %s", m_connection.id(owner));
|
m_log.info("Replacing selection manager %s", m_connection.id(owner));
|
||||||
}
|
} else {
|
||||||
|
|
||||||
m_log.trace("tray: Change selection owner to %s", m_connection.id(m_tray));
|
m_log.trace("tray: Change selection owner to %s", m_connection.id(m_tray));
|
||||||
m_connection.set_selection_owner_checked(m_tray, m_atom, XCB_CURRENT_TIME);
|
m_connection.set_selection_owner_checked(m_tray, m_atom, XCB_CURRENT_TIME);
|
||||||
|
|
||||||
@ -686,6 +678,7 @@ void tray_manager::acquire_selection() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
m_acquired_selection = false;
|
m_acquired_selection = false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -709,7 +702,6 @@ void tray_manager::notify_clients_delayed(chrono::duration<double, std::milli> d
|
|||||||
if (m_delaythread.joinable()) {
|
if (m_delaythread.joinable()) {
|
||||||
m_delaythread.join();
|
m_delaythread.join();
|
||||||
}
|
}
|
||||||
|
|
||||||
m_delaythread = thread([&] {
|
m_delaythread = thread([&] {
|
||||||
this_thread::sleep_for(delay);
|
this_thread::sleep_for(delay);
|
||||||
notify_clients();
|
notify_clients();
|
||||||
@ -733,17 +725,10 @@ void tray_manager::track_selection_owner(xcb_window_t owner) {
|
|||||||
* Process client docking request
|
* Process client docking request
|
||||||
*/
|
*/
|
||||||
void tray_manager::process_docking_request(xcb_window_t win) {
|
void tray_manager::process_docking_request(xcb_window_t win) {
|
||||||
auto client = find_client(win);
|
|
||||||
|
|
||||||
if (client) {
|
|
||||||
m_log.warn("Tray client %s already embedded, ignoring request...", m_connection.id(win));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
m_log.info("Processing docking request from %s", m_connection.id(win));
|
m_log.info("Processing docking request from %s", m_connection.id(win));
|
||||||
|
|
||||||
m_clients.emplace_back(make_shared<tray_client>(m_connection, win, m_opts.width, m_opts.height));
|
m_clients.emplace_back(factory_util::shared<tray_client>(m_connection, win, m_opts.width, m_opts.height));
|
||||||
client = m_clients.back();
|
auto& client = m_clients.back();
|
||||||
|
|
||||||
try {
|
try {
|
||||||
m_log.trace("tray: Get client _XEMBED_INFO");
|
m_log.trace("tray: Get client _XEMBED_INFO");
|
||||||
@ -752,19 +737,17 @@ void tray_manager::process_docking_request(xcb_window_t win) {
|
|||||||
m_log.err(err.what());
|
m_log.err(err.what());
|
||||||
} catch (const xpp::x::error::window& err) {
|
} catch (const xpp::x::error::window& err) {
|
||||||
m_log.err("Failed to query for _XEMBED_INFO, removing client... (%s)", err.what());
|
m_log.err("Failed to query for _XEMBED_INFO, removing client... (%s)", err.what());
|
||||||
remove_client(client, false);
|
remove_client(win, false);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
m_log.trace("tray: Update client window");
|
|
||||||
{
|
|
||||||
// clang-format off
|
|
||||||
const uint32_t mask{XCB_CW_BACK_PIXMAP | XCB_CW_EVENT_MASK};
|
const uint32_t mask{XCB_CW_BACK_PIXMAP | XCB_CW_EVENT_MASK};
|
||||||
const uint32_t values[]{XCB_BACK_PIXMAP_PARENT_RELATIVE, XCB_EVENT_MASK_PROPERTY_CHANGE | XCB_EVENT_MASK_STRUCTURE_NOTIFY};
|
const uint32_t values[]{
|
||||||
|
XCB_BACK_PIXMAP_PARENT_RELATIVE, XCB_EVENT_MASK_PROPERTY_CHANGE | XCB_EVENT_MASK_STRUCTURE_NOTIFY};
|
||||||
|
|
||||||
|
m_log.trace("tray: Update client window");
|
||||||
m_connection.change_window_attributes_checked(client->window(), mask, values);
|
m_connection.change_window_attributes_checked(client->window(), mask, values);
|
||||||
// clang-format on
|
|
||||||
}
|
|
||||||
|
|
||||||
m_log.trace("tray: Configure client size");
|
m_log.trace("tray: Configure client size");
|
||||||
client->reconfigure(0, 0);
|
client->reconfigure(0, 0);
|
||||||
@ -785,44 +768,20 @@ void tray_manager::process_docking_request(xcb_window_t win) {
|
|||||||
}
|
}
|
||||||
} catch (const xpp::x::error::window& err) {
|
} catch (const xpp::x::error::window& err) {
|
||||||
m_log.err("Failed to setup tray client, removing... (%s)", err.what());
|
m_log.err("Failed to setup tray client, removing... (%s)", err.what());
|
||||||
remove_client(client, false);
|
remove_client(win, false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Signal handler connected to the bar window's visibility change signal.
|
|
||||||
* This is used as a fallback in case the window restacking fails. It will
|
|
||||||
* toggle the tray window whenever the visibility of the bar window changes.
|
|
||||||
*/
|
|
||||||
void tray_manager::bar_visibility_change(bool visible) {
|
|
||||||
m_log.trace("tray: visibility_change %d", visible);
|
|
||||||
m_hidden = !visible;
|
|
||||||
|
|
||||||
if (!m_activated || m_restacked) {
|
|
||||||
return;
|
|
||||||
} else if (!m_hidden && !m_mapped) {
|
|
||||||
m_connection.map_window(m_tray);
|
|
||||||
} else if (m_hidden && m_mapped) {
|
|
||||||
m_connection.unmap_window(m_tray);
|
|
||||||
} else if (m_mapped && !m_hidden) {
|
|
||||||
redraw_window();
|
|
||||||
}
|
|
||||||
|
|
||||||
m_connection.flush();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Calculate x position of tray window
|
* Calculate x position of tray window
|
||||||
*/
|
*/
|
||||||
int16_t tray_manager::calculate_x(uint16_t width) const {
|
int16_t tray_manager::calculate_x(uint16_t width) const {
|
||||||
auto x = m_opts.orig_x;
|
auto x = m_opts.orig_x;
|
||||||
|
|
||||||
if (m_opts.align == alignment::RIGHT) {
|
if (m_opts.align == alignment::RIGHT) {
|
||||||
x -= ((m_opts.width + m_opts.spacing) * m_clients.size() + m_opts.spacing);
|
x -= ((m_opts.width + m_opts.spacing) * m_clients.size() + m_opts.spacing);
|
||||||
} else if (m_opts.align == alignment::CENTER) {
|
} else if (m_opts.align == alignment::CENTER) {
|
||||||
x -= (width / 2) - (m_opts.width / 2);
|
x -= (width / 2) - (m_opts.width / 2);
|
||||||
}
|
}
|
||||||
|
|
||||||
return x;
|
return x;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -838,14 +797,14 @@ int16_t tray_manager::calculate_y() const {
|
|||||||
*/
|
*/
|
||||||
uint16_t tray_manager::calculate_w() const {
|
uint16_t tray_manager::calculate_w() const {
|
||||||
uint16_t width = m_opts.spacing;
|
uint16_t width = m_opts.spacing;
|
||||||
|
size_t count{0};
|
||||||
for (auto&& client : m_clients) {
|
for (auto&& client : m_clients) {
|
||||||
if (client->mapped()) {
|
if (client->mapped()) {
|
||||||
|
count++;
|
||||||
width += m_opts.spacing + m_opts.width;
|
width += m_opts.spacing + m_opts.width;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
return count ? width : 0;
|
||||||
return width;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -874,6 +833,14 @@ int16_t tray_manager::calculate_client_y() {
|
|||||||
return (m_opts.height_fill - m_opts.height) / 2;
|
return (m_opts.height_fill - m_opts.height) / 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if the given window is embedded
|
||||||
|
*/
|
||||||
|
bool tray_manager::is_embedded(const xcb_window_t& win) const {
|
||||||
|
return m_clients.end() != std::find_if(m_clients.begin(), m_clients.end(),
|
||||||
|
[win](shared_ptr<tray_client> client) { return client->match(win); });
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Find tray client by window
|
* Find tray client by window
|
||||||
*/
|
*/
|
||||||
@ -883,14 +850,22 @@ shared_ptr<tray_client> tray_manager::find_client(const xcb_window_t& win) const
|
|||||||
return shared_ptr<tray_client>{client.get(), factory_util::null_deleter{}};
|
return shared_ptr<tray_client>{client.get(), factory_util::null_deleter{}};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return {};
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Client error handling
|
* Remove tray client
|
||||||
*/
|
*/
|
||||||
void tray_manager::remove_client(shared_ptr<tray_client>& client, bool reconfigure) {
|
void tray_manager::remove_client(shared_ptr<tray_client>& client, bool reconfigure) {
|
||||||
m_clients.erase(std::find(m_clients.begin(), m_clients.end(), client));
|
remove_client(client->window(), reconfigure);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Remove tray client by window
|
||||||
|
*/
|
||||||
|
void tray_manager::remove_client(xcb_window_t win, bool reconfigure) {
|
||||||
|
m_clients.erase(std::remove_if(
|
||||||
|
m_clients.begin(), m_clients.end(), [win](shared_ptr<tray_client> client) { return client->match(win); }));
|
||||||
|
|
||||||
if (reconfigure) {
|
if (reconfigure) {
|
||||||
tray_manager::reconfigure();
|
tray_manager::reconfigure();
|
||||||
@ -900,8 +875,8 @@ void tray_manager::remove_client(shared_ptr<tray_client>& client, bool reconfigu
|
|||||||
/**
|
/**
|
||||||
* Get number of mapped clients
|
* Get number of mapped clients
|
||||||
*/
|
*/
|
||||||
int tray_manager::mapped_clients() const {
|
size_t tray_manager::mapped_clients() const {
|
||||||
int mapped_clients = 0;
|
size_t mapped_clients = 0;
|
||||||
|
|
||||||
for (auto&& client : m_clients) {
|
for (auto&& client : m_clients) {
|
||||||
if (client->mapped()) {
|
if (client->mapped()) {
|
||||||
@ -937,21 +912,20 @@ void tray_manager::handle(const evt::visibility_notify& evt) {
|
|||||||
void tray_manager::handle(const evt::client_message& evt) {
|
void tray_manager::handle(const evt::client_message& evt) {
|
||||||
if (!m_activated) {
|
if (!m_activated) {
|
||||||
return;
|
return;
|
||||||
}
|
} else if (evt->type == WM_PROTOCOLS && evt->data.data32[0] == WM_DELETE_WINDOW && evt->window == m_tray) {
|
||||||
|
|
||||||
if (evt->type == WM_PROTOCOLS && evt->data.data32[0] == WM_DELETE_WINDOW) {
|
|
||||||
if (evt->window == m_tray) {
|
|
||||||
m_log.warn("Received WM_DELETE");
|
m_log.warn("Received WM_DELETE");
|
||||||
m_tray = 0;
|
m_tray = 0;
|
||||||
deactivate();
|
deactivate();
|
||||||
}
|
} else if (evt->type == _NET_SYSTEM_TRAY_OPCODE && evt->format == 32) {
|
||||||
}
|
|
||||||
|
|
||||||
if (evt->type == _NET_SYSTEM_TRAY_OPCODE && evt->format == 32) {
|
|
||||||
m_log.trace("tray: Received client_message");
|
m_log.trace("tray: Received client_message");
|
||||||
|
|
||||||
if (SYSTEM_TRAY_REQUEST_DOCK == evt->data.data32[1]) {
|
if (SYSTEM_TRAY_REQUEST_DOCK == evt->data.data32[1]) {
|
||||||
|
if (!is_embedded(evt->data.data32[2])) {
|
||||||
process_docking_request(evt->data.data32[2]);
|
process_docking_request(evt->data.data32[2]);
|
||||||
|
} else {
|
||||||
|
auto win = evt->data.data32[2];
|
||||||
|
m_log.warn("Tray client %s already embedded, ignoring request...", m_connection.id(win));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -964,22 +938,14 @@ void tray_manager::handle(const evt::client_message& evt) {
|
|||||||
* so we return an answer that'll put him in place.
|
* so we return an answer that'll put him in place.
|
||||||
*/
|
*/
|
||||||
void tray_manager::handle(const evt::configure_request& evt) {
|
void tray_manager::handle(const evt::configure_request& evt) {
|
||||||
if (!m_activated) {
|
if (m_activated && is_embedded(evt->window)) {
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto client = find_client(evt->window);
|
|
||||||
|
|
||||||
if (!client) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
m_log.trace("tray: Client configure request %s", m_connection.id(evt->window));
|
m_log.trace("tray: Client configure request %s", m_connection.id(evt->window));
|
||||||
client->configure_notify(calculate_client_x(evt->window), calculate_client_y());
|
find_client(evt->window)->configure_notify(calculate_client_x(evt->window), calculate_client_y());
|
||||||
} catch (const xpp::x::error::window& err) {
|
} catch (const xpp::x::error::window& err) {
|
||||||
m_log.err("Failed to reconfigure tray client, removing... (%s)", err.what());
|
m_log.err("Failed to reconfigure tray client, removing... (%s)", err.what());
|
||||||
remove_client(client);
|
remove_client(evt->window);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -987,22 +953,14 @@ void tray_manager::handle(const evt::configure_request& evt) {
|
|||||||
* @see tray_manager::handle(const evt::configure_request&);
|
* @see tray_manager::handle(const evt::configure_request&);
|
||||||
*/
|
*/
|
||||||
void tray_manager::handle(const evt::resize_request& evt) {
|
void tray_manager::handle(const evt::resize_request& evt) {
|
||||||
if (!m_activated) {
|
if (m_activated && is_embedded(evt->window)) {
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto client = find_client(evt->window);
|
|
||||||
|
|
||||||
if (!client) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
m_log.trace("tray: Received resize_request for client %s", m_connection.id(evt->window));
|
m_log.trace("tray: Received resize_request for client %s", m_connection.id(evt->window));
|
||||||
client->configure_notify(calculate_client_x(evt->window), calculate_client_y());
|
find_client(evt->window)->configure_notify(calculate_client_x(evt->window), calculate_client_y());
|
||||||
} catch (const xpp::x::error::window& err) {
|
} catch (const xpp::x::error::window& err) {
|
||||||
m_log.err("Failed to reconfigure tray client, removing... (%s)", err.what());
|
m_log.err("Failed to reconfigure tray client, removing... (%s)", err.what());
|
||||||
remove_client(client);
|
remove_client(evt->window);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1042,7 +1000,10 @@ void tray_manager::handle(const evt::property_notify& evt) {
|
|||||||
redraw_window(true);
|
redraw_window(true);
|
||||||
} else if (evt->atom == ESETROOT_PMAP_ID) {
|
} else if (evt->atom == ESETROOT_PMAP_ID) {
|
||||||
redraw_window(true);
|
redraw_window(true);
|
||||||
} else if (evt->atom == _XEMBED_INFO) {
|
} else if (evt->atom != _XEMBED_INFO) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
auto client = find_client(evt->window);
|
auto client = find_client(evt->window);
|
||||||
|
|
||||||
if (!client) {
|
if (!client) {
|
||||||
@ -1065,22 +1026,15 @@ void tray_manager::handle(const evt::property_notify& evt) {
|
|||||||
if ((client->xembed()->flags & XEMBED_MAPPED) & XEMBED_MAPPED) {
|
if ((client->xembed()->flags & XEMBED_MAPPED) & XEMBED_MAPPED) {
|
||||||
reconfigure();
|
reconfigure();
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Event callback : XCB_REPARENT_NOTIFY
|
* Event callback : XCB_REPARENT_NOTIFY
|
||||||
*/
|
*/
|
||||||
void tray_manager::handle(const evt::reparent_notify& evt) {
|
void tray_manager::handle(const evt::reparent_notify& evt) {
|
||||||
if (!m_activated) {
|
if (m_activated && is_embedded(evt->window) && evt->parent != m_tray) {
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto client = find_client(evt->window);
|
|
||||||
|
|
||||||
if (client && evt->parent != m_tray) {
|
|
||||||
m_log.trace("tray: Received reparent_notify for client, remove...");
|
m_log.trace("tray: Received reparent_notify for client, remove...");
|
||||||
remove_client(client);
|
remove_client(evt->window);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1094,13 +1048,10 @@ void tray_manager::handle(const evt::destroy_notify& evt) {
|
|||||||
m_log.trace("tray: Received destroy_notify");
|
m_log.trace("tray: Received destroy_notify");
|
||||||
// m_log.info("Tray selection available... re-activating");
|
// m_log.info("Tray selection available... re-activating");
|
||||||
// activate();
|
// activate();
|
||||||
} else if (m_activated) {
|
} else if (m_activated && is_embedded(evt->window)) {
|
||||||
auto client = find_client(evt->window);
|
|
||||||
|
|
||||||
if (client) {
|
|
||||||
m_log.trace("tray: Received destroy_notify for client, remove...");
|
m_log.trace("tray: Received destroy_notify for client, remove...");
|
||||||
remove_client(client);
|
remove_client(evt->window);
|
||||||
}
|
redraw_window();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1108,22 +1059,15 @@ void tray_manager::handle(const evt::destroy_notify& evt) {
|
|||||||
* Event callback : XCB_MAP_NOTIFY
|
* Event callback : XCB_MAP_NOTIFY
|
||||||
*/
|
*/
|
||||||
void tray_manager::handle(const evt::map_notify& evt) {
|
void tray_manager::handle(const evt::map_notify& evt) {
|
||||||
if (!m_activated) {
|
if (m_activated && evt->window == m_tray) {
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (evt->window == m_tray) {
|
|
||||||
m_log.trace("tray: Received map_notify");
|
m_log.trace("tray: Received map_notify");
|
||||||
m_log.trace("tray: Update container mapped flag");
|
m_log.trace("tray: Update container mapped flag");
|
||||||
m_mapped = true;
|
m_mapped = true;
|
||||||
} else {
|
redraw_window();
|
||||||
auto client = find_client(evt->window);
|
} else if (is_embedded(evt->window)) {
|
||||||
|
|
||||||
if (client) {
|
|
||||||
m_log.trace("tray: Received map_notify");
|
m_log.trace("tray: Received map_notify");
|
||||||
m_log.trace("tray: Set client mapped");
|
m_log.trace("tray: Set client mapped");
|
||||||
client->mapped(true);
|
find_client(evt->window)->mapped(true);
|
||||||
}
|
|
||||||
|
|
||||||
if (mapped_clients() > m_opts.configured_slots) {
|
if (mapped_clients() > m_opts.configured_slots) {
|
||||||
reconfigure();
|
reconfigure();
|
||||||
@ -1135,25 +1079,42 @@ void tray_manager::handle(const evt::map_notify& evt) {
|
|||||||
* Event callback : XCB_UNMAP_NOTIFY
|
* Event callback : XCB_UNMAP_NOTIFY
|
||||||
*/
|
*/
|
||||||
void tray_manager::handle(const evt::unmap_notify& evt) {
|
void tray_manager::handle(const evt::unmap_notify& evt) {
|
||||||
if (!m_activated) {
|
if (m_activated && evt->window == m_tray) {
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (evt->window == m_tray) {
|
|
||||||
m_log.trace("tray: Received unmap_notify");
|
m_log.trace("tray: Received unmap_notify");
|
||||||
m_log.trace("tray: Update container mapped flag");
|
m_log.trace("tray: Update container mapped flag");
|
||||||
m_mapped = false;
|
m_mapped = false;
|
||||||
} else {
|
} else if (m_activated && is_embedded(evt->window)) {
|
||||||
auto client = find_client(evt->window);
|
|
||||||
|
|
||||||
if (client) {
|
|
||||||
m_log.trace("tray: Received unmap_notify");
|
m_log.trace("tray: Received unmap_notify");
|
||||||
m_log.trace("tray: Set client unmapped");
|
m_log.trace("tray: Set client unmapped");
|
||||||
client->mapped(true);
|
find_client(evt->window)->mapped(true);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// }}}
|
/**
|
||||||
|
* Signal handler connected to the bar window's visibility change signal.
|
||||||
|
* This is used as a fallback in case the window restacking fails. It will
|
||||||
|
* toggle the tray window whenever the visibility of the bar window changes.
|
||||||
|
*/
|
||||||
|
bool tray_manager::on(const visibility_change& evt) {
|
||||||
|
bool visible{*evt()};
|
||||||
|
size_t clients{mapped_clients()};
|
||||||
|
|
||||||
|
m_log.trace("tray: visibility_change %d", visible);
|
||||||
|
m_hidden = !visible;
|
||||||
|
|
||||||
|
if (!m_activated || m_restacked) {
|
||||||
|
return false;
|
||||||
|
} else if (!m_hidden && !m_mapped && clients) {
|
||||||
|
m_connection.map_window(m_tray);
|
||||||
|
} else if ((!clients || m_hidden) && m_mapped) {
|
||||||
|
m_connection.unmap_window(m_tray);
|
||||||
|
} else if (m_mapped && !m_hidden && clients) {
|
||||||
|
redraw_window();
|
||||||
|
}
|
||||||
|
|
||||||
|
m_connection.flush();
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
POLYBAR_NS_END
|
POLYBAR_NS_END
|
@ -7,43 +7,34 @@
|
|||||||
POLYBAR_NS
|
POLYBAR_NS
|
||||||
|
|
||||||
namespace wm_util {
|
namespace wm_util {
|
||||||
void set_wmname(xcb_connection_t* conn, xcb_window_t win, const string& wm_name, const string& wm_class) {
|
void set_wm_name(xcb_connection_t* conn, xcb_window_t win, const string& wm_name, const string& wm_class) {
|
||||||
xcb_icccm_set_wm_name(conn, win, XCB_ATOM_STRING, 8, wm_name.length(), wm_name.c_str());
|
xcb_icccm_set_wm_name(conn, win, XCB_ATOM_STRING, 8, wm_name.length(), wm_name.c_str());
|
||||||
xcb_icccm_set_wm_class(conn, win, wm_class.length(), wm_class.c_str());
|
xcb_icccm_set_wm_class(conn, win, wm_class.length(), wm_class.c_str());
|
||||||
}
|
}
|
||||||
|
|
||||||
void set_wmprotocols(xcb_connection_t* conn, xcb_window_t win, vector<xcb_atom_t> flags) {
|
void set_wm_protocols(xcb_connection_t* conn, xcb_window_t win, vector<xcb_atom_t> flags) {
|
||||||
xcb_icccm_set_wm_protocols(conn, win, WM_PROTOCOLS, flags.size(), flags.data());
|
xcb_icccm_set_wm_protocols(conn, win, WM_PROTOCOLS, flags.size(), flags.data());
|
||||||
}
|
}
|
||||||
|
|
||||||
void set_windowtype(xcb_connection_t* conn, xcb_window_t win, vector<xcb_atom_t> types) {
|
void set_wm_window_type(xcb_connection_t* conn, xcb_window_t win, vector<xcb_atom_t> types) {
|
||||||
xcb_change_property(
|
xcb_change_property(
|
||||||
conn, XCB_PROP_MODE_REPLACE, win, _NET_WM_WINDOW_TYPE, XCB_ATOM_ATOM, 32, types.size(), types.data());
|
conn, XCB_PROP_MODE_REPLACE, win, _NET_WM_WINDOW_TYPE, XCB_ATOM_ATOM, 32, types.size(), types.data());
|
||||||
}
|
}
|
||||||
|
|
||||||
void set_wmstate(xcb_connection_t* conn, xcb_window_t win, vector<xcb_atom_t> states) {
|
void set_wm_state(xcb_connection_t* conn, xcb_window_t win, vector<xcb_atom_t> states) {
|
||||||
xcb_change_property(
|
xcb_change_property(
|
||||||
conn, XCB_PROP_MODE_REPLACE, win, _NET_WM_STATE, XCB_ATOM_ATOM, 32, states.size(), states.data());
|
conn, XCB_PROP_MODE_REPLACE, win, _NET_WM_STATE, XCB_ATOM_ATOM, 32, states.size(), states.data());
|
||||||
}
|
}
|
||||||
|
|
||||||
void set_wmpid(xcb_connection_t* conn, xcb_window_t win, pid_t pid) {
|
void set_wm_pid(xcb_connection_t* conn, xcb_window_t win, pid_t pid) {
|
||||||
pid = getpid();
|
pid = getpid();
|
||||||
xcb_change_property(conn, XCB_PROP_MODE_REPLACE, win, _NET_WM_PID, XCB_ATOM_CARDINAL, 32, 1, &pid);
|
xcb_change_property(conn, XCB_PROP_MODE_REPLACE, win, _NET_WM_PID, XCB_ATOM_CARDINAL, 32, 1, &pid);
|
||||||
}
|
}
|
||||||
|
|
||||||
void set_wmdesktop(xcb_connection_t* conn, xcb_window_t win, uint32_t desktop) {
|
void set_wm_desktop(xcb_connection_t* conn, xcb_window_t win, uint32_t desktop) {
|
||||||
const uint32_t value_list[1]{desktop};
|
const uint32_t value_list[1]{desktop};
|
||||||
xcb_change_property(conn, XCB_PROP_MODE_REPLACE, win, _NET_WM_DESKTOP, XCB_ATOM_CARDINAL, 32, 1, value_list);
|
xcb_change_property(conn, XCB_PROP_MODE_REPLACE, win, _NET_WM_DESKTOP, XCB_ATOM_CARDINAL, 32, 1, value_list);
|
||||||
}
|
}
|
||||||
|
|
||||||
void set_trayorientation(xcb_connection_t* conn, xcb_window_t win, uint32_t orientation) {
|
|
||||||
xcb_change_property(conn, XCB_PROP_MODE_REPLACE, win, _NET_SYSTEM_TRAY_ORIENTATION, _NET_SYSTEM_TRAY_ORIENTATION,
|
|
||||||
32, 1, &orientation);
|
|
||||||
}
|
|
||||||
|
|
||||||
void set_trayvisual(xcb_connection_t* conn, xcb_window_t win, xcb_visualid_t visual) {
|
|
||||||
xcb_change_property(conn, XCB_PROP_MODE_REPLACE, win, _NET_SYSTEM_TRAY_VISUAL, XCB_ATOM_VISUALID, 32, 1, &visual);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
POLYBAR_NS_END
|
POLYBAR_NS_END
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
#include <X11/Xlib.h>
|
#include <X11/Xlib.h>
|
||||||
|
#include <cstring>
|
||||||
#include <utility>
|
#include <utility>
|
||||||
|
|
||||||
#include "utils/factory.hpp"
|
#include "utils/factory.hpp"
|
||||||
@ -11,9 +11,9 @@ POLYBAR_NS
|
|||||||
/**
|
/**
|
||||||
* Configure injection module
|
* Configure injection module
|
||||||
*/
|
*/
|
||||||
di::injector<const xresource_manager&> configure_xresource_manager() {
|
const xresource_manager& make_xresource_manager() {
|
||||||
auto instance = factory_util::generic_singleton<xresource_manager>();
|
auto instance = factory_util::singleton<xresource_manager>();
|
||||||
return di::make_injector(di::bind<>().to(instance));
|
return static_cast<const xresource_manager&>(*instance);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -35,14 +35,6 @@ namespace xutils {
|
|||||||
return *g_connection_fd.get();
|
return *g_connection_fd.get();
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t event_timer_ms(const config& conf, const xcb_button_press_event_t&) {
|
|
||||||
return conf.get<uint32_t>("settings", "x-delay-buttonpress", 25);
|
|
||||||
}
|
|
||||||
|
|
||||||
uint32_t event_timer_ms(const config& conf, const xcb_randr_notify_event_t&) {
|
|
||||||
return conf.get<uint32_t>("settings", "x-delay-randrnotify", 50);
|
|
||||||
}
|
|
||||||
|
|
||||||
void pack_values(uint32_t mask, const uint32_t* src, uint32_t* dest) {
|
void pack_values(uint32_t mask, const uint32_t* src, uint32_t* dest) {
|
||||||
for (; mask; mask >>= 1, src++) {
|
for (; mask; mask >>= 1, src++) {
|
||||||
if (mask & 1) {
|
if (mask & 1) {
|
||||||
|
Loading…
Reference in New Issue
Block a user