I have a program with multiple multiple loops, each one ran in a Goroutine. I need to plug or unplug monitors while my program runs, so I have to restart the sdl to let it find my new monitors, I do it by sdl.quit() to quit the last sdl and sdl.init(sdl.InitEverything) to initialize it again. My problem is that I have to handle the sdl events in a loop, If I don't it will become unresponsive, but this loop will block my Main code. I don't need to handle any events like mouse clicks, I just want to show some simple picture and manipulate them, is there any way to stop events or run the whole sdl in a goroutine? I tried but get weird results. This is my struct:
type SDLstruct{
window *sdl.Window
renderer *sdl.Renderer
texture *sdl.Texture
src, dst sdl.Rect
event sdl.Event
Close bool
winWidth, winHeight int32
}
This function starts a window and a renderer:
func (sdlVars *SDLstruct)StartWindow() (err error) {
sdlVars.winWidth, sdlVars.winHeight = 1920,1080
sdl.Init(sdl.INIT_VIDEO)
Num,err :=sdl.GetNumVideoDisplays()
if err!=nil {
return err
}
var rect sdl.Rect
rect,err = sdl.GetDisplayBounds(0)
if err!=nil {
return err
}
for i:=Num-1;i>=0;i--{
Mod , _:=sdl.GetDisplayMode(i,0)
if Mod.W ==info.winWidth && Mod.H==info.winHeight{
rect,err = sdl.GetDisplayBounds(i)
if err!=nil {
return err
}
break
}
}
sdlVars.window, err = sdl.CreateWindow(winTitle, rect.X, rect.Y,
rect.W, rect.H, sdl.WINDOW_SHOWN)
sdlVars.window.SetBordered(false)
sdlVars.window.SetFullscreen(1)
if err != nil {
fmt.Fprintf(os.Stderr, "Failed to create window: %s\n", err)
return err
}
sdlVars.renderer, err = sdl.CreateRenderer(sdlVars.window, -1, sdl.RENDERER_ACCELERATED)
if err != nil {
fmt.Fprintf(os.Stderr, "Failed to create renderer: %s\n", err)
return err
}
sdlVars.renderer.Clear()
sdlVars.renderer.SetDrawColor(0, 0, 0, 255)
sdlVars.renderer.FillRect(&sdl.Rect{0, 0, int32(info.winWidth), int32(info.winHeight)})
sdlVars.renderer.Present()
sdl.ShowCursor(0)
return nil
}
This function handle events:
func (sdlVars *SDLstruct)HandleEvents() {
for sdlVars.event = sdl.PollEvent(); sdlVars.event != nil; sdlVars.event = sdl.PollEvent() {
switch t := sdlVars.event.(type) {
case *sdl.QuitEvent:
sdlVars.Close = true
}
}
}
and this one closes everything:
func (sdlVars *SDLstruct)CloseSDL() (err error) {
err =sdlVars.renderer.Destroy()
if err!=nil{
return err
}
err = sdlVars.window.Destroy()
if err!=nil{
return err
}
sdl.Quit()
return nil
}
This is my Main function:
func main() {
var wg sync.WaitGroup
SdlVars:= new(SDLstruct)
wg.Add(1)
go SdlVars.StartSDL()
time.Sleep(time.Second*5)
SdlVars.Close = true
time.Sleep(time.Second*15)
}
In my Main function I tell it to start the sdl and after 5 seconds close everything and wait 15 seconds, but it doesn't close window.
Be careful as using SDL from multiple threads is not entirely trivial. Typically, your SDL loop must sit in the main
thread. There is a good reason for that and it's because the event loop is part of the main
thread and many of your objects are created and mutated on the main
thread...or at least they should be.
When you introduce multiple threads weird undefined and dangerous behavior could happen. This is why a good rule of thumb is to use runtime.LockOSThread
to ensure the Go runtime doesn't pin your main
goroutine to other threads and keeps it on the main
thread.
See this for more details: enter link description here