added output-dimensions option
This commit is contained in:
@@ -24,6 +24,8 @@ struct waybar_output {
|
|||||||
Glib::RefPtr<Gdk::Monitor> monitor;
|
Glib::RefPtr<Gdk::Monitor> monitor;
|
||||||
std::string name;
|
std::string name;
|
||||||
std::string identifier;
|
std::string identifier;
|
||||||
|
int32_t width;
|
||||||
|
int32_t height;
|
||||||
|
|
||||||
std::unique_ptr<struct zxdg_output_v1, decltype(&zxdg_output_v1_destroy)> xdg_output = {
|
std::unique_ptr<struct zxdg_output_v1, decltype(&zxdg_output_v1_destroy)> xdg_output = {
|
||||||
nullptr, &zxdg_output_v1_destroy};
|
nullptr, &zxdg_output_v1_destroy};
|
||||||
|
|||||||
@@ -45,6 +45,7 @@ class Client {
|
|||||||
static void handleGlobal(void* data, struct wl_registry* registry, uint32_t name,
|
static void handleGlobal(void* data, struct wl_registry* registry, uint32_t name,
|
||||||
const char* interface, uint32_t version);
|
const char* interface, uint32_t version);
|
||||||
static void handleGlobalRemove(void* data, struct wl_registry* registry, uint32_t name);
|
static void handleGlobalRemove(void* data, struct wl_registry* registry, uint32_t name);
|
||||||
|
static void handleOutputLogicalSize(void*, struct zxdg_output_v1*, int32_t, int32_t);
|
||||||
static void handleOutputDone(void*, struct zxdg_output_v1*);
|
static void handleOutputDone(void*, struct zxdg_output_v1*);
|
||||||
void createBarsBatch();
|
void createBarsBatch();
|
||||||
static void handleOutputName(void*, struct zxdg_output_v1*, const char*);
|
static void handleOutputName(void*, struct zxdg_output_v1*, const char*);
|
||||||
|
|||||||
+2
-1
@@ -29,7 +29,8 @@ class Config {
|
|||||||
|
|
||||||
Json::Value& getConfig() { return config_; }
|
Json::Value& getConfig() { return config_; }
|
||||||
|
|
||||||
std::vector<Json::Value> getOutputConfigs(const std::string& name, const std::string& identifier);
|
std::vector<Json::Value> getOutputConfigs(const std::string& name, const std::string& identifier,
|
||||||
|
int32_t width, int32_t height);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void setupConfig(Json::Value& dst, const std::string& config_file, int depth);
|
void setupConfig(Json::Value& dst, const std::string& config_file, int depth);
|
||||||
|
|||||||
@@ -50,6 +50,10 @@ The visual display elements for waybar use a CSS stylesheet. Waybar supports *st
|
|||||||
Output specification follows sway's and can either be the output port such as "HDMI-A-1" or a string consisting of the make, model, and serial such as "Some Company ABC123 0x00000000". See *sway-output(5)* for details.
|
Output specification follows sway's and can either be the output port such as "HDMI-A-1" or a string consisting of the make, model, and serial such as "Some Company ABC123 0x00000000". See *sway-output(5)* for details.
|
||||||
In an array, star '*\**' can be used at the end to accept all outputs, in case all previous entries are exclusions.
|
In an array, star '*\**' can be used at the end to accept all outputs, in case all previous entries are exclusions.
|
||||||
|
|
||||||
|
*output-dimensions* ++
|
||||||
|
typeof: string|array ++
|
||||||
|
If *output* is not specified, allows selecting outputs by dimensions. Format "(width/height) (</>) (value)", e.g. "width > 1080". Multiple conditions can be chained.
|
||||||
|
|
||||||
*position* ++
|
*position* ++
|
||||||
typeof: string ++
|
typeof: string ++
|
||||||
default: top ++
|
default: top ++
|
||||||
@@ -417,6 +421,24 @@ To hide the power group if it is empty, apply to #power and all its children:
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
## Select outputs by dimensions
|
||||||
|
|
||||||
|
```
|
||||||
|
{
|
||||||
|
"layer": "top",
|
||||||
|
"output-dimensions": "width > 1080",
|
||||||
|
...
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
```
|
||||||
|
{
|
||||||
|
"layer": "top",
|
||||||
|
"output-dimensions": ["width < 3840", "height < 2160"],
|
||||||
|
...
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
# SUPPORTED MODULES
|
# SUPPORTED MODULES
|
||||||
|
|
||||||
- *waybar-backlight(5)*
|
- *waybar-backlight(5)*
|
||||||
|
|||||||
+14
-2
@@ -58,7 +58,7 @@ void waybar::Client::handleGlobalRemove(void* data, struct wl_registry* /*regist
|
|||||||
void waybar::Client::handleOutput(struct waybar_output& output) {
|
void waybar::Client::handleOutput(struct waybar_output& output) {
|
||||||
static const struct zxdg_output_v1_listener xdgOutputListener = {
|
static const struct zxdg_output_v1_listener xdgOutputListener = {
|
||||||
.logical_position = [](void*, struct zxdg_output_v1*, int32_t, int32_t) {},
|
.logical_position = [](void*, struct zxdg_output_v1*, int32_t, int32_t) {},
|
||||||
.logical_size = [](void*, struct zxdg_output_v1*, int32_t, int32_t) {},
|
.logical_size = &handleOutputLogicalSize,
|
||||||
.done = &handleOutputDone,
|
.done = &handleOutputDone,
|
||||||
.name = &handleOutputName,
|
.name = &handleOutputName,
|
||||||
.description = &handleOutputDescription,
|
.description = &handleOutputDescription,
|
||||||
@@ -79,7 +79,19 @@ struct waybar::waybar_output& waybar::Client::getOutput(void* addr) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
std::vector<Json::Value> waybar::Client::getOutputConfigs(struct waybar_output& output) {
|
std::vector<Json::Value> waybar::Client::getOutputConfigs(struct waybar_output& output) {
|
||||||
return config.getOutputConfigs(output.name, output.identifier);
|
return config.getOutputConfigs(output.name, output.identifier, output.width, output.height);
|
||||||
|
}
|
||||||
|
|
||||||
|
void waybar::Client::handleOutputLogicalSize(void* data, struct zxdg_output_v1* object,
|
||||||
|
int32_t width, int32_t height) {
|
||||||
|
auto client = waybar::Client::inst();
|
||||||
|
try {
|
||||||
|
auto& output = client->getOutput(data);
|
||||||
|
output.width = width;
|
||||||
|
output.height = height;
|
||||||
|
} catch (const std::exception& e) {
|
||||||
|
std::cerr << e.what() << std::endl;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void waybar::Client::handleOutputDone(void* data, struct zxdg_output_v1* /*xdg_output*/) {
|
void waybar::Client::handleOutputDone(void* data, struct zxdg_output_v1* /*xdg_output*/) {
|
||||||
|
|||||||
+38
-5
@@ -174,8 +174,8 @@ void Config::mergeConfig(Json::Value& a_config_, Json::Value& b_config_) {
|
|||||||
spdlog::error("Cannot merge config, conflicting or invalid JSON types");
|
spdlog::error("Cannot merge config, conflicting or invalid JSON types");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
bool isValidOutput(const Json::Value& config, const std::string& name,
|
bool isValidOutput(const Json::Value& config, const std::string& name, const std::string& identifier,
|
||||||
const std::string& identifier) {
|
int32_t width, int32_t height) {
|
||||||
const auto isOutputMatches = [&](const std::string& output) -> bool {
|
const auto isOutputMatches = [&](const std::string& output) -> bool {
|
||||||
if (output.substr(0, 1) == "$") {
|
if (output.substr(0, 1) == "$") {
|
||||||
auto* const environment_value = std::getenv(output.substr(1).c_str());
|
auto* const environment_value = std::getenv(output.substr(1).c_str());
|
||||||
@@ -227,6 +227,38 @@ bool isValidOutput(const Json::Value& config, const std::string& name,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// if "output-dimensions" is a string, make it an array of size 1
|
||||||
|
Json::Value config_output_dimensions = config["output-dimensions"];
|
||||||
|
if (config_output_dimensions.isString()) {
|
||||||
|
Json::Value jsonArray(Json::arrayValue);
|
||||||
|
jsonArray.append(config_output_dimensions);
|
||||||
|
config_output_dimensions = jsonArray;
|
||||||
|
}
|
||||||
|
if (config_output_dimensions.isArray()) {
|
||||||
|
for (auto const &config_output_dimension : config_output_dimensions) {
|
||||||
|
if (!config_output_dimension.isString()) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
std::string str = config_output_dimension.asString();
|
||||||
|
int i = str.find(" ");
|
||||||
|
std::string dimension = str.substr(0, i);
|
||||||
|
str = str.substr(i + 1);
|
||||||
|
i = str.find(" ");
|
||||||
|
std::string comparator = str.substr(0, i);
|
||||||
|
int value = std::stoi(str.substr(i));
|
||||||
|
|
||||||
|
if (dimension == "height" && comparator == "<" && height >= value) {
|
||||||
|
return false;
|
||||||
|
} else if (dimension == "height" && comparator == ">" && height <= value) {
|
||||||
|
return false;
|
||||||
|
}else if (dimension == "width" && comparator == "<" && width >= value) {
|
||||||
|
return false;
|
||||||
|
}else if (dimension == "width" && comparator == ">" && width <= value) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -242,15 +274,16 @@ void Config::load(const std::string& config) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
std::vector<Json::Value> Config::getOutputConfigs(const std::string& name,
|
std::vector<Json::Value> Config::getOutputConfigs(const std::string& name,
|
||||||
const std::string& identifier) {
|
const std::string& identifier, int32_t width,
|
||||||
|
int32_t height) {
|
||||||
std::vector<Json::Value> configs;
|
std::vector<Json::Value> configs;
|
||||||
if (config_.isArray()) {
|
if (config_.isArray()) {
|
||||||
for (auto const& config : config_) {
|
for (auto const& config : config_) {
|
||||||
if (config.isObject() && isValidOutput(config, name, identifier)) {
|
if (config.isObject() && isValidOutput(config, name, identifier, width, height)) {
|
||||||
configs.push_back(config);
|
configs.push_back(config);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if (isValidOutput(config_, name, identifier)) {
|
} else if (isValidOutput(config_, name, identifier, width, height)) {
|
||||||
configs.push_back(config_);
|
configs.push_back(config_);
|
||||||
}
|
}
|
||||||
return configs;
|
return configs;
|
||||||
|
|||||||
+11
-11
@@ -16,11 +16,11 @@ TEST_CASE("Load simple config", "[config]") {
|
|||||||
REQUIRE(data["height"].asInt() == 30);
|
REQUIRE(data["height"].asInt() == 30);
|
||||||
}
|
}
|
||||||
SECTION("select configs for configured output") {
|
SECTION("select configs for configured output") {
|
||||||
auto configs = conf.getOutputConfigs("HDMI-0", "Fake HDMI output #0");
|
auto configs = conf.getOutputConfigs("HDMI-0", "Fake HDMI output #0", 0, 0);
|
||||||
REQUIRE(configs.size() == 1);
|
REQUIRE(configs.size() == 1);
|
||||||
}
|
}
|
||||||
SECTION("select configs for missing output") {
|
SECTION("select configs for missing output") {
|
||||||
auto configs = conf.getOutputConfigs("HDMI-1", "Fake HDMI output #1");
|
auto configs = conf.getOutputConfigs("HDMI-1", "Fake HDMI output #1", 0, 0);
|
||||||
REQUIRE(configs.empty());
|
REQUIRE(configs.empty());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -30,7 +30,7 @@ TEST_CASE("Load config with multiple bars", "[config]") {
|
|||||||
conf.load("test/config/multi.json");
|
conf.load("test/config/multi.json");
|
||||||
|
|
||||||
SECTION("select multiple configs #1") {
|
SECTION("select multiple configs #1") {
|
||||||
auto data = conf.getOutputConfigs("DP-0", "Fake DisplayPort output #0");
|
auto data = conf.getOutputConfigs("DP-0", "Fake DisplayPort output #0", 0, 0);
|
||||||
REQUIRE(data.size() == 4);
|
REQUIRE(data.size() == 4);
|
||||||
REQUIRE(data[0]["layer"].asString() == "bottom");
|
REQUIRE(data[0]["layer"].asString() == "bottom");
|
||||||
REQUIRE(data[0]["height"].asInt() == 20);
|
REQUIRE(data[0]["height"].asInt() == 20);
|
||||||
@@ -43,7 +43,7 @@ TEST_CASE("Load config with multiple bars", "[config]") {
|
|||||||
REQUIRE(data[3]["height"].asInt() == 24);
|
REQUIRE(data[3]["height"].asInt() == 24);
|
||||||
}
|
}
|
||||||
SECTION("select multiple configs #2") {
|
SECTION("select multiple configs #2") {
|
||||||
auto data = conf.getOutputConfigs("HDMI-0", "Fake HDMI output #0");
|
auto data = conf.getOutputConfigs("HDMI-0", "Fake HDMI output #0", 0, 0);
|
||||||
REQUIRE(data.size() == 2);
|
REQUIRE(data.size() == 2);
|
||||||
REQUIRE(data[0]["layer"].asString() == "bottom");
|
REQUIRE(data[0]["layer"].asString() == "bottom");
|
||||||
REQUIRE(data[0]["height"].asInt() == 20);
|
REQUIRE(data[0]["height"].asInt() == 20);
|
||||||
@@ -52,7 +52,7 @@ TEST_CASE("Load config with multiple bars", "[config]") {
|
|||||||
REQUIRE(data[1]["height"].asInt() == 23);
|
REQUIRE(data[1]["height"].asInt() == 23);
|
||||||
}
|
}
|
||||||
SECTION("select single config by output description") {
|
SECTION("select single config by output description") {
|
||||||
auto data = conf.getOutputConfigs("HDMI-1", "Fake HDMI output #1");
|
auto data = conf.getOutputConfigs("HDMI-1", "Fake HDMI output #1", 0, 0);
|
||||||
REQUIRE(data.size() == 1);
|
REQUIRE(data.size() == 1);
|
||||||
REQUIRE(data[0]["layer"].asString() == "overlay");
|
REQUIRE(data[0]["layer"].asString() == "overlay");
|
||||||
REQUIRE(data[0]["position"].asString() == "left");
|
REQUIRE(data[0]["position"].asString() == "left");
|
||||||
@@ -75,11 +75,11 @@ TEST_CASE("Load simple config with include", "[config]") {
|
|||||||
REQUIRE((data.isMember("nullOption") && data["nullOption"].isNull()));
|
REQUIRE((data.isMember("nullOption") && data["nullOption"].isNull()));
|
||||||
}
|
}
|
||||||
SECTION("select configs for configured output") {
|
SECTION("select configs for configured output") {
|
||||||
auto configs = conf.getOutputConfigs("HDMI-0", "Fake HDMI output #0");
|
auto configs = conf.getOutputConfigs("HDMI-0", "Fake HDMI output #0", 0, 0);
|
||||||
REQUIRE(configs.size() == 1);
|
REQUIRE(configs.size() == 1);
|
||||||
}
|
}
|
||||||
SECTION("select configs for missing output") {
|
SECTION("select configs for missing output") {
|
||||||
auto configs = conf.getOutputConfigs("HDMI-1", "Fake HDMI output #1");
|
auto configs = conf.getOutputConfigs("HDMI-1", "Fake HDMI output #1", 0, 0);
|
||||||
REQUIRE(configs.empty());
|
REQUIRE(configs.empty());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -116,25 +116,25 @@ TEST_CASE("Load multiple bar config with include", "[config]") {
|
|||||||
conf.load("test/config/include-multi.json");
|
conf.load("test/config/include-multi.json");
|
||||||
|
|
||||||
SECTION("bar config with sole include") {
|
SECTION("bar config with sole include") {
|
||||||
auto data = conf.getOutputConfigs("OUT-0", "Fake output #0");
|
auto data = conf.getOutputConfigs("OUT-0", "Fake output #0", 0, 0);
|
||||||
REQUIRE(data.size() == 1);
|
REQUIRE(data.size() == 1);
|
||||||
REQUIRE(data[0]["height"].asInt() == 20);
|
REQUIRE(data[0]["height"].asInt() == 20);
|
||||||
}
|
}
|
||||||
|
|
||||||
SECTION("bar config with output and include") {
|
SECTION("bar config with output and include") {
|
||||||
auto data = conf.getOutputConfigs("OUT-1", "Fake output #1");
|
auto data = conf.getOutputConfigs("OUT-1", "Fake output #1", 0, 0);
|
||||||
REQUIRE(data.size() == 1);
|
REQUIRE(data.size() == 1);
|
||||||
REQUIRE(data[0]["height"].asInt() == 21);
|
REQUIRE(data[0]["height"].asInt() == 21);
|
||||||
}
|
}
|
||||||
|
|
||||||
SECTION("bar config with output override") {
|
SECTION("bar config with output override") {
|
||||||
auto data = conf.getOutputConfigs("OUT-2", "Fake output #2");
|
auto data = conf.getOutputConfigs("OUT-2", "Fake output #2", 0, 0);
|
||||||
REQUIRE(data.size() == 1);
|
REQUIRE(data.size() == 1);
|
||||||
REQUIRE(data[0]["height"].asInt() == 22);
|
REQUIRE(data[0]["height"].asInt() == 22);
|
||||||
}
|
}
|
||||||
|
|
||||||
SECTION("multiple levels of include") {
|
SECTION("multiple levels of include") {
|
||||||
auto data = conf.getOutputConfigs("OUT-3", "Fake output #3");
|
auto data = conf.getOutputConfigs("OUT-3", "Fake output #3", 0, 0);
|
||||||
REQUIRE(data.size() == 1);
|
REQUIRE(data.size() == 1);
|
||||||
REQUIRE(data[0]["height"].asInt() == 23);
|
REQUIRE(data[0]["height"].asInt() == 23);
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user