Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feature request: Size reset command #1623

Closed
Deiz opened this issue Apr 1, 2015 · 20 comments
Closed

feature request: Size reset command #1623

Deiz opened this issue Apr 1, 2015 · 20 comments

Comments

@Deiz
Copy link
Contributor

Deiz commented Apr 1, 2015

I'm envisioning a command that would operate on containers that have multiple children. It would iterate over all of the children and reset their percentages so they're evenly distributed.

As an example, running resetsize on a split container with three children would result in each child container having a third of the parent's width.

Ideally, the resizing would be implemented purely using existing code paths, which seems feasible as long as it doesn't attempt to preserve size ratios among the children, et cetera.

I'm willing to implement this if it's judged as a desirable feature.

@stapelberg
Copy link
Member

I think this should be done in an external script using the IPC interface (in fact, I have a script which will establish a 60/40 ratio of the currently focused container).

@vaterp
Copy link

vaterp commented Apr 6, 2015

I'd love something like this! One vote from me.

@Airblader
Copy link
Member

@vaterp Why can't you use an IPC script as suggested by Michael?
Maybe @stapelberg wants to share his 60/40 scripts here as a base.

@vaterp
Copy link

vaterp commented Apr 6, 2015

If the script is shared, i'd have no problem using that as the solution.... perhpas i missed it (this is the first time i've attempted to track an issue of a 3rd party project with github) but i dont see any attached script.

@stapelberg
Copy link
Member

This is the script I was talking about:

#!/usr/bin/env perl
# vim:ts=4:sw=4:expandtab

use strict;
use warnings;
use AnyEvent::I3;
use v5.10;

my $tree = i3->get_tree()->recv();
sub get_focused {
    my ($node) = @_;
    return $node if @{$node->{focus}} == 0;

    my $focused = $node->{focus}->[0];
    my ($child) = grep { $_->{id} == $focused } @{$node->{nodes}};
    return get_focused($child);
}

sub get_parent {
    my ($node, $id) = @_;

    my $focused = $node->{focus}->[0];
    my ($matching) = grep { $_->{id} == $id } @{$node->{nodes}};
    return $node if defined($matching);
    my ($child) = grep { $_->{id} == $focused } @{$node->{nodes}};
    return get_parent($child, $id);
}

my $focused_node = get_focused($tree);
my $parent = get_parent($tree, $focused_node->{id});
my $diff = 0.6 - $parent->{percent};
my $verb = ($diff > 0 ? "grow" : "shrink");
i3->command('[con_id="' . $parent->{id} . '"] resize ' . $verb . ' height 10 px or ' . sprintf("%.0f", $diff * 100) . ' ppt')->recv();

It’s by no means finished, polished or supportable. I’m posting this so that you know what to build, not as a turnkey solution.

@mattiasflodin
Copy link

mattiasflodin commented Mar 28, 2020

@stapelberg I'm trying to implement a script for this but am failing miserably. My approach is to get all the child nodes of the currently focused container, then setting the size of all of them to the same value. But whenever I set the size of one window, i3 rebalances its siblings so that every window except one ends up with a different size than I wanted.

How on earth does your script work? It looks like it's only resizing the parent of the focused container. con_id matches a single container, yes? But the idea was to set the size of multiple windows to the same size.

I don't really see how this could ever be accomplished without at least introducing some way to atomically run commands on multiple windows without i3 interfering with the size of windows until all commands have finished.

My script is below:

import i3ipc

i3 = i3ipc.Connection()
container = i3.get_tree().find_focused()
children = list(container.nodes)
ppt = int(100/len(children))
for child in children:
    i3.command(("[con_id=%d] resize set width %d ppt" % (child.id, ppt)))

What happens now is that when I run it, sizes converge asymptotically toward a balanced size distribution. I have to run it about five times in a row before sizes stabilize at an equilibrium.

(I tried running your script but Perl complains that $parent->{percent} is an uninitialized value.)

@stapelberg
Copy link
Member

I have since rewritten this in Go, which might make it slightly easier to read: https://github.com/stapelberg/percentage-for-i3/blob/master/percentage.go

But yeah, I only resize one window.

Not sure what’s going on with regards to the percentage setting not resulting in the desired sizes. Can you open a separate bug for that with minimal steps to reproduce please?

@mattiasflodin
Copy link

mattiasflodin commented Mar 31, 2020

I'm not sure that it is a bug per se, it's just a consequence of how the layout algorithm is intended to work?

Say I have three containers with sizes 20% + 30%+ 50%, and I want them all at 33%.

  1. I set the first window to 33%. To make room i3 proportionally shrinks the other two windows, so I get 33% + 25% + 42%.

  2. I set the second window to 33%. The other two windows are shrunk proportionally to make room so I get 30% + 33% + 37%.

  3. I set the third window to 33%. Since the window shrinks the other two windows are grown proportionally, so I get 32% + 35% + 33%.

If I had a way to set the size of each window individually within one "transaction" without causing automatic resize of the other windows until the transaction is done, then this method would work. But without that I don't think it could.

@stapelberg
Copy link
Member

If I had a way to set the size of each window individually within one "transaction" without causing automatic resize of the other windows until the transaction is done, then this method would work. But without that I don't think it could.

Have you tried using one IPC request (with commands separated by ;) instead of multiple requests?

@mattiasflodin
Copy link

Tried it now, same thing happens.

@atreyasha
Copy link

I made a repo based on i3ipc-python to address window size resetting/balancing for both simple and complex workspace layouts. Have a look (https://github.com/atreyasha/i3-balance-workspace) and let me know if it addresses the issue. I would be happy to collaborate to improve this tool further.

@mattiasflodin
Copy link

I haven't tried running it yet but looking at the source it seems to iterate in a loop until sizes converge to the desired target. Which... can work, of course, but if this is the best possible solution then I still think it indicates a missing feature in i3.

@atreyasha
Copy link

atreyasha commented Jul 7, 2020

@mattiasflodin True; although the upper-bound number of iterations for convergence is pre-computed (based on some resizing dynamics) in the source-code so at least we can guarantee that loops are finite and deterministic. Based on my tests, even complex (nested) workspaces can be balanced in ~0.2-0.3s.

I am not sure what could be improved in i3 to address this. IMO the main reason we can't just execute commands such as resize set { width | height } N px for each container is that these commands are executed sequentially and therefore one container's increase in size resorts to another container's decrease in size. Depending on how the resizing occurs, things can get complicated and that's where the problems start happening.

@mattiasflodin
Copy link

Sure, I'm not criticizing your solution. I'm only saying that I don't think the principle "if it can be done in a script it shouldn't be added to i3" applies in this instance, because the script solution becomes necessarily suboptimal without additional functionality in i3.

@stapelberg
Copy link
Member

Sure, I'm not criticizing your solution. I'm only saying that I don't think the principle "if it can be done in a script it shouldn't be added to i3" applies in this instance, because the script solution becomes necessarily suboptimal without additional functionality in i3.

I tend to agree to this, but at the same time it is not clear to me what the minimum thing is we could add to i3 that would help here?

We should be careful to not expose too many internals, or add a too-complex mechanism, just to satisfy this use-case.

@mattiasflodin
Copy link

The minimal thing I guess would be to delay the automatic resize of other items within the same container until a sequence of commands has finished. i3 would need to keep track of which containers were touched as it executed the commands, then only apply the automatic resize to those containers that weren't touched.

@hirowatari
Copy link

I would also like this functionality. To me it doesn't seem like an edge case that one would want to be able to resize three windows to a precise size. Or perhaps another way to put it is that it seems like a bug that asking for 3 windows to be resized to a 1/3 of the space would do something different.

I think as a workaround, one could potentially use append_layout to achieve this, but I haven't look into this and would be much more complicated.

My humble suggestion is to allow for things to happen in a transaction eg.

i3-msg [con_id=1] resize set width 33 ppt, [con_id=2] resize set width 33 ppt, [con_id=3] resize set width 33 ppt

rather than in three separate commands.

Anyway, just a small vote for this. Thanks for all your work on this project.

@Airblader
Copy link
Member

My humble suggestion is to allow for things to happen in a transaction eg.

Apart from this being a breaking change, there's really nothing simple about transactions — not in DBMS and not in i3. This would essentially require a rewrite if the entire command stack.

@hirowatari
Copy link

@Airblader I didn't mean to say it was simple. I had considered that I might be able to implement it myself, but rewriting the command stack does not seem reasonable. Thanks for taking the time to respond.

@noperator
Copy link

noperator commented Oct 21, 2020

@atreyasha, I just tried out i3-balance-workspace—it works great. Thank you!

I cut my teeth on tiling windows with i3, then spent the past year using yabai on macOS. Now, coming back to i3, I've missed yabai's ability to balance windows.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

9 participants