commit 0543020038edb5de1162863e7401ea36f8a8584c
parent 2e3b351c355bd241de4aa4f2bdafd633ccef6eac
Author: hhvn <dev@hhvn.uk>
Date: Tue, 8 Aug 2023 10:46:53 +0100
Channel-based bspwm communication
Diffstat:
M | bspc/bspc.go | | | 66 | +++++++++++++++++++++++++++++++++++++++--------------------------- |
M | common/common.go | | | 13 | ++++++++++++- |
M | main.go | | | 72 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++------------- |
3 files changed, 110 insertions(+), 41 deletions(-)
diff --git a/bspc/bspc.go b/bspc/bspc.go
@@ -63,11 +63,19 @@ func LoadState() (*State, error) {
}
type Subscriber struct {
+ Event chan *Event
+ cleanup chan bool
cmd *exec.Cmd
pipe io.ReadCloser
scanner *bufio.Scanner
}
+type Event struct {
+ Err error
+ Name string
+ Tokens []string
+}
+
func Subscribe() (*Subscriber, error) {
cmd := exec.Command("bspc", "subscribe", "all")
@@ -80,20 +88,35 @@ func Subscribe() (*Subscriber, error) {
return nil, common.Perror("cmd.Start", err)
}
- var ret Subscriber
- ret.cmd = cmd
- ret.pipe = pipe
- ret.scanner = bufio.NewScanner(ret.pipe)
-
- return &ret, nil
+ var s Subscriber
+ s.Event = make(chan *Event)
+ s.cleanup = make(chan bool)
+ s.cmd = cmd
+ s.pipe = pipe
+ s.scanner = bufio.NewScanner(s.pipe)
+
+ go func() {
+ for {
+ select {
+ case <- s.cleanup:
+ s.cmd.Wait()
+ return
+ default:
+ if event := s.get(); event != nil {
+ s.Event <- event
+ }
+ }
+ }
+ }()
+
+ return &s, nil
}
-type Event struct {
- Name string
- Tokens []string
+func (s *Subscriber) Close() {
+ s.cleanup <- true
}
-func (s *Subscriber) GetLine() (string, error) {
+func (s *Subscriber) getLine() (string, error) {
if s.scanner.Scan() {
return s.scanner.Text(), nil
}
@@ -105,29 +128,18 @@ func (s *Subscriber) GetLine() (string, error) {
return "", nil
}
-func (s *Subscriber) Get() (*Event, error) {
+func (s *Subscriber) get() (*Event) {
var line string
var err error
for {
- line, err = s.GetLine()
+ line, err = s.getLine()
if line[0] != 'W' { break }
}
- if err != nil { return nil, err }
- if line == "" { return nil, nil }
-
- name, tokens, found := strings.Cut(line, " ")
+ if line == "" { return nil }
+ if err != nil { return &Event{err, "", nil} }
- var event Event
- event.Name = name
- event.Tokens = strings.Split(tokens, " ")
-
- // We do not found. Shut up, compiler.
- found = !found
-
- return &event, nil
-}
+ name, tokens, _ := strings.Cut(line, " ")
-func (s *Subscriber) Close() error {
- return s.cmd.Wait()
+ return &Event{nil, name, strings.Split(tokens, " ")}
}
diff --git a/common/common.go b/common/common.go
@@ -3,6 +3,7 @@ package common
import (
"os"
"fmt"
+ "strconv"
)
func Perror(function string, err error) error {
@@ -10,5 +11,15 @@ func Perror(function string, err error) error {
}
func Error(format string, a ... any) (int, error) {
- return fmt.Fprintf(os.Stderr, format, a)
+ fmt.Fprintf(os.Stderr, "error: ")
+ if (len(a) == 0) {
+ return fmt.Fprintf(os.Stderr, format)
+ } else {
+ return fmt.Fprintf(os.Stderr, format, a)
+ }
+}
+
+func Intify(s string) (int, error) {
+ i, err := strconv.ParseInt(s, 0, 0)
+ return int(i), err
}
diff --git a/main.go b/main.go
@@ -1,7 +1,7 @@
package main
import (
- "fmt"
+ "strings"
"hhvn.uk/hbspbar/common"
"hhvn.uk/hbspbar/bspc"
@@ -13,32 +13,78 @@ import (
*/
)
+var reloadEvents = []string{
+ "monitor_rename",
+ "monitor_swap",
+ "monitor_focus",
+ "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 handleEvent(events *bspc.Subscriber) (bool) {
+ var event *bspc.Event
+
+ select {
+ case event = <-events.Event:
+ break
+ default:
+ return false
+ }
+
+ if event.Err != nil {
+ common.Error("Couldn't read event: %s\n", event.Err)
+ return false
+ }
+
+ for i := 0; i < len(reloadEvents); i++ {
+ if event.Name == reloadEvents[i] {
+ return true
+ }
+ }
+
+ return false
+}
+
func main() {
state, err := bspc.LoadState()
if (err != nil) {
- common.Error("Couldn't load bspwm state: %s", err)
+ 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", err)
+ common.Error("Couldn't subscribe to bspwm: %s\n", err)
return
}
defer events.Close()
- fmt.Println(state.Monitors[0].ID)
for {
- event, err := events.Get()
-
- if err != nil {
- common.Error("Couldn't read event: %s", err)
- return
- }
-
- if event != nil {
- fmt.Printf("Event: %v %v\n", event.Name, event.Tokens)
+ if reload := handleEvent(events); reload {
+ state, err = reloadState(state)
+ if err != nil {
+ common.Error("Couldn't reload bspwm state: %s\n", err)
+ }
}
}
}