hbspbar

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

commit bc9ea1846fb9b64479190b878a14498bb692c192
parent 2a8069eb9606af55f76ac43e187ca83a7dd6957f
Author: hhvn <dev@hhvn.uk>
Date:   Thu, 16 Nov 2023 20:45:11 +0000

Create x package

Diffstat:
Mbar/bar.go | 127++++++++++++++++++++++++++-----------------------------------------------------
Dbar/x.go | 79-------------------------------------------------------------------------------
Mmain.go | 10++++++----
Ax/x.go | 100+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
4 files changed, 148 insertions(+), 168 deletions(-)

diff --git a/bar/bar.go b/bar/bar.go @@ -3,10 +3,13 @@ package bar // import "hhvn.uk/hbspbar/bar" import ( "fmt" "sync" + "image" "errors" + "hhvn.uk/hbspbar/config" "hhvn.uk/hbspbar/common" "hhvn.uk/hbspbar/bspc" + X "hhvn.uk/hbspbar/x" "github.com/jezek/xgb" "github.com/jezek/xgb/xproto" @@ -15,113 +18,94 @@ import ( "github.com/jezek/xgbutil/icccm" "github.com/jezek/xgbutil/ewmh" "github.com/jezek/xgbutil/xgraphics" - - "github.com/BurntSushi/freetype-go/freetype/truetype" ) -var conf = struct { - H uint - Bg uint32 - Bg2 uint32 - Bg3 uint32 - Fg uint32 - FgDark uint32 - Sel uint32 - Urg uint32 - Font string - FontSize float64 - FontYPad int -} { 17, - 0xff050a10, - 0xff0c1726, - 0xff14283c, - 0xffeeeeee, - 0xff444444, - 0xff1b364b, - 0xff90222b, - "/usr/share/fonts/TTF/DejaVuSansMono.ttf", - 11.0, 1 } var bars map[int]*bar -var font *truetype.Font var stoploop chan bool type bar struct { - X *xgb.Conn - Xu *xgbutil.XUtil - Scr *xproto.ScreenInfo Mon *bspc.Monitor w xproto.Window i *xgraphics.Image - tw, th int - tbpad int drawing sync.Mutex } func (b *bar) init() error { var err error - go b.Mon.TopPadding(conf.H) + go b.Mon.TopPadding(config.H) - b.w, err = xproto.NewWindowId(b.X) + b.w, err = xproto.NewWindowId(X.X) if err != nil { return common.Perror("xproto.NewWindowId", err) } geom := b.Mon.Rectangle - xproto.CreateWindow(b.X, b.Scr.RootDepth, b.w, b.Scr.Root, - int16(geom.X), int16(geom.Y), uint16(geom.Width), uint16(conf.H), 0, - xproto.WindowClassInputOutput, b.Scr.RootVisual, + xproto.CreateWindow(X.X, X.Screen.RootDepth, b.w, X.Screen.Root, + int16(geom.X), int16(geom.Y), uint16(geom.Width), uint16(config.H), 0, + xproto.WindowClassInputOutput, X.Screen.RootVisual, xproto.CwBackPixel|xproto.CwEventMask, []uint32{ - conf.Bg, + config.Bg, xproto.EventMaskStructureNotify }) class := icccm.WmClass{"hbspbar", "hbspbar"} - icccm.WmClassSet(b.Xu, b.w, &class) + icccm.WmClassSet(X.XU, b.w, &class) - ewmh.WmWindowTypeSet(b.Xu, b.w, []string{"_NET_WM_WINDOW_TYPE_DOCK"}) - ewmh.WmStateSet(b.Xu, b.w, []string{"_NET_WM_STATE_STICKY", "_NET_WM_STATE_ABOVE"}) + ewmh.WmWindowTypeSet(X.XU, b.w, []string{"_NET_WM_WINDOW_TYPE_DOCK"}) + ewmh.WmStateSet(X.XU, b.w, []string{"_NET_WM_STATE_STICKY", "_NET_WM_STATE_ABOVE"}) - err = xproto.MapWindowChecked(b.X, b.w).Check() + err = xproto.MapWindowChecked(X.X, b.w).Check() if err != nil { return common.Perror("xproto.MapWindow", err) } - b.drawReInit() - b.tw, b.th, _ = b.i.Text(0, 0, int2BGRA(conf.Fg), conf.FontSize, font, "X") - b.tbpad = (int(conf.H) - b.th) / 2 + b.reInit() return nil } +func (b *bar) reInit() { + X.GraphicReInit(&b.i, image.Rect(0, 0, + int(b.Mon.Rectangle.Width), int(config.H))) +} + +func (b *bar) drawText(x int, col uint32, text string) (int, error) { + return X.DrawText(b.i, x, col, text) +} + +func (b *bar) drawRect(x, y, w, h int, c uint32, fill bool) { + X.DrawRect(b.i, x, y, w, h, c, fill) +} + func (b *bar) draw() { var bg uint32 var filled bool b.drawing.Lock() - b.drawReInit() + b.reInit() // Dimensions of drawing space cx := 0 w := int(b.Mon.Rectangle.Width) - h := int(conf.H) + h := int(config.H) // Draw background - b.drawRect(0, 0, w, h, conf.Bg, true) + b.drawRect(0, 0, w, h, config.Bg, true) // Monitor montext := b.Mon.Name - monw := 6 + b.textWidth(montext) + 8 + monw := 6 + X.TextWidth(montext) + 8 if b.Mon.Focused { - bg = conf.Sel + bg = config.Sel } else { - bg = conf.Bg2 + bg = config.Bg2 } b.drawRect(cx, 0, monw, h, bg, true) - b.drawText(cx + 6, conf.Fg, montext) + b.drawText(cx + 6, config.Fg, montext) cx += monw // Desktops @@ -130,7 +114,7 @@ func (b *bar) draw() { dw := 4 + (4 + boxw + 2 + 3) * ds + 5 for i := 0; i < ds; i++ { - dw += b.textWidth(b.Mon.Desktops[i].Name) + dw += X.TextWidth(b.Mon.Desktops[i].Name) } cx += 4 @@ -140,16 +124,16 @@ func (b *bar) draw() { cx += 5 if d.Focused { - bg = conf.Sel + bg = config.Sel } else { - bg = conf.FgDark + bg = config.FgDark } filled = d.Root != nil b.drawRect(cx, 3, boxw, h - 7, bg, filled) cx += boxw + 2 - ax, _ := b.drawText(cx, conf.Fg, d.Name) + ax, _ := b.drawText(cx, config.Fg, d.Name) cx += ax + 2 } cx += 5 @@ -165,7 +149,7 @@ func (b *bar) destroy() { if (b.Mon != nil) { b.Mon.TopPadding(0) } - xproto.DestroyWindow(b.X, b.w) + xproto.DestroyWindow(X.X, b.w) } type eventwrap struct { @@ -181,33 +165,9 @@ type handle struct { Err chan error } -var InitErr error var Handle handle func init() { - InitErr = nil - - x, err := xgb.NewConn() - if err != nil { - InitErr = err - return - } - - xu, err := xgbutil.NewConnXgb(x) - if err != nil { - InitErr = err - return - } - - font, err = getFont(conf.Font) - if err != nil { - InitErr = err - return - } - - setup := xproto.Setup(x) - screen := setup.DefaultScreen(x) - var state *bspc.State state = nil @@ -221,7 +181,7 @@ func init() { xstop := make(chan bool, 1) go func() { for { - ev, err := x.WaitForEvent() + ev, err := X.X.WaitForEvent() w := eventwrap{ev, err} select { @@ -250,7 +210,7 @@ func init() { } if e.Err != nil { - common.Perror("x.WaitForEvents", err) + common.Perror("X.WaitForEvents", e.Err) continue } @@ -269,7 +229,7 @@ func init() { return } if _, ok := bars[id]; ok { break } - if err := create(x, xu, screen, state.GetMon(id)); err != nil { + if err := create(X.X, X.XU, X.Screen, state.GetMon(id)); err != nil { Handle.Err <- fmt.Errorf("Couldn't create window: %s\n", err) return } @@ -291,9 +251,6 @@ func create(x *xgb.Conn, xu *xgbutil.XUtil, scr *xproto.ScreenInfo, m *bspc.Monitor) (error) { var b bar - b.X = x - b.Xu = xu - b.Scr = scr b.Mon = m b.i = nil diff --git a/bar/x.go b/bar/x.go @@ -1,79 +0,0 @@ -package bar // import "hhvn.uk/hbspbar/bar" - -import ( - "os" - "image" - - "hhvn.uk/hbspbar/common" - - "github.com/jezek/xgbutil/xgraphics" - "github.com/BurntSushi/freetype-go/freetype/truetype" -) - -func getFont(path string) (*truetype.Font, error) { - read, err := os.Open(path) - if err != nil { - return nil, common.Perror("os.Open", err) - } - - font, err := xgraphics.ParseFont(read) - if err != nil { - return nil, common.Perror("xgraphics.ParseFont", err) - } - - return font, nil -} - -func int2BGRA(argb uint32) (xgraphics.BGRA) { - return xgraphics.BGRA{ - B: uint8( argb & 0x000000ff), - G: uint8((argb & 0x0000ff00) >> 8), - R: uint8((argb & 0x00ff0000) >> 16), - A: uint8((argb & 0xff000000) >> 24) } -} - -func (b *bar) rect() image.Rectangle { - return image.Rect( 0, 0, - int(b.Mon.Rectangle.Width), int(conf.H)) -} - -func (b *bar) drawReInit() { - if b.i != nil { - b.i.Destroy() - } - - b.i = xgraphics.New(b.Xu, b.rect()) -} - -func (b *bar) drawText(x int, col uint32, text string) (int, error) { - nx, _, err := b.i.Text(x, conf.FontYPad, - int2BGRA(col), conf.FontSize, font, text) - return nx - x, err -} - -func (b *bar) textWidth(str string) int { - return len(str) * b.tw -} - -func pointInRect(px, py, x, y, w, h int) bool { - if px >= x && px <= x + w && py >= x && py <= y + h { - return true - } else { - return false - } -} - -func (b *bar) drawRect(x, y, w, h int, c uint32, fill bool) { - col := int2BGRA(c) - - var ix, iy int - - for ix = x; ix < x + w; ix++ { - for iy = y; iy < y + h; iy++ { - if fill || ix == x || ix == x + w - 1 || - iy == y || iy == y + h - 1 { - b.i.Set(ix, iy, col) - } - } - } -} diff --git a/main.go b/main.go @@ -7,8 +7,9 @@ import ( "os/signal" "hhvn.uk/hbspbar/common" - "hhvn.uk/hbspbar/bspc" + "hhvn.uk/hbspbar/x" "hhvn.uk/hbspbar/bar" + "hhvn.uk/hbspbar/bspc" ) func main() { @@ -18,11 +19,12 @@ func main() { syscall.SIGHUP, syscall.SIGTERM) - if bar.InitErr != nil { - common.Error("Couldn't initialize X: %s\n", bar.InitErr) + defer bar.Cleanup() + + if x.InitErr != nil { + common.Error("Couldn't initialize X: %s\n", x.InitErr) return } - defer bar.Cleanup() if bspc.InitErr != nil { common.Error("Couldn't subscribe to bspwm: %s\n", bspc.InitErr) diff --git a/x/x.go b/x/x.go @@ -0,0 +1,100 @@ +package x // import "hhvn.uk/hbspbar/x" + +import ( + "os" + "image" + + "hhvn.uk/hbspbar/config" + "hhvn.uk/hbspbar/common" + + "github.com/jezek/xgb" + "github.com/jezek/xgb/xproto" + "github.com/jezek/xgbutil" + "github.com/jezek/xgbutil/xgraphics" + "github.com/BurntSushi/freetype-go/freetype/truetype" +) + +var InitErr error +var X *xgb.Conn +var XU *xgbutil.XUtil +var Screen *xproto.ScreenInfo + +var font *truetype.Font +var tw, th int +var tbpad int + +func init() { + var err error + + X, err = xgb.NewConn() + if err != nil { + InitErr = err + return + } + + XU, err = xgbutil.NewConnXgb(X) + if err != nil { + InitErr = err + return + } + + setup := xproto.Setup(X) + Screen = setup.DefaultScreen(X) + + read, err := os.Open(config.Font) + if err != nil { + InitErr = common.Perror("os.Open", err) + return + } + + font, err = xgraphics.ParseFont(read) + if err != nil { + InitErr = common.Perror("xgraphics.ParseFont", err) + return + } + + test := xgraphics.New(XU, image.Rect(0, 0, int(config.FontSize * 10), int(config.FontSize * 10))) + tw, th, _ = test.Text(0, 0, int2BGRA(config.Fg), config.FontSize, font, "X") + tbpad = (int(config.H) - th) / 2 +} + +func int2BGRA(argb uint32) (xgraphics.BGRA) { + return xgraphics.BGRA{ + B: uint8( argb & 0x000000ff), + G: uint8((argb & 0x0000ff00) >> 8), + R: uint8((argb & 0x00ff0000) >> 16), + A: uint8((argb & 0xff000000) >> 24) } +} + +func GraphicReInit(i **xgraphics.Image, r image.Rectangle) { + if *i != nil { + (*i).Destroy() + } + + *i = xgraphics.New(XU, r) +} + +func DrawText(i *xgraphics.Image, x int, col uint32, text string) (int, error) { + nx, _, err := i.Text(x, config.FontYPad, + int2BGRA(col), config.FontSize, font, text) + return nx - x, err +} + +func TextWidth(text string) (int) { + return tw * len(text) +} + +func DrawRect(i *xgraphics.Image, x, y, w, h int, c uint32, fill bool) { + col := int2BGRA(c) + + var ix, iy int + + for ix = x; ix < x + w; ix++ { + for iy = y; iy < y + h; iy++ { + if fill || ix == x || ix == x + w - 1 || + iy == y || iy == y + h - 1 { + i.Set(ix, iy, col) + } + } + } +}