diff --git a/README.md b/README.md index 9f835bb..b91f915 100644 --- a/README.md +++ b/README.md @@ -104,6 +104,7 @@ wideriver \ --outer-gaps 0 \ --border-width 2 \ --border-width-monocle 0 \ + --border-width-smart-gaps 0 \ --border-color-focused "0x93a1a1" \ --border-color-focused-monocle "0x586e75" \ --border-color-unfocused "0x586e75" \ @@ -322,6 +323,8 @@ Gaps, in pixels, between windows may be injected. They are off by default. `--smart-gaps` automatically hides the gaps when there is only one view or monocle layout. +`--border-width-smart-gaps` the border width for when smart gaps hides the gaps, excluding monocle layout. For a seamless experience, set this to the same value as `--border-width-monocle` + ---------------------------------------------------------- | o o o o o o o o o o o o | | ---------------------- ----------------------- | @@ -382,6 +385,7 @@ Should install under `/usr/local` --border-width pixels 2 0 <= width --border-width-monocle pixels 0 0 <= width + --border-width-smart-gaps pixels 0 0 <= width --border-color-focused 0xRRGGBB[AA] 0x93a1a1 --border-color-focused-monocle 0xRRGGBB[AA] 0x586e75 @@ -439,6 +443,9 @@ Border width for all layouts except monocle, default `2`, minimum `0`. `--border-width-monocle` *pixels* Border width for monocle layout, default `0`, minimum `0`. +`--border-width-smart-gaps` *pixels* +Border width for when smart gaps hides the gaps for all layouts except monocle, default `0`, minimum `0`. Has no effect if `--no-smart-gaps`. + `--border-color-focused` `0x`*RRGGBB*\[*AA*\] Border color for focused views in all layouts excluding monocle, default `0x93a1a1`. diff --git a/config.mk b/config.mk index d184540..bd7d8e7 100644 --- a/config.mk +++ b/config.mk @@ -1,4 +1,4 @@ -VERSION ?= "1.1.1-SNAPSHOT" +VERSION ?= "1.2.0-SNAPSHOT" RIVER_LAYOUT_V3_VERSION = 2 diff --git a/doc/templ/20.man.readme.md b/doc/templ/20.man.readme.md index 25a4223..6026973 100644 --- a/doc/templ/20.man.readme.md +++ b/doc/templ/20.man.readme.md @@ -271,6 +271,8 @@ Gaps, in pixels, between windows may be injected. They are off by default. `--smart-gaps` automatically hides the gaps when there is only one view or monocle layout. +`--border-width-smart-gaps` the border width for when smart gaps hides the gaps, excluding monocle layout. +For a seamless experience, set this to the same value as `--border-width-monocle` ``` ---------------------------------------------------------- | o o o o o o o o o o o o | diff --git a/doc/templ/40.man.readme.md b/doc/templ/40.man.readme.md index d8c0e66..1e9bc85 100644 --- a/doc/templ/40.man.readme.md +++ b/doc/templ/40.man.readme.md @@ -41,6 +41,10 @@ The default value is best suited to ultrawide monitors, a value of `0.5` may be `--border-width-monocle` *pixels* : Border width for monocle layout, default `0`, minimum `0`. +`--border-width-smart-gaps` *pixels* +: Border width for when smart gaps hides the gaps for all layouts except monocle, default `0`, minimum `0`. +Has no effect if `--no-smart-gaps`. + `--border-color-focused` `0x`*RRGGBB*[*AA*] : Border color for focused views in all layouts excluding monocle, default `0x93a1a1`. diff --git a/inc/cfg.h b/inc/cfg.h index ebc386d..96bae8d 100644 --- a/inc/cfg.h +++ b/inc/cfg.h @@ -20,6 +20,9 @@ #define SMART_GAPS_DEFAULT false +#define BORDER_WIDTH_SMART_GAPS_MIN 0 +#define BORDER_WIDTH_SMART_GAPS_DEFAULT 0 + #define INNER_GAPS_MIN 0 #define INNER_GAPS_DEFAULT 0 @@ -50,6 +53,7 @@ struct Cfg { uint32_t count_wide_left; double ratio_wide; bool smart_gaps; + uint32_t border_width_smart_gaps; uint32_t inner_gaps; uint32_t outer_gaps; size_t border_width; @@ -68,6 +72,7 @@ bool cfg_set_ratio_master(const char *s); bool cfg_set_count_wide_left(const char *s); bool cfg_set_ratio_wide(const char *s); void cfg_set_smart_gaps(bool smart_gaps); +bool cfg_set_border_width_smart_gaps(const char *s); bool cfg_set_inner_gaps(const char *s); bool cfg_set_outer_gaps(const char *s); bool cfg_set_border_width(const char *s); diff --git a/inc/displ.h b/inc/displ.h index 1a8b27b..e26a7ad 100644 --- a/inc/displ.h +++ b/inc/displ.h @@ -3,6 +3,7 @@ #include #include +#include #include "output.h" #include "tag.h" @@ -42,6 +43,6 @@ bool displ_init(void); void displ_destroy(void); // request style as per tag, output must be focused or no focus reported (startup case) -void displ_request_style(const struct Output *output, const struct Tag *tag); +void displ_request_style(const struct Output *output, const struct Tag *tag, const uint32_t view_count); #endif // DISPL_H diff --git a/man/wideriver.1 b/man/wideriver.1 index 777041e..62d5410 100644 --- a/man/wideriver.1 +++ b/man/wideriver.1 @@ -1,7 +1,7 @@ '\" t .\" Automatically generated by Pandoc 3.1.8 .\" -.TH "WIDERIVER" "1" "2024/04/23" "wideriver" "User Manuals" +.TH "WIDERIVER" "1" "2024/05/28" "wideriver" "User Manuals" .SH NAME \f[CR]wideriver\f[R] - tiling window manager for the river wayland compositor .SH SYNOPSIS @@ -146,6 +146,7 @@ wideriver \[rs] --outer-gaps 0 \[rs] --border-width 2 \[rs] --border-width-monocle 0 \[rs] + --border-width-smart-gaps 0 \[rs] --border-color-focused \[dq]0x93a1a1\[dq] \[rs] --border-color-focused-monocle \[dq]0x586e75\[dq] \[rs] --border-color-unfocused \[dq]0x586e75\[dq] \[rs] @@ -340,6 +341,9 @@ They are off by default. \f[CR]--outer-gaps\f[R] (\f[CR]o\f[R]) are between the edge of the screen and windows. .PP \f[CR]--smart-gaps\f[R] automatically hides the gaps when there is only one view or monocle layout. +.PP +\f[CR]--border-width-smart-gaps\f[R] the border width for when smart gaps hides the gaps, excluding monocle layout. +For a seamless experience, set this to the same value as \f[CR]--border-width-monocle\f[R] .IP .EX ---------------------------------------------------------- @@ -401,6 +405,10 @@ Border width for all layouts except monocle, default \f[CR]2\f[R], minimum \f[CR \f[CR]--border-width-monocle\f[R] \f[I]pixels\f[R] Border width for monocle layout, default \f[CR]0\f[R], minimum \f[CR]0\f[R]. .TP +\f[CR]--border-width-smart-gaps\f[R] \f[I]pixels\f[R] +Border width for when smart gaps hides the gaps for all layouts except monocle, default \f[CR]0\f[R], minimum \f[CR]0\f[R]. +Has no effect if \f[CR]--no-smart-gaps\f[R]. +.TP \f[CR]--border-color-focused\f[R] \f[CR]0x\f[R]\f[I]RRGGBB\f[R][\f[I]AA\f[R]] Border color for focused views in all layouts excluding monocle, default \f[CR]0x93a1a1\f[R]. .TP diff --git a/src/args.c b/src/args.c index f731fa3..28b7066 100644 --- a/src/args.c +++ b/src/args.c @@ -22,17 +22,18 @@ static struct option cli_long_options[] = { { "ratio-wide", required_argument, 0, 0, }, // 6 { "smart-gaps", no_argument, 0, 0, }, // 7 { "no-smart-gaps", no_argument, 0, 0, }, // 8 - { "inner-gaps", required_argument, 0, 0, }, // 9 - { "outer-gaps", required_argument, 0, 0, }, // 10 - { "border-width", required_argument, 0, 0, }, // 11 - { "border-width-monocle", required_argument, 0, 0, }, // 12 - { "border-color-focused", required_argument, 0, 0, }, // 13 - { "border-color-focused-monocle", required_argument, 0, 0, }, // 14 - { "border-color-unfocused", required_argument, 0, 0, }, // 15 - { "help", no_argument, 0, 0, }, // 16 - { "help-defaults", no_argument, 0, 0, }, // 17 - { "log-threshold", required_argument, 0, 0, }, // 18 - { "version", no_argument, 0, 0, }, // 19 + { "border-width-smart-gaps", required_argument, 0, 0, }, // 9 + { "inner-gaps", required_argument, 0, 0, }, // 10 + { "outer-gaps", required_argument, 0, 0, }, // 11 + { "border-width", required_argument, 0, 0, }, // 12 + { "border-width-monocle", required_argument, 0, 0, }, // 13 + { "border-color-focused", required_argument, 0, 0, }, // 14 + { "border-color-focused-monocle", required_argument, 0, 0, }, // 15 + { "border-color-unfocused", required_argument, 0, 0, }, // 16 + { "help", no_argument, 0, 0, }, // 17 + { "help-defaults", no_argument, 0, 0, }, // 18 + { "log-threshold", required_argument, 0, 0, }, // 19 + { "version", no_argument, 0, 0, }, // 20 { 0, 0, 0, 0, } }; @@ -106,68 +107,75 @@ void args_cli(int argc, char **argv) { cfg_set_smart_gaps(false); break; case 9: + if (!cfg_set_border_width_smart_gaps(optarg)) { + log_error("invalid --border-width-smart-gaps '%s'\n", optarg); + usage(EXIT_FAILURE); + return; + } + break; + case 10: if (!cfg_set_inner_gaps(optarg)) { log_error("invalid --inner-gaps '%s'\n", optarg); usage(EXIT_FAILURE); return; } break; - case 10: + case 11: if (!cfg_set_outer_gaps(optarg)) { log_error("invalid --outer-gaps '%s'\n", optarg); usage(EXIT_FAILURE); return; } break; - case 11: + case 12: if (!cfg_set_border_width(optarg)) { log_error("invalid --border-width '%s'\n", optarg); usage(EXIT_FAILURE); return; } break; - case 12: + case 13: if (!cfg_set_border_width_monocle(optarg)) { log_error("invalid --border-width-monocle '%s'\n", optarg); usage(EXIT_FAILURE); return; } break; - case 13: + case 14: if (!cfg_set_border_color_focused(optarg)) { log_error("invalid --border-color-focused '%s'\n", optarg); usage(EXIT_FAILURE); return; } break; - case 14: + case 15: if (!cfg_set_border_color_focused_monocle(optarg)) { log_error("invalid --border-color-focused-monocle '%s'\n", optarg); usage(EXIT_FAILURE); return; } break; - case 15: + case 16: if (!cfg_set_border_color_unfocused(optarg)) { log_error("invalid --border-color-unfocused '%s'\n", optarg); usage(EXIT_FAILURE); return; } break; - case 16: + case 17: usage(EXIT_SUCCESS); return; - case 17: + case 18: usage_defaults(); return; - case 18: + case 19: if (!log_set_threshold(optarg)) { log_error("invalid --log-threshold '%s'\n", optarg); usage(EXIT_FAILURE); return; } break; - case 19: + case 20: fprintf(stdout, "wideriver version %s\n", VERSION); exit(EXIT_SUCCESS); return; @@ -190,6 +198,7 @@ void args_cli(int argc, char **argv) { log_info("--outer-gaps %u", cfg->outer_gaps); log_info("--border-width %u", cfg->border_width); log_info("--border-width-monocle %u", cfg->border_width_monocle); + log_info("--border-width-smart-gaps %u", cfg->border_width_smart_gaps); log_info("--border-color-focused %s", cfg->border_color_focused); log_info("--border-color-focused-monocle %s", cfg->border_color_focused_monocle); log_info("--border-color-unfocused %s", cfg->border_color_unfocused); diff --git a/src/cfg.c b/src/cfg.c index 24ec893..ea6acd3 100644 --- a/src/cfg.c +++ b/src/cfg.c @@ -16,6 +16,7 @@ struct Cfg c = { .count_wide_left = COUNT_WIDE_LEFT_DEFAULT, .ratio_wide = RATIO_WIDE_DEFAULT, .smart_gaps = SMART_GAPS_DEFAULT, + .border_width_smart_gaps = BORDER_WIDTH_SMART_GAPS_DEFAULT, .inner_gaps = INNER_GAPS_DEFAULT, .outer_gaps = OUTER_GAPS_DEFAULT, .border_width = BORDER_WIDTH_DEFAULT, @@ -129,6 +130,18 @@ void cfg_set_smart_gaps(bool smart_gaps) { c.smart_gaps = smart_gaps; } +bool cfg_set_border_width_smart_gaps(const char *s) { + char *endptr; + long l = strtol(s, &endptr, 10); + + if (*s == '\0' || endptr == s || *endptr != '\0' || l < BORDER_WIDTH_SMART_GAPS_MIN) { + return false; + } else { + c.border_width_smart_gaps = l; + return true; + } +} + bool cfg_set_inner_gaps(const char *s) { char *endptr; long l = strtol(s, &endptr, 10); diff --git a/src/displ.c b/src/displ.c index 125daf0..b94b6fd 100644 --- a/src/displ.c +++ b/src/displ.c @@ -1,4 +1,5 @@ #include +#include #include #include #include @@ -39,11 +40,14 @@ void complete_border_color_unfocused(void) { d.style_current.border_color_unfocused = d.style_desired.border_color_unfocused; } -void desire_style(const struct Tag *tag) { +void desire_style(const struct Tag *tag, const uint32_t view_count) { if (tag) { if (tag->layout_cur == MONOCLE) { d.style_desired.border_width = cfg->border_width_monocle; d.style_desired.border_color_focused = cfg->border_color_focused_monocle; + } else if (view_count == 1 && tag->smart_gaps) { + d.style_desired.border_width = cfg->border_width_smart_gaps; + d.style_desired.border_color_focused = cfg->border_color_focused; } else { d.style_desired.border_width = cfg->border_width; d.style_desired.border_color_focused = cfg->border_color_focused; @@ -167,7 +171,7 @@ void displ_destroy(void) { memset(&d, 0, sizeof(struct Displ)); } -void displ_request_style(const struct Output *output, const struct Tag *tag) { +void displ_request_style(const struct Output *output, const struct Tag *tag, const uint32_t view_count) { if (!output || !tag) return; @@ -177,7 +181,7 @@ void displ_request_style(const struct Output *output, const struct Tag *tag) { } // desire - desire_style(tag); + desire_style(tag, view_count); // execute control_command_style(d.style_desired, d.style_current); diff --git a/src/listener_river_layout.c b/src/listener_river_layout.c index d89b623..82950f6 100644 --- a/src/listener_river_layout.c +++ b/src/listener_river_layout.c @@ -54,7 +54,7 @@ static void layout_handle_layout_demand(void *data, river_layout_v3_commit(output->river_layout, layout_name, serial); // maybe style - displ_request_style(output, tag); + displ_request_style(output, tag, view_count); } static void layout_handle_namespace_in_use(void *data, diff --git a/src/usage.c b/src/usage.c index b6bb9d1..ed22531 100644 --- a/src/usage.c +++ b/src/usage.c @@ -29,6 +29,7 @@ void usage(const int status) { "\n" " --border-width pixels %d %d <= width\n" " --border-width-monocle pixels %d %d <= width\n" + " --border-width-smart-gaps pixels %d %d <= width\n" "\n" " --border-color-focused 0xRRGGBB[AA] %s\n" " --border-color-focused-monocle 0xRRGGBB[AA] %s\n" @@ -59,6 +60,7 @@ void usage(const int status) { OUTER_GAPS_DEFAULT, OUTER_GAPS_MIN, BORDER_WIDTH_DEFAULT, BORDER_WIDTH_MIN, BORDER_WIDTH_MONOCLE_DEFAULT, BORDER_WIDTH_MONOCLE_MIN, + BORDER_WIDTH_SMART_GAPS_DEFAULT, BORDER_WIDTH_SMART_GAPS_MIN, BORDER_COLOR_FOCUSED_DEFAULT, BORDER_COLOR_FOCUSED_MONOCLE_DEFAULT, BORDER_COLOR_UNFOCUSED_DEFAULT, @@ -87,6 +89,7 @@ void usage_defaults(void) { " --outer-gaps %d \\\n" " --border-width %d \\\n" " --border-width-monocle %d \\\n" + " --border-width-smart-gaps %d \\\n" " --border-color-focused \"%s\" \\\n" " --border-color-focused-monocle \"%s\" \\\n" " --border-color-unfocused \"%s\" \\\n" @@ -97,11 +100,10 @@ void usage_defaults(void) { COUNT_WIDE_LEFT_DEFAULT, RATIO_WIDE_DEFAULT, INNER_GAPS_DEFAULT, OUTER_GAPS_DEFAULT, - BORDER_WIDTH_DEFAULT, BORDER_WIDTH_MONOCLE_DEFAULT, + BORDER_WIDTH_DEFAULT, BORDER_WIDTH_MONOCLE_DEFAULT, BORDER_WIDTH_SMART_GAPS_DEFAULT, BORDER_COLOR_FOCUSED_DEFAULT, BORDER_COLOR_FOCUSED_MONOCLE_DEFAULT, BORDER_COLOR_UNFOCUSED_DEFAULT, log_threshold_name(LOG_THRESHOLD_DEFAULT) ); exit(EXIT_SUCCESS); } - diff --git a/tst/tst-args_cli.c b/tst/tst-args_cli.c index b750871..183c93c 100644 --- a/tst/tst-args_cli.c +++ b/tst/tst-args_cli.c @@ -32,7 +32,7 @@ int after_each(void **state) { } void args_parse_cli__valid(void **state) { - int argc = 32; + int argc = 34; char *argv[] = { "dummy", "--layout", "left", "--layout-alt", "right", @@ -42,6 +42,7 @@ void args_parse_cli__valid(void **state) { "--count-wide-left", "8", "--ratio-wide", "0.8", "--smart-gaps", + "--border-width-smart-gaps", "8", "--inner-gaps", "6", "--outer-gaps", "6", "--border-width", "5", @@ -62,6 +63,7 @@ void args_parse_cli__valid(void **state) { assert_int_equal(cfg->count_wide_left, 8); assert_float_equal(cfg->ratio_wide, 0.8, 0.001); assert_true(cfg->smart_gaps); + assert_int_equal(cfg->border_width_smart_gaps, 8); assert_int_equal(cfg->inner_gaps, 6); assert_int_equal(cfg->outer_gaps, 6); assert_int_equal(cfg->border_width, 5); @@ -83,6 +85,7 @@ void args_parse_cli__valid(void **state) { "--outer-gaps 6\n" "--border-width 5\n" "--border-width-monocle 10\n" + "--border-width-smart-gaps 8\n" "--border-color-focused 0xAABBCC\n" "--border-color-focused-monocle 0xDDEEFFA9\n" "--border-color-unfocused 0x001122\n" @@ -181,6 +184,19 @@ void args_parse_cli__bad_ratio_wide(void **state) { assert_log(ERROR, "invalid --ratio-wide '-1'\n\n"); } +void args_parse_cli__bad_border_width_smart_gaps(void **state) { + int argc = 3; + char *argv[] = { "dummy", + "--border-width-smart-gaps", "-1", + }; + + expect_value(__wrap_usage, status, EXIT_FAILURE); + + args_cli(argc, argv); + + assert_log(ERROR, "invalid --border-width-smart-gaps '-1'\n\n"); +} + void args_parse_cli__bad_inner_gaps(void **state) { int argc = 3; char *argv[] = { "dummy", @@ -295,6 +311,7 @@ int main(void) { TEST(args_parse_cli__bad_ratio_master), TEST(args_parse_cli__bad_count_wide_left), TEST(args_parse_cli__bad_ratio_wide), + TEST(args_parse_cli__bad_border_width_smart_gaps), TEST(args_parse_cli__bad_inner_gaps), TEST(args_parse_cli__bad_outer_gaps), TEST(args_parse_cli__bad_border_width),