From 05c448f058f046b6faa81f90b84ce421020b18a6 Mon Sep 17 00:00:00 2001 From: Sasha Koshka Date: Fri, 11 Nov 2022 22:30:59 -0500 Subject: [PATCH] Applications can now manually call a screen redraw in a way that I think is thread safe --- application.go | 5 +++ backend.go | 1 + backends/x/x.go | 17 ++++++++++ examples/hello/main.go | 70 +++++++++++++++++++++++++++--------------- 4 files changed, 69 insertions(+), 24 deletions(-) diff --git a/application.go b/application.go index 0e94e0b..206af06 100644 --- a/application.go +++ b/application.go @@ -46,6 +46,11 @@ func (application *Application) Run () ( 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 // window's name. func (application *Application) SetTitle (title string) (err error) { diff --git a/backend.go b/backend.go index c4f8278..96678fc 100644 --- a/backend.go +++ b/backend.go @@ -7,6 +7,7 @@ type Backend interface { Run (channel chan(Event)) SetTitle (title string) (err error) SetIcon (icons []image.Image) (err error) + Draw () } type BackendFactory func (application *Application) (backend Backend, err error) diff --git a/backends/x/x.go b/backends/x/x.go index fc5be02..ffd2f14 100644 --- a/backends/x/x.go +++ b/backends/x/x.go @@ -1,6 +1,7 @@ package x import "os" +import "sync" import "image" import "image/draw" import "golang.org/x/image/font" @@ -28,6 +29,8 @@ type Backend struct { canvas *xgraphics.Image channel chan(stone.Event) + drawLock sync.Mutex + ping struct { before 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) { err = ewmh.WmNameSet(backend.connection, backend.window.Id, title) return @@ -191,6 +205,9 @@ func (backend *Backend) calculateWindowSize () (x, y int) { } func (backend *Backend) reallocateCanvas () { + backend.drawLock.Lock() + defer backend.drawLock.Unlock() + if backend.canvas != nil { backend.canvas.Destroy() } diff --git a/examples/hello/main.go b/examples/hello/main.go index 38b168b..0c37f84 100644 --- a/examples/hello/main.go +++ b/examples/hello/main.go @@ -8,8 +8,11 @@ import _ "image/png" import "git.tebibyte.media/sashakoshka/stone" import _ "git.tebibyte.media/sashakoshka/stone/backends/x" +var application = &stone.Application { } +var currentTime = time.Time { } +var tickPing = make(chan(struct { })) + func main () { - application := &stone.Application { } application.SetTitle("hellorld") application.SetSize(12, 2) @@ -29,32 +32,51 @@ func main () { channel, err := application.Run() if err != nil { panic(err) } - currentTime := time.Time { } + redraw() + application.Draw() + go tick() for { - event := <- channel - switch event.(type) { - case stone.EventQuit: - os.Exit(0) + select { + case <- tickPing: + redraw() + application.Draw() + + case event := <- channel: + switch event.(type) { + case stone.EventQuit: + os.Exit(0) - case stone.EventResize: - 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)) + case stone.EventResize: + redraw() + } } } } + +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) + } +}