diff --git a/README.md b/README.md index 16c12fe..3298648 100644 --- a/README.md +++ b/README.md @@ -1,12 +1,85 @@ [![Go Report Card](https://goreportcard.com/badge/github.com/onodera-punpun/melonbar)](https://goreportcard.com/report/github.com/onodera-punpun/melonbar) -melonbar - A Concurrent, hackable bar/panel for X written in Go. +melonbar - A concurrent, hackable bar/panel for X written in Go. ## INSTALLATION `go get github.com/onodera-punpun/melonbar` +`melonbar` depends on Go 1.9 or newer. + + +## USAGE + +So the idea is that this bar is very "easy" to configure by just +modifying the source code, à la suckless. + +Users can modify, configure and create new "blocks" in `blocks.go`. +and configure the position, width and font of the bar in `main.go`. + + +## CREATING A BLOCK FUNCTIONS + +On top of each block function you should run `bar.initBlock()`, this +is where most of the configuration happens. Here is a short +explanation of each parameter from left to right: + +* The name of the block, this is and gets used as the name + of the block map key. (`string`) +* The initial string the block should display. (`string`) +* The width of the block. (`int`) +* The aligment of the text, this can be `'l'` for left aligment, `'c'` + for center aligment and `'r'` for right aligment. (`rune`) +* Additional x offset to further tweak the location of the text. + (`int`) +* The foreground color of the block in hexadecimal. (`string`) +* The background color of the block in hexadecimal. (`string`) + + +--- + +Everything that should not be ran in a loop should of course be +specified before the `for` loop. For example setting up a connection +to mpd. + +If you want something to only be done *after* the very first loop - an +example of this would be not waiting for a workspace chance event, but +immediately checking the current workspace. - use: + +```go +init := true +for { + if !init { + // Things you only want to do after the first loop. + } + init = false + ... +``` + +This can be helpful because else the bar would display `"?"` before +the user changes his workspace for the first time. + + +--- + +When you've gathered all needed information you can: + +* Update the foreground color of the block using + `bar.updateBlockFg()`. This function takes two parameters, the first + one being the block map key, and the second one the new string the + new foreground color of the block, in hexadecimal. +* Update the background color of the block using + `bar.updateBlockBg()`. This function takes the same parameters as + `bar.updateBlockFg()`. +* Update the text of the block using `bar.updateBlockTxt()`. Again, + this function takes two parameters, the second one being the new + string the block should display. + +Agter having ran the required `updateBlock*` functions you must run +`bar.redraw <- "blockname"`, where blockname is the name of the block +map key. + ## AUTHORS diff --git a/bar.go b/bar.go index 9e9d896..582f43d 100644 --- a/bar.go +++ b/bar.go @@ -2,7 +2,6 @@ package main import ( "image" - "log" "os" "sync" "time" @@ -17,13 +16,6 @@ import ( // Bar is a struct with information about the bar. type Bar struct { - // The width and height of the bar. - w, h int - - // This is a sum of all of the block widths, used to draw a block - // to the right of the last block. - xsum int - // Connection to the X server, the abe window, and the bar image. xu *xgbutil.XUtil win *xwindow.Window @@ -33,6 +25,13 @@ type Bar struct { font *truetype.Font fontSize float64 + // The width and height of the bar. + w, h int + + // This is a sum of all of the block widths, used to draw a block + // to the right of the last block. + xsum int + // A map with information about the block, see `Block`. block *sync.Map @@ -49,10 +48,13 @@ type Block struct { // The x coordinate and width of the bar. x, w int - // How to align the text, 'l' for left, 'c' for center and 'r' for - // right. + /// The aligment of the text, this can be `'l'` for left aligment, + // `'c'` for center aligment and `'r'` for right aligment. align rune + // Additional x offset to further tweak the location of the text. + xoff int + // The foreground and background colors. bg, fg xgraphics.BGRA @@ -65,9 +67,6 @@ func initBar(x, y, w, h int, font string, fontSize float64) (*Bar, bar := new(Bar) var err error - bar.w = w - bar.h = h - // Connect to X. bar.xu, err = xgbutil.NewConn() if err != nil { @@ -107,15 +106,18 @@ func initBar(x, y, w, h int, font string, fontSize float64) (*Bar, } bar.fontSize = fontSize + bar.w = w + bar.h = h + bar.block = new(sync.Map) bar.redraw = make(chan string) return bar, nil } -func (bar *Bar) initBlock(name string, width int, align rune, txt, bg, - fg string) { - bar.block.Store(name, &Block{txt, bar.xsum, width, align, +func (bar *Bar) initBlock(name, txt string, width int, align rune, + xoff int, bg, fg string) { + bar.block.Store(name, &Block{txt, bar.xsum, width, align, xoff, hexToBGRA(bg), hexToBGRA(fg), bar.img.SubImage(image.Rect( bar.xsum, 0, bar.xsum+width, bar.h)).(*xgraphics.Image)}) bar.xsum += width @@ -142,9 +144,9 @@ func (bar *Bar) updateBlockTxt(name, txt string) { block.txt = txt } -func (bar *Bar) draw(name string) { - // Needed to prevent a `interface conversion: interface {} is nil, - // not *main.Block` panic for some reason... +func (bar *Bar) draw(name string) error { + // Needed to prevent an `interface conversion: interface {} is + // nil, not *main.Block` panic for some reason... time.Sleep(time.Nanosecond) i, _ := bar.block.Load(name) @@ -155,27 +157,29 @@ func (bar *Bar) draw(name string) { return block.bg }) - // Calculate the required x for the different aligments. + // Calculate the required x coordinate for the different + // aligments. var x int switch block.align { case 'l': - x = block.x + x = block.x + block.xoff case 'c': tw, _ := xgraphics.Extents(bar.font, bar.fontSize, block.txt) - x = block.x + ((block.w / 2) - (tw / 2)) + x = block.x + ((block.w / 2) - (tw / 2)) + block.xoff case 'r': tw, _ := xgraphics.Extents(bar.font, bar.fontSize, block.txt) - x = (block.x + block.w) - tw + x = (block.x + block.w) - tw + block.xoff } // TODO: Center vertically automatically. // Draw the text. if _, _, err := block.img.Text(x, 6, block.fg, bar.fontSize, bar.font, block.txt); err != nil { - log.Fatal(err) + return err } block.img.XDraw() + return nil } func (bar *Bar) paint() { diff --git a/blocks.go b/blocks.go index 3234831..edf7be7 100644 --- a/blocks.go +++ b/blocks.go @@ -15,8 +15,8 @@ import ( "github.com/fsnotify/fsnotify" ) -func (bar *Bar) clockFun(width int, bg, fg string) { - bar.initBlock("clock", width, 'c', "?", bg, fg) +func (bar *Bar) clockFun() { + bar.initBlock("clock", "?", 800, 'c', 300, "#445967", "#CCCCCC") init := true for { @@ -33,8 +33,8 @@ func (bar *Bar) clockFun(width int, bg, fg string) { } } -func (bar *Bar) musicFun(width int, bg, fg string) { - bar.initBlock("music", width, 'r', "?", bg, fg) +func (bar *Bar) musicFun() error { + bar.initBlock("music", "?", 660, 'r', -10, "#3C4F5B", "#CCCCCC") watcher, err := mpd.NewWatcher("tcp", ":6600", "", "player") if err != nil { @@ -82,8 +82,8 @@ func (bar *Bar) musicFun(width int, bg, fg string) { } } -func (bar *Bar) todoFun(width int, bg, fg string) { - bar.initBlock("todo", width, 'c', "?", bg, fg) +func (bar *Bar) todoFun() { + bar.initBlock("todo", "?", 29, 'c', 0, "#5394C9", "#FFFFFF") watcher, err := fsnotify.NewWatcher() if err != nil { @@ -123,8 +123,8 @@ func (bar *Bar) todoFun(width int, bg, fg string) { } } -func (bar *Bar) weatherFun(width int, bg, fg string) { - bar.initBlock("weather", width, 'r', "?", bg, fg) +func (bar *Bar) weatherFun() { + bar.initBlock("weather", "?", 29, 'r', 0, "#5394C9", "#FFFFFF") w, err := owm.NewCurrent("C", "en") if err != nil { @@ -173,8 +173,8 @@ func (bar *Bar) weatherFun(width int, bg, fg string) { } } -func (bar *Bar) windowFun(width int, bg, fg string) { - bar.initBlock("window", width, 'c', "?", bg, fg) +func (bar *Bar) windowFun() { + bar.initBlock("window", "?", 220, 'c', 0, "#37BF8D", "#FFFFFF") init := true var Owin string @@ -218,11 +218,10 @@ func (bar *Bar) windowFun(width int, bg, fg string) { } } -func (bar *Bar) workspaceFun(widthWWW, widthIRC, widthSRC int, bgi, - bga, fg string) { - bar.initBlock("workspaceWWW", widthWWW, 'c', "www", bgi, fg) - bar.initBlock("workspaceIRC", widthIRC, 'c', "irc", bgi, fg) - bar.initBlock("workspaceSRC", widthSRC, 'c', "src", bgi, fg) +func (bar *Bar) workspaceFun() { + bar.initBlock("www", "www", 74, 'c', 0, "#5394C9", "#FFFFFF") + bar.initBlock("irc", "irc", 67, 'c', 0, "#5394C9", "#FFFFFF") + bar.initBlock("src", "src", 70, 'c', 0, "#5394C9", "#FFFFFF") init := true var Owsp uint @@ -258,20 +257,20 @@ func (bar *Bar) workspaceFun(widthWWW, widthIRC, widthSRC int, bgi, switch wsp { case 0: - bar.updateBlockBg("workspaceWWW", bga) - bar.updateBlockBg("workspaceIRC", bgi) - bar.updateBlockBg("workspaceSRC", bgi) + bar.updateBlockBg("www", "#72A7D3") + bar.updateBlockBg("irc", "#5394C9") + bar.updateBlockBg("src", "#5394C9") case 1: - bar.updateBlockBg("workspaceWWW", bgi) - bar.updateBlockBg("workspaceIRC", bga) - bar.updateBlockBg("workspaceSRC", bgi) + bar.updateBlockBg("www", "#5394C9") + bar.updateBlockBg("irc", "#72A7D3") + bar.updateBlockBg("src", "#5394C9") case 2: - bar.updateBlockBg("workspaceWWW", bgi) - bar.updateBlockBg("workspaceIRC", bgi) - bar.updateBlockBg("workspaceSRC", bga) + bar.updateBlockBg("www", "#5394C9") + bar.updateBlockBg("irc", "#5394C9") + bar.updateBlockBg("src", "#72A7D3") } - bar.redraw <- "workspaceWWW" - bar.redraw <- "workspaceIRC" - bar.redraw <- "workspaceSRC" + bar.redraw <- "www" + bar.redraw <- "irc" + bar.redraw <- "src" } } diff --git a/main.go b/main.go index ed093fe..7cc85c9 100644 --- a/main.go +++ b/main.go @@ -6,27 +6,33 @@ import ( ) func main() { - b, err := initBar(0, 0, 1920, 29, "/home/onodera/.fonts/cure.ttf", - 11) + bar, err := initBar(0, 0, 1920, 29, + "/home/onodera/.fonts/cure.ttf", 11) if err != nil { log.Fatal(err) } // Run bar block functions. Make sure to sleep a millisecond after // each block, else they won't appear in the right order. - go b.windowFun(220, "#37BF8D", "#FFFFFF") + go bar.windowFun() time.Sleep(time.Millisecond) - go b.workspaceFun(74, 67, 70, "#5394C9", "#72A7D3", "#FFFFFF") + + go bar.workspaceFun() time.Sleep(time.Millisecond * 3) - go b.clockFun(900, "#445967", "#CCCCCC") + + go bar.clockFun() time.Sleep(time.Millisecond) - go b.musicFun(600, "#3C4F5B", "#CCCCCC") + + go bar.musicFun() + time.Sleep(time.Millisecond) + + go bar.todoFun() time.Sleep(time.Millisecond) - //go b.todoFun(200) - //time.Sleep(time.Millisecond) for { - b.draw(<-b.redraw) - b.paint() + if err := bar.draw(<-bar.redraw); err != nil { + log.Fatal(err) + } + bar.paint() } }