x backend has an event loop

This commit is contained in:
Sasha Koshka 2022-11-09 18:53:14 -05:00
parent 0c5118b59a
commit c93ca17fe5
3 changed files with 110 additions and 59 deletions

View File

@ -44,7 +44,13 @@ func (application *Application) Run () (
if err != nil { return }
channel = make(chan(Event))
application.backend.Run(channel)
go application.backend.Run(channel)
return
}
// Config returns a pointer to the application's configuration.
func (application *Application) Config () (config *Config) {
config = &application.config
return
}

View File

@ -4,25 +4,49 @@ import "image"
import "github.com/jezek/xgbutil"
// import "github.com/jezek/xgbutil/ewmh"
// import "github.com/jezek/xgbutil/xevent"
import "github.com/jezek/xgbutil/xevent"
import "github.com/jezek/xgbutil/xwindow"
import "github.com/jezek/xgbutil/xgraphics"
import "git.tebibyte.media/sashakoshka/stone"
type Backend struct {
connection *xgbutil.Conn
window *xwindow.Window
canvas *xgraphics.Image
application *stone.Application
config *stone.Config
connection *xgbutil.XUtil
window *xwindow.Window
canvas *xgraphics.Image
channel chan(stone.Event)
ping struct {
before chan(struct { })
after chan(struct { })
quit chan(struct { })
}
metrics struct {
cellWidth int
cellHeight int
padding int
paddingX int
paddingY int
descent int
}
}
func (backend *Backend) Run (channel chan(stone.Event)) {
// TODO: setup
go backend.mainLoop(channel)
}
func (backend *Backend) mainLoop (channel chan(stone.Event)) {
backend.channel = channel
for {
select {
case <- backend.ping.before:
<- backend.ping.after
case <- backend.ping.quit:
backend.shutDown()
return
}
}
}
func (backend *Backend) SetTitle (title string) {
@ -32,3 +56,72 @@ func (backend *Backend) SetTitle (title string) {
func (backend *Backend) SetIcon (icons []image.Image) {
}
func (backend *Backend) shutDown () {
backend.channel <- stone.EventQuit { }
}
// calculateWindowSize calculates window bounds based on the internal buffer
// size.
func (backend *Backend) calculateWindowSize () (x, y int) {
width, height := backend.application.Size()
x =
width * backend.metrics.cellWidth +
backend.metrics.padding * 2
y =
height * backend.metrics.cellHeight +
backend.metrics.padding * 2
return
}
// factory instantiates an X backend.
func factory (application *stone.Application) (output stone.Backend, err error) {
backend := &Backend {
application: application,
config: application.Config(),
}
// calculate metrics
// TODO: base these off of font metrics
backend.metrics.cellWidth = 8
backend.metrics.cellHeight = 16
backend.metrics.padding =
backend.config.Padding() *
backend.metrics.cellHeight
backend.metrics.paddingX = backend.metrics.padding
backend.metrics.paddingY = backend.metrics.padding
// connect to X
backend.connection, err = xgbutil.NewConn()
if err != nil { return }
backend.window, err = xwindow.Generate(backend.connection)
if err != nil { return }
// create the window
windowWidth, windowHeight := backend.calculateWindowSize()
backend.window.Create (
backend.connection.RootWin(),
0, 0, windowWidth, windowHeight,
0)
backend.window.Map()
// attatch graceful close handler
backend.window.WMGracefulClose (func (window *xwindow.Window) {
backend.window.Destroy()
backend.shutDown()
})
// start event loop
backend.ping.before,
backend.ping.after,
backend.ping.quit = xevent.MainPing(backend.connection)
output = backend
return
}
// init registers this backend when the program starts.
func init () {
stone.RegisterBackend(factory)
}

View File

@ -4,7 +4,7 @@ import "os"
import "fmt"
import "time"
import "git.tebibyte.media/sashakoshka/stone"
// import _ "git.tebibyte.media/sashakoshka/stone/backends/x"
import _ "git.tebibyte.media/sashakoshka/stone/backends/x"
func main () {
application := &stone.Application { }
@ -40,51 +40,3 @@ func main () {
}
}
}
// func run (application *stone.Application) {
// currentTime := time.Time { }
// frameDelay := time.Second / 2
// textBuffer := ""
//
// for {
// typed := application.Typed()
// textBuffer += typed
//
// shouldRender :=
// application.Resized() ||
// time.Since(currentTime) > frameDelay ||
// len(typed) > 0
//
// if shouldRender {
// currentTime = time.Now()
//
// application.ResetDot()
// fmt.Fprintln(application, "hellorld!")
//
// hour := currentTime.Hour()
// minute := currentTime.Minute()
// second := currentTime.Second()
//
// application.SetRune(0, 1, rune(hour / 10 + 48))
// application.SetRune(1, 1, rune(hour % 10 + 48))
// application.SetRune(2, 1, ':')
// application.SetRune(3, 1, rune(minute / 10 + 48))
// application.SetRune(4, 1, rune(minute % 10 + 48))
// application.SetRune(5, 1, ':')
// application.SetRune(6, 1, rune(second / 10 + 48))
// application.SetRune(7, 1, rune(second % 10 + 48))
//
// application.Dot.X = 0
// application.Dot.Y = 2
// fmt.Fprintln(application, textBuffer)
//
// }
//
// if application.Pressed(stone.MouseButtonLeft) {
// x, y := application.MousePosition()
// application.SetRune(x, y, '#')
// }
//
// if !application.Await(frameDelay) { break }
// }
// }