diff options
Diffstat (limited to 'bar')
| -rw-r--r-- | bar/bar.go | 200 |
1 files changed, 200 insertions, 0 deletions
diff --git a/bar/bar.go b/bar/bar.go new file mode 100644 index 0000000..6ab7f35 --- /dev/null +++ b/bar/bar.go @@ -0,0 +1,200 @@ +package bar + +import ( + "fmt" + "container/list" + + "hhvn.uk/hbspbar/common" + "hhvn.uk/hbspbar/bspc" + + "github.com/jezek/xgb" + "github.com/jezek/xgb/xproto" + + "github.com/jezek/xgbutil" + "github.com/jezek/xgbutil/icccm" + "github.com/jezek/xgbutil/ewmh" +) + +var conf = struct { + H uint + Bg uint32 + Fg uint32 + Sel uint32 + Urg uint32 +} { 16, + 0xff050a10, + 0xffeeeeee, + 0xff1b364b, + 0xff90222b } + +var bars *list.List + +type bar struct { + X *xgb.Conn + Xu *xgbutil.XUtil + Scr *xproto.ScreenInfo + Mon *bspc.Monitor + w xproto.Window +} + +func (b *bar) Init() error { + var err error + + b.w, err = xproto.NewWindowId(b.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.CwBackPixel|xproto.CwEventMask, []uint32{ + conf.Bg, + xproto.EventMaskStructureNotify }) + + class := icccm.WmClass{"hbspbar", "hbspbar"} + icccm.WmClassSet(b.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"}) + + err = xproto.MapWindowChecked(b.X, b.w).Check() + if err != nil { + return common.Perror("xproto.MapWindow", err) + } + + go b.Mon.TopPadding(conf.H) + + return nil +} + +func (b *bar) Destroy() { + b.Mon.TopPadding(0) +} + +type eventwrap struct { + Ev xgb.Event + Err error +} + +// External interface +type Handle struct { + Create chan int + Destroy chan int + NewState chan *bspc.State + Err chan error +} + +func Init(state *bspc.State) (*Handle, error) { + bars = list.New() + + x, err := xgb.NewConn() + if err != nil { return nil, err } + + xu, err := xgbutil.NewConnXgb(x) + if err != nil { return nil, err } + + setup := xproto.Setup(x) + screen := setup.DefaultScreen(x) + + var h Handle + h.Create = make(chan int) + h.Destroy = make(chan int) + h.NewState = make(chan *bspc.State) + h.Err = make(chan error) + + events := make(chan *eventwrap) + + go func() { for { + ev, err := x.WaitForEvent() + w := eventwrap{ev, err} + events <- &w + + select { + case <- events: return + default: + } + }}() + + go func() { + defer func() { events <- nil }() + + for { + select { + case e := <- events: + if e.Ev == nil && e.Err == nil { + h.Err <- fmt.Errorf("X connection clossed") + return + } + + if e.Err != nil { + common.Perror("x.WaitForEvents", err) + continue + } + + switch e.Ev.(type) { + case xproto.DestroyNotifyEvent: + h.Err <- fmt.Errorf("Window destroyed") + return + } + case id := <- h.Destroy: + destroy(id) + case id := <- h.Create: + if err := create(x, xu, screen, state.GetMon(id)); err != nil { + h.Err <- fmt.Errorf("Couldn't create window: %s\n", err) + return + } + case state := <- h.NewState: + for e := bars.Front(); e != nil; e = e.Next() { + v := e.Value.(*bar) + v.Mon = state.GetMon(v.Mon.ID) + } + default: + } + } + }() + + return &h, nil +} + +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 + + if err := b.Init(); err != nil { + return err + } + + bars.PushBack(&b) + return nil +} + +func destroy(monid int) (bool) { + var next *list.Element + + for e := bars.Front(); e != nil; e = next { + next = e.Next() + v := e.Value.(*bar) + + /* A monid of -1 means that we're doing + the bar.Cleanup schermoodle today */ + if monid == -1 || monid > 0 && v.Mon.ID == int(monid) { + v.Destroy() + bars.Remove(e) + if monid != -1 { return true } + } + } + + if monid == -1 { return true } + return false +} + +func Cleanup() { + destroy(-1) +} |