From b4da3d53fdc8cb26e5da72a261671c63540a62d4 Mon Sep 17 00:00:00 2001 From: a Date: Sun, 11 Jun 2023 05:24:15 -0500 Subject: [PATCH] ok --- Makefile | 5 ++- cmd/bspc/main.go | 7 +++- cmd/bspwm/main.go | 34 +++++++++++----- go.mod | 19 +++------ go.sum | 29 +------------- src/bsp/loop.go | 33 +++++++++++++++ src/bsp/node.go | 1 - src/bsp/wm.go | 46 +++++++++++++++++++++ src/copies/errors.go | 9 ++++- src/handler/domain.go | 19 +++++++++ src/handler/domains/common.go | 15 +++++++ src/handler/domains/echo.go | 3 +- src/handler/domains/node.go | 3 +- src/handler/domains/query.go | 75 ++++++++++++++++++++++++++++++++--- src/handler/domains/todo.go | 14 +++++++ src/handler/handler.go | 40 +++++++++++-------- src/sock/msg.go | 2 +- src/sock/server.go | 38 ++++++++++++------ xgb | 1 + xgbutil | 1 + 20 files changed, 301 insertions(+), 93 deletions(-) create mode 100644 src/bsp/loop.go delete mode 100644 src/bsp/node.go create mode 100644 src/bsp/wm.go create mode 100644 src/handler/domain.go create mode 100644 src/handler/domains/common.go create mode 100644 src/handler/domains/todo.go create mode 160000 xgb create mode 160000 xgbutil diff --git a/Makefile b/Makefile index 24b1589..06a84a7 100644 --- a/Makefile +++ b/Makefile @@ -19,9 +19,10 @@ all: bspwm bspc VPATH=src -bspwm: +bspwm: cmd/bspwm src/**/* + go build -o bspwm ./cmd/bspwm -bspc: cmd/bspc src +bspc: cmd/bspc src/**/* go build -o bspc ./cmd/bspc xephyr: diff --git a/cmd/bspc/main.go b/cmd/bspc/main.go index 866f4b9..c82f593 100644 --- a/cmd/bspc/main.go +++ b/cmd/bspc/main.go @@ -10,7 +10,12 @@ import ( func main() { s, err := sock.Client("") errExit(err) - resp, err := s.Send(os.Args[1:]...) + o := os.Args[1:] + if len(o) == 0 { + fmt.Println("no arguments given.") + return + } + resp, err := s.Send(o...) errExit(err) fmt.Print(resp) } diff --git a/cmd/bspwm/main.go b/cmd/bspwm/main.go index fe40792..1b99a4d 100644 --- a/cmd/bspwm/main.go +++ b/cmd/bspwm/main.go @@ -2,40 +2,56 @@ package main import ( "context" - "fmt" "log" "os" "os/signal" "syscall" + "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() { + // create socket ln, err := sock.Server("./bspwm.sock") if err != nil { panic(err) } defer ln.Close() log.Printf("starting bspwm") - ctx, stop := signal.NotifyContext(context.Background(), os.Interrupt, syscall.SIGTERM, - syscall.SIGQUIT) + syscall.SIGQUIT, + syscall.SIGINT, + ) defer stop() - - h := &handler.Handler{} - + // initialize WM state + w := bsp.NewWM() + // create a wm manager + xwm := bsp.NewXWM(w, ln.X11()) + // install the handler + h := &handler.Handler{ + XWM: xwm, + } + handler.AddDomain[domains.Todo](h, "node") + handler.AddDomain[domains.Todo](h, "desktop") + handler.AddDomain[domains.Todo](h, "monitor") + handler.AddDomain[domains.Todo](h, "wm") + handler.AddDomain[domains.Todo](h, "rule") + handler.AddDomain[domains.Todo](h, "config") + handler.AddDomain[domains.Todo](h, "subscribe") + handler.AddDomain[domains.Todo](h, "quit") + handler.AddDomain[domains.Query](h, "query") + handler.AddDomain[domains.Echo](h, "echo") for { select { case m := <-ln.Msg(): - log.Printf("got cmd: %s", m.Args()) h.Run(m) case <-ctx.Done(): - fmt.Println() - log.Printf("bspwm shutting down...") + log.Println("bspwm shutting down...") return } } diff --git a/go.mod b/go.mod index 0739552..163d28b 100644 --- a/go.mod +++ b/go.mod @@ -2,19 +2,10 @@ module tuxpa.in/t/wm go 1.19 -require github.com/alecthomas/kong v0.7.1 +replace github.com/jezek/xgb v1.1.0 => ./xgb -require github.com/jezek/xgb v1.1.0 // indirect +replace github.com/jezek/xgbutil v0.0.0-20230603163917-04188eb39cf0 => ./xgbutil -require ( - github.com/google/uuid v1.3.0 // indirect - github.com/mattn/go-isatty v0.0.16 // indirect - github.com/remyoudompheng/bigfft v0.0.0-20200410134404-eec4a21b6bb0 // indirect - golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab // indirect - modernc.org/libc v1.21.2 // indirect - modernc.org/mathutil v1.5.0 // indirect - modernc.org/memory v1.4.0 // indirect - modernc.org/xau v1.0.13 // indirect - modernc.org/xcb v1.0.13 - modernc.org/xdmcp v1.0.14 // indirect -) +require github.com/jezek/xgb v1.1.0 + +require github.com/jezek/xgbutil v0.0.0-20230603163917-04188eb39cf0 diff --git a/go.sum b/go.sum index 2c79f25..e99f9ea 100644 --- a/go.sum +++ b/go.sum @@ -1,27 +1,2 @@ -github.com/alecthomas/assert/v2 v2.1.0 h1:tbredtNcQnoSd3QBhQWI7QZ3XHOVkw1Moklp2ojoH/0= -github.com/alecthomas/kong v0.7.1 h1:azoTh0IOfwlAX3qN9sHWTxACE2oV8Bg2gAwBsMwDQY4= -github.com/alecthomas/kong v0.7.1/go.mod h1:n1iCIO2xS46oE8ZfYCNDqdR0b0wZNrXAIAqro/2132U= -github.com/alecthomas/repr v0.1.0 h1:ENn2e1+J3k09gyj2shc0dHr/yjaWSHRlrJ4DPMevDqE= -github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I= -github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= -github.com/hexops/gotextdiff v1.0.3 h1:gitA9+qJrrTCsiCl7+kh75nPqQt1cx4ZkudSTLoUqJM= -github.com/jezek/xgb v1.1.0 h1:wnpxJzP1+rkbGclEkmwpVFQWpuE2PUGNUzP8SbfFobk= -github.com/jezek/xgb v1.1.0/go.mod h1:nrhwO0FX/enq75I7Y7G8iN1ubpSGZEiA3v9e9GyRFlk= -github.com/mattn/go-isatty v0.0.16 h1:bq3VjFmv/sOjHtdEhmkEV4x1AJtvUvOJ2PFAZ5+peKQ= -github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= -github.com/remyoudompheng/bigfft v0.0.0-20200410134404-eec4a21b6bb0 h1:OdAsTTz6OkFY5QxjkYwrChwuRruF69c169dPK26NUlk= -github.com/remyoudompheng/bigfft v0.0.0-20200410134404-eec4a21b6bb0/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo= -golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab h1:2QkjZIsXupsJbJIdSjjUOgWK3aEtzyuh2mPt3l/CkeU= -golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -modernc.org/libc v1.21.2 h1:V053DgNSpAY+IPrO3XlWqrFKUiQqHyPqG4dsx42Ulck= -modernc.org/libc v1.21.2/go.mod h1:przBsL5RDOZajTVslkugzLBj1evTue36jEomFQOoYuI= -modernc.org/mathutil v1.5.0 h1:rV0Ko/6SfM+8G+yKiyI830l3Wuz1zRutdslNoQ0kfiQ= -modernc.org/mathutil v1.5.0/go.mod h1:mZW8CKdRPY1v87qxC/wUdX5O1qDzXMP5TH3wjfpga6E= -modernc.org/memory v1.4.0 h1:crykUfNSnMAXaOJnnxcSzbUGMqkLWjklJKkBK2nwZwk= -modernc.org/memory v1.4.0/go.mod h1:PkUhL0Mugw21sHPeskwZW4D6VscE/GQJOnIpCnW6pSU= -modernc.org/xau v1.0.13 h1:AEYsSsJFSmkfhSwV6/dx6GoHt02BnZLmMcRT1O8EUOo= -modernc.org/xau v1.0.13/go.mod h1:5ORRqBKlhiUXwoVdM0+ZPy8plvcq0OPOdEgTWyeokhk= -modernc.org/xcb v1.0.13 h1:SIMh1yKsKjkfT/qAxcxSv/W+mRe4RnPzp+XewnD4rS4= -modernc.org/xcb v1.0.13/go.mod h1:M5m1dSVaHvBUf5XUg5Y/b1DZdJs6NK7pYLqsQ+d0swU= -modernc.org/xdmcp v1.0.14 h1:hRCxbYfl75rvOdCmVCPLBRCedClOPjpHiq+tOBzGS3Q= -modernc.org/xdmcp v1.0.14/go.mod h1:TDsH3iMey1HJ3tMCePfTy4dIX6hL/MIVnGREX97nCrE= +github.com/BurntSushi/freetype-go v0.0.0-20160129220410-b763ddbfe298/go.mod h1:D+QujdIlUNfa0igpNMk6UIvlb6C252URs4yupRUV4lQ= +github.com/BurntSushi/graphics-go v0.0.0-20160129215708-b43f31a4a966/go.mod h1:Mid70uvE93zn9wgF92A/r5ixgnvX8Lh68fxp9KQBaI0= diff --git a/src/bsp/loop.go b/src/bsp/loop.go new file mode 100644 index 0000000..791271c --- /dev/null +++ b/src/bsp/loop.go @@ -0,0 +1,33 @@ +package bsp + +import ( + "context" + + "github.com/jezek/xgbutil" +) + +type XWM struct { + w *WM + x *xgbutil.XUtil +} + +func NewXWM(w *WM, x *xgbutil.XUtil) *XWM { + xwm := &XWM{ + w: w, + x: x, + } + return xwm +} + +func (xwm *XWM) Start(ctx context.Context) error { + for { + err := xwm.run(ctx) + if err != nil { + return err + } + } +} + +func (xwm *XWM) run(ctx context.Context) error { + return nil +} diff --git a/src/bsp/node.go b/src/bsp/node.go deleted file mode 100644 index 27a6bb9..0000000 --- a/src/bsp/node.go +++ /dev/null @@ -1 +0,0 @@ -package bsp diff --git a/src/bsp/wm.go b/src/bsp/wm.go new file mode 100644 index 0000000..10a3a6f --- /dev/null +++ b/src/bsp/wm.go @@ -0,0 +1,46 @@ +package bsp + +import ( + "sync" +) + +type WM struct { + Desktops []*Desktop + Monitors []*Monitor + + mu sync.RWMutex +} + +type Desktop struct { + Name string + Monitor *Monitor +} + +type Monitor struct { + Name string +} + +func (w *WM) Mutate(fn func() error) { + w.mu.Lock() + defer w.mu.Unlock() + if fn != nil { + fn() + } +} + +func (w *WM) View(fn func() error) { + w.mu.RLock() + defer w.mu.RUnlock() + if fn != nil { + fn() + } +} + +func (w *WM) AddDesktop(name string) { + +} + +func NewWM() *WM { + w := &WM{} + return w +} diff --git a/src/copies/errors.go b/src/copies/errors.go index 203d50e..9aed45d 100644 --- a/src/copies/errors.go +++ b/src/copies/errors.go @@ -22,7 +22,14 @@ type ErrMissingArguments struct { } func (m *ErrMissingArguments) Error() string { - return `Missing Arguments` + return `Missing arguments` +} + +type ErrNoCommandsGiven struct { +} + +func (m *ErrNoCommandsGiven) Error() string { + return `No commands given` } type ErrTODO struct { diff --git a/src/handler/domain.go b/src/handler/domain.go new file mode 100644 index 0000000..c96251c --- /dev/null +++ b/src/handler/domain.go @@ -0,0 +1,19 @@ +package handler + +import ( + "tuxpa.in/t/wm/src/bsp" + "tuxpa.in/t/wm/src/sock" +) + +type Domain interface { + DomainRunner + DomainState +} + +type DomainRunner interface { + Run(*sock.Msg) ([]byte, error) +} + +type DomainState interface { + SetXWM(*bsp.XWM) +} diff --git a/src/handler/domains/common.go b/src/handler/domains/common.go new file mode 100644 index 0000000..bda266e --- /dev/null +++ b/src/handler/domains/common.go @@ -0,0 +1,15 @@ +package domains + +import "tuxpa.in/t/wm/src/bsp" + +type inject struct { + xwm +} + +type xwm struct { + XWM *bsp.XWM +} + +func (x xwm) SetXWM(z *bsp.XWM) { + x.XWM = z +} diff --git a/src/handler/domains/echo.go b/src/handler/domains/echo.go index f9464e7..f0bec6e 100644 --- a/src/handler/domains/echo.go +++ b/src/handler/domains/echo.go @@ -8,9 +8,10 @@ import ( ) type Echo struct { + inject } -func (n *Echo) Run(msg *sock.Msg) ([]byte, error) { +func (n Echo) Run(msg *sock.Msg) ([]byte, error) { if !msg.HasNext() { return nil, &copies.ErrMissingArguments{} } diff --git a/src/handler/domains/node.go b/src/handler/domains/node.go index 34db0ba..96bfdd5 100644 --- a/src/handler/domains/node.go +++ b/src/handler/domains/node.go @@ -3,9 +3,10 @@ package domains import "tuxpa.in/t/wm/src/copies" type Node struct { + inject } -func (n *Node) Run(args ...string) error { +func (n Node) Run(args ...string) error { if len(args) == 0 { return &copies.ErrMissingArguments{} } diff --git a/src/handler/domains/query.go b/src/handler/domains/query.go index fba7d63..4256f31 100644 --- a/src/handler/domains/query.go +++ b/src/handler/domains/query.go @@ -1,13 +1,78 @@ package domains -import "tuxpa.in/t/wm/src/copies" +import ( + "bytes" + "fmt" + + "tuxpa.in/t/wm/src/copies" + "tuxpa.in/t/wm/src/sock" +) type Query struct { + Command string + + UseNames bool + + inject } -func (n *Query) Run(args ...string) error { - if len(args) == 0 { - return &copies.ErrMissingArguments{} +func (n Query) Run(msg *sock.Msg) ([]byte, error) { + if !msg.HasNext() { + return nil, &copies.ErrMissingArguments{} + } + for { + ok, err := n.parse(msg) + if err != nil { + return nil, err + } + if !ok { + break + } + } + switch n.Command { + case "desktops": + return n.desktops(msg) + default: + return nil, &copies.ErrTODO{} } - return nil +} + +func (n *Query) desktops(msg *sock.Msg) ([]byte, error) { + o := new(bytes.Buffer) + o.WriteString("hi there") + return o.Bytes(), nil + +} + +func (n *Query) parse(msg *sock.Msg) (bool, error) { + if !msg.HasNext() { + return false, &copies.ErrMissingArguments{} + } + arg := msg.Next() + switch arg { + case "--desktop", "-d": + case "--desktops", "-D": + return n.readCommand(msg, "desktops") + case "--monitor", "-m": + case "--monitors", "-M": + return n.readCommand(msg, "monitors") + case "--names": + n.UseNames = true + case "--node", "-n": + case "--nodes", "-N": + return n.readCommand(msg, "nodes") + case "--tree", "-T": + return n.readCommand(msg, "tree") + default: + return false, fmt.Errorf(`unknown option: '%s'`, arg) + } + return msg.HasNext(), nil +} + +func (n *Query) readCommand(msg *sock.Msg, c string) (bool, error) { + if n.Command == "" { + n.Command = c + return msg.HasNext(), nil + } + return false, fmt.Errorf("multiple commands given") } diff --git a/src/handler/domains/todo.go b/src/handler/domains/todo.go new file mode 100644 index 0000000..fa4e5e6 --- /dev/null +++ b/src/handler/domains/todo.go @@ -0,0 +1,14 @@ +package domains + +import ( + "tuxpa.in/t/wm/src/copies" + "tuxpa.in/t/wm/src/sock" +) + +type Todo struct { + inject +} + +func (n Todo) Run(msg *sock.Msg) ([]byte, error) { + return nil, &copies.ErrTODO{} +} diff --git a/src/handler/handler.go b/src/handler/handler.go index 102b85c..cf41984 100644 --- a/src/handler/handler.go +++ b/src/handler/handler.go @@ -3,12 +3,29 @@ package handler import ( "fmt" + "tuxpa.in/t/wm/src/bsp" "tuxpa.in/t/wm/src/copies" - "tuxpa.in/t/wm/src/handler/domains" "tuxpa.in/t/wm/src/sock" ) type Handler struct { + XWM *bsp.XWM + + domains map[string]func() Domain +} + +func AddDomain[T any, PT interface { + Domain + *T +}](h *Handler, name string) { + if h.domains == nil { + h.domains = map[string]func() Domain{} + } + h.domains[name] = func() Domain { + domain := PT(new(T)) + domain.SetXWM(h.XWM) + return domain + } } func (h *Handler) Run(msg *sock.Msg) { @@ -28,26 +45,15 @@ func (h *Handler) run(msg *sock.Msg) ([]byte, error) { return nil, &copies.ErrMissingArguments{} } cmd := msg.Next() - switch cmd { - case "node", - "desktop", - "monitor", - "query", - "wm", - "rule", - "config", - "subscribe", - "quit": - return nil, &copies.ErrTODO{Kind: "domain", Name: cmd} - case "echo": - return h.runDomain(cmd, msg, (&domains.Echo{}).Run) - default: + d, ok := h.domains[cmd] + if !ok { return nil, &copies.ErrUnknownDomainOrCommand{Str: cmd} } + return h.runDomain(cmd, msg, d()) } -func (h *Handler) runDomain(name string, msg *sock.Msg, fn func(*sock.Msg) ([]byte, error)) ([]byte, error) { - str, err := fn(msg) +func (h *Handler) runDomain(name string, msg *sock.Msg, d DomainRunner) ([]byte, error) { + str, err := d.Run(msg) if err != nil { return nil, fmt.Errorf("%s: %w", name, err) } diff --git a/src/sock/msg.go b/src/sock/msg.go index 02646c3..bfad81a 100644 --- a/src/sock/msg.go +++ b/src/sock/msg.go @@ -20,7 +20,7 @@ func (m *Msg) Peek() string { return m.Get(0) } func (m *Msg) Next() string { - if m.Has(m.cur) { + if m.Has(0) { m.cur = m.cur + 1 return m.args[m.cur-1] } diff --git a/src/sock/server.go b/src/sock/server.go index ee30787..4d6c355 100644 --- a/src/sock/server.go +++ b/src/sock/server.go @@ -5,12 +5,13 @@ import ( "fmt" "net" "os" + "strings" - "github.com/jezek/xgb" + "github.com/jezek/xgbutil" ) type SockListener struct { - xgb *xgb.Conn + xgb *xgbutil.XUtil l *net.UnixListener ch chan *Msg @@ -19,24 +20,32 @@ type SockListener struct { func (s *SockListener) Msg() <-chan *Msg { return s.ch } -func Server(path string) (*SockListener, error) { - s := &SockListener{} - s.ch = make(chan *Msg, 1) - xc, err := xgb.NewConnDisplay("") - if err != nil { - return nil, err - } - s.xgb = xc +func (s *SockListener) X11() *xgbutil.XUtil { + return s.xgb +} +func getUnixAddr(xc *xgbutil.XUtil, path string) *net.UnixAddr { if path == "" { path = os.Getenv(SOCKET_ENV_VAR) } if path == "" { - path = fmt.Sprintf(SOCKET_PATH_TPL, "", xc.DisplayNumber, xc.DefaultScreen) + path = fmt.Sprintf(SOCKET_PATH_TPL, "", xc.Conn().DisplayNumber, xc.Conn().DefaultScreen) } addr, err := net.ResolveUnixAddr("unix", path) + if err != nil { + panic(err) + } + return addr +} + +func Server(path string) (*SockListener, error) { + s := &SockListener{} + s.ch = make(chan *Msg, 1) + xc, err := xgbutil.NewConn() if err != nil { return nil, err } + s.xgb = xc + addr := getUnixAddr(xc, path) conn, err := net.ListenUnix("unix", addr) if err != nil { return nil, err @@ -59,7 +68,8 @@ func Server(path string) (*SockListener, error) { return s, nil } func (s *SockListener) Close() error { - return s.l.Close() + err := s.l.Close() + return err } func (s *SockListener) acceptConn(c *net.UnixConn) error { msg := &Msg{} @@ -71,7 +81,9 @@ func (s *SockListener) acceptConn(c *net.UnixConn) error { bts = bts[:n] splt := bytes.Split(bts, []byte{0}) for _, v := range splt { - msg.args = append(msg.args, string(v)) + if len(strings.TrimSpace(string(v))) > 0 { + msg.args = append(msg.args, string(v)) + } } msg.c = c s.ch <- msg diff --git a/xgb b/xgb new file mode 160000 index 0000000..a57abb5 --- /dev/null +++ b/xgb @@ -0,0 +1 @@ +Subproject commit a57abb570aeba12f867c58afe22ce49ac5db4872 diff --git a/xgbutil b/xgbutil new file mode 160000 index 0000000..04188eb --- /dev/null +++ b/xgbutil @@ -0,0 +1 @@ +Subproject commit 04188eb39cf0fa005f5b3aec48faa82541748b79