
* add units support (POINT, PIXEL, SPACE) for polybar - add a size_with_unit struct - add a geometry_format_values struct - move dpi initialisation from renderer.cpp to bar.cpp - add a string to size_with_unit converter - add point support (with pt) - add pixel support (with px) * Fix unit test compilation * clang-format * Better names The old names didn't really capture the purpose of the structs and function. space_type -> spacing_type space_size -> spacing_val size_type -> extent_type geometry -> extent_val geometry_format_values -> percentage_with_offset * Remove parse_size_with_unit No longer needed. The convert<spacing_val> function in config.cpp already does all the work for us and always setting the type to pixel was wrong. In addition, line-size should not be of type spacing_val but extent_val. * Cleanup I tried to address most of my comments on the old PR * Fix renderer width calculation We can't just blindly add the x difference to the width because for example the width should increase if x < width and the increase keeps x < width. Similarly, we can't just add the offset to the width. * Rename geom_format_to_pixels to percentage_with_offset_to_pixel * Cleanup * Apply suggested changes from Patrick on GitHub Co-authored-by: Patrick Ziegler <p.ziegler96@gmail.com> * Update src/components/bar.cpp Co-authored-by: Patrick Ziegler <p.ziegler96@gmail.com> * Update src/components/config.cpp Co-authored-by: Patrick Ziegler <p.ziegler96@gmail.com> * Update src/components/builder.cpp Co-authored-by: Patrick Ziegler <p.ziegler96@gmail.com> * Update src/components/builder.cpp Co-authored-by: Patrick Ziegler <p.ziegler96@gmail.com> * config: Use stod for parsing percentage * Use stof instead of strtof * units: Fix test edge cases * Remove unnecessary clang-format toggle * Use percentage_with_offset for margin-{top,bottom} * Support negative extent values * Rename unit to units and create a cpp file * Move percentage_with_offset_to_pixel unit test to units * Add unit tests for units_utils * Clarify when and how negative spacing/extent is allowed Negative spacing is never allowed and produces a config error. Extents allow negative values in theory, but only a few use-cases accept it. Only the extent value used for the `%{O}` tag and the offset value in percentage_with_offset can be negative. Everything else is capped below at 0. The final pixel value of percentage_with_offset also caps below at 0. * Fix parsing errors not being caught in config * Print a proper error message for uncaught exceptions * Cleanup module::get_output All changes preserve the existing semantics * Stop using remove_trailing_space in module::get_output Instead, we first check if the current tag is built, and only if it is, the spacing is prepended. * Remove unused imports * Restore old behavior If there are two tags and the second one isn't built (module::build returns false), the space in between them is removed. For example in the mpd module: format-online = <toggle> <label-song> foo If mpd is not running, the mpd module will return false when trying to build the `<label-song>` tag. If we don't remove the space between `<toggle>` and `<label-song>`, we end up with two spaces between `<toggle>` and `foo`. This change is to match the old behavior where at least one trailing space character was removed from the builder. * Add changelog entry * Remove unused setting * Use percentage with offset for tray-offset Co-authored-by: Jérôme BOULMIER <jerome.boulmier@outlook.fr> Co-authored-by: Joe Groocock <github@frebib.net>
181 lines
6.4 KiB
C++
181 lines
6.4 KiB
C++
#include "components/bar.hpp"
|
|
#include "components/command_line.hpp"
|
|
#include "components/config.hpp"
|
|
#include "components/config_parser.hpp"
|
|
#include "components/controller.hpp"
|
|
#include "ipc/ipc.hpp"
|
|
#include "utils/env.hpp"
|
|
#include "utils/inotify.hpp"
|
|
#include "utils/process.hpp"
|
|
#include "x11/connection.hpp"
|
|
|
|
using namespace polybar;
|
|
using namespace eventloop;
|
|
|
|
int main(int argc, char** argv) {
|
|
// clang-format off
|
|
const command_line::options opts{
|
|
command_line::option{"-h", "--help", "Display this help and exit"},
|
|
command_line::option{"-v", "--version", "Display build details and exit"},
|
|
command_line::option{"-l", "--log", "Set the logging verbosity (default: notice)", "LEVEL", {"error", "warning", "notice", "info", "trace"}},
|
|
command_line::option{"-q", "--quiet", "Be quiet (will override -l)"},
|
|
command_line::option{"-c", "--config", "Path to the configuration file", "FILE"},
|
|
command_line::option{"-r", "--reload", "Reload when the configuration has been modified"},
|
|
command_line::option{"-d", "--dump", "Print value of PARAM in bar section and exit", "PARAM"},
|
|
command_line::option{"-m", "--list-monitors", "Print list of available monitors and exit (Removes cloned monitors)"},
|
|
command_line::option{"-M", "--list-all-monitors", "Print list of all available monitors (Including cloned monitors) and exit"},
|
|
command_line::option{"-w", "--print-wmname", "Print the generated WM_NAME and exit"},
|
|
command_line::option{"-s", "--stdout", "Output data to stdout instead of drawing it to the X window"},
|
|
command_line::option{"-p", "--png", "Save png snapshot to FILE after running for 3 seconds", "FILE"},
|
|
};
|
|
// clang-format on
|
|
|
|
unsigned char exit_code{EXIT_SUCCESS};
|
|
bool reload{false};
|
|
|
|
logger& logger{const_cast<decltype(logger)>(logger::make(loglevel::NOTICE))};
|
|
|
|
try {
|
|
//==================================================
|
|
// Parse command line arguments
|
|
//==================================================
|
|
string scriptname{argv[0]};
|
|
vector<string> args{argv + 1, argv + argc};
|
|
|
|
command_line::parser::make_type cli{command_line::parser::make(move(scriptname), move(opts))};
|
|
cli->process_input(args);
|
|
|
|
if (cli->has("quiet")) {
|
|
logger.verbosity(loglevel::ERROR);
|
|
} else if (cli->has("log")) {
|
|
logger.verbosity(logger::parse_verbosity(cli->get("log")));
|
|
}
|
|
|
|
if (cli->has("help")) {
|
|
cli->usage();
|
|
return EXIT_SUCCESS;
|
|
} else if (cli->has("version")) {
|
|
print_build_info(version_details(args));
|
|
return EXIT_SUCCESS;
|
|
}
|
|
|
|
loop loop{};
|
|
|
|
//==================================================
|
|
// Connect to X server
|
|
//==================================================
|
|
auto xcb_error = 0;
|
|
auto xcb_screen = 0;
|
|
auto xcb_connection = xcb_connect(nullptr, &xcb_screen);
|
|
|
|
if (xcb_connection == nullptr) {
|
|
throw application_error("A connection to X could not be established...");
|
|
} else if ((xcb_error = xcb_connection_has_error(xcb_connection))) {
|
|
throw application_error("X connection error... (what: " + connection::error_str(xcb_error) + ")");
|
|
}
|
|
|
|
connection& conn{connection::make(xcb_connection, xcb_screen)};
|
|
conn.ensure_event_mask(conn.root(), XCB_EVENT_MASK_PROPERTY_CHANGE);
|
|
|
|
//==================================================
|
|
// List available XRandR entries
|
|
//==================================================
|
|
if (cli->has("list-monitors") || cli->has("list-all-monitors")) {
|
|
bool purge_clones = !cli->has("list-all-monitors");
|
|
auto monitors = randr_util::get_monitors(conn, conn.root(), true, purge_clones);
|
|
for (auto&& mon : monitors) {
|
|
if (mon->output == XCB_NONE) {
|
|
printf("%s: %ix%i+%i+%i (no output%s)\n", mon->name.c_str(), mon->w, mon->h, mon->x, mon->y,
|
|
mon->primary ? ", primary" : "");
|
|
} else {
|
|
printf("%s: %ix%i+%i+%i%s\n", mon->name.c_str(), mon->w, mon->h, mon->x, mon->y,
|
|
mon->primary ? " (primary)" : "");
|
|
}
|
|
}
|
|
return EXIT_SUCCESS;
|
|
}
|
|
|
|
//==================================================
|
|
// Load user configuration
|
|
//==================================================
|
|
string confpath;
|
|
|
|
// Make sure a bar name is passed in
|
|
if (cli->has(1)) {
|
|
fprintf(stderr, "Unrecognized argument \"%s\"\n", cli->get(1).c_str());
|
|
cli->usage();
|
|
return EXIT_FAILURE;
|
|
}
|
|
|
|
if (cli->has("config")) {
|
|
confpath = cli->get("config");
|
|
} else {
|
|
confpath = file_util::get_config_path();
|
|
|
|
if (string_util::ends_with(confpath, "/config")) {
|
|
logger::make().warn(
|
|
"Naming your configuration file 'config' is deprecated, the expected name is 'config.ini'.");
|
|
}
|
|
}
|
|
|
|
if (confpath.empty()) {
|
|
throw application_error("Define configuration using --config=PATH");
|
|
}
|
|
|
|
string barname;
|
|
if (cli->has(0)) {
|
|
barname = cli->get(0);
|
|
}
|
|
|
|
config_parser parser{logger, move(confpath), move(barname)};
|
|
config::make_type conf = parser.parse();
|
|
|
|
//==================================================
|
|
// Dump requested data
|
|
//==================================================
|
|
if (cli->has("dump")) {
|
|
printf("%s\n", conf.get(conf.section(), cli->get("dump")).c_str());
|
|
return EXIT_SUCCESS;
|
|
}
|
|
if (cli->has("print-wmname")) {
|
|
printf("%s\n", bar::make(loop, true)->settings().wmname.c_str());
|
|
return EXIT_SUCCESS;
|
|
}
|
|
|
|
//==================================================
|
|
// Create controller and run application
|
|
//==================================================
|
|
unique_ptr<ipc::ipc> ipc{};
|
|
|
|
if (conf.get(conf.section(), "enable-ipc", false)) {
|
|
try {
|
|
ipc = ipc::ipc::make(loop);
|
|
} catch (const std::exception& e) {
|
|
ipc.reset();
|
|
logger.err("Disabling IPC channels due to error: %s", e.what());
|
|
}
|
|
}
|
|
|
|
auto ctrl = controller::make((bool)ipc, loop);
|
|
|
|
if (!ctrl->run(cli->has("stdout"), cli->get("png"), cli->has("reload"))) {
|
|
reload = true;
|
|
}
|
|
} catch (const exception& err) {
|
|
logger.err("Uncaught exception, shutting down: %s", err.what());
|
|
exit_code = EXIT_FAILURE;
|
|
}
|
|
|
|
logger.info("Waiting for spawned processes to end");
|
|
while (process_util::notify_childprocess()) {
|
|
;
|
|
}
|
|
|
|
if (reload) {
|
|
logger.info("Re-launching application...");
|
|
process_util::exec(move(argv[0]), move(argv));
|
|
}
|
|
|
|
logger.info("Reached end of application...");
|
|
return exit_code;
|
|
}
|