diff options
| author | crecher <crecher@crecher.net> | 2026-10-21 22:16:49 +0000 |
|---|---|---|
| committer | crecher <crecher@crecher.net> | 2026-10-21 22:16:49 +0000 |
| commit | 5f2faec53cd88d723d8e7572e2f2a73949d6025a (patch) | |
| tree | e7d5402a51cdac1262d843088067ef2a0e7e4268 /restart.go | |
| parent | 4539e476b6644e961a4a96e3253c615bc4673b0c (diff) | |
| download | wm-5f2faec53cd88d723d8e7572e2f2a73949d6025a.tar.gz wm-5f2faec53cd88d723d8e7572e2f2a73949d6025a.zip | |
fix: crash on startup, feat: hot reload
Signed-off-by: crecher <crecher@onyx.home>
Diffstat (limited to 'restart.go')
| -rw-r--r-- | restart.go | 108 |
1 files changed, 108 insertions, 0 deletions
diff --git a/restart.go b/restart.go new file mode 100644 index 0000000..87c6c41 --- /dev/null +++ b/restart.go @@ -0,0 +1,108 @@ +package main + +import ( + "encoding/json" + "log" + "os" + "strings" + "syscall" + + "github.com/BurntSushi/xgb" + "github.com/BurntSushi/xgb/xproto" +) + +const stateEnv = "WM_STATE" + +type savedClient struct { + Win xproto.Window + Floating bool + Tags BitMask +} + +type savedState struct { + Clients []savedClient + GlobalTags BitMask + Layout string + Focused xproto.Window +} + +func restart() { + st := savedState{GlobalTags: GlobalTags, Layout: layout, Focused: focused} + for _, c := range clientList { + st.Clients = append(st.Clients, savedClient{c.Win, c.Floating, c.Tags}) + } + data, err := json.Marshal(st) + if err != nil { + log.Println("restart: failed to save state:", err) + return + } + + exe, err := os.Executable() + if err != nil { + exe = os.Args[0] + } + exe = strings.TrimSuffix(exe, " (deleted)") + + env := append(os.Environ(), stateEnv+"="+string(data)) + log.Println("restarting", exe) + if err := syscall.Exec(exe, os.Args, env); err != nil { + log.Println("restart: exec failed:", err) + } +} + +func restoreState(conn *xgb.Conn) bool { + raw, ok := os.LookupEnv(stateEnv) + if !ok { + return false + } + os.Unsetenv(stateEnv) + + var st savedState + if err := json.Unmarshal([]byte(raw), &st); err != nil { + log.Println("restore: bad state:", err) + return false + } + + GlobalTags = st.GlobalTags + if st.Layout != "" { + layout = st.Layout + } + + for _, sc := range st.Clients { + geom, err := xproto.GetGeometry(conn, xproto.Drawable(sc.Win)).Reply() + if err != nil { + continue + } + client := &Client{ + Win: sc.Win, + X: geom.X, + Y: geom.Y, + Width: geom.Width, + Height: geom.Height, + Floating: sc.Floating, + Tags: sc.Tags, + } + clients[sc.Win] = client + clientList = append(clientList, client) + + xproto.ChangeWindowAttributes(conn, sc.Win, + xproto.CwEventMask, + []uint32{ + xproto.EventMaskEnterWindow | + xproto.EventMaskFocusChange | + xproto.EventMaskPropertyChange, + }) + } + + if _, ok := clients[st.Focused]; ok { + focused = st.Focused + setInputFocus(conn, focused) + } + + for _, c := range clients { + xproto.UnmapWindow(conn, c.Win) + } + updateWindows(conn) + drawBar(conn) + return true +} |