diff --git a/internal/driver/glfw/canvas_test.go b/internal/driver/glfw/canvas_test.go index 8638eaa4b5..1b49dc2851 100644 --- a/internal/driver/glfw/canvas_test.go +++ b/internal/driver/glfw/canvas_test.go @@ -427,7 +427,10 @@ func TestGlCanvas_ResizeWithOtherOverlay(t *testing.T) { content := widget.NewLabel("Content") over := widget.NewLabel("Over") w.SetContent(content) - w.Canvas().Overlays().Add(over) + overlays := w.Canvas().Overlays() + runOnMain(func() { + overlays.Add(over) + }) ensureCanvasSize(t, w, fyne.NewSize(69, 36)) // TODO: address #707; overlays should always be canvas size size := w.Canvas().Size() diff --git a/internal/driver/glfw/loop.go b/internal/driver/glfw/loop.go index 41d0f65821..c228fcd0c3 100644 --- a/internal/driver/glfw/loop.go +++ b/internal/driver/glfw/loop.go @@ -56,6 +56,10 @@ var refreshingCanvases []fyne.Canvas func (d *gLDriver) drawSingleFrame() { for _, win := range d.windowList() { + if win == nil { + continue + } + w := win.(*window) canvas := w.canvas closing := w.closing @@ -113,15 +117,20 @@ func (d *gLDriver) runGL() { f.done <- struct{}{} case <-eventTick.C: d.pollEvents() - windowsToRemove := 0 - for _, win := range d.windowList() { + runWindowCleanup := false + for i, win := range d.windowList() { + if win == nil { + continue + } + w := win.(*window) if w.viewport == nil { continue } if w.viewport.ShouldClose() { - windowsToRemove++ + d.destroyWindow(w, i) + runWindowCleanup = true continue } @@ -139,37 +148,13 @@ func (d *gLDriver) runGL() { } } - d.animation.TickAnimations() - d.drawSingleFrame() } - if windowsToRemove > 0 { - oldWindows := d.windowList() - newWindows := make([]fyne.Window, 0, len(oldWindows)-windowsToRemove) - - for _, win := range oldWindows { - w := win.(*window) - if w.viewport == nil { - continue - } - if w.viewport.ShouldClose() { - w.visible = false - v := w.viewport + d.animation.TickAnimations() + d.drawSingleFrame() - // remove window from window list - v.Destroy() - w.destroy(d) - continue - } - - newWindows = append(newWindows, win) - } - - d.windows = newWindows - - if len(newWindows) == 0 { - d.Quit() - } + if runWindowCleanup { + d.removeDestroyedWindows() } case set := <-settingsChange: painter.ClearFontCache() @@ -187,6 +172,34 @@ func (d *gLDriver) runGL() { } } +func (d *gLDriver) destroyWindow(w *window, index int) { + w.visible = false + + // Remove window from window list: + d.windows[index] = nil + w.viewport.Destroy() + w.destroy(d) +} + +func (d *gLDriver) removeDestroyedWindows() { + // Copy items from front to back to move as few objects as possible. + for i := len(d.windows) - 1; i >= 0; i-- { + if d.windows[i] != nil { + continue + } + + if i < len(d.windows)-1 { + copy(d.windows[i:], d.windows[i+1:]) + } + d.windows[len(d.windows)-1] = nil + d.windows = d.windows[:len(d.windows)-1] + } + + if len(d.windows) == 0 { + d.Quit() + } +} + func (d *gLDriver) repaintWindow(w *window) { canvas := w.canvas w.RunWithContext(func() { @@ -221,5 +234,5 @@ func updateGLContext(w *window) { winHeight := float32(scale.ToScreenCoordinate(canvas, size.Height)) * canvas.texScale canvas.Painter().SetFrameBufferScale(canvas.texScale) - w.canvas.Painter().SetOutputSize(int(winWidth), int(winHeight)) + canvas.Painter().SetOutputSize(int(winWidth), int(winHeight)) }