package x import "image" import "errors" import "git.tebibyte.media/tomo/tomo" import "git.tebibyte.media/tomo/xgbkb" import "git.tebibyte.media/tomo/tomo/canvas" import "git.tebibyte.media/tomo/backend/x/canvas" import "git.tebibyte.media/tomo/backend/internal/system" import "github.com/jezek/xgbutil" import "github.com/jezek/xgb/xproto" import "github.com/jezek/xgbutil/xevent" import "github.com/jezek/xgbutil/keybind" import "github.com/jezek/xgbutil/mousebind" type Backend struct { x *xgbutil.XUtil system *system.System doChannel chan func() windows map[xproto.Window] *window open bool } type backendLink struct { backend *Backend } func (this *backendLink) NewTexture (source image.Image) canvas.TextureCloser { return this.backend.NewTexture(source) } func (this *backendLink) NewCanvas (bounds image.Rectangle) canvas.Canvas { return this.backend.NewCanvas(bounds) } func (this *backendLink) NewSurface (bounds image.Rectangle) (system.SurfaceLink, error) { // TODO return nil, errors.New("x: not implemented") } func New () (tomo.Backend, error) { backend := &Backend { doChannel: make(chan func (), 32), windows: make(map[xproto.Window] *window), open: true, } link := &backendLink { backend: backend, } backend.system = system.New(link) var err error backend.x, err = xgbutil.NewConn() if err != nil { return nil, err } keybind .Initialize(backend.x) xgbkb .Initialize(backend.x) mousebind.Initialize(backend.x) return backend, nil } func (this *Backend) Run () error { this.assert() pingBefore, pingAfter, pingQuit := xevent.MainPing(this.x) for { select { case <- pingBefore: <- pingAfter case callback := <- this.doChannel: callback() case <- pingQuit: return nil // FIXME: if we exited due to an error say so } this.afterEvent() } } func (this *Backend) Stop () { this.assert() if !this.open { return } this.open = false toClose := []*window { } for _, panel := range this.windows { toClose = append(toClose, panel) } for _, panel := range toClose { panel.Close() } xevent.Quit(this.x) this.x.Conn().Close() } func (this *Backend) Do (callback func ()) { this.assert() this.doChannel <- callback } func (this *Backend) NewBox () tomo.Box { return this.system.NewBox() } func (this *Backend) NewCanvasBox () tomo.CanvasBox { return this.system.NewCanvasBox() } func (this *Backend) NewContainerBox () tomo.ContainerBox { return this.system.NewContainerBox() } func (this *Backend) NewSurfaceBox () (tomo.SurfaceBox, error) { return this.system.NewSurfaceBox() } func (this *Backend) NewTextBox () tomo.TextBox { return this.system.NewTextBox() } func (this *Backend) NewTexture (source image.Image) canvas.TextureCloser { return xcanvas.NewTextureFrom(source) } func (this *Backend) NewCanvas (bounds image.Rectangle) canvas.Canvas { return xcanvas.NewCanvas(this.x, bounds) } func (this *Backend) assert () { if this == nil { panic("x: nil backend") } } func (this *Backend) afterEvent () { for _, window := range this.windows { window.hierarchy.AfterEvent() } }