我终于把sway布局设置成我想要的样子自动启动了。
I finally got my sway layout to autostart the way I like it

原始链接: https://hugues.betakappaphi.com/2026/01/19/sway-layout/

多年来,作者一直苦于Sway缺少自动保存和恢复应用程序的功能——在从KDE切换后,这是一个令人沮丧的缺失。现有的解决方案不可靠,并且充斥着各种变通方法。最近,在将他的自建实验室迁移到更标准化的Ansible配置时,他重新审视了这个问题,并在Claude Code的帮助下,尝试构建一个解决方案。 最初的尝试重蹈覆辙,受到竞态条件的困扰。然而,深入研究Sway的文档后,他获得了一个关键的见解:窗口创建事件流包含进程ID。这使得他能够采用一种新的方法——同时启动所有应用程序,跟踪它们的PID,然后排列它们,从而避免了时序问题。 虽然Claude帮助完成了初始脚本,但作者完善了核心逻辑(完全没有使用AI),以处理嵌套窗口层次结构,克服了Sway IPC的限制。最终的结果,**sway-layout**,是一个基于Go的工具,它读取JSON配置文件以定义启动时的窗口布局。 目前,它在处理分离进程和窗口排序方面存在局限性,但提供了一个强大的自动启动解决方案。未来的开发可能包括通过事件跟踪和布局快照来实现会话保存/恢复。代码可在[GitHub](原文未提供链接)上找到。

一位Hacker News用户最近分享了成功定制Sway窗口管理器启动的经验。Sway是一个平铺式窗口管理器,定位为i3的即插即用替代品,但开箱即用需要大量的配置。 虽然用户喜欢定制过程以及由此带来的对系统组件更深入的理解,但许多人认为它最初感觉“不完整”,缺乏像系统时钟在状态栏中这样的合理默认设置。一位用户指出,所付出的努力凸显了隐藏在GNOME等更全面的桌面环境中的复杂性。 这次讨论促使另一位用户终于尝试Sway,因为其与i3的兼容性,此前他缺乏定制i3本身的动力。总的来说,该帖子反映了对Sway的积极体验,尽管最初的设置需要投入。
相关文章

原文

I have been using sway as my default window manager on my laptop for a few years. One of the things that I’ve found most annoying about it, after over a decade of using KDE, was the lack of automated save and restore of running applications. There is a way to auto-start applications, but not to specify the way the resulting windows will be laid out.

Every time I went looking, I could only find partial, hacky, or unreliable solutions, often full of artificial delays to try to address race conditions. Suffice to say I was not satisfied with anything I found, so I accepted that I had to setup my starting configuration on every reboot.

Another round of experiments

Over the last couple of months, with tremendous help from Claude Code, I have been migrating my janky homelab, haphazardly hand-crafted over the course of ~7 years, to a more reproducible setup, standardizing on a single distro (Arch), and using Ansible to provision each machine.

As I was looking through a variety of config files on my main laptop, and deciding what to manage with ansible, I was once again reminded of my desire for a smoother and more automated session startup, so I decided to run a few experiments with Claude.

The results were honestly pretty bad.

Claude was running into the same race conditions that countless humans had to wrestle with before, and despite valiant efforts, none of its approaches were getting anywhere satisfying…

RTFM

I was too invested to just give up though, so I took a serious look at the sway manpages, and, right there, staring at me, I found the kernel of a solution: the event stream for created windows includes the pid of the process that spawns it!

What if…

What if, instead of trying to painstakingly setup the layout before spawning each new window, and waiting for each window to spawn before moving to the next one…

… we just spawn all the windows at once, let them go wherever they will, track which windows corresponds to which process, and then once all windows are up, we re-arrange them all at once!

This approach has a number of benefits:

  • all applications can be started in parallel, enabling a much faster startup
  • the config doesn’t need to specify any rules to map spawned windows to the appropriate layout spot
  • dealing with applications that spawn variable numbers of windows becomes trivial
  • the whole thing is extremely robust and doesn’t require any arbitrary delay between steps

Given a clear plan for this better approach, Claude did a decent enough job. It set up solid wiring for spawning processes and tracking the resulting windows. However, it fumbled on one critical aspect: the wrapper script that was supposed to introduce the layout metadata in the process tree was exec-ing the underlying command instead of creating a subprocess, losing the layout metadata in the process! Oops…

Going deep

After the initial high of a working prototype, I had another unpleasant surprise: the code would always flatten the layout into a single container, instead of faithfully reproducing arbitrarily nested hierarchies. As it turns out, that’s actually a fairly tricky problem to get right, given that sway neither allows empty containers, nor offers any form of placeholders for incrementally building nested hierarchies. It took me a few hours of experiments to come to terms with the severe limitations of the IPC API in that respect, and to refine the two primitives that enable a simple recursive algorithm to robustly reproduce arbitrarily nested window hierarchies. That core logic is 100% AI-free!

Introducing sway-layout

The prototype worked really well, so I decided to clean it up and make it publicly available, as I figure other people might find it useful.

After a mix of Bash and Python for the prototype, I went with Go for the cleaned up version, to make it easy to deploy a single binary.

The source code is available at the following two mirrors:

Installing it is as simple as:

go build
cp sway-layout /usr/local/bin

To use it, create your layout config as json, in ~/.config/sway/layouts/startup.json.

For instance, here’s my ridiculously nested test config:

{
  "workspaces": {
    "6": {
      "splitv": [
        {
          "splith": [
            "speedcrunch",
            {
              "tabbed": [
                "alacritty",
                "alacritty"
              ]
            },
            {
              "stacking": [
                "alacritty",
                "alacritty"
              ]
            }
          ]
        },
        {
          "splith": [
            "alacritty -e btop",
            "alacritty"
          ]
        },
        "speedcrunch",
        "alacritty -e htop"
      ]
    }
  }
}

and, to make sure it gets invoked by sway on startup, add the following stanza to your config (adjusting the path as needed obviously):

exec /usr/local/bin/sway-layout

Limitations and future work

As it is, sway-layout gets the job done, but it’s far from perfect.

In particular:

  • it will not track windows from processes that detach from their parent, as detaching will break our ability to map process id back to layout metadata. Thankfully, detaching is rarely used by graphical applications so it’s unlikely to be an issue in practice.
  • applications that spawn multiple window will have all their windows grouped together, in the order in which they appeared, which may or may not be the prefered order…
  • there is currently no way to specify a custom window size that deviates from the default even allocation of space within a split container.

Beyond that, it would probably be practical to keep track of an evolving layout throughout a session: by subscribing to sway events, walking the process tree to figure out which command to record for each new window (with some careful de-duping for commands that spawn multiple windows), and snapshotting the actual layout via the get_tree IPC call every time a window is created, moved, or resized, it would be possible to implement a fairly robust automated save/restore, and not merely and autostart.

I will leave that as an exercise for future me, or some motivated reader :)

联系我们 contact @ memedata.com