commit 2f2a90ba85c36a0935840654fd45d9a8a9798610
parent 0b3d4426cb585ceade7a27ed28cfe08f1710738d
Author: hhvn <dev@hhvn.uk>
Date: Wed, 21 Feb 2024 18:21:18 +0000
Make bar part of main
Diffstat:
A | bar.go | | | 201 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
D | bar/bar.go | | | 241 | ------------------------------------------------------------------------------- |
M | main.go | | | 54 | ++++++++++++++++++++++++++++++++++++++---------------- |
3 files changed, 239 insertions(+), 257 deletions(-)
diff --git a/bar.go b/bar.go
@@ -0,0 +1,201 @@
+package main
+
+import (
+ "image"
+ "errors"
+ "image/color"
+
+ "hhvn.uk/hbspbar/config"
+ "hhvn.uk/hbspbar/status"
+ "hhvn.uk/hbspbar/bspc"
+ "hhvn.uk/hbspbar/drw"
+)
+
+var bars map[int]*bar = make(map[int]*bar)
+
+type bar struct {
+ id int
+ w *drw.Window
+ i *image.RGBA
+}
+
+var (
+ ErrNoState = errors.New("attempted to create a bar with uninitialized state")
+ ErrNoSuchBar = errors.New("attempted to destroy non-existant bar")
+)
+
+func (b *bar) init(id int, state *bspc.State) error {
+ b.id = id
+ b.i = nil
+
+ mon, err := b.getmon(state)
+ if err != nil { return err }
+
+ go mon.TopPadding(config.H)
+
+ geom := mon.Rectangle
+
+ b.w, err = drw.WindowCreate(geom.X, geom.Y, geom.Width, config.H)
+ if err != nil { return err }
+
+ rect := image.Rect(0, 0, int(mon.Rectangle.Width), int(config.H))
+ b.i = image.NewRGBA(rect)
+
+ return nil
+}
+
+func (b *bar) destroy(state *bspc.State) {
+ mon, _ := b.getmon(state)
+ if (mon != nil) {
+ mon.TopPadding(0)
+ }
+}
+
+func (b bar) getmon(state *bspc.State) (*bspc.Monitor, error) {
+ return state.GetMon(b.id)
+}
+
+func (b *bar) drawText(x int, col color.Color, text string) (int, error) {
+ return drw.DrawText(b.i, x, col, text)
+}
+
+func (b *bar) drawRect(x, y, w, h int, c color.Color, fill bool) {
+ drw.DrawRect(b.i, x, y, w, h, c, fill)
+}
+
+func (b bar) draw(state *bspc.State, blocks []*status.Block) error {
+ var bg color.Color
+ var filled bool
+
+ if blocks == nil {
+ return nil
+ }
+
+ mon, err := b.getmon(state)
+ if err != nil {
+ return err
+ }
+
+ // Dimensions of drawing space
+ cx := 0
+ w := int(mon.Rectangle.Width)
+ h := int(config.H)
+
+
+ // Draw background
+ b.drawRect(0, 0, w, h, config.Bg, true)
+
+ // Monitor
+ montext := mon.Name
+ monw := 6 + drw.TextWidth(montext) + 8
+
+ if mon.Focused {
+ bg = config.Sel
+ } else {
+ bg = config.UnselMon
+ }
+
+ b.drawRect(cx, 0, monw, h, bg, true)
+ b.drawText(cx + 6, config.Fg, montext)
+ cx += monw
+
+ // Desktops
+ boxw := 4
+ ds := len(mon.Desktops)
+ dw := 4 + (4 + boxw + 2 + 3) * ds + 5
+
+ for i := 0; i < ds; i++ {
+ dw += drw.TextWidth(mon.Desktops[i].Name)
+ }
+
+ cx += 4
+ for i := 0; i < ds; i++ {
+ d := mon.Desktops[i]
+
+ cx += 5
+
+ if d.Focused {
+ bg = config.Sel
+ } else {
+ bg = config.FgDark
+ }
+
+ filled = d.Root != nil
+
+ b.drawRect(cx, 3, boxw, h - 7, bg, filled)
+ cx += boxw + 2
+ ax, _ := b.drawText(cx, config.Fg, d.Name)
+ cx += ax + 2
+ }
+
+ cx = int(mon.Rectangle.Width)
+ for _, s := range blocks {
+ if s != nil {
+ cx -= s.W
+ cx -= config.StatusPad
+ }
+ }
+
+ b.drawRect(cx, 0, int(mon.Rectangle.Width) - cx, int(config.H),
+ config.Status, true)
+
+ cx += config.StatusPad / 2
+
+ for _, s := range blocks {
+ if s != nil {
+ drw.AddImg(b.i, cx, s.W, s.I)
+
+ cx += s.W + config.StatusPad
+ }
+ }
+
+ b.w.Paint(b.i)
+
+ return nil
+}
+
+func Create(state *bspc.State, id int) (error) {
+ var b bar
+
+ if state == nil {
+ return ErrNoState
+ }
+
+ if _, ok := bars[id]; ok {
+ // Already created, whatever.
+ return nil
+ }
+
+ if err := b.init(id, state); err != nil {
+ return err
+ }
+
+ bars[b.id] = &b
+ return nil
+}
+
+func Redraw(state *bspc.State, blocks []*status.Block) {
+ for _, b := range bars {
+ b.draw(state, blocks)
+ }
+}
+
+func Destroy(state *bspc.State, id int) error {
+ b, ok := bars[id]
+ if !ok {
+ return ErrNoSuchBar
+ }
+
+ b.destroy(state)
+ delete(bars, id)
+
+ return nil
+}
+
+func Cleanup(state *bspc.State) {
+ if state != nil {
+ for _, b := range bars {
+ b.destroy(finalstate)
+ }
+ }
+}
diff --git a/bar/bar.go b/bar/bar.go
@@ -1,241 +0,0 @@
-package bar // import "hhvn.uk/hbspbar/bar"
-
-import (
- "fmt"
- "image"
- "errors"
- "image/color"
-
- "hhvn.uk/hbspbar/config"
- "hhvn.uk/hbspbar/common"
- "hhvn.uk/hbspbar/status"
- "hhvn.uk/hbspbar/bspc"
- "hhvn.uk/hbspbar/drw"
-)
-
-
-var bars map[int]*bar
-
-type bar struct {
- id int
- w *drw.Window
- i *image.RGBA
-}
-
-func create(state *bspc.State, id int) (error) {
- var b bar
-
- if err := b.init(id, state); err != nil {
- return err
- }
-
- if bars == nil {
- bars = make(map[int]*bar)
- }
-
- bars[b.id] = &b
- return nil
-}
-
-func (b *bar) init(id int, state *bspc.State) error {
- b.id = id
- b.i = nil
-
- mon, err := b.getmon(state)
- if err != nil { return err }
-
- go mon.TopPadding(config.H)
-
- geom := mon.Rectangle
-
- b.w, err = drw.WindowCreate(geom.X, geom.Y, geom.Width, config.H)
- if err != nil { return err }
-
- rect := image.Rect(0, 0, int(mon.Rectangle.Width), int(config.H))
- b.i = image.NewRGBA(rect)
-
- return nil
-}
-
-func (b *bar) destroy(state *bspc.State) {
- mon, _ := b.getmon(state)
- if (mon != nil) {
- mon.TopPadding(0)
- }
-}
-
-func (b bar) getmon(state *bspc.State) (*bspc.Monitor, error) {
- return state.GetMon(b.id)
-}
-
-func (b *bar) drawText(x int, col color.Color, text string) (int, error) {
- return drw.DrawText(b.i, x, col, text)
-}
-
-func (b *bar) drawRect(x, y, w, h int, c color.Color, fill bool) {
- drw.DrawRect(b.i, x, y, w, h, c, fill)
-}
-
-func (b bar) draw(state *bspc.State, blocks []*status.Block) {
- var bg color.Color
- var filled bool
-
- if blocks == nil {
- return
- }
-
- mon, err := b.getmon(state)
- if err != nil {
- return
- }
-
- // Dimensions of drawing space
- cx := 0
- w := int(mon.Rectangle.Width)
- h := int(config.H)
-
-
- // Draw background
- b.drawRect(0, 0, w, h, config.Bg, true)
-
- // Monitor
- montext := mon.Name
- monw := 6 + drw.TextWidth(montext) + 8
-
- if mon.Focused {
- bg = config.Sel
- } else {
- bg = config.UnselMon
- }
-
- b.drawRect(cx, 0, monw, h, bg, true)
- b.drawText(cx + 6, config.Fg, montext)
- cx += monw
-
- // Desktops
- boxw := 4
- ds := len(mon.Desktops)
- dw := 4 + (4 + boxw + 2 + 3) * ds + 5
-
- for i := 0; i < ds; i++ {
- dw += drw.TextWidth(mon.Desktops[i].Name)
- }
-
- cx += 4
- for i := 0; i < ds; i++ {
- d := mon.Desktops[i]
-
- cx += 5
-
- if d.Focused {
- bg = config.Sel
- } else {
- bg = config.FgDark
- }
-
- filled = d.Root != nil
-
- b.drawRect(cx, 3, boxw, h - 7, bg, filled)
- cx += boxw + 2
- ax, _ := b.drawText(cx, config.Fg, d.Name)
- cx += ax + 2
- }
-
- cx = int(mon.Rectangle.Width)
- for _, s := range blocks {
- if s != nil {
- cx -= s.W
- cx -= config.StatusPad
- }
- }
-
- b.drawRect(cx, 0, int(mon.Rectangle.Width) - cx, int(config.H),
- config.Status, true)
-
- cx += config.StatusPad / 2
-
- for _, s := range blocks {
- if s != nil {
- drw.AddImg(b.i, cx, s.W, s.I)
-
- cx += s.W + config.StatusPad
- }
- }
-
- b.w.Paint(b.i)
-}
-
-var Create = make(chan int)
-var Destroy = make(chan int)
-var NewState = make(chan *bspc.State)
-var Err = make(chan error)
-
-// Store the state for when bar.Cleanup() is called
-// This is a bit hacky but I don't really see any alternative
-var finalstate *bspc.State = nil
-
-func init() {
- var state *bspc.State = nil
- var blocks []*status.Block = nil
-
- go func() {
- defer func() {
- close(Create)
- close(Destroy)
- close(NewState)
- close(Err)
- }()
-
- for {
- select {
- case e := <- drw.Events:
- if e.Ev == nil && e.Err == nil {
- Err <- fmt.Errorf("X connection clossed")
- return
- }
-
- if e.Err != nil {
- common.Perror("X.WaitForEvents", e.Err)
- continue
- }
-
- // switch e.Ev.(type) {
- // case xproto.DestroyNotifyEvent:
- // Err <- fmt.Errorf("Window destroyed")
- // return
- // default:
- // }
- case id := <- Destroy:
- bars[id].destroy(state)
- delete(bars, id)
- case id := <- Create:
- if state == nil {
- Err <- errors.New("attempted to create a bar with uninitialized state")
- return
- }
- if _, ok := bars[id]; ok { break }
- if err := create(state, id); err != nil {
- Err <- fmt.Errorf("Couldn't create window: %s\n", err)
- return
- }
- case blocks = <- status.NewBlocks:
- for _, b := range bars {
- b.draw(state, blocks)
- }
- case state = <- NewState:
- finalstate = state
- for _, b := range bars {
- b.draw(state, blocks)
- }
- }
- }
- }()
-}
-
-func Cleanup() {
- if finalstate != nil {
- for _, b := range bars {
- b.destroy(finalstate)
- }
- }
-}
diff --git a/main.go b/main.go
@@ -6,12 +6,16 @@ import (
"strings"
"syscall"
- "hhvn.uk/hbspbar/bar"
"hhvn.uk/hbspbar/bspc"
"hhvn.uk/hbspbar/common"
"hhvn.uk/hbspbar/drw"
+ "hhvn.uk/hbspbar/status"
)
+// Store the state for when bar.Cleanup() is called
+// This is a bit hacky but I don't really see any alternative
+var finalstate *bspc.State = nil
+
func main() {
signals := make(chan os.Signal, 1)
signal.Notify(signals,
@@ -19,8 +23,6 @@ func main() {
syscall.SIGHUP,
syscall.SIGTERM)
- defer bar.Cleanup()
-
if drw.InitErr != nil {
common.Error("Couldn't initialize X: %s\n", drw.InitErr)
return
@@ -33,22 +35,37 @@ func main() {
defer bspc.Cleanup()
state := <- bspc.NewState
- bar.NewState <- state
for _, m := range state.Monitors {
- bar.Create <- m.ID
+ Create(state, m.ID)
}
- for {
+ var blocks []*status.Block = nil
+
+ mainloop: for {
select {
case s := <-signals:
common.Error("%s\n", s)
- return
- case err := <-bar.Err:
- common.Error("%s\n", err)
- return
+ break mainloop
+ case e := <- drw.Events:
+ if e.Ev == nil && e.Err == nil {
+ common.Error("X connection clossed\n")
+ break mainloop
+ }
+
+ if e.Err != nil {
+ common.Perror("X.WaitForEvents", e.Err)
+ continue
+ }
+
+ // switch e.Ev.(type) {
+ // case xproto.DestroyNotifyEvent:
+ // Err <- fmt.Errorf("Window destroyed")
+ // return
+ // default:
+ // }
case err := <-bspc.EvErr:
common.Error("Couldn't read event: %s\n", err)
- return
+ break mainloop
case event := <-bspc.Event:
if strings.HasPrefix(event.Name, "monitor_") {
id, err := common.Intify(event.Tokens[0])
@@ -56,17 +73,22 @@ func main() {
switch event.Name {
case "monitor_add":
case "monitor_geometry":
- bar.Create <- id
+ Create(state, id)
case "monitor_remove":
- bar.Destroy <- id
+ Destroy(state, id)
}
}
}
case err := <-bspc.StErr:
common.Error("Couldn't load bspwm state: %s\n", err)
- return
- case s := <-bspc.NewState:
- bar.NewState <- s
+ break mainloop
+ case blocks = <- status.NewBlocks:
+ Redraw(state, blocks)
+ case state = <- bspc.NewState:
+ finalstate = state
+ Redraw(state, blocks)
}
}
+
+ Cleanup(finalstate)
}