-
Notifications
You must be signed in to change notification settings - Fork 1.1k
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
Layout save/restore #1005
Comments
I did a bit of research using the documentation as a reference. Effectively the way this is implemented (I don't use this feature at all) is this:
So from what I can see there are a few things we need to implement and/or consider:
|
I've decided that we are just not going to support this i3 feature, ever. |
@SirCmpwn Any specific reason why? |
It's too complicated and hacky for too little benefit. I don't like the design constraints it imposes upon sway. |
Would you reconsider your decision? This feature is actually quite useful in some (could even say rare) professional settings, e.g. setting up a music production with a midi mixer, synthesizer, sequencer, and composition programs open in their specific layout every time, or just general software development with editors, compilers, debuggers and test windows. While there is no point in being i3 compliant on this, I think a good discussion in trying to come up with a better solution would be quite beneficial. |
No, I won't reconsider. However, you should be able to accomplish something similar with a script that starts up the software you need and arranges it appropriately via IPC. |
I would love to say "Would you like to reconsider whether you would like to reconsider 'No, I won't reconsider' ", but that might easily overflow the buffer if not implemented correctly. Anyway, I do think writing a script for that should be straightforward so thanks! |
it's a shame that this great i3 feature is dropped simply because "I'm too lazy to implement something I personally do not use". Please tell me how am I suppose to do swallowing in a script? How do I assign a program window to a specific layout window using IPC? If I start a program I only know its process id and what is available in the /proc/proc_id. |
This is why it was dropped, not because, quote, "I'm too lazy to implement something I personally do not use." You can use IPC to move a window to a specific workspace over IPC with criteria. You can split the window and move things around, too. The pid associated with a window is included in the IPC_GET_TREE output, along with a unique ID you can use for criteria. |
give an IPC command example please of moving a program window into a specific layout window on a workspaceX |
To arrange three windows like this on an empty workspace:
|
right, why there can't be a method that does exactly this if it is so easy? It would just have to parse a layout file additionally, right? Now using your approach what would I do if I wanted to change my layout a bit, like resize here and there provided that my layout is a little bit more complex rather that just 3 windows? Currently I just have to resize and overwrite my layout file. And btw I'm inside of a bash script so how do I get an IPC notification? |
See
If you want to write a script which implements i3 layout save/restore as an external program, you should do so, but no one is going to write it for you. This project is run by volunteers, and no one is volunteering to do this.
By not being in a bash script |
nope, I'm not going to implement a script because
without proper support from underlying framework. Your script "example" could only work for very simple layouts. It's because if you have a generic layout description you'd have to start with a specific program window traversing the layout up the tree trying to figure out where that window would land in the end and how the inverted IPC command chain would look like. btw feature that allows restoring a complex working environment (up to starting terminals with specific commands) just by a keyboard shortcut brings rather huge benefit than "too little benefit". Lacking such a feature is a road block for me => no switching from i3. Chusikowski |
I agree that i3's implementation of this feature has its own set of shortcomings. However, the proposed alternative of using IPC feels rather clunky since all it allows is akin to replaying a keyboard macro. A more powerful alternative would be to extend the API to allow passing a tree of existing windows referenced by ID or criteria, with optional hints for layout and sizing, and have sway apply that atomically. Note that my proposal differs from i3 in two ways:
|
I would consider a patch, but I'm not interested in doing this myself and I'm worried about the complexity/value tradeoff. |
That's all I needed to hear. I would gladly write this feature myself, but I'm currently focusing on other projects so i3 is still my daily driver for now. I'll probably come back to it later, unless someone else is interested in doing it before me. |
I completely agree with all of this. The placeholder system in i3 is not very good and you have to use hacks like unmapping and remapping windows with xdotool to get a layout to apply to existing windows. Let me know when you get time to start working on it. I'd be eager to help out. |
I've recently been looking at the code that i3 uses when restoring a layout.
So it checks for the type of the data it loads from the file whose path you pass to If the content is of type "workspace", it appends the layout to the currently focused output's workspace array. If it is a con, it searches upwards from the currently focused node until it finds a workspace, then it appends the layout to the workspace's child array. The fact that it only appends nodes to an array and does not modify or replace existing nodes means that it is actually quite clean. I've come to appreciate the simplicity of this approach, as opposed to rewriting the existing tree. The only part of their implementation that still seems bad to me is that placeholder container matching is only done when windows are created. We could just implement layout restoring almost exactly the same as i3, but just search the whole workspace for matching windows right after the layout is appended, instead of when new windows are mapped. Or we could have the best of both worlds and check for matches after layout appending, and on window creation, for those use cases where placeholder windows/deferred swallowing is desirable (these cases really do exist). The caveat of this is obviously that it's less self-contained because of having to monitor window creation events. Either way it doesn't seem like this would be that hard to implement. Edit: All that's needed right now is:
|
lets say I have 100 windows in my layout. Right now I have a simple script that loads specific layout and then starts 100 programs in the background. Your suggestion would imply that I have to implement additional 'wait_for_all_100_windows_be_opened_before_loading_layout' and which is more important 'do_x_if_window_y_wont_appear_within_z_sec' logics. Is that what you're saying @JonnyHaystack ? |
@ddevault your assertion that this could be easily done in a script is incorrect. I know because I tried it. sway doesn't have good enough commands to make it easy to be accomplished for an arbitrary layout. For example, there is no "move to this container." Instead you have to make a mark, and then move to that mark. This ends up being error prone. Another thing I tried is creating a placeholder window so that I knew its con_id and I could target it without needing to use marks as a place to drop windows on. This too is error prone as the timing required to make sure that windows transfer is not so straightforward. Finally, there's also not a good way of modifying the layout of windows without focusing them. You may thing that criteria targetting would work, but it doesn't work reliably. And this is all from 2020 when I tried it. At the time that you made the suggestion to make a script in 2017, I am certain sway was in an even less adequate state to achieve it. Maybe I'm not smart enough to get it done, but then again that also proves the value of having it built into sway or having an official solution. I could try to spend more time on it, but I have already sunk 3 hours into it. It's likely not worth it to do in such a hacky way. And if you want dozens of other people to spend/waste their time simply because you are still under the misconception that this is "easy to do" then I think it would be fair to apologize for the time that others have spent and will spend time on this. |
Ref #3022 |
No, ideally swallowing would occur in 3 situation:
All three of these could be handled in different ways, but here's my take:
For the first and second situation, there should not be too much added complexity, but it would presumably require small modifications to event handlers in the main codebase. I could be wrong here because I haven't looked at sway's code in depth. For the third situation, there could be a fair bit of added complexity in having to recurse over the target workspace's tree, but I think this could be kept separate from the main codebase, as part of the append_layout command's implementation. Alternatively if there's any tool for wayland/sway that lets you unmap/remap the windows in the workspace similar to what you can do with xdotool, that would be acceptable and situation 3 could be ignored, but again, that's kinda hacky. |
Are there any good options for restoring layouts at this point? I'm a software developer and I use If anybody has any good workarounds using IPC I would love to see some examples. I'm not savvy enough with Sway to have any clue what ddevault is talking about when he says things like |
Hi, #!/usr/bin/env python3
from i3ipc import Connection
conn = Connection()
def run(cmd):
conn.command(cmd)
ilen = len(conn.get_tree().workspaces()[-1].descendants())
while len(conn.get_tree().workspaces()[-1].descendants()) == ilen:
True
con_id = max(i.id for i in conn.get_tree().workspaces()[-1].descendants())
return con_id
conn.command("workspace file")
con_id1 = run("exec wayst -e sf /")
con_id2 = run("exec wayst -e sf ~/Downloads")
con_id3 = run(f"[con_id={con_id1}] focus; splitv; exec wayst -e sf /tmp")
con_id4 = run(f"[con_id={con_id2}] focus; splitv; exec wayst -e sf /mnt")
conn.command(f"[con_id={con_id1}] focus") Any suggestions are welcome |
Aha, I see... Your example would probably work in some simple cases, but I can already see it falling apart with applications like Discord, where it displays a loading splash screen for a little while before starting, and often also starts an updater. Although this could be worked around by waiting for a new window that matches certain filters. Also it has to open applications one at a time, which could be potentially very slow, but getting around that would be pretty complicated 🤔 I'm imagining a script that would launch a bunch of applications simultaneously, then loop on from sway_layout import Row, Column, Application, launch
launch(
Column(
Application("chromium --app=https://messenger.com", cls="Chromium", instance="^Messenger$"),
Application("slack", cls="Slack", instance="^Messenger$"),
),
Column(
Application("viber", cls="^Viber$"),
Row(
Application("discord", cls="^discord$", instance="^discord$", window_type="normal", name="- Discord$"),
Application("teamspeak3", cls="^TeamSpeak3$"),
)
)
) I don't see any reason this wouldn't be possible to implement. I will probably take a swing at it when I get some free time, I am really missing this feature. |
This is my take on the problem, it's definitely not bulletproof but it works most of the time for me. https://github.com/9ary/dotfiles/blob/master/i3/ws-1.py |
@9ary can you explain a bit to me how this works? I couldn't get your example working after a day or so, but it could be due to my lack of experience with the sway IPC. in particular, https://github.com/9ary/dotfiles/blob/master/i3/ws-1.py#L83
It seems to never respond, or report back anything after it hits this point. What am I doing wrong? |
Yeah, it blocks until every leaf node has a match, so it won't do anything until all members of your layout exist (I would have to implement placeholders otherwise, which is significantly more work, and my workflow doesn't require them). |
Thanks for the explanation. Got it working after learning more about the script and |
@9ary How would you match the window by ID considering the ID the next time you launch the program will be different from when you saved the layout? |
The point is that an external program could query the tree to identify the desired windows, and even spawn placeholder windows, effectively taking the complexity out of sway, and enabling more complex use cases. |
Right, I get you |
I expanded some example script to make it work. The requirements are in the file. Only issue is that multiple windows of an application aren't handled. |
@Nama This script doesn't seem to work for me. It is able to save the tree, but can't restore it from the file. |
Do you get any error? If yes, pls post. |
@Nama No error, no duplicate monitors. When it finishes is says that the session was successfully loaded, but no programs were started and no already open programs were moved to the workspace they should be moved to. |
The script doesn't start any programs. Can you send the tree json the script saved? |
Please send such long text as file. You should edit and delete your json tree now. "window_properties": {
"class": "firefox",
"instance": "Navigator",
"title": "Variable refresh rate - ArchWiki — Mozilla Firefox",
"transient_for": null,
"window_role": "browser",
"window_type": "normal"
} I don't know why. The only differences seem to be that Do you have any workspaces which aren't vertically aligned? I have only one vertical workspace, but the My version of sway is 1:1.7. |
Apologies for the long text. I've attached the file to this message. Workspace Tree: |
Figured it out. My script is useless. |
You could change the script to also check for the |
And to move multiple windows of the same type, you could use the |
Oh yeah, Isn't the |
Wayland apps are now working. I'll look into handling multiple windows now. |
I've modified @Nama's script above to support multiple windows of the same program - for my many firefox windows... https://git.sr.ht/~roselandgoose/Sway_Layout_Restore/blob/main/sway_workspaces.py |
Oh that's nice! Thank you, @roselandgoose. I created a repo without your changes, so you can PR your changes. Would be more convenient to work on it in a repo (and move the discussion from this issue XD). |
As a TLDR; for people looking for this feature, the sway dev doesn't want to add it but Nama has created a plugin that somewhat recreates i3-save-tree. |
@Nama I can traverse recursively a saved json from python3 ./srws.py --workspace myworkspacename --save ./test.json
python3 ./srws.py --load ./test.json |
Layout save/restore is an i3 feature that serializes your layout to JSON and attempts to arrange windows in the same way in a later session. First step is to research how i3 does it and propose some strategies for implementing it in sway.
The text was updated successfully, but these errors were encountered: