hbspbar

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

commit 6117c8a98a39cd8bc1ca6b2436b6dab8873053f9
parent 2b7504f96fcb8878ac5ed089940868517a74da79
Author: hhvn <dev@hhvn.uk>
Date:   Sat, 18 Nov 2023 14:13:25 +0000

Draw to an image.RGBA

Diffstat:
Mbar/bar.go | 48++++++++++++++++++++++++------------------------
Adrw/drw.go | 44++++++++++++++++++++++++++++++++++++++++++++
Adrw/x.go | 68++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Mmain.go | 6+++---
Dx/x.go | 100-------------------------------------------------------------------------------
5 files changed, 139 insertions(+), 127 deletions(-)

diff --git a/bar/bar.go b/bar/bar.go @@ -9,7 +9,7 @@ import ( "hhvn.uk/hbspbar/config" "hhvn.uk/hbspbar/common" "hhvn.uk/hbspbar/bspc" - X "hhvn.uk/hbspbar/x" + "hhvn.uk/hbspbar/drw" "github.com/jezek/xgb" "github.com/jezek/xgb/xproto" @@ -27,7 +27,7 @@ var stoploop chan bool type bar struct { Mon *bspc.Monitor w xproto.Window - i *xgraphics.Image + i *image.RGBA drawing sync.Mutex } @@ -36,46 +36,45 @@ func (b *bar) init() error { go b.Mon.TopPadding(config.H) - b.w, err = xproto.NewWindowId(X.X) + b.w, err = xproto.NewWindowId(drw.X) if err != nil { return common.Perror("xproto.NewWindowId", err) } geom := b.Mon.Rectangle - xproto.CreateWindow(X.X, X.Screen.RootDepth, b.w, X.Screen.Root, + xproto.CreateWindow(drw.X, drw.Screen.RootDepth, b.w, drw.Screen.Root, int16(geom.X), int16(geom.Y), uint16(geom.Width), uint16(config.H), 0, - xproto.WindowClassInputOutput, X.Screen.RootVisual, + xproto.WindowClassInputOutput, drw.Screen.RootVisual, xproto.CwBackPixel|xproto.CwEventMask, []uint32{ config.Bg, xproto.EventMaskStructureNotify }) class := icccm.WmClass{"hbspbar", "hbspbar"} - icccm.WmClassSet(X.XU, b.w, &class) + icccm.WmClassSet(drw.XU, b.w, &class) - 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"}) + ewmh.WmWindowTypeSet(drw.XU, b.w, []string{"_NET_WM_WINDOW_TYPE_DOCK"}) + ewmh.WmStateSet(drw.XU, b.w, []string{"_NET_WM_STATE_STICKY", "_NET_WM_STATE_ABOVE"}) - err = xproto.MapWindowChecked(X.X, b.w).Check() + err = xproto.MapWindowChecked(drw.X, b.w).Check() if err != nil { return common.Perror("xproto.MapWindow", err) } - b.reInit() + b.i = image.NewRGBA(b.rect()) 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) rect() image.Rectangle { + return 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) + return drw.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) + drw.DrawRect(b.i, x, y, w, h, c, fill) } func (b *bar) draw() { @@ -83,7 +82,6 @@ func (b *bar) draw() { var filled bool b.drawing.Lock() - b.reInit() // Dimensions of drawing space cx := 0 @@ -96,7 +94,7 @@ func (b *bar) draw() { // Monitor montext := b.Mon.Name - monw := 6 + X.TextWidth(montext) + 8 + monw := 6 + drw.TextWidth(montext) + 8 if b.Mon.Focused { bg = config.Sel @@ -114,7 +112,7 @@ func (b *bar) draw() { dw := 4 + (4 + boxw + 2 + 3) * ds + 5 for i := 0; i < ds; i++ { - dw += X.TextWidth(b.Mon.Desktops[i].Name) + dw += drw.TextWidth(b.Mon.Desktops[i].Name) } cx += 4 @@ -138,9 +136,11 @@ func (b *bar) draw() { } cx += 5 - b.i.XSurfaceSet(b.w) - b.i.XDraw() - b.i.XPaint(b.w) + xgr := xgraphics.NewConvert(drw.XU, b.i) + + xgr.XSurfaceSet(b.w) + xgr.XDraw() + xgr.XPaint(b.w) b.drawing.Unlock() } @@ -149,7 +149,7 @@ func (b *bar) destroy() { if (b.Mon != nil) { b.Mon.TopPadding(0) } - xproto.DestroyWindow(X.X, b.w) + xproto.DestroyWindow(drw.X, b.w) } type eventwrap struct { @@ -181,7 +181,7 @@ func init() { xstop := make(chan bool, 1) go func() { for { - ev, err := X.X.WaitForEvent() + ev, err := drw.X.WaitForEvent() w := eventwrap{ev, err} select { @@ -229,7 +229,7 @@ func init() { return } if _, ok := bars[id]; ok { break } - if err := create(X.X, X.XU, X.Screen, state.GetMon(id)); err != nil { + if err := create(drw.X, drw.XU, drw.Screen, state.GetMon(id)); err != nil { Handle.Err <- fmt.Errorf("Couldn't create window: %s\n", err) return } diff --git a/drw/drw.go b/drw/drw.go @@ -0,0 +1,44 @@ +package drw // import "hhvn.uk/hbspbar/drw" + +import ( + "image" + + "hhvn.uk/hbspbar/config" + + "github.com/jezek/xgbutil/xgraphics" + "github.com/BurntSushi/freetype-go/freetype" +) + +func DrawText(i *image.RGBA, x int, col uint32, text string) (int, error) { + ft.SetClip(i.Bounds()) + ft.SetDst(i) + + src := image.NewUniform(int2rgb(col)) + ft.SetSrc(src) + + pt := freetype.Pt(x, config.FontYPad+ + int(ft.PointToFix32(config.FontSize)>>8)) + npt, err := ft.DrawString(text, pt) + + return int(npt.X / 256) - x, err +} + +func TextWidth(text string) (int) { + w, _ := xgraphics.Extents(font, config.FontSize, text) + return w +} + +func DrawRect(i *image.RGBA, x, y, w, h int, c uint32, fill bool) { + col := int2rgb(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) + } + } + } +} diff --git a/drw/x.go b/drw/x.go @@ -0,0 +1,68 @@ +package drw // import "hhvn.uk/hbspbar/drw" + +import ( + "os" + "image/color" + + "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" + "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 ft *freetype.Context + +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 + } + + ft = freetype.NewContext() + ft.SetDPI(72) + ft.SetFont(font) + ft.SetFontSize(config.FontSize) +} + +func int2rgb(argb uint32) (color.RGBA) { + return color.RGBA{ + B: uint8( argb & 0x000000ff), + G: uint8((argb & 0x0000ff00) >> 8), + R: uint8((argb & 0x00ff0000) >> 16), + A: uint8((argb & 0xff000000) >> 24) } +} diff --git a/main.go b/main.go @@ -7,7 +7,7 @@ import ( "os/signal" "hhvn.uk/hbspbar/common" - "hhvn.uk/hbspbar/x" + "hhvn.uk/hbspbar/drw" "hhvn.uk/hbspbar/bar" "hhvn.uk/hbspbar/bspc" ) @@ -21,8 +21,8 @@ func main() { defer bar.Cleanup() - if x.InitErr != nil { - common.Error("Couldn't initialize X: %s\n", x.InitErr) + if drw.InitErr != nil { + common.Error("Couldn't initialize X: %s\n", drw.InitErr) return } diff --git a/x/x.go b/x/x.go @@ -1,100 +0,0 @@ -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) - } - } - } -}