hbspbar

[WIP] bspwm status bar
git clone https://hhvn.uk/hbspbar
git clone git://hhvn.uk/hbspbar
Log | Files | Refs

commit 2a8069eb9606af55f76ac43e187ca83a7dd6957f
parent feffd883dce08ada407c67810f522bd2790cb6b0
Author: hhvn <dev@hhvn.uk>
Date:   Thu, 16 Nov 2023 19:20:50 +0000

Single select in main controls entire process

Diffstat:
Mbspc/bspc.go | 108+++++++++++++++++++++++++++++++++++++++++++++++++++++--------------------------
Mmain.go | 128++++++++++++++++++-------------------------------------------------------------
2 files changed, 101 insertions(+), 135 deletions(-)

diff --git a/bspc/bspc.go b/bspc/bspc.go @@ -77,7 +77,26 @@ type Desktop struct { Root *Node } -func LoadState() (*State, error) { +var reloadEvents = []string{ + "monitor_rename", + "monitor_swap", + "monitor_focus", + "monitor_remove", + "monitor_geometry", // only event we get for monitors on restart + "desktop_add", + "desktop_rename", + "desktop_remove", + "desktop_swap", + "desktop_transfer", + "desktop_focus", + "desktop_activate", + "desktop_layout", + "node_add", + "node_remove", + "node_swap", + "node_transfer" } + +func getState() (*State, error) { cmd := exec.Command("bspc", "wm", "-d") out, err := cmd.StdoutPipe() @@ -115,13 +134,15 @@ func LoadState() (*State, error) { return &state, nil } -type Subscriber struct { - Event chan *Event - Err chan error - cleanup chan bool - cmd *exec.Cmd - pipe io.ReadCloser - scanner *bufio.Scanner +type subscriber struct { + State *State + StateUpdate chan bool + StErr chan error + Event chan *Event + EvErr chan error + cmd *exec.Cmd + pipe io.ReadCloser + scanner *bufio.Scanner } type Event struct { @@ -129,67 +150,84 @@ type Event struct { Tokens []string } -func Subscribe() (*Subscriber, error) { +var InitErr error +var Handle subscriber + +func init() { cmd := exec.Command("bspc", "subscribe", "all") pipe, err := cmd.StdoutPipe() if err != nil { - return nil, common.Perror("cmd.StdoutPipe", err) + InitErr = common.Perror("cmd.StdoutPipe", err) + return } if err = cmd.Start(); err != nil { - return nil, common.Perror("cmd.Start", err) + InitErr = common.Perror("cmd.Start", err) + return } - var s Subscriber - s.Event = make(chan *Event) - s.Err = make(chan error) - s.cleanup = make(chan bool) - s.cmd = cmd - s.pipe = pipe - s.scanner = bufio.NewScanner(s.pipe) + istate, err := getState() + if err != nil { + InitErr = common.Perror("getState", err) + return + } + + Handle.State = istate + Handle.StateUpdate = make(chan bool) + Handle.StErr = make(chan error) + Handle.Event = make(chan *Event) + Handle.EvErr = make(chan error) + Handle.cmd = cmd + Handle.pipe = pipe + Handle.scanner = bufio.NewScanner(Handle.pipe) go func() { for { - event, err := s.get() + event, err := get() if event != nil { - s.Event <- event + for i := 0; i < len(reloadEvents); i++ { + if event.Name == reloadEvents[i] { + state, serr := getState() + if serr != nil { + Handle.StErr <- serr + return + } + Handle.State = state + Handle.StateUpdate <- true + } + } + Handle.Event <- event } if err != nil { - s.Err <- err + Handle.EvErr <- err return } }}() - - return &s, nil } -func (s *Subscriber) Close() { - s.cmd.Process.Kill() +func Close() { + Handle.cmd.Process.Kill() } -func (s *Subscriber) getLine() (string, error) { - if s.scanner.Scan() { - return s.scanner.Text(), nil +func getLine() (string, error) { + if Handle.scanner.Scan() { + return Handle.scanner.Text(), nil } - if err := s.scanner.Err(); err != nil { + if err := Handle.scanner.Err(); err != nil { return "", common.Perror("scanner.Err", err) } return "", nil } -func (s *Subscriber) get() (*Event, error) { +func get() (*Event, error) { var line string var err error for { - line, err = s.getLine() - // if line == "W" { - // // Send this pseudo event so we know to reload the state - // return &Event{"reload", make([]string, 0)}, nil - // } + line, err = getLine() if len(line) > 0 && line[0] != 'W' { break } } diff --git a/main.go b/main.go @@ -11,72 +11,6 @@ import ( "hhvn.uk/hbspbar/bar" ) -var reloadEvents = []string{ - "monitor_rename", - "monitor_swap", - "monitor_focus", - "monitor_remove", - "monitor_geometry", // only event we get for monitors on restart - "desktop_add", - "desktop_rename", - "desktop_remove", - "desktop_swap", - "desktop_transfer", - "desktop_focus", - "desktop_activate", - "desktop_layout", - "node_add", - "node_remove", - "node_swap", - "node_transfer" } - -func reloadState(current *bspc.State) (*bspc.State, error) { - state, err := bspc.LoadState() - - if err != nil { - return current, err - } else { - return state, nil - } -} - -func handleEvents(events *bspc.Subscriber) (chan error, chan bool) { - var event *bspc.Event - - errors := make(chan error) - reload := make(chan bool) - - go func(){ for { - select { - case err := <-events.Err: - errors <- err - return - case event = <- events.Event: - } - - if strings.HasPrefix(event.Name, "monitor_") { - id, err := common.Intify(event.Tokens[0]) - if err == nil { - switch (event.Name) { - case "monitor_add": - case "monitor_geometry": - bar.Handle.Create <- id - case "monitor_remove": - bar.Handle.Destroy <- id - } - } - } - - for i := 0; i < len(reloadEvents); i++ { - if event.Name == reloadEvents[i] { - reload <- true - } - } - }}() - - return errors, reload -} - func main() { signals := make(chan os.Signal, 1) signal.Notify(signals, @@ -84,58 +18,52 @@ func main() { syscall.SIGHUP, syscall.SIGTERM) - state, err := bspc.LoadState() - if err != nil { - common.Error("Couldn't load bspwm state: %s\n", err) - return - } - - events, err := bspc.Subscribe() - if err != nil { - common.Error("Couldn't subscribe to bspwm: %s\n", err) + if bar.InitErr != nil { + common.Error("Couldn't initialize X: %s\n", bar.InitErr) return } - defer events.Close() - - everr, evreload := handleEvents(events) + defer bar.Cleanup() - if bar.InitErr != nil { - common.Error("Couldn't initialize X: %s\n", err) + if bspc.InitErr != nil { + common.Error("Couldn't subscribe to bspwm: %s\n", bspc.InitErr) return } - defer bar.Cleanup() - bar.Handle.NewState <- state + defer bspc.Close() - for _, m := range state.Monitors { + bar.Handle.NewState <- bspc.Handle.State + for _, m := range bspc.Handle.State.Monitors { bar.Handle.Create <- m.ID } for { select { - case err := <- everr: - common.Error("Couldn't read event: %s\n", err) - return case s := <- signals: common.Error("%s\n", s) return case err := <- bar.Handle.Err: common.Error("%s\n", err) return - case <- evreload: - state, err = reloadState(state) - if err != nil { - common.Error("Couldn't reload bspwm state: %s\n", err) - } - - // Check if there's been an error before sending the - // new state (or else the program gets stuck) - select { - case err := <- bar.Handle.Err: - common.Error("%s\n", err) - return - default: + case err := <- bspc.Handle.EvErr: + common.Error("Couldn't read event: %s\n", err) + return + case event := <- bspc.Handle.Event: + if strings.HasPrefix(event.Name, "monitor_") { + id, err := common.Intify(event.Tokens[0]) + if err == nil { + switch (event.Name) { + case "monitor_add": + case "monitor_geometry": + bar.Handle.Create <- id + case "monitor_remove": + bar.Handle.Destroy <- id + } + } } - bar.Handle.NewState <- state + case err := <- bspc.Handle.StErr: + common.Error("Couldn't load bspwm state: %s\n", err) + return + case <- bspc.Handle.StateUpdate: + bar.Handle.NewState <- bspc.Handle.State } } }