package main import ( "context" "fmt" "net" "os" "os/signal" "strconv" "syscall" "github.com/jezek/xgbutil" "github.com/jezek/xgbutil/xevent" "tuxpa.in/a/zlog/log" "tuxpa.in/t/wm/src/bsp" "tuxpa.in/t/wm/src/handler" "tuxpa.in/t/wm/src/handler/domains" "tuxpa.in/t/wm/src/sock" ) func main() { c, err := _main() if err != nil { panic(err) } os.Exit(c) } func _main() (code int, err error) { // connect to the x server log.Printf("connecting to xorg") x11, err := xgbutil.NewConn() if err != nil { return 1, err } defer x11.Conn().Close() addr := parsePath(x11, "./bspwm.sock") // create socket log.Printf("starting bspwm") ln, err := sock.Server(addr) if err != nil { return 1, err } defer ln.Close() // construct context ctx, stop := signal.NotifyContext(context.Background(), os.Interrupt, syscall.SIGTERM, syscall.SIGQUIT, syscall.SIGINT, ) defer stop() // initialize WM state w := bsp.NewWM() // create a wm-x11 connection xwm := bsp.NewXWM(w, x11) go func() { err := xwm.Start(ctx) if err != nil { log.Err(err).Msg("x server shutdown") stop() } }() // create a handler h := &handler.Handler{ XWM: xwm, } // install the handlers handler.AddDomain[domains.Node](h, "node") handler.AddDomain[domains.Todo](h, "desktop") handler.AddDomain[domains.Monitor](h, "monitor") handler.AddDomain[domains.Wm](h, "wm") handler.AddDomain[domains.Todo](h, "rule") handler.AddDomain[domains.Config](h, "config") handler.AddDomain[domains.Todo](h, "subscribe") handler.AddDomain[domains.Query](h, "query") handler.AddDomain[domains.Echo](h, "echo") codeCh := make(chan int, 1) handler.AddDomain[domains.Todo](h, "quit") h.AddDomainFunc("quit", func() handler.Domain { d := &domains.Lambda{ Fn: func(x *bsp.XWM, msg *sock.Msg) ([]byte, error) { if !msg.HasNext() { codeCh <- 0 return nil, nil } str := msg.Next() cd, err := strconv.Atoi(str) if err != nil { return nil, err } codeCh <- cd return nil, nil }, } return d }) beforeCh, afterCh, quitCh := xevent.MainPing(xwm.X) // message listen loop for { select { case <-beforeCh: <-afterCh case m := <-ln.Msg(): h.Run(m) case cint := <-codeCh: stop() return cint, nil case <-quitCh: stop() case <-ctx.Done(): return 0, nil } } } func parsePath(xc *xgbutil.XUtil, path string) *net.UnixAddr { if path == "" { path = os.Getenv(sock.SOCKET_ENV_VAR) } if path == "" { path = fmt.Sprintf(sock.SOCKET_PATH_TPL, "", xc.Conn().DisplayNumber, xc.Conn().DefaultScreen) } addr, err := net.ResolveUnixAddr("unix", path) if err != nil { panic(err) } return addr }