87 lines
2.5 KiB
Go
87 lines
2.5 KiB
Go
package tomo
|
|
|
|
import "sort"
|
|
import "image"
|
|
import "errors"
|
|
import "git.tebibyte.media/tomo/tomo/canvas"
|
|
|
|
// Backend is any Tomo implementation. Backends handle window creation, layout,
|
|
// rendering, and events so that there can be as many platform-specific
|
|
// optimizations as possible.
|
|
type Backend interface {
|
|
// These methods create new objects. The backend must reject any object
|
|
// that was not made by it.
|
|
NewWindow (image.Rectangle) (MainWindow, error)
|
|
NewBox () Box
|
|
NewTextBox () TextBox
|
|
NewCanvasBox () CanvasBox
|
|
NewContainerBox () ContainerBox
|
|
|
|
// NewTexture creates a new texture from an image. The backend must
|
|
// reject any texture that was not made by it.
|
|
NewTexture (image.Image) canvas.TextureCloser
|
|
|
|
// Run runs the event loop until Stop() is called, or the backend
|
|
// experiences a fatal error.
|
|
Run () error
|
|
|
|
// Stop must unblock run.
|
|
Stop ()
|
|
|
|
// Do performs a callback function in the event loop thread as soon as
|
|
// possible. This method must be safe to call concurrently.
|
|
Do (func ())
|
|
}
|
|
|
|
// Factory is a function that attempts to instatiate a backend. If the
|
|
// instantiation process fails at any point, it must clean up all resources and
|
|
// return nil and an error explaining what happened.
|
|
type Factory func () (Backend, error)
|
|
|
|
var registered []factoryEntry
|
|
type factoryEntry struct {
|
|
Factory
|
|
priority int
|
|
}
|
|
|
|
// Register registers a backend factory with the given priority number.
|
|
func Register (priority int, factory Factory) {
|
|
registered = append(registered, factoryEntry {
|
|
priority: priority,
|
|
Factory: factory,
|
|
})
|
|
}
|
|
|
|
// Initialize instantiates a backend. The first backend (sorted by priority)
|
|
// that does not throw an error when initialized is used. If no backend could be
|
|
// instantiated, this function returns an error. This function should be called
|
|
// only once.
|
|
func Initialize () (Backend, error) {
|
|
backend, err := instantiate()
|
|
if err != nil { return nil, err }
|
|
return backend, err
|
|
}
|
|
|
|
func instantiate () (Backend, error) {
|
|
if len(registered) < 0 {
|
|
return nil, errors.New("no available backends")
|
|
}
|
|
|
|
// sort backends by priority
|
|
sort.Slice(registered, func (left, right int) bool {
|
|
return registered[left].priority < registered[right].priority
|
|
})
|
|
|
|
// attempt to instantiate
|
|
errorLog := ""
|
|
for _, factory := range registered {
|
|
backend, err := factory.Factory()
|
|
if err == nil {
|
|
return backend, nil
|
|
} else {
|
|
errorLog += " " + err.Error() + "\n"
|
|
}
|
|
}
|
|
return nil, errors.New("all backends failed:\n" + errorLog)
|
|
}
|