From 2bfbc2bc4adcff5b0374bd2cbeb9d7501afe3c58 Mon Sep 17 00:00:00 2001 From: Camille Scholtz Date: Wed, 12 Jul 2017 18:21:51 +0200 Subject: [PATCH] Make openbox compatible --- README.md | 4 +-- bar.go | 54 +++++++++++++++++++++++++++++++-------- blocks.go | 76 +++++++++++++++++++++++-------------------------------- 3 files changed, 77 insertions(+), 57 deletions(-) diff --git a/README.md b/README.md index c720028..fb72afc 100644 --- a/README.md +++ b/README.md @@ -25,8 +25,8 @@ 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 name of the block, this is 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'` diff --git a/bar.go b/bar.go index 81563f0..33fa229 100644 --- a/bar.go +++ b/bar.go @@ -1,6 +1,7 @@ package main import ( + "fmt" "image" "os" "sync" @@ -10,6 +11,7 @@ import ( "github.com/BurntSushi/xgb/xproto" "github.com/BurntSushi/xgbutil" "github.com/BurntSushi/xgbutil/ewmh" + "github.com/BurntSushi/xgbutil/xevent" "github.com/BurntSushi/xgbutil/xgraphics" "github.com/BurntSushi/xgbutil/xwindow" ) @@ -72,27 +74,46 @@ func initBar(x, y, w, h int, font string, fontSize float64) (*Bar, if err != nil { return nil, err } + go xevent.Main(bar.xu) - // Listen to the root window for events. - xwindow.New(bar.xu, bar.xu.RootWin()).Listen( - xproto.EventMaskPropertyChange) + // Listen to the root window for property change event, used to + // check if the user changed the focused window or active + // workspace. + if err := xwindow.New(bar.xu, bar.xu.RootWin()).Listen( + xproto.EventMaskPropertyChange); err != nil { + return nil, err + } // Create a window. bar.win, err = xwindow.Generate(bar.xu) if err != nil { return nil, err } - bar.win.Create(bar.xu.RootWin(), x, y, w, h, xproto.CwBackPixel, - 0x000000) + bar.win.Create(bar.xu.RootWin(), x, y, w, h, xproto.CwBackPixel| + xproto.CwEventMask, 0x000000, xproto.EventMaskPropertyChange) + // TODO: `WmStateSet` and `WmDesktopSet` are basically here to + // keep OpenBox happy, can I somehow remove them and just use + // `_NET_WM_WINDOW_TYPE_DOCK`? // EWMH stuff. if err := ewmh.WmWindowTypeSet(bar.xu, bar.win.Id, []string{ "_NET_WM_WINDOW_TYPE_DOCK"}); err != nil { return nil, err } + if err := ewmh.WmStateSet(bar.xu, bar.win.Id, []string{ + "_NET_WM_STATE_STICKY"}); err != nil { + return nil, err + } + if err := ewmh.WmDesktopSet(bar.xu, bar.win.Id, ^uint(0)); err != nil { + return nil, err + } + if err := ewmh.WmNameSet(bar.xu, bar.win.Id, "melonbar"); err != nil { + return nil, err + } // Map window. bar.win.Map() + bar.win.Move(x, y) // Create bar image. bar.img = xgraphics.New(bar.xu, image.Rect(0, 0, w, h)) @@ -178,14 +199,9 @@ func (bar *Bar) draw(name string) error { i, _ := bar.block.Load(name) block := i.(*Block) - // Color the backround. - tw, _ := xgraphics.Extents(bar.font, bar.fontSize, block.txt) - block.img.For(func(x, y int) xgraphics.BGRA { - return block.bg - }) - // Calculate the required x coordinate for the different // aligments. + tw, _ := xgraphics.Extents(bar.font, bar.fontSize, block.txt) var x int switch block.align { case 'l': @@ -194,8 +210,24 @@ func (bar *Bar) draw(name string) error { x = block.x + ((block.w / 2) - (tw / 2)) + block.xoff case 'r': x = (block.x + block.w) - tw + block.xoff + default: + return fmt.Errorf("draw %#U: Not a valid aligment rune", + block.align) } + // Color the backround. + block.img.For(func(cx, cy int) xgraphics.BGRA { + // Hack for music block background. + if name == "music" { + if cx < x+block.xoff { + return hexToBGRA("#445967") + } + return block.bg + } + + return block.bg + }) + // TODO: Center vertically automatically. // Draw the text. if _, _, err := block.img.Text(x, 6, block.fg, bar.fontSize, diff --git a/blocks.go b/blocks.go index 491d453..30489ae 100644 --- a/blocks.go +++ b/blocks.go @@ -7,8 +7,10 @@ import ( "strconv" "time" - "github.com/BurntSushi/xgb/xproto" + "github.com/BurntSushi/xgbutil" "github.com/BurntSushi/xgbutil/ewmh" + "github.com/BurntSushi/xgbutil/icccm" + "github.com/BurntSushi/xgbutil/xevent" "github.com/BurntSushi/xgbutil/xprop" owm "github.com/briandowns/openweathermap" "github.com/fhs/gompd/mpd" @@ -170,39 +172,33 @@ func (bar *Bar) weatherFun() { func (bar *Bar) windowFun() { bar.initBlock("window", "?", 220, 'c', 0, "#37BF8D", "#FFFFFF") - init := true - for { - if !init { - ev, xgbErr := bar.xu.Conn().WaitForEvent() - if xgbErr != nil { - log.Print(xgbErr) - continue - } - - atom, err := xprop.Atm(bar.xu, "_NET_ACTIVE_WINDOW") - if ev.(xproto.PropertyNotifyEvent).Atom != atom { - continue - } - if err != nil { - log.Print(err) - continue - } + // TODO: I'm not sure how I can use init here? + xevent.PropertyNotifyFun(func(xu *xgbutil.XUtil, + ev xevent.PropertyNotifyEvent) { + atom, err := xprop.Atm(bar.xu, "_NET_ACTIVE_WINDOW") + if ev.Atom != atom { + return + } + if err != nil { + log.Print(err) + return } - init = false id, err := ewmh.ActiveWindowGet(bar.xu) if err != nil { log.Print(err) - continue + return } win, err := ewmh.WmNameGet(bar.xu, id) - if err != nil { - log.Print(err) - continue + if err != nil || len(win) == 0 { + win, err = icccm.WmNameGet(bar.xu, id) + if err != nil || len(win) == 0 { + win = "?" + } } bar.updateBlockTxt("window", win) - } + }).Connect(bar.xu, bar.xu.RootWin()) } func (bar *Bar) workspaceFun() { @@ -210,30 +206,22 @@ func (bar *Bar) workspaceFun() { bar.initBlock("irc", "irc", 67, 'c', 0, "#5394C9", "#FFFFFF") bar.initBlock("src", "src", 70, 'c', 0, "#5394C9", "#FFFFFF") - init := true - for { - if !init { - ev, xgbErr := bar.xu.Conn().WaitForEvent() - if xgbErr != nil { - log.Print(xgbErr) - continue - } - - atom, err := xprop.Atm(bar.xu, "WINDOWCHEF_ACTIVE_GROUPS") - if ev.(xproto.PropertyNotifyEvent).Atom != atom { - continue - } - if err != nil { - log.Print(err) - continue - } + // TODO: I'm not sure how I can use init here? + xevent.PropertyNotifyFun(func(xu *xgbutil.XUtil, + ev xevent.PropertyNotifyEvent) { + atom, err := xprop.Atm(bar.xu, "_NET_CURRENT_DESKTOP") + if ev.Atom != atom { + return + } + if err != nil { + log.Print(err) + return } - init = false wsp, err := ewmh.CurrentDesktopGet(bar.xu) if err != nil { log.Print(err) - continue + return } switch wsp { @@ -250,5 +238,5 @@ func (bar *Bar) workspaceFun() { bar.updateBlockBg("irc", "#5394C9") bar.updateBlockBg("src", "#72A7D3") } - } + }).Connect(bar.xu, bar.xu.RootWin()) }