146 lines
3.1 KiB
Go
146 lines
3.1 KiB
Go
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) 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.CanvasCloser {
|
|
return xcanvas.NewCanvas(this.x, bounds)
|
|
}
|
|
|
|
func (this *Backend) SetStyle (style tomo.Style) {
|
|
this.system.SetStyle(style)
|
|
}
|
|
|
|
func (this *Backend) SetIcons (icons tomo.Icons) {
|
|
this.system.SetIcons(icons)
|
|
}
|
|
|
|
func (this *Backend) assert () {
|
|
if this == nil { panic("x: nil backend") }
|
|
}
|
|
|
|
func (this *Backend) afterEvent () {
|
|
for _, window := range this.windows {
|
|
window.hierarchy.AfterEvent()
|
|
}
|
|
}
|