Applications can now manually call a screen redraw in a way that I think is thread safe

This commit is contained in:
Sasha Koshka 2022-11-11 22:30:59 -05:00
parent ea32b7899b
commit 05c448f058
4 changed files with 69 additions and 24 deletions

View File

@ -46,6 +46,11 @@ func (application *Application) Run () (
return return
} }
// Draw "commits" changes made in the buffer to the display.
func (application *Application) Draw () {
application.backend.Draw()
}
// SetTitle sets the application's title. If in a window, it will appear as the // SetTitle sets the application's title. If in a window, it will appear as the
// window's name. // window's name.
func (application *Application) SetTitle (title string) (err error) { func (application *Application) SetTitle (title string) (err error) {

View File

@ -7,6 +7,7 @@ type Backend interface {
Run (channel chan(Event)) Run (channel chan(Event))
SetTitle (title string) (err error) SetTitle (title string) (err error)
SetIcon (icons []image.Image) (err error) SetIcon (icons []image.Image) (err error)
Draw ()
} }
type BackendFactory func (application *Application) (backend Backend, err error) type BackendFactory func (application *Application) (backend Backend, err error)

View File

@ -1,6 +1,7 @@
package x package x
import "os" import "os"
import "sync"
import "image" import "image"
import "image/draw" import "image/draw"
import "golang.org/x/image/font" import "golang.org/x/image/font"
@ -28,6 +29,8 @@ type Backend struct {
canvas *xgraphics.Image canvas *xgraphics.Image
channel chan(stone.Event) channel chan(stone.Event)
drawLock sync.Mutex
ping struct { ping struct {
before chan(struct { }) before chan(struct { })
after chan(struct { }) after chan(struct { })
@ -80,6 +83,17 @@ func (backend *Backend) Run (channel chan(stone.Event)) {
} }
} }
func (backend *Backend) Draw () {
backend.drawLock.Lock()
defer backend.drawLock.Unlock()
backend.drawCells(true)
backend.canvas.XDraw()
backend.canvas.XPaint(backend.window.Id)
// FIXME use this instead once it works
// backend.updateWindowAreas(...)
}
func (backend *Backend) SetTitle (title string) (err error) { func (backend *Backend) SetTitle (title string) (err error) {
err = ewmh.WmNameSet(backend.connection, backend.window.Id, title) err = ewmh.WmNameSet(backend.connection, backend.window.Id, title)
return return
@ -191,6 +205,9 @@ func (backend *Backend) calculateWindowSize () (x, y int) {
} }
func (backend *Backend) reallocateCanvas () { func (backend *Backend) reallocateCanvas () {
backend.drawLock.Lock()
defer backend.drawLock.Unlock()
if backend.canvas != nil { if backend.canvas != nil {
backend.canvas.Destroy() backend.canvas.Destroy()
} }

View File

@ -8,8 +8,11 @@ import _ "image/png"
import "git.tebibyte.media/sashakoshka/stone" import "git.tebibyte.media/sashakoshka/stone"
import _ "git.tebibyte.media/sashakoshka/stone/backends/x" import _ "git.tebibyte.media/sashakoshka/stone/backends/x"
var application = &stone.Application { }
var currentTime = time.Time { }
var tickPing = make(chan(struct { }))
func main () { func main () {
application := &stone.Application { }
application.SetTitle("hellorld") application.SetTitle("hellorld")
application.SetSize(12, 2) application.SetSize(12, 2)
@ -29,32 +32,51 @@ func main () {
channel, err := application.Run() channel, err := application.Run()
if err != nil { panic(err) } if err != nil { panic(err) }
currentTime := time.Time { } redraw()
application.Draw()
go tick()
for { for {
event := <- channel select {
switch event.(type) { case <- tickPing:
case stone.EventQuit: redraw()
os.Exit(0) application.Draw()
case stone.EventResize: case event := <- channel:
currentTime = time.Now() switch event.(type) {
case stone.EventQuit:
os.Exit(0)
application.ResetDot() case stone.EventResize:
fmt.Fprintln(application, "hellorld!") redraw()
}
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))
} }
} }
} }
func redraw () {
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))
}
func tick () {
for {
tickPing <- struct { } { }
time.Sleep(time.Second)
}
}