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 } for _, c := range clients { xproto.UnmapWindow(conn, c.Win) } updateWindows(conn) drawBar(conn) return true }