commit 19781aeb974bd20c421a6b4677ffab348df8faf9
parent 505685c6d546cab46f919f6b5296ca73b80d09b2
Author: hhvn <dev@hhvn.uk>
Date: Sat, 18 Nov 2023 19:50:26 +0000
Statuses
Diffstat:
6 files changed, 252 insertions(+), 10 deletions(-)
diff --git a/bar/bar.go b/bar/bar.go
@@ -8,6 +8,7 @@ import (
"hhvn.uk/hbspbar/config"
"hhvn.uk/hbspbar/common"
+ "hhvn.uk/hbspbar/status"
"hhvn.uk/hbspbar/bspc"
"hhvn.uk/hbspbar/drw"
)
@@ -71,7 +72,7 @@ func (b *bar) draw() {
if b.Mon.Focused {
bg = config.Sel
} else {
- bg = config.Bg2
+ bg = config.UnselMon
}
b.drawRect(cx, 0, monw, h, bg, true)
@@ -106,7 +107,34 @@ func (b *bar) draw() {
ax, _ := b.drawText(cx, config.Fg, d.Name)
cx += ax + 2
}
- cx += 5
+
+ status.Mutex.Lock()
+ cx = int(b.Mon.Rectangle.Width) - 6
+ for i := len(status.Status) - 1; i >= 0; i -= 1 {
+ s, ok := status.Status[i]
+ if ok {
+ cx -= s.W
+ cx -= config.StatusPad
+ }
+ }
+ cx += config.StatusPad
+ cx -= 6
+
+ b.drawRect(cx, 0, int(b.Mon.Rectangle.Width) - cx, int(config.H),
+ config.Status, true)
+
+ cx = int(b.Mon.Rectangle.Width) - 6
+ for i := len(status.Status) - 1; i >= 0; i -= 1 {
+ s, ok := status.Status[i]
+ if ok {
+ cx -= s.W
+
+ drw.AddImg(b.i, cx, s.W, s.I)
+
+ cx -= config.StatusPad
+ }
+ }
+ status.Mutex.Unlock()
b.w.Paint(b.i)
@@ -178,6 +206,10 @@ func init() {
Handle.Err <- fmt.Errorf("Couldn't create window: %s\n", err)
return
}
+ case <- status.Updated:
+ for _, b := range bars {
+ go b.draw()
+ }
case state = <- Handle.NewState:
for _, b := range bars {
b.Mon = state.GetMon(b.Mon.ID)
diff --git a/config/config.go b/config/config.go
@@ -5,7 +5,8 @@ var H uint = 17
// Colours
var Bg uint32 = 0xff050a10
-var Bg2 uint32 = 0xff0c1726
+var UnselMon uint32 = 0xff0c1726
+var Status uint32 = 0xff0a2126
var Fg uint32 = 0xffeeeeee
var FgDark uint32 = 0xff444444
var Sel uint32 = 0xff1b364b
diff --git a/drw/drw.go b/drw/drw.go
@@ -2,6 +2,7 @@ package drw // import "hhvn.uk/hbspbar/drw"
import (
"image"
+ "image/draw"
"hhvn.uk/hbspbar/config"
@@ -10,6 +11,10 @@ import (
)
func DrawText(i *image.RGBA, x int, col uint32, text string) (int, error) {
+ ft := freetype.NewContext()
+ ft.SetDPI(72)
+ ft.SetFont(font)
+ ft.SetFontSize(config.FontSize)
ft.SetClip(i.Bounds())
ft.SetDst(i)
@@ -42,3 +47,8 @@ func DrawRect(i *image.RGBA, x, y, w, h int, c uint32, fill bool) {
}
}
}
+
+func AddImg(dst *image.RGBA, x, w int, src *image.RGBA) {
+ r := image.Rect(x, 0, x + w, int(config.H))
+ draw.Draw(dst, r, src, image.Pt(0,0), draw.Src)
+}
diff --git a/drw/x.go b/drw/x.go
@@ -14,7 +14,6 @@ import (
"github.com/jezek/xgbutil/icccm"
"github.com/jezek/xgbutil/ewmh"
"github.com/jezek/xgbutil/xgraphics"
- "github.com/BurntSushi/freetype-go/freetype"
"github.com/BurntSushi/freetype-go/freetype/truetype"
)
@@ -30,7 +29,6 @@ var xc *xgb.Conn
var xu *xgbutil.XUtil
var screen *xproto.ScreenInfo
var font *truetype.Font
-var ft *freetype.Context
func init() {
var err error
@@ -62,11 +60,6 @@ func init() {
return
}
- ft = freetype.NewContext()
- ft.SetDPI(72)
- ft.SetFont(font)
- ft.SetFontSize(config.FontSize)
-
Events := make(chan *eventwrap)
go func() { for {
diff --git a/status/00-status.go b/status/00-status.go
@@ -0,0 +1,97 @@
+package status // import "hhvn.uk/hbspbar/status"
+
+import (
+ "time"
+ "sync"
+ "image"
+
+ "hhvn.uk/hbspbar/config"
+ "hhvn.uk/hbspbar/drw"
+)
+
+var Status map[int]*status
+var Mutex sync.Mutex
+var statusid map[string]int
+var Updated chan bool
+var updates chan *status
+
+const (
+ Red = 0xffaa2222
+ Orange = 0xffaa7700
+ Green = 0xff00aa00
+ Black = 0xff000000
+ Grey = 0xff888888
+ Yellow = 0xffaaaa00
+ White = 0xffcccccc
+)
+
+func init() {
+ Status = make(map[int]*status)
+ statusid = make(map[string]int)
+ Updated = make(chan bool)
+ updates = make(chan *status)
+
+ go func() {
+ for {
+ s := <- updates
+
+ id := statusid[s.Name]
+
+ Mutex.Lock()
+ Status[id] = s
+ Mutex.Unlock()
+
+ Updated <- true
+ }
+ }()
+}
+
+func register(name string) {
+ nid := 0
+ for _, id := range statusid {
+ if id >= nid {
+ nid = id + 1
+ }
+ }
+ statusid[name] = nid
+}
+
+type status struct {
+ Name string
+ I *image.RGBA
+ W int
+}
+
+func newUpdate(name string) (*status) {
+ var s status
+
+ s.Name = name
+ s.W = 0
+ s.I = image.NewRGBA(image.Rect(0, 0, 1000, int(config.H)))
+
+ // Use drw's in order not to modify s.W
+ drw.DrawRect(s.I, 0, 0, 1000, int(config.H), config.Status, true)
+
+ return &s
+}
+
+func sleep(s int) {
+ time.Sleep(time.Duration(s) * time.Second)
+}
+
+func (s *status) furthest(x int) {
+ if x > s.W {
+ s.W = x
+ }
+}
+
+func (s *status) drawText(x int, col uint32, text string) (int, error) {
+ w, err := drw.DrawText(s.I, x, col, text)
+ s.furthest(x + w)
+ return w, err
+}
+
+func (s *status) drawRect(x, y, w, h int, c uint32, fill bool) {
+ drw.DrawRect(s.I, x, y, w, h, c, fill)
+ s.furthest(x + w)
+}
diff --git a/status/01-bat.go b/status/01-bat.go
@@ -0,0 +1,109 @@
+package status // import "hhvn.uk/hbspbar/status"
+
+import (
+ "os"
+ "io"
+ "path"
+ "strings"
+
+ // "hhvn.uk/hbspbar/drw"
+ "hhvn.uk/hbspbar/config"
+ "hhvn.uk/hbspbar/common"
+)
+
+func read(file string) (string, error) {
+ f, err := os.Open(file)
+ if err != nil { return "", err }
+
+ content, err := io.ReadAll(f)
+ if err != nil { return "", err }
+
+ str := strings.TrimSuffix(string(content), "\n")
+
+ return str, nil
+}
+
+func init() {
+ name := "bat"
+ register(name)
+
+ dir := "/sys/class/power_supply"
+
+ const (
+ nothing = iota
+ charging
+ discharging
+ )
+
+ go func(){
+ for {
+ u := newUpdate(name)
+
+ dirs, _ := os.ReadDir(dir)
+ if dirs == nil { return }
+
+ totalcap := 0
+ usedcap := 0
+
+ stati := nothing
+
+ for _, d := range dirs {
+ if !strings.HasPrefix(d.Name(), "BAT") { continue }
+
+ caps, err := read(path.Join(dir, d.Name(), "capacity"))
+ if err != nil { return }
+
+ capi, err := common.Intify(caps)
+ if err != nil { return }
+
+ totalcap += 100
+ usedcap += capi
+
+ stats, err := read(path.Join(dir, d.Name(), "status"))
+ if err != nil { return }
+
+ // Doesn't deal with 1 battery charging, and another discharging but w/e
+ switch stats {
+ case "Charging": if charging > stati { stati = charging }
+ case "Discharging": if discharging > stati { stati = discharging}
+ }
+ }
+
+ if totalcap == 0 { return }
+
+ avgcap := (usedcap * 100) / totalcap
+
+ var c uint32
+
+ // Colour of outline = charge indicator
+ switch stati {
+ case nothing: c = config.Fg
+ case charging: c = Green
+ case discharging: c = Red
+ }
+
+ var iw int = 20
+ var ih int = int(config.H) - 8
+ var w int = iw * avgcap / 100
+
+ // Draw nose
+ u.drawRect(2, int((config.H - 5) / 2), 2, 5, c, true)
+
+ // Draw border
+ u.drawRect(4, 3, iw + 2, ih + 2, c, false)
+
+ switch {
+ case avgcap < 25: c = Red
+ case avgcap >= 99: c = Green
+ default: c = config.FgDark
+ }
+
+ // Fill
+ u.drawRect(4 + iw - w, 4, w + 1, ih, c, true)
+
+ updates <- u
+ sleep(1)
+ }
+
+ }()
+}