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:
M | bspc/bspc.go | | | 108 | +++++++++++++++++++++++++++++++++++++++++++++++++++++-------------------------- |
M | main.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
}
}
}