Hyprland icon indicating copy to clipboard operation
Hyprland copied to clipboard

Save restore dwindle layout

Open Natr1x opened this issue 10 months ago • 5 comments

Describe your PR, what does it fix/add?

To make it possible to save and restore dwindle workspace layouts via hyprctl.

To be able to "restore" layouts it adds an "opennexton" layoutmsg handler for the dwindle layout. It works like "preselect" but with a dwindle node instead.

"Saving" layouts is done with hyprctl layoutdata workspaceinfo <workspace_id>.

The hyprctl cmd ("layoutdata") which kind of does the same thing as "dispatch layoutmsg" but allows the layout to send a response. workspaceinfo is then a handler implemented for the dwindle layout.

Is there anything you want to mention? (unchecked code, possible bugs, found problems, breaking compatibility, etc.)

Some points which need to be discussed:

  • [ ] The format of the first argument to the opennexton layoutmsg handler may not be particularly intuitive. I think there should be a way to target nodes which contain more than one window. And targeting the root is really useful if you want to do something like "maximize to half the screen". But it may be better to just leave out that functionality for now.
  • [ ] The names "layoutdata" and "workspaceinfo" for the new hyprctl cmd should probably be something else. (Especially "layoutdata"). I don't like that a new hyprctl command was needed to begin with but I don't see how else you would do it.
  • [ ] Something like a "setnodesplitratio" layoutmsg handler is also needed if you want to restore the window sizes of the layout. I thought dispatch splitratio could be used it does not take a window argument. And even if it did there would be no way to target nodes which are not single windows.
  • [ ] Master layout? This is currently only for the dwindle layout and I don't see how it could be done in a generic way which would work with every possible layout. But if we are adding a new layout specific hyprctl command then maybe we should implement at least the "workspaceinfo" handler for the master layout as well.

Is it ready for merging, or does it need work?

NO, the questions above need to be addressed first. But aside from that there is also the documentation and stuff like tab completions for hyprctl.

Natr1x avatar Jan 13 '25 20:01 Natr1x

How would this be used, exactly?

vaxerski avatar Jan 15 '25 16:01 vaxerski

How would this be used, exactly?

Personally, I like to have my windows in a specific arrangement when I'm working, and I hate having to remake the layout every time, so that's how I would use it.

poseidon-rises avatar Jan 15 '25 17:01 poseidon-rises

It's not entirely clear to me how restoring is supposed to work with this?

There's some utility to making this generic (i.e a matching 'restore your state from this dump you provided earlier' dispatcher). Being able to do stuff like gather all windows on a workspace into a tabbed group and then 'release' them back into the layout with the same exact positioning as before would be one use for a generic save/restore.

Unfortunately I don't think there's a good way to do this without requiring every layout to contain a json parser....

zakk4223 avatar Jan 16 '25 03:01 zakk4223

that would be understandable but I am asking in this MR, specifically, cuz I fail to see it

vaxerski avatar Jan 16 '25 14:01 vaxerski

How would this be used, exactly?

Let's say I have a workspace where I keep all of my open chat/communication clients (discord, steam, email, etc). And I have them laid out in my own preferred way (discord always on top of steam chat in a vertical split or something).

Now say I want to temporarily focus on one of these clients in another workspace which I am currently focusing. This can easily be done with something like hyprctl dispatch movetoworkspace m+0, address:<discord window address>. And I already have my own script for doing this that allows me to select a window using tofi.

But then when I am done with the window I want to send it back to where I want it inside of my chat workspace (on top of steam). Currently there is no way to do this but with opennexton it would be possible to do something like this:

hyprctl dispatch --batch 'layoutmsg preselect t ; layoutmsg opennexton . address:<steam chat window address> ; movetoworkspacesilent name:Chat, address:<discord window address>'

If we also add layoutmsg setnodesplitratio (something I have not implemented in this MR yet) you would be able to set up a dwindle workspace according to any layout you want via the hyprctl batch commands.

I thought that together with hyprctl -j clients this would allow me to write my own script for saving and restoring sessions. Unfortunately hyprctl -j clients does not contain enough information to determine the dwindle node tree.

Which is why I added the hyprctl layoutdata workspaceinfo command. Which for the dwindle layout prints the current node tree of a workspace.

It's not entirely clear to me how restoring is supposed to work with this?

There's some utility to making this generic (i.e a matching 'restore your state from this dump you provided earlier' dispatcher). Being able to do stuff like gather all windows on a workspace into a tabbed group and then 'release' them back into the layout with the same exact positioning as before would be one use for a generic save/restore.

Unfortunately I don't think there's a good way to do this without requiring every layout to contain a json parser....

The idea is that the layouts would not have to be responsible for saving or restoring anything. Merely to have a way to be queried for layout specific state information. It would be up to the users or tool authors to make use of this information if they want to restore a session.

I'm also not advocating for this to be a requirement either. Merely for layout authors to have the option to implement custom queries the same ways they have a proper way to implement dispatch commands via layoutmsg.

Natr1x avatar Jan 20 '25 10:01 Natr1x

Trying to understand the state of this MR - my understanding is that this would allow for a native session restore like capability as well?

I'm a new user to hyprland and have been researching how to implement a session restore after a power off or shutdown scenario. And wanted to use this as a way to periodically save state.

VDuda avatar Jul 22 '25 21:07 VDuda

Trying to understand the state of this MR - my understanding is that this would allow for a native session restore like capability as well?

I'm a new user to hyprland and have been researching how to implement a session restore after a power off or shutdown scenario. And wanted to use this as a way to periodically save state.

Yes and no. Essentially hyprland comes builtin with two 'Layouts' (Dwindle and Master) which manage where windows are placed and such. You can also add your own layouts by writing a plugin which implements the Layout interface.

This interface contains a method called layoutMessage which is used to receive layout specific dispatch messages from key bindings. The ones implemented by the dwindle layout are described here: https://wiki.hypr.land/0.46.0/Configuring/Dwindle-Layout/#layout-messages

If we want to perform a session restore then we need to be able to tell the layout precisely where to open windows. But the dwindle layout in its current form does not allow you to do this. It only allows you to set what direction the next window should be split, not what window it should be split from.

The merge request proposes to add a command to the dwindle layoutMessage called nexton which would allow you to specify where the next window should appear.

Unfortunately, for that command to be useful you need to know the state of the layouts internal node tree. Because dwindle organises windows in terms of nodes, where a node can either contain a window or two other nodes.

Eg. if you have three windows open then they would be organised as one top node containing two nodes where one of these nodes would contain one of the windows and the other would contain two nodes with one of the remaining windows each.


# Possible Node tree
SplitNode:
  - WindowNode: WindowA
  - SplitNode:
    - WindowNode: WindowB
    - WindowNode: WindowC

# Another possible node tree
SplitNode:
  - SplitNode:
    - WindowNode: WindowA
    - WindowNode: WindowB
  - WindowNode: WindowC

Without knowing this node tree there is not much point in being able to specify what node to open the next window on. The solution then is to create a layoutMessage command that queries the state of the dwindle node tree. We want this to be a layoutMessage because other layouts may not have a node tree so it needs to be layout specific.

However, this runs into a problem. The layoutMessage method does not return any data. The actual method return std::any but the result is always discarded since it is supposed to be called from a keybound dispatch which cannot return a result either way.

Layouts can implement custom commands that can be called with keybind or hyprctl dispatch but not custom 'Queries'.

This means that since most layouts are likely to have state information specific to that layout and this information cannot be conveyed over the layout interface, you will never be able to implement a session restoration tool which only uses the hyprctl socket. Each layout which wanted to convey session information would need to implement some other way to convey this information.

So thats the second thing which this MR proposes. An addition to the LayoutInterface for 'Queries'. Which would work like layoutMessage but also be able to return responses.

But it's more of a proposal than an actual request to be merged. And it wouldn't give you the ability to restore sessions by itself. You would still need to build a tool which could save the layout state and then put it back. And if you wanted to use it for layouts other than dwindle then you would still need to add the required queries and commands to those layouts.

But it would make it possible to do so.

Natr1x avatar Jul 28 '25 07:07 Natr1x