mirror of https://github.com/polybar/polybar.git
268 lines
10 KiB
C++
268 lines
10 KiB
C++
#include "bar.hpp"
|
|
#include "config.hpp"
|
|
#include "registry.hpp"
|
|
#include "services/builder.hpp"
|
|
#include "utils/config.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/memory.hpp"
|
|
#include "modules/menu.hpp"
|
|
#include "modules/script.hpp"
|
|
#include "modules/text.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
|
|
|
|
std::shared_ptr<Bar> bar;
|
|
std::shared_ptr<Bar> get_bar()
|
|
{
|
|
if (bar == nullptr)
|
|
bar = std::make_shared<Bar>();
|
|
return bar;
|
|
}
|
|
|
|
std::shared_ptr<Options> bar_opts() {
|
|
return get_bar()->opts;
|
|
}
|
|
|
|
/**
|
|
* Bar constructor
|
|
*/
|
|
Bar::Bar() : config_path(config::get_bar_path()), opts(std::make_shared<Options>())
|
|
{
|
|
struct Options defaults;
|
|
|
|
try {
|
|
this->opts->locale = config::get<std::string>(this->config_path, "locale");
|
|
std::locale::global(std::locale(this->opts->locale.c_str()));
|
|
} catch (config::MissingValueException &e) {}
|
|
|
|
auto monitor_name = config::get<std::string>(this->config_path, "monitor", "");
|
|
auto monitors = xcb::monitor::get_list(x::connection(), x::connection().root());
|
|
|
|
// In case we're not connected to X, we'll just ignore the monitor
|
|
if (!monitors.empty()) {
|
|
if (monitor_name.empty() && !monitors.empty())
|
|
monitor_name = monitors[0]->name;
|
|
|
|
for (auto &&monitor : monitors) {
|
|
if (monitor_name.compare(monitor->name) == 0) {
|
|
this->opts->monitor = monitor;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (!this->opts->monitor)
|
|
throw ConfigurationError("Could not find monitor: "+ monitor_name);
|
|
}
|
|
|
|
this->opts->wm_name = "lemonbuddy-"+ this->config_path.substr(4);
|
|
if (this->opts->monitor)
|
|
this->opts->wm_name += "_"+ std::string(this->opts->monitor->name);
|
|
this->opts->wm_name = string::replace(config::get<std::string>(this->config_path, "wm_name", this->opts->wm_name), " ", "-");
|
|
|
|
// Create an empty monitor as fallback
|
|
if (!this->opts->monitor)
|
|
this->opts->monitor = xcb::monitor::make_object();
|
|
|
|
this->opts->offset_x = config::get<int>(this->config_path, "offset_x", defaults.offset_x);
|
|
this->opts->offset_y = config::get<int>(this->config_path, "offset_y", defaults.offset_y);
|
|
|
|
auto width = config::get<std::string>(this->config_path, "width", "100%");
|
|
auto height = config::get<std::string>(this->config_path, "height", "30");
|
|
|
|
if (width.find("%") != std::string::npos) {
|
|
this->opts->width = this->opts->monitor->bounds.width * (std::atoi(width.c_str()) / 100.0) + 0.5;
|
|
this->opts->width -= this->opts->offset_x * 2;
|
|
} else {
|
|
this->opts->width = std::atoi(width.c_str());
|
|
}
|
|
|
|
if (height.find("%") != std::string::npos) {
|
|
this->opts->height = this->opts->monitor->bounds.height * (std::atoi(height.c_str()) / 100.0) + 0.5;
|
|
this->opts->width -= this->opts->offset_y * 2;
|
|
} else {
|
|
this->opts->height = std::atoi(height.c_str());
|
|
}
|
|
|
|
this->opts->background = config::get<std::string>(this->config_path, "background", defaults.background);
|
|
this->opts->foreground = config::get<std::string>(this->config_path, "foreground", defaults.foreground);
|
|
this->opts->linecolor = config::get<std::string>(this->config_path, "linecolor", defaults.linecolor);
|
|
|
|
this->opts->bottom = config::get<bool>(this->config_path, "bottom", defaults.bottom);
|
|
this->opts->dock = config::get<bool>(this->config_path, "dock", defaults.dock);
|
|
this->opts->clickareas = config::get<int>(this->config_path, "clickareas", defaults.clickareas);
|
|
|
|
this->opts->separator = config::get<std::string>(this->config_path, "separator", defaults.separator);
|
|
|
|
this->opts->spacing = config::get<int>(this->config_path, "spacing", defaults.spacing);
|
|
this->opts->lineheight = config::get<int>(this->config_path, "lineheight", defaults.lineheight);
|
|
|
|
this->opts->padding_left = config::get<int>(this->config_path, "padding_left", defaults.padding_left);
|
|
this->opts->padding_right = config::get<int>(this->config_path, "padding_right", defaults.padding_right);
|
|
|
|
this->opts->module_margin_left = config::get<int>(this->config_path, "module_margin_left", defaults.module_margin_left);
|
|
this->opts->module_margin_right = config::get<int>(this->config_path, "module_margin_right", defaults.module_margin_right);
|
|
|
|
for (auto f : config::get_list<std::string>(this->config_path, "font")) {
|
|
std::vector<std::string> font;
|
|
string::split_into(f, ';', font);
|
|
if (font.size() < 2)
|
|
font.emplace_back("0");
|
|
this->opts->fonts.emplace_back(std::make_unique<Font>(font[0], std::stoi(font[1])));
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Loads all modules configured for the current bar
|
|
*/
|
|
void Bar::load(std::shared_ptr<Registry> registry)
|
|
{
|
|
this->registry = registry;
|
|
|
|
auto add_modules = [&](std::string modlist, std::vector<std::string> &vec){
|
|
std::vector<std::string> modules;
|
|
string::split_into(modlist, ' ', modules);
|
|
|
|
for (auto &&mod : modules) {
|
|
std::unique_ptr<modules::ModuleInterface> module;
|
|
auto type = config::get<std::string>("module/"+ mod, "type");
|
|
|
|
if (!ENABLE_ALSA && type == "internal/volume")
|
|
throw CompiledWithoutModuleSupport(type);
|
|
if (!ENABLE_I3 && type == "internal/i3")
|
|
throw CompiledWithoutModuleSupport(type);
|
|
if (!ENABLE_MPD && type == "internal/mpd")
|
|
throw CompiledWithoutModuleSupport(type);
|
|
if (!ENABLE_NETWORK && type == "internal/network")
|
|
throw CompiledWithoutModuleSupport(type);
|
|
|
|
if (type == "internal/counter") module = std::make_unique<modules::CounterModule>(mod);
|
|
else if (type == "internal/backlight") module = std::make_unique<modules::BacklightModule>(mod);
|
|
else if (type == "internal/battery") module = std::make_unique<modules::BatteryModule>(mod);
|
|
else if (type == "internal/bspwm") module = std::make_unique<modules::BspwmModule>(mod, this->opts->monitor->name);
|
|
else if (type == "internal/cpu") module = std::make_unique<modules::CpuModule>(mod);
|
|
else if (type == "internal/date") module = std::make_unique<modules::DateModule>(mod);
|
|
else if (type == "internal/memory") module = std::make_unique<modules::MemoryModule>(mod);
|
|
#if ENABLE_I3
|
|
else if (type == "internal/i3") module = std::make_unique<modules::i3Module>(mod, this->opts->monitor->name);
|
|
#endif
|
|
#if ENABLE_MPD
|
|
else if (type == "internal/mpd") module = std::make_unique<modules::MpdModule>(mod);
|
|
#endif
|
|
#if ENABLE_ALSA
|
|
else if (type == "internal/volume") module = std::make_unique<modules::VolumeModule>(mod);
|
|
#endif
|
|
#if ENABLE_NETWORK
|
|
else if (type == "internal/network") module = std::make_unique<modules::NetworkModule>(mod);
|
|
#endif
|
|
else if (type == "custom/text") module = std::make_unique<modules::TextModule>(mod);
|
|
else if (type == "custom/script") module = std::make_unique<modules::ScriptModule>(mod);
|
|
else if (type == "custom/menu") module = std::make_unique<modules::MenuModule>(mod);
|
|
else throw ConfigurationError("Unknown module: "+ mod);
|
|
|
|
module->attach_registry(this->registry);
|
|
|
|
vec.emplace_back(module->name());
|
|
this->registry->insert(std::move(module));
|
|
}
|
|
};
|
|
|
|
add_modules(config::get<std::string>(this->config_path, "modules-left", ""), this->mod_left);
|
|
add_modules(config::get<std::string>(this->config_path, "modules-center", ""), this->mod_center);
|
|
add_modules(config::get<std::string>(this->config_path, "modules-right", ""), this->mod_right);
|
|
|
|
if (this->mod_left.empty() && this->mod_center.empty() && this->mod_right.empty())
|
|
throw ConfigurationError("The bar does not contain any modules...");
|
|
}
|
|
|
|
/**
|
|
* Builds the output string by combining the output
|
|
* of all added modules
|
|
*/
|
|
std::string Bar::get_output()
|
|
{
|
|
auto builder = std::make_unique<Builder>();
|
|
auto pad_left = std::string(this->opts->padding_left, ' ');
|
|
auto pad_right = std::string(this->opts->padding_right, ' ');
|
|
|
|
auto output_modules = [&](Builder::Alignment align, std::vector<std::string> &mods){
|
|
if (!pad_left.empty() && !mods.empty() && align == Builder::ALIGN_LEFT)
|
|
builder->append_module_output(align, pad_left, false, false);
|
|
|
|
for (auto &mod_name : mods) {
|
|
auto mod_output = this->registry->get(mod_name);
|
|
builder->append_module_output(align, mod_output,
|
|
!(align == Builder::ALIGN_LEFT && mod_name == mods.front()),
|
|
!(align == Builder::ALIGN_RIGHT && mod_name == mods.back()));
|
|
|
|
if (!mod_output.empty() && !this->opts->separator.empty() && mod_name != mods.back())
|
|
builder->append(this->opts->separator);
|
|
}
|
|
|
|
if (!pad_right.empty() && !mods.empty() && align == Builder::ALIGN_RIGHT)
|
|
builder->append_module_output(align, pad_right, false, false);
|
|
};
|
|
|
|
output_modules(Builder::ALIGN_LEFT, this->mod_left);
|
|
output_modules(Builder::ALIGN_CENTER, this->mod_center);
|
|
output_modules(Builder::ALIGN_RIGHT, this->mod_right);
|
|
|
|
auto data = builder->flush();
|
|
|
|
// return data;
|
|
return string::replace_all(data, "}%{", " ");
|
|
}
|
|
|
|
|
|
/**
|
|
* Builds the command line string used to execute
|
|
* lemonbar using the specified bar
|
|
*/
|
|
std::string Bar::get_exec_line()
|
|
{
|
|
std::stringstream buffer;
|
|
|
|
buffer << "lemonbar -p";
|
|
if (!this->opts->wm_name.empty())
|
|
buffer << " -n " << this->opts->wm_name;
|
|
if (!this->opts->background.empty())
|
|
buffer << " -B " << this->opts->background;
|
|
if (!this->opts->foreground.empty())
|
|
buffer << " -F " << this->opts->foreground;
|
|
if (!this->opts->linecolor.empty())
|
|
buffer << " -U " << this->opts->linecolor;
|
|
if (this->opts->bottom)
|
|
buffer << " -b ";
|
|
if (this->opts->dock)
|
|
buffer << " -d ";
|
|
|
|
for (auto &&font : this->opts->fonts) {
|
|
buffer << " -f " << string::replace(font->id, " ", "-");
|
|
buffer << " -o " << font->offset;
|
|
}
|
|
|
|
buffer << " -u " << this->opts->lineheight;
|
|
buffer << " -a " << this->opts->clickareas;
|
|
buffer << " -g " << this->opts->get_geom();
|
|
buffer << " " << this->opts->monitor->name;
|
|
|
|
buffer.flush();
|
|
|
|
return string::squeeze(buffer.str(), ' ');
|
|
}
|