diff options
author | Sean Whitton <spwhitton@spwhitton.name> | 2024-01-16 17:43:08 +0000 |
---|---|---|
committer | Sean Whitton <spwhitton@spwhitton.name> | 2024-01-16 18:10:25 +0000 |
commit | 2de521a884bc18a80d3aa7b58591019f2257fcd0 (patch) | |
tree | 920d1ba67ab3684acf2f68bb138327be7079c2b2 | |
parent | 5a7cf7e3595c3a25c8885d40a0793228b80be7c1 (diff) | |
download | dotfiles-2de521a884bc18a80d3aa7b58591019f2257fcd0.tar.gz |
i3status-wrapper: rewrite normalise_ws_cols, improve monocle mode
-rwxr-xr-x | scripts/desktop/i3status-wrapper | 136 |
1 files changed, 94 insertions, 42 deletions
diff --git a/scripts/desktop/i3status-wrapper b/scripts/desktop/i3status-wrapper index 81e1e7cc..11864e23 100755 --- a/scripts/desktop/i3status-wrapper +++ b/scripts/desktop/i3status-wrapper @@ -31,7 +31,7 @@ use Sys::Hostname; use POSIX "floor", "mkfifo"; use File::Basename "basename", "dirname"; use File::Spec::Functions "catfile"; -use List::Util "first", "max"; +use List::Util qw(first min max); $| = 1; @@ -274,8 +274,13 @@ unless (fork // warn "couldn't fork command pipe reader") { $mv->($i-1); } } elsif ($cmd eq "monocle toggle\n") { - $ws->{monocle} = !$ws->{monocle}; - normalise_ws_cols(); + if (my $m = $ws->{monocle}) { + undef $ws->{monocle}; + normalise_ws_cols(abs ++$m); + } else { + $ws->{monocle} = -$i-1; + normalise_ws_cols(); + } kill USR1 => $i3status; } @@ -394,7 +399,7 @@ sub normalise_ws_cols { my $ws = $info{paper_ws}{$info{focused_ws}}; my $floating_focus; my $old_cols = $ws->{cols}; - my $old_i = first { $old_cols->[$_] == $ws->{focused_col} } + my $old_i = shift // first { $old_cols->[$_] == $ws->{focused_col} } 0..$#$old_cols; my @trees = $wmipc->get_tree; while (@trees) { @@ -409,47 +414,94 @@ sub normalise_ws_cols { } } my $cols = $ws->{cols}; - with_ignored_events { - $wmipc->cmd("focus tiling"); - while (1) { - my $i = first { $cols->[$_] eq $ws->{focused_col} } 0..$#$cols; - my $mid_i = floor @$cols/2; - # Pull column in if there are too few columns but some available. - if (!$ws->{monocle} && $ws->{ncols} > @$cols - && ($ws->{off_left}->@* || $ws->{off_right}->@*)) { - - if ($ws->{off_left}->@* # pull from left - && ($i < $mid_i || !$ws->{off_right}->@*)) { - my $pulled = pop $ws->{off_left}->@*; - my $k = $old_i == $#$old_cols ? $i+1 : $i; - $wmipc->cmd(("focus left")x$i, - show_con($pulled), "move left", - ("focus right")x$k); - unshift @$cols, $pulled; - $ws->{focused_col} = $cols->[$k]; - - } elsif ($ws->{off_right}->@* # pull from right - && ($i >= $mid_i || !$ws->{off_left}->@*)) { - my $j = $#$cols - $i; - my $pulled = pop $ws->{off_right}->@*; - $wmipc->cmd(("focus right")x$j, - show_con($pulled), - ("focus left")x($old_i == 0 ? $j+1 : $j)); - push @$cols, $pulled; - $ws->{focused_col} = $cols->[$old_i == 0 ? $i : $i+1]; - } + my $i = first { $cols->[$_] eq $ws->{focused_col} } 0..$#$cols; + + my @cmds; + my $avail_l = scalar $ws->{off_left}->@*; + my $avail_r = scalar $ws->{off_right}->@*; + if (!$ws->{monocle} && $ws->{ncols} > @$cols && ($avail_l || $avail_r)) { + # Pull columns in if there are too few columns but some available. + # Want the focused column, after pulls, to be the $old_i'th. + my ($from_l, $from_r); + my $want = $ws->{ncols} - @$cols; + # When we lose columns, the focused column either moves left or + # stays the same. So always $old_i >= $i. + if ($old_i > $i) { + if ($old_i == $#$old_cols) { + # We were in the final column. Either we closed the + # rightmost column, or we lost arbitrary columns from the + # left (e.g. monocle from the last column). + # In either case it is fine to pull more from the left. + $from_l = min $avail_l, $want; + } else { + # We have $i < $old_i < $#$old_cols. + # We must have lost at least $old_i-$i from the left. + $from_l = min $avail_l, $old_i-$i; } - # Push a column off if there are too many columns. - elsif (@$cols > $ws->{ncols} || $ws->{monocle} && @$cols > 1) { - my $pushed = $i < $mid_i ? pop @$cols : shift @$cols; - $wmipc->cmd(hide_con($pushed)); - push $ws->{$i < $mid_i ? "off_right" : "off_left"}->@*, - $pushed; + } else { # $old_i == $i. + if ($old_i == 0) { + # We were in the first column. Either we closed the leftmost + # column, or we lost arbitrary columns from the left + # (e.g. monocle from the first column). We prefer to pull + # from the left in the former case. If we are indeed exiting + # monocle mode, we must pull from the right. + if (@$cols == 1) { + $from_r = min $avail_r, $want; + } else { + $from_l = !!$avail_l; + } + } else { + # It must be that we lost columns from the right. + $from_r = min $avail_r, $want; } - # Number of columns is correct. - else { last } } - $wmipc->cmd("focus floating") if $floating_focus; + + if ($from_l //= min $avail_l, $want-$from_r) { + my @pulled = splice $ws->{off_left}->@*, -$from_l, $from_l; + push @cmds, ("focus left")x$i, + map +(show_con($_), "move left"), reverse @pulled; + unshift @$cols, @pulled; + $i = 0; + } + if ($from_r //= min $avail_r, $want-$from_l) { + my @pulled + = reverse splice $ws->{off_right}->@*, -$from_r, $from_r; + push @cmds, ("focus right")x($#$cols-$i), + map show_con($_), @pulled; + push @$cols, @pulled; + $i = $#$cols; + } + + if ($i > $old_i) { + push @cmds, ("focus left")x($i-$old_i); + } elsif ($old_i > $i) { + push @cmds, ("focus right")x($old_i-$i); + } + + $ws->{focused_col} = $cols->[$old_i]; + } + # Push columns off if there are too many columns. + # This should never change which container is focused. + elsif (my $n = $ws->{monocle} ? @$cols-1 : @$cols-$ws->{ncols} > 0) { + my $left = $i; + my $right = $#$cols-$i; + if ($left >= $right) { + $left = min $left, $n; + $right = $n-$left; + } else { + $right = min $right, $n; + $left = $n-$right; + } + my @to_left = splice @$cols, 0, $left; + my @to_right = reverse splice @$cols, -$right, $right; + + push @cmds, map hide_con($_), @to_left, @to_right; + push $ws->{off_left}->@*, @to_left; + push $ws->{off_right}->@*, @to_right; + } + if (@cmds) { + push @cmds, "focus floating" if $floating_focus; + with_ignored_events { $wmipc->cmd("focus tiling", @cmds) } } } |