From 27148de03d105c58d4c9875437ef357995193317 Mon Sep 17 00:00:00 2001 From: Andy Williams Date: Mon, 16 Dec 2024 19:25:18 +0000 Subject: [PATCH 1/9] Move event execution to the same thread as well --- internal/driver/common/window.go | 14 +++++++++----- internal/driver/glfw/loop.go | 1 + internal/driver/glfw/window.go | 1 - internal/driver/mobile/driver.go | 2 +- 4 files changed, 11 insertions(+), 7 deletions(-) diff --git a/internal/driver/common/window.go b/internal/driver/common/window.go index a01576819a..ab5e499e74 100644 --- a/internal/driver/common/window.go +++ b/internal/driver/common/window.go @@ -26,11 +26,15 @@ func (w *Window) QueueEvent(fn func()) { w.eventQueue.In() <- fn } -// RunEventQueue runs the event queue. This should called inside a go routine. -// This function blocks. -func (w *Window) RunEventQueue() { - for fn := range w.eventQueue.Out() { - fn() +// ProcessEventQueue runs all the items in the event queue, returning once it is empty again. +func (w *Window) ProcessEventQueue() { + for { + select { + case fn := <-w.eventQueue.Out(): + fn() + default: + return + } } } diff --git a/internal/driver/glfw/loop.go b/internal/driver/glfw/loop.go index 8d26dbb683..8bcc8b68cf 100644 --- a/internal/driver/glfw/loop.go +++ b/internal/driver/glfw/loop.go @@ -128,6 +128,7 @@ func (d *gLDriver) runGL() { if w.viewport == nil { continue } + w.ProcessEventQueue() if w.viewport.ShouldClose() { windowsToRemove++ diff --git a/internal/driver/glfw/window.go b/internal/driver/glfw/window.go index ba23a6cfdf..b0302448d3 100644 --- a/internal/driver/glfw/window.go +++ b/internal/driver/glfw/window.go @@ -994,7 +994,6 @@ func (d *gLDriver) createWindow(title string, decorate bool) fyne.Window { ret = &window{title: title, decorate: decorate, driver: d} // This queue is destroyed when the window is closed. ret.InitEventQueue() - go ret.RunEventQueue() ret.canvas = newCanvas() ret.canvas.context = ret diff --git a/internal/driver/mobile/driver.go b/internal/driver/mobile/driver.go index 28a69aff89..96315c873b 100644 --- a/internal/driver/mobile/driver.go +++ b/internal/driver/mobile/driver.go @@ -75,7 +75,6 @@ func (d *driver) CreateWindow(title string) fyne.Window { c := newCanvas(fyne.CurrentDevice()).(*canvas) // silence lint ret := &window{title: title, canvas: c, isChild: len(d.windows) > 0} ret.InitEventQueue() - go ret.RunEventQueue() c.setContent(&fynecanvas.Rectangle{FillColor: theme.Color(theme.ColorNameBackground)}) c.SetPainter(pgl.NewPainter(c, ret)) d.windows = append(d.windows, ret) @@ -178,6 +177,7 @@ func (d *driver) Run() { if current == nil { continue } + current.ProcessEventQueue() c := current.Canvas().(*canvas) switch e := a.Filter(e).(type) { From 3f051ca124ab525844a982bacdcd9a20ebf2dd58 Mon Sep 17 00:00:00 2001 From: Andy Williams Date: Mon, 16 Dec 2024 19:26:43 +0000 Subject: [PATCH 2/9] Remove canvas, view and mouse locks from GLFW driver that we no longer need --- internal/driver/common/canvas.go | 26 -------- internal/driver/glfw/canvas.go | 59 ++++-------------- internal/driver/glfw/loop.go | 13 +--- internal/driver/glfw/window.go | 82 +++----------------------- internal/driver/glfw/window_desktop.go | 11 ---- 5 files changed, 18 insertions(+), 173 deletions(-) diff --git a/internal/driver/common/canvas.go b/internal/driver/common/canvas.go index 80c61ecf9a..b6a917a0f4 100644 --- a/internal/driver/common/canvas.go +++ b/internal/driver/common/canvas.go @@ -25,8 +25,6 @@ type SizeableCanvas interface { // Canvas defines common canvas implementation. type Canvas struct { - sync.RWMutex - OnFocus func(obj fyne.Focusable) OnUnfocus func() @@ -91,18 +89,13 @@ func (c *Canvas) EnsureMinSize() bool { csize := c.impl.Size() min := c.impl.MinSize() - c.RLock() - defer c.RUnlock() - var parentNeedingUpdate *RenderCacheNode ensureMinSize := func(node *RenderCacheNode, pos fyne.Position) { obj := node.obj cache.SetCanvasForObject(obj, c.impl, func() { if img, ok := obj.(*canvas.Image); ok { - c.RUnlock() img.Refresh() // this may now have a different texScale - c.RLock() } }) @@ -111,13 +104,10 @@ func (c *Canvas) EnsureMinSize() bool { parentNeedingUpdate = nil } - c.RUnlock() if !obj.Visible() { - c.RLock() return } minSize := obj.MinSize() - c.RLock() minSizeChanged := node.minSize != minSize if minSizeChanged { @@ -126,14 +116,10 @@ func (c *Canvas) EnsureMinSize() bool { parentNeedingUpdate = node.parent } else { windowNeedsMinSizeUpdate = true - c.RUnlock() size := obj.Size() - c.RLock() expectedSize := minSize.Max(size) if expectedSize != size && size != csize { - c.RUnlock() obj.Resize(expectedSize) - c.RLock() } else { c.updateLayout(obj) } @@ -144,9 +130,7 @@ func (c *Canvas) EnsureMinSize() bool { shouldResize := windowNeedsMinSizeUpdate && (csize.Width < min.Width || csize.Height < min.Height) if shouldResize { - c.RUnlock() c.impl.Resize(csize.Max(min)) - c.RLock() } return windowNeedsMinSizeUpdate } @@ -161,9 +145,7 @@ func (c *Canvas) Focus(obj fyne.Focusable) { return } - c.RLock() focusMgrs := append([]*app.FocusManager{c.contentFocusMgr, c.menuFocusMgr}, c.overlays.ListFocusManagers()...) - c.RUnlock() for _, mgr := range focusMgrs { if mgr == nil { @@ -305,7 +287,6 @@ func (c *Canvas) Initialize(impl SizeableCanvas, onOverlayChanged func()) { // // This function uses lock. func (c *Canvas) ObjectTrees() []fyne.CanvasObject { - c.RLock() var content, menu fyne.CanvasObject if c.contentTree != nil && c.contentTree.root != nil { content = c.contentTree.root.obj @@ -313,7 +294,6 @@ func (c *Canvas) ObjectTrees() []fyne.CanvasObject { if c.menuTree != nil && c.menuTree.root != nil { menu = c.menuTree.root.obj } - c.RUnlock() trees := make([]fyne.CanvasObject, 0, len(c.Overlays().List())+2) trees = append(trees, content) if menu != nil { @@ -434,8 +414,6 @@ func (c *Canvas) focusManager() *app.FocusManager { if focusMgr := c.overlays.TopFocusManager(); focusMgr != nil { return focusMgr } - c.RLock() - defer c.RUnlock() if c.isMenuActive() { return c.menuFocusMgr } @@ -580,14 +558,10 @@ func (c *Canvas) updateLayout(objToLayout fyne.CanvasObject) { if cont.Layout != nil { layout := cont.Layout objects := cont.Objects - c.RUnlock() layout.Layout(objects, cont.Size()) - c.RLock() } case fyne.Widget: renderer := cache.Renderer(cont) - c.RUnlock() renderer.Layout(cont.Size()) - c.RLock() } } diff --git a/internal/driver/glfw/canvas.go b/internal/driver/glfw/canvas.go index f7dbcbe193..5080f2008b 100644 --- a/internal/driver/glfw/canvas.go +++ b/internal/driver/glfw/canvas.go @@ -48,18 +48,12 @@ func (c *glCanvas) Capture() image.Image { } func (c *glCanvas) Content() fyne.CanvasObject { - c.RLock() - retval := c.content - c.RUnlock() - return retval + return c.content } func (c *glCanvas) DismissMenu() bool { - c.RLock() - menu := c.menu - c.RUnlock() - if menu != nil && menu.(*MenuBar).IsActive() { - menu.(*MenuBar).Toggle() + if c.menu != nil && c.menu.(*MenuBar).IsActive() { + c.menu.(*MenuBar).Toggle() return true } return false @@ -70,8 +64,6 @@ func (c *glCanvas) InteractiveArea() (fyne.Position, fyne.Size) { } func (c *glCanvas) MinSize() fyne.Size { - c.RLock() - defer c.RUnlock() return c.canvasSize(c.content.MinSize()) } @@ -96,11 +88,7 @@ func (c *glCanvas) Padded() bool { } func (c *glCanvas) PixelCoordinateForPosition(pos fyne.Position) (int, int) { - c.RLock() - texScale := c.texScale - scale := c.scale - c.RUnlock() - multiple := scale * texScale + multiple := c.scale * c.texScale scaleInt := func(x float32) int { return int(math.Round(float64(x * multiple))) } @@ -114,9 +102,7 @@ func (c *glCanvas) Resize(size fyne.Size) { // This can easily be seen with fyne/cmd/hello and a scale == 1 as the text will happear blurry without the following line. nearestSize := fyne.NewSize(float32(math.Ceil(float64(size.Width))), float32(math.Ceil(float64(size.Height)))) - c.Lock() c.size = nearestSize - c.Unlock() if c.webExtraWindows != nil { c.webExtraWindows.Resize(size) @@ -131,13 +117,11 @@ func (c *glCanvas) Resize(size fyne.Size) { } } - c.RLock() content := c.content contentSize := c.contentSize(nearestSize) contentPos := c.contentPos() menu := c.menu menuHeight := c.menuHeight() - c.RUnlock() content.Resize(contentSize) content.Move(contentPos) @@ -149,20 +133,16 @@ func (c *glCanvas) Resize(size fyne.Size) { } func (c *glCanvas) Scale() float32 { - c.RLock() - defer c.RUnlock() return c.scale } func (c *glCanvas) SetContent(content fyne.CanvasObject) { content.Resize(content.MinSize()) // give it the space it wants then calculate the real min - c.Lock() // the pass above makes some layouts wide enough to wrap, so we ask again what the true min is. newSize := c.size.Max(c.canvasSize(content.MinSize())) c.setContent(content) - c.Unlock() c.Resize(newSize) c.SetDirty() @@ -185,50 +165,35 @@ func (c *glCanvas) SetOnTypedRune(typed func(rune)) { } func (c *glCanvas) SetPadded(padded bool) { - c.Lock() - content := c.content c.padded = padded - pos := c.contentPos() - c.Unlock() - content.Move(pos) + c.content.Move(c.contentPos()) } func (c *glCanvas) reloadScale() { w := c.context.(*window) - w.viewLock.RLock() windowVisible := w.visible - w.viewLock.RUnlock() if !windowVisible { return } - c.Lock() c.scale = w.calculatedScale() - c.Unlock() c.SetDirty() c.context.RescaleContext() } func (c *glCanvas) Size() fyne.Size { - c.RLock() - defer c.RUnlock() return c.size } func (c *glCanvas) ToggleMenu() { - c.RLock() - menu := c.menu - c.RUnlock() - if menu != nil { - menu.(*MenuBar).Toggle() + if c.menu != nil { + c.menu.(*MenuBar).Toggle() } } func (c *glCanvas) buildMenu(w *window, m *fyne.MainMenu) { - c.Lock() - defer c.Unlock() c.setMenuOverlay(nil) if m == nil { return @@ -331,15 +296,11 @@ func (c *glCanvas) setMenuOverlay(b fyne.CanvasObject) { } func (c *glCanvas) applyThemeOutOfTreeObjects() { - c.RLock() - menu := c.menu - padded := c.padded - c.RUnlock() - if menu != nil { - app.ApplyThemeTo(menu, c) // Ensure our menu gets the theme change message as it's out-of-tree + if c.menu != nil { + app.ApplyThemeTo(c.menu, c) // Ensure our menu gets the theme change message as it's out-of-tree } - c.SetPadded(padded) // refresh the padding for potential theme differences + c.SetPadded(c.padded) // refresh the padding for potential theme differences } func newCanvas() *glCanvas { diff --git a/internal/driver/glfw/loop.go b/internal/driver/glfw/loop.go index 8bcc8b68cf..ca51b0bd9f 100644 --- a/internal/driver/glfw/loop.go +++ b/internal/driver/glfw/loop.go @@ -63,11 +63,9 @@ var refreshingCanvases []fyne.Canvas func (d *gLDriver) drawSingleFrame() { for _, win := range d.windowList() { w := win.(*window) - w.viewLock.RLock() canvas := w.canvas closing := w.closing visible := w.visible - w.viewLock.RUnlock() // CheckDirtyAndClear must be checked after visibility, // because when a window becomes visible, it could be @@ -135,18 +133,15 @@ func (d *gLDriver) runGL() { continue } - w.viewLock.RLock() expand := w.shouldExpand fullScreen := w.fullScreen - w.viewLock.RUnlock() if expand && !fullScreen { w.fitContent() - w.viewLock.Lock() shouldExpand := w.shouldExpand w.shouldExpand = false view := w.viewport - w.viewLock.Unlock() + if shouldExpand && runtime.GOOS != "js" { view.SetSize(w.shouldWidth, w.shouldHeight) } @@ -166,10 +161,8 @@ func (d *gLDriver) runGL() { } if w.viewport.ShouldClose() { - w.viewLock.Lock() w.visible = false v := w.viewport - w.viewLock.Unlock() // remove window from window list v.Destroy() @@ -208,19 +201,15 @@ func (d *gLDriver) repaintWindow(w *window) { canvas := w.canvas w.RunWithContext(func() { if canvas.EnsureMinSize() { - w.viewLock.Lock() w.shouldExpand = true - w.viewLock.Unlock() } canvas.FreeDirtyTextures() updateGLContext(w) canvas.paint(canvas.Size()) - w.viewLock.RLock() view := w.viewport visible := w.visible - w.viewLock.RUnlock() if view != nil && visible { view.SwapBuffers() diff --git a/internal/driver/glfw/window.go b/internal/driver/glfw/window.go index b0302448d3..08e04eae9b 100644 --- a/internal/driver/glfw/window.go +++ b/internal/driver/glfw/window.go @@ -56,14 +56,12 @@ func (w *window) Resize(size fyne.Size) { // we cannot perform this until window is prepared as we don't know its scale! bigEnough := size.Max(w.canvas.canvasSize(w.canvas.Content().MinSize())) w.runOnMainWhenCreated(func() { - w.viewLock.Lock() - width, height := scale.ToScreenCoordinate(w.canvas, bigEnough.Width), scale.ToScreenCoordinate(w.canvas, bigEnough.Height) if w.fixedSize || !w.visible { // fixed size ignores future `resized` and if not visible we may not get the event w.shouldWidth, w.shouldHeight = width, height w.width, w.height = width, height } - w.viewLock.Unlock() + w.requestedWidth, w.requestedHeight = width, height if runtime.GOOS != "js" { w.view().SetSize(width, height) @@ -148,9 +146,7 @@ func (w *window) doShow() { } runOnMain(func() { - w.viewLock.Lock() w.visible = true - w.viewLock.Unlock() view := w.view() view.SetTitle(w.title) @@ -184,15 +180,12 @@ func (w *window) doShow() { func (w *window) Hide() { runOnMain(func() { - w.viewLock.Lock() if w.closing || w.viewport == nil { - w.viewLock.Unlock() return } w.visible = false v := w.viewport - w.viewLock.Unlock() v.Hide() @@ -215,9 +208,7 @@ func (w *window) Close() { // set w.closing flag inside draw thread to ensure we can free textures runOnMainWithContext(w, func() { - w.viewLock.Lock() w.closing = true - w.viewLock.Unlock() w.viewport.SetShouldClose(true) cache.RangeTexturesFor(w.canvas, w.canvas.Painter().Free) @@ -245,9 +236,7 @@ func (w *window) Content() fyne.CanvasObject { } func (w *window) SetContent(content fyne.CanvasObject) { - w.viewLock.RLock() visible := w.visible - w.viewLock.RUnlock() // hide old canvas element if visible && w.canvas.Content() != nil { w.canvas.Content().Hide() @@ -329,13 +318,8 @@ func (w *window) processFrameSized(width, height int) { winWidth, _ := w.view().GetSize() newTexScale := float32(width) / float32(winWidth) // This will be > 1.0 on a HiDPI screen - w.canvas.RLock() - texScale := w.canvas.texScale - w.canvas.RUnlock() - if texScale != newTexScale { - w.canvas.Lock() + if w.canvas.texScale != newTexScale { w.canvas.texScale = newTexScale - w.canvas.Unlock() w.canvas.Refresh(w.canvas.Content()) // reset graphics to apply texture scale } } @@ -349,14 +333,12 @@ func (w *window) findObjectAtPositionMatching(canvas *glCanvas, mouse fyne.Posit } func (w *window) processMouseMoved(xpos float64, ypos float64) { - w.mouseLock.Lock() previousPos := w.mousePos w.mousePos = fyne.NewPos(scale.ToFyneCoordinate(w.canvas, int(xpos)), scale.ToFyneCoordinate(w.canvas, int(ypos))) mousePos := w.mousePos mouseButton := w.mouseButton mouseDragPos := w.mouseDragPos mouseOver := w.mouseOver - w.mouseLock.Unlock() cursor := desktop.Cursor(desktop.DefaultCursor) @@ -394,20 +376,14 @@ func (w *window) processMouseMoved(xpos float64, ypos float64) { overThreshold := math.Abs(float64(deltaX)) >= dragMoveThreshold || math.Abs(float64(deltaY)) >= dragMoveThreshold if wid, ok := obj.(fyne.Draggable); ok && overThreshold { - w.mouseLock.Lock() w.mouseDragged = wid w.mouseDraggedOffset = previousPos.Subtract(pos) w.mouseDraggedObjStart = obj.Position() w.mouseDragStarted = true - w.mouseLock.Unlock() } } - w.mouseLock.RLock() - isObjDragged := w.objIsDragged(obj) - isMouseOverDragged := w.objIsDragged(mouseOver) - w.mouseLock.RUnlock() - if obj != nil && !isObjDragged { + if obj != nil && !w.objIsDragged(obj) { ev := &desktop.MouseEvent{Button: mouseButton} ev.AbsolutePosition = mousePos ev.Position = pos @@ -433,32 +409,25 @@ func (w *window) processMouseMoved(xpos float64, ypos float64) { w.mouseOut() } } - } else if mouseOver != nil && !isMouseOverDragged { + } else if mouseOver != nil && !w.objIsDragged(mouseOver) { w.mouseOut() } - w.mouseLock.RLock() - mouseButton = w.mouseButton mouseDragged := w.mouseDragged - mouseDraggedObjStart := w.mouseDraggedObjStart - mouseDraggedOffset := w.mouseDraggedOffset mouseDragPos = w.mouseDragPos - w.mouseLock.RUnlock() - if mouseDragged != nil && mouseButton != desktop.MouseButtonSecondary { + if mouseDragged != nil && w.mouseButton != desktop.MouseButtonSecondary { if w.mouseButton > 0 { - draggedObjDelta := mouseDraggedObjStart.Subtract(mouseDragged.(fyne.CanvasObject).Position()) + draggedObjDelta := w.mouseDraggedObjStart.Subtract(mouseDragged.(fyne.CanvasObject).Position()) ev := &fyne.DragEvent{} ev.AbsolutePosition = mousePos - ev.Position = mousePos.Subtract(mouseDraggedOffset).Add(draggedObjDelta) + ev.Position = mousePos.Subtract(w.mouseDraggedOffset).Add(draggedObjDelta) ev.Dragged = fyne.NewDelta(mousePos.X-mouseDragPos.X, mousePos.Y-mouseDragPos.Y) wd := mouseDragged w.QueueEvent(func() { wd.Dragged(ev) }) } - w.mouseLock.Lock() w.mouseDragStarted = true w.mouseDragPos = mousePos - w.mouseLock.Unlock() } } @@ -475,38 +444,28 @@ func (w *window) mouseIn(obj desktop.Hoverable, ev *desktop.MouseEvent) { if obj != nil { obj.MouseIn(ev) } - w.mouseLock.Lock() w.mouseOver = obj - w.mouseLock.Unlock() }) } func (w *window) mouseOut() { w.QueueEvent(func() { - w.mouseLock.RLock() mouseOver := w.mouseOver - w.mouseLock.RUnlock() if mouseOver != nil { mouseOver.MouseOut() - w.mouseLock.Lock() w.mouseOver = nil - w.mouseLock.Unlock() } }) } func (w *window) processMouseClicked(button desktop.MouseButton, action action, modifiers fyne.KeyModifier) { - w.mouseLock.RLock() w.mouseDragPos = w.mousePos mousePos := w.mousePos mouseDragStarted := w.mouseDragStarted - w.mouseLock.RUnlock() if mousePos.IsZero() { // window may not be focused (darwin mostly) and so position callbacks not happening xpos, ypos := w.view().GetCursorPos() - w.mouseLock.Lock() w.mousePos = fyne.NewPos(scale.ToFyneCoordinate(w.canvas, int(xpos)), scale.ToFyneCoordinate(w.canvas, int(ypos))) mousePos = w.mousePos - w.mouseLock.Unlock() } co, pos, _ := w.findObjectAtPositionMatching(w.canvas, mousePos, func(object fyne.CanvasObject) bool { @@ -554,7 +513,6 @@ func (w *window) processMouseClicked(button desktop.MouseButton, action action, } } - w.mouseLock.Lock() if action == press { w.mouseButton |= button } else if action == release { @@ -566,30 +524,23 @@ func (w *window) processMouseClicked(button desktop.MouseButton, action action, mouseOver := w.mouseOver shouldMouseOut := w.objIsDragged(mouseOver) && !w.objIsDragged(coMouse) mousePressed := w.mousePressed - w.mouseLock.Unlock() if action == release && mouseDragged != nil { if mouseDragStarted { w.QueueEvent(mouseDragged.DragEnd) - w.mouseLock.Lock() w.mouseDragStarted = false - w.mouseLock.Unlock() } if shouldMouseOut { w.mouseOut() } - w.mouseLock.Lock() w.mouseDragged = nil - w.mouseLock.Unlock() } _, tap := co.(fyne.Tappable) secondary, altTap := co.(fyne.SecondaryTappable) if tap || altTap { if action == press { - w.mouseLock.Lock() w.mousePressed = co - w.mouseLock.Unlock() } else if action == release { if co == mousePressed { if button == desktop.MouseButtonSecondary && altTap { @@ -610,10 +561,8 @@ func (w *window) mouseClickedHandleMouseable(mev *desktop.MouseEvent, action act if action == press { w.QueueEvent(func() { wid.MouseDown(mev) }) } else if action == release { - w.mouseLock.RLock() mouseDragged := w.mouseDragged mouseDraggedOffset := w.mouseDraggedOffset - w.mouseLock.RUnlock() if mouseDragged == nil { w.QueueEvent(func() { wid.MouseUp(mev) }) } else { @@ -630,38 +579,29 @@ func (w *window) mouseClickedHandleMouseable(mev *desktop.MouseEvent, action act func (w *window) mouseClickedHandleTapDoubleTap(co fyne.CanvasObject, ev *fyne.PointEvent) { _, doubleTap := co.(fyne.DoubleTappable) if doubleTap { - w.mouseLock.Lock() w.mouseClickCount++ w.mouseLastClick = co mouseCancelFunc := w.mouseCancelFunc - w.mouseLock.Unlock() if mouseCancelFunc != nil { mouseCancelFunc() return } go w.waitForDoubleTap(co, ev) } else { - w.mouseLock.Lock() if wid, ok := co.(fyne.Tappable); ok && co == w.mousePressed { w.QueueEvent(func() { wid.Tapped(ev) }) } w.mousePressed = nil - w.mouseLock.Unlock() } } func (w *window) waitForDoubleTap(co fyne.CanvasObject, ev *fyne.PointEvent) { var ctx context.Context - w.mouseLock.Lock() ctx, w.mouseCancelFunc = context.WithDeadline(context.TODO(), time.Now().Add(w.driver.DoubleTapDelay())) defer w.mouseCancelFunc() - w.mouseLock.Unlock() <-ctx.Done() - w.mouseLock.Lock() - defer w.mouseLock.Unlock() - if w.mouseClickCount == 2 && w.mouseLastClick == co { if wid, ok := co.(fyne.DoubleTappable); ok { w.QueueEvent(func() { wid.DoubleTapped(ev) }) @@ -679,9 +619,7 @@ func (w *window) waitForDoubleTap(co fyne.CanvasObject, ev *fyne.PointEvent) { } func (w *window) processMouseScrolled(xoff float64, yoff float64) { - w.mouseLock.RLock() mousePos := w.mousePos - w.mouseLock.RUnlock() co, pos, _ := w.findObjectAtPositionMatching(w.canvas, mousePos, func(object fyne.CanvasObject) bool { _, ok := object.(fyne.Scrollable) return ok @@ -812,9 +750,7 @@ func (w *window) processFocused(focus bool) { w.QueueEvent(w.canvas.FocusGained) } else { w.QueueEvent(w.canvas.FocusLost) - w.mouseLock.Lock() w.mousePos = fyne.Position{} - w.mouseLock.Unlock() go func() { // check whether another window was focused or not time.Sleep(time.Millisecond * 100) @@ -1019,16 +955,12 @@ func (w *window) doShowAgain() { view.SetPos(w.xpos, w.ypos) } view.Show() - w.viewLock.Lock() w.visible = true - w.viewLock.Unlock() }) } func (w *window) isClosing() bool { - w.viewLock.RLock() closing := w.closing || w.viewport == nil - w.viewLock.RUnlock() return closing } diff --git a/internal/driver/glfw/window_desktop.go b/internal/driver/glfw/window_desktop.go index 0be26422a1..b9dca89968 100644 --- a/internal/driver/glfw/window_desktop.go +++ b/internal/driver/glfw/window_desktop.go @@ -64,7 +64,6 @@ type window struct { common.Window viewport *glfw.Window - viewLock sync.RWMutex createLock sync.Once decorate bool closing bool @@ -83,7 +82,6 @@ type window struct { centered bool visible bool - mouseLock sync.RWMutex mousePos fyne.Position mouseDragged fyne.Draggable mouseDraggedObjStart fyne.Position @@ -246,9 +244,7 @@ func (w *window) fitContent() { } minWidth, minHeight := w.minSizeOnScreen() - w.viewLock.RLock() view := w.viewport - w.viewLock.RUnlock() w.shouldWidth, w.shouldHeight = w.width, w.height if w.width < minWidth || w.height < minHeight { if w.width < minWidth { @@ -257,9 +253,7 @@ func (w *window) fitContent() { if w.height < minHeight { w.shouldHeight = minHeight } - w.viewLock.Lock() w.shouldExpand = true // queue the resize to happen on main - w.viewLock.Unlock() } if w.fixedSize { if w.shouldWidth > w.requestedWidth { @@ -750,9 +744,7 @@ func (w *window) create() { return } - w.viewLock.Lock() w.viewport = win - w.viewLock.Unlock() }) if w.view() == nil { // something went wrong above, it will have been logged return @@ -804,9 +796,6 @@ func (w *window) create() { } func (w *window) view() *glfw.Window { - w.viewLock.RLock() - defer w.viewLock.RUnlock() - if w.closing { return nil } From 48373567db24ef765928b283515b98269ce95a9f Mon Sep 17 00:00:00 2001 From: Andy Williams Date: Mon, 16 Dec 2024 19:45:24 +0000 Subject: [PATCH 3/9] Remove internal property lock from base widget too --- widget/accordion.go | 30 --------- widget/button.go | 12 ---- widget/check.go | 14 +--- widget/check_group.go | 4 -- widget/entry.go | 122 +--------------------------------- widget/entry_password.go | 2 - widget/entry_validation.go | 2 - widget/fileicon.go | 9 --- widget/hyperlink.go | 17 ----- widget/icon.go | 4 -- widget/label.go | 5 -- widget/list.go | 7 -- widget/progressbarinfinite.go | 25 ------- widget/richtext.go | 20 +----- widget/select.go | 7 -- widget/table.go | 29 -------- widget/tree.go | 21 ------ widget/widget.go | 17 +---- 18 files changed, 5 insertions(+), 342 deletions(-) diff --git a/widget/accordion.go b/widget/accordion.go index a904ea55f8..9d617838cf 100644 --- a/widget/accordion.go +++ b/widget/accordion.go @@ -28,33 +28,26 @@ func NewAccordion(items ...*AccordionItem) *Accordion { // Append adds the given item to this Accordion. func (a *Accordion) Append(item *AccordionItem) { - a.propertyLock.Lock() a.Items = append(a.Items, item) - a.propertyLock.Unlock() a.Refresh() } // Close collapses the item at the given index. func (a *Accordion) Close(index int) { - a.propertyLock.Lock() if index < 0 || index >= len(a.Items) { - a.propertyLock.Unlock() return } a.Items[index].Open = false - a.propertyLock.Unlock() a.Refresh() } // CloseAll collapses all items. func (a *Accordion) CloseAll() { - a.propertyLock.Lock() for _, i := range a.Items { i.Open = false } - a.propertyLock.Unlock() a.Refresh() } @@ -75,10 +68,7 @@ func (a *Accordion) MinSize() fyne.Size { // Open expands the item at the given index. func (a *Accordion) Open(index int) { - a.propertyLock.Lock() - if index < 0 || index >= len(a.Items) { - a.propertyLock.Unlock() return } @@ -89,35 +79,27 @@ func (a *Accordion) Open(index int) { ai.Open = false } } - a.propertyLock.Unlock() a.Refresh() } // OpenAll expands all items. func (a *Accordion) OpenAll() { - a.propertyLock.RLock() multiOpen := a.MultiOpen - a.propertyLock.RUnlock() if !multiOpen { return } - a.propertyLock.Lock() for _, i := range a.Items { i.Open = true } - a.propertyLock.Unlock() a.Refresh() } // Remove deletes the given item from this Accordion. func (a *Accordion) Remove(item *AccordionItem) { - a.propertyLock.Lock() - defer a.propertyLock.Unlock() - for i, ai := range a.Items { if ai == item { a.Items = append(a.Items[:i], a.Items[i+1:]...) @@ -128,13 +110,10 @@ func (a *Accordion) Remove(item *AccordionItem) { // RemoveIndex deletes the item at the given index from this Accordion. func (a *Accordion) RemoveIndex(index int) { - a.propertyLock.Lock() if index < 0 || index >= len(a.Items) { - a.propertyLock.Unlock() return } a.Items = append(a.Items[:index], a.Items[index+1:]...) - a.propertyLock.Unlock() a.Refresh() } @@ -155,9 +134,6 @@ func (r *accordionRenderer) Layout(size fyne.Size) { y := float32(0) hasOpen := 0 - r.container.propertyLock.RLock() - defer r.container.propertyLock.RUnlock() - for i, ai := range r.container.Items { h := r.headers[i] min := h.MinSize().Height @@ -206,9 +182,6 @@ func (r *accordionRenderer) MinSize() fyne.Size { pad := th.Size(theme.SizeNamePadding) size := fyne.Size{} - r.container.propertyLock.RLock() - defer r.container.propertyLock.RUnlock() - for i, ai := range r.container.Items { if i != 0 { size.Height += pad @@ -234,9 +207,6 @@ func (r *accordionRenderer) Refresh() { } func (r *accordionRenderer) updateObjects() { - r.container.propertyLock.RLock() - defer r.container.propertyLock.RUnlock() - th := r.container.themeWithLock() is := len(r.container.Items) hs := len(r.headers) diff --git a/widget/button.go b/widget/button.go index c508bc0013..eea6fca21d 100644 --- a/widget/button.go +++ b/widget/button.go @@ -94,9 +94,6 @@ func (b *Button) CreateRenderer() fyne.WidgetRenderer { th := b.Theme() v := fyne.CurrentApp().Settings().ThemeVariant() - b.propertyLock.RLock() - defer b.propertyLock.RUnlock() - seg := &TextSegment{Text: b.Text, Style: RichTextStyleStrong} seg.Style.Alignment = fyne.TextAlignCenter text := NewRichText(seg) @@ -166,18 +163,14 @@ func (b *Button) MouseOut() { // SetIcon updates the icon on a label - pass nil to hide an icon func (b *Button) SetIcon(icon fyne.Resource) { - b.propertyLock.Lock() b.Icon = icon - b.propertyLock.Unlock() b.Refresh() } // SetText allows the button label to be changed func (b *Button) SetText(text string) { - b.propertyLock.Lock() b.Text = text - b.propertyLock.Unlock() b.Refresh() } @@ -245,9 +238,6 @@ func (r *buttonRenderer) Layout(size fyne.Size) { iconSize := fyne.NewSquareSize(th.Size(theme.SizeNameInlineIcon)) labelSize := r.label.MinSize() - r.button.propertyLock.RLock() - defer r.button.propertyLock.RUnlock() - if hasLabel { if hasIcon { // Both @@ -303,11 +293,9 @@ func (r *buttonRenderer) Refresh() { th := r.button.Theme() r.label.inset = fyne.NewSquareSize(th.Size(theme.SizeNameInnerPadding)) - r.button.propertyLock.RLock() r.label.Segments[0].(*TextSegment).Text = r.button.Text r.updateIconAndText() r.applyTheme() - r.button.propertyLock.RUnlock() r.background.Refresh() r.Layout(r.button.Size()) diff --git a/widget/check.go b/widget/check.go index ef57bd4d21..3466b71cfc 100644 --- a/widget/check.go +++ b/widget/check.go @@ -73,16 +73,13 @@ func (c *Check) Bind(data binding.Bool) { // SetChecked sets the checked state and refreshes widget // If the `Partial` state is set this will be turned off to respect the `checked` bool passed in here. func (c *Check) SetChecked(checked bool) { - c.propertyLock.Lock() if checked == c.Checked && !c.Partial { - c.propertyLock.Unlock() return } c.Partial = false c.Checked = checked onChanged := c.OnChanged - c.propertyLock.Unlock() if onChanged != nil { onChanged(checked) @@ -169,8 +166,6 @@ func (c *Check) CreateRenderer() fyne.WidgetRenderer { bg := canvas.NewImageFromResource(th.Icon(theme.IconNameCheckButtonFill)) icon := canvas.NewImageFromResource(th.Icon(theme.IconNameCheckButton)) - c.propertyLock.RLock() - defer c.propertyLock.RUnlock() text := canvas.NewText(c.Text, th.Color(theme.ColorNameForeground, v)) text.Alignment = fyne.TextAlignLeading @@ -224,9 +219,7 @@ func (c *Check) TypedKey(key *fyne.KeyEvent) {} // // Since: 2.4 func (c *Check) SetText(text string) { - c.propertyLock.Lock() c.Text = text - c.propertyLock.Unlock() c.Refresh() } @@ -291,10 +284,7 @@ func (c *checkRenderer) MinSize() fyne.Size { pad4 := th.Size(theme.SizeNameInnerPadding) * 2 min := c.label.MinSize().Add(fyne.NewSize(th.Size(theme.SizeNameInlineIcon)+pad4, pad4)) - c.check.propertyLock.RLock() - text := c.check.Text - c.check.propertyLock.RUnlock() - if text != "" { + if c.check.Text != "" { min.Add(fyne.NewSize(th.Size(theme.SizeNamePadding), 0)) } @@ -338,12 +328,10 @@ func (c *checkRenderer) Refresh() { th := c.check.Theme() v := fyne.CurrentApp().Settings().ThemeVariant() - c.check.propertyLock.RLock() c.applyTheme(th, v) c.updateLabel() c.updateResource(th) c.updateFocusIndicator(th, v) - c.check.propertyLock.RUnlock() canvas.Refresh(c.check.super()) } diff --git a/widget/check_group.go b/widget/check_group.go index e2725b35ed..5c9c5764db 100644 --- a/widget/check_group.go +++ b/widget/check_group.go @@ -48,8 +48,6 @@ func (r *CheckGroup) Append(option string) { // CreateRenderer is a private method to Fyne which links this widget to its renderer func (r *CheckGroup) CreateRenderer() fyne.WidgetRenderer { r.ExtendBaseWidget(r) - r.propertyLock.Lock() - defer r.propertyLock.Unlock() r.update() objects := make([]fyne.CanvasObject, len(r.items)) @@ -70,9 +68,7 @@ func (r *CheckGroup) MinSize() fyne.Size { // // Implements: fyne.CanvasObject func (r *CheckGroup) Refresh() { - r.propertyLock.Lock() r.update() - r.propertyLock.Unlock() r.BaseWidget.Refresh() } diff --git a/widget/entry.go b/widget/entry.go index 0f6b6198ba..ea732543dd 100644 --- a/widget/entry.go +++ b/widget/entry.go @@ -266,12 +266,10 @@ func (e *Entry) isTripleTap(nowMilli int64) bool { // // Implements: fyne.Draggable func (e *Entry) DragEnd() { - e.propertyLock.Lock() if e.CursorColumn == e.selectColumn && e.CursorRow == e.selectRow { e.selecting = false } shouldRefresh := !e.selecting - e.propertyLock.Unlock() if shouldRefresh { e.Refresh() } @@ -307,9 +305,7 @@ func (e *Entry) ExtendBaseWidget(wid fyne.Widget) { e.impl.Store(&wid) - e.propertyLock.Lock() e.registerShortcut() - e.propertyLock.Unlock() } // FocusGained is called when the Entry has been given focus. @@ -353,9 +349,6 @@ func (e *Entry) Hide() { // // Implements: mobile.Keyboardable func (e *Entry) Keyboard() mobile.KeyboardType { - e.propertyLock.RLock() - defer e.propertyLock.RUnlock() - if e.MultiLine { return mobile.DefaultKeyboard } else if e.Password { @@ -402,9 +395,7 @@ func (e *Entry) KeyUp(key *fyne.KeyEvent) { // // Implements: fyne.Widget func (e *Entry) MinSize() fyne.Size { - e.propertyLock.RLock() cached := e.minCache - e.propertyLock.RUnlock() if !cached.IsZero() { return cached } @@ -412,9 +403,7 @@ func (e *Entry) MinSize() fyne.Size { e.ExtendBaseWidget(e) min := e.BaseWidget.MinSize() - e.propertyLock.Lock() e.minCache = min - e.propertyLock.Unlock() return min } @@ -427,14 +416,12 @@ func (e *Entry) MouseDown(m *desktop.MouseEvent) { e.selectCurrentRow() return } - e.propertyLock.Lock() if e.selectKeyDown { e.selecting = true } if e.selecting && !e.selectKeyDown && m.Button == desktop.MouseButtonPrimary { e.selecting = false } - e.propertyLock.Unlock() e.updateMousePointer(m.Position, m.Button == desktop.MouseButtonSecondary) @@ -449,9 +436,6 @@ func (e *Entry) MouseDown(m *desktop.MouseEvent) { // // Implements: desktop.Mouseable func (e *Entry) MouseUp(m *desktop.MouseEvent) { - e.propertyLock.Lock() - defer e.propertyLock.Unlock() - start, _ := e.selection() if start == -1 && e.selecting && !e.selectKeyDown { e.selecting = false @@ -462,9 +446,7 @@ func (e *Entry) MouseUp(m *desktop.MouseEvent) { // // Since: 2.5 func (e *Entry) Redo() { - e.propertyLock.Lock() newText, action := e.undoStack.Redo(e.Text) - e.propertyLock.Unlock() modify, ok := action.(*entryModifyAction) if !ok { return @@ -473,17 +455,13 @@ func (e *Entry) Redo() { if !modify.Delete { pos += len(modify.Text) } - e.propertyLock.Lock() e.updateText(newText, false) e.CursorRow, e.CursorColumn = e.rowColFromTextPos(pos) - e.propertyLock.Unlock() e.Refresh() } func (e *Entry) Refresh() { - e.propertyLock.Lock() e.minCache = fyne.Size{} - e.propertyLock.Unlock() e.BaseWidget.Refresh() } @@ -491,9 +469,6 @@ func (e *Entry) Refresh() { // SelectedText returns the text currently selected in this Entry. // If there is no selection it will return the empty string. func (e *Entry) SelectedText() string { - e.propertyLock.RLock() - defer e.propertyLock.RUnlock() - if !e.selecting { return "" } @@ -521,9 +496,7 @@ func (e *Entry) SetMinRowsVisible(count int) { func (e *Entry) SetPlaceHolder(text string) { e.Theme() // setup theme cache before locking - e.propertyLock.Lock() e.PlaceHolder = text - e.propertyLock.Unlock() e.placeholderProvider().Segments[0].(*TextSegment).Text = text e.placeholder.updateRowBounds() @@ -541,23 +514,19 @@ func (e *Entry) setText(text string, fromBinding bool) { e.updateTextAndRefresh(text, fromBinding) e.updateCursorAndSelection() - e.propertyLock.Lock() e.undoStack.Clear() - e.propertyLock.Unlock() } // Append appends the text to the end of the entry. // // Since: 2.4 func (e *Entry) Append(text string) { - e.propertyLock.Lock() provider := e.textProvider() provider.insertAt(provider.len(), []rune(text)) content := provider.String() changed := e.updateText(content, false) cb := e.OnChanged e.undoStack.Clear() - e.propertyLock.Unlock() if changed { e.validate() @@ -616,9 +585,7 @@ func (e *Entry) TappedSecondary(pe *fyne.PointEvent) { menu = fyne.NewMenu("", pasteItem, selectAllItem) } else { var menuItems []*fyne.MenuItem - e.propertyLock.Lock() canUndo, canRedo := e.undoStack.CanUndo(), e.undoStack.CanRedo() - e.propertyLock.Unlock() if canUndo { menuItems = append(menuItems, undoItem) } @@ -680,10 +647,8 @@ func (e *Entry) TypedKey(key *fyne.KeyEvent) { if e.cursorAnim != nil { e.cursorAnim.interrupt() } - e.propertyLock.RLock() provider := e.textProvider() multiLine := e.MultiLine - e.propertyLock.RUnlock() if e.selectKeyDown || e.selecting { if e.selectingKeyHandler(key) { @@ -694,14 +659,11 @@ func (e *Entry) TypedKey(key *fyne.KeyEvent) { switch key.Name { case fyne.KeyBackspace: - e.propertyLock.RLock() isEmpty := provider.len() == 0 || (e.CursorColumn == 0 && e.CursorRow == 0) - e.propertyLock.RUnlock() if isEmpty { return } - e.propertyLock.Lock() pos := e.cursorTextPos() deletedText := provider.deleteFromTo(pos-1, pos) e.CursorRow, e.CursorColumn = e.rowColFromTextPos(pos - 1) @@ -710,21 +672,18 @@ func (e *Entry) TypedKey(key *fyne.KeyEvent) { Position: pos - 1, Text: deletedText, }) - e.propertyLock.Unlock() case fyne.KeyDelete: pos := e.cursorTextPos() if provider.len() == 0 || pos == provider.len() { return } - e.propertyLock.Lock() deletedText := provider.deleteFromTo(pos, pos+1) e.undoStack.MergeOrAdd(&entryModifyAction{ Delete: true, Position: pos, Text: deletedText, }) - e.propertyLock.Unlock() case fyne.KeyReturn, fyne.KeyEnter: e.typedKeyReturn(provider, multiLine) case fyne.KeyTab: @@ -742,33 +701,27 @@ func (e *Entry) TypedKey(key *fyne.KeyEvent) { case fyne.KeyHome: e.typedKeyHome() case fyne.KeyPageUp: - e.propertyLock.Lock() if e.MultiLine { e.CursorRow = 0 } e.CursorColumn = 0 - e.propertyLock.Unlock() case fyne.KeyPageDown: - e.propertyLock.Lock() if e.MultiLine { e.CursorRow = provider.rows() - 1 e.CursorColumn = provider.rowLength(e.CursorRow) } else { e.CursorColumn = provider.len() } - e.propertyLock.Unlock() default: return } - e.propertyLock.Lock() content := provider.String() changed := e.updateText(content, false) if e.CursorRow == e.selectRow && e.CursorColumn == e.selectColumn { e.selecting = false } cb := e.OnChanged - e.propertyLock.Unlock() if changed { e.validate() if cb != nil { @@ -782,9 +735,7 @@ func (e *Entry) TypedKey(key *fyne.KeyEvent) { // // Since: 2.5 func (e *Entry) Undo() { - e.propertyLock.Lock() newText, action := e.undoStack.Undo(e.Text) - e.propertyLock.Unlock() modify, ok := action.(*entryModifyAction) if !ok { return @@ -793,16 +744,12 @@ func (e *Entry) Undo() { if modify.Delete { pos += len(modify.Text) } - e.propertyLock.Lock() e.updateText(newText, false) e.CursorRow, e.CursorColumn = e.rowColFromTextPos(pos) - e.propertyLock.Unlock() e.Refresh() } func (e *Entry) typedKeyUp(provider *RichText) { - e.propertyLock.Lock() - if e.CursorRow > 0 { e.CursorRow-- } else { @@ -813,11 +760,9 @@ func (e *Entry) typedKeyUp(provider *RichText) { if e.CursorColumn > rowLength { e.CursorColumn = rowLength } - e.propertyLock.Unlock() } func (e *Entry) typedKeyDown(provider *RichText) { - e.propertyLock.Lock() rowLength := provider.rowLength(e.CursorRow) if e.CursorRow < provider.rows()-1 { @@ -830,22 +775,18 @@ func (e *Entry) typedKeyDown(provider *RichText) { if e.CursorColumn > rowLength { e.CursorColumn = rowLength } - e.propertyLock.Unlock() } func (e *Entry) typedKeyLeft(provider *RichText) { - e.propertyLock.Lock() if e.CursorColumn > 0 { e.CursorColumn-- } else if e.MultiLine && e.CursorRow > 0 { e.CursorRow-- e.CursorColumn = provider.rowLength(e.CursorRow) } - e.propertyLock.Unlock() } func (e *Entry) typedKeyRight(provider *RichText) { - e.propertyLock.Lock() if e.MultiLine { rowLength := provider.rowLength(e.CursorRow) if e.CursorColumn < rowLength { @@ -857,23 +798,18 @@ func (e *Entry) typedKeyRight(provider *RichText) { } else if e.CursorColumn < provider.len() { e.CursorColumn++ } - e.propertyLock.Unlock() } func (e *Entry) typedKeyHome() { - e.propertyLock.Lock() e.CursorColumn = 0 - e.propertyLock.Unlock() } func (e *Entry) typedKeyEnd(provider *RichText) { - e.propertyLock.Lock() if e.MultiLine { e.CursorColumn = provider.rowLength(e.CursorRow) } else { e.CursorColumn = provider.len() } - e.propertyLock.Unlock() } // handler for Ctrl+[backspace/delete] - delete the word @@ -924,7 +860,6 @@ func (e *Entry) TypedRune(r rune) { return } - e.propertyLock.Lock() if e.popUp != nil { e.popUp.Hide() } @@ -949,7 +884,6 @@ func (e *Entry) TypedRune(r rune) { Position: pos, Text: runes, }) - e.propertyLock.Unlock() e.validate() if cb != nil { @@ -1012,11 +946,9 @@ func (e *Entry) cutToClipboard(clipboard fyne.Clipboard) { } e.copyToClipboard(clipboard) - e.propertyLock.Lock() e.eraseSelectionAndUpdate() content := e.Text cb := e.OnChanged - e.propertyLock.Unlock() e.validate() if cb != nil { @@ -1063,8 +995,6 @@ func (e *Entry) eraseSelectionAndUpdate() { func (e *Entry) getRowCol(p fyne.Position) (int, int) { th := e.Theme() textSize := th.Size(theme.SizeNameText) - e.propertyLock.RLock() - defer e.propertyLock.RUnlock() rowHeight := e.textProvider().charMinSize(e.Password, e.TextStyle, textSize).Height row := int(math.Floor(float64(p.Y+e.scroll.Offset.Y-th.Size(theme.SizeNameLineSpacing)) / float64(rowHeight))) @@ -1086,9 +1016,7 @@ func (e *Entry) getRowCol(p fyne.Position) (int, int) { func (e *Entry) pasteFromClipboard(clipboard fyne.Clipboard) { text := clipboard.Content() if text == "" { - e.propertyLock.Lock() changed := e.selecting && e.eraseSelection() - e.propertyLock.Unlock() if changed { e.Refresh() @@ -1102,7 +1030,6 @@ func (e *Entry) pasteFromClipboard(clipboard fyne.Clipboard) { text = strings.Replace(text, "\n", " ", -1) } - e.propertyLock.Lock() if e.selecting { e.eraseSelection() } @@ -1120,7 +1047,6 @@ func (e *Entry) pasteFromClipboard(clipboard fyne.Clipboard) { e.updateText(content, false) e.CursorRow, e.CursorColumn = e.rowColFromTextPos(pos + len(runes)) cb := e.OnChanged - e.propertyLock.Unlock() e.validate() if cb != nil { @@ -1228,10 +1154,7 @@ func (e *Entry) registerShortcut() { if s.(*desktop.CustomShortcut).KeyName == fyne.KeyLeft { e.typedKeyHome() } else { - e.propertyLock.RLock() - provider := e.textProvider() - e.propertyLock.RUnlock() - e.typedKeyEnd(provider) + e.typedKeyEnd(e.textProvider()) } e.Refresh() } @@ -1322,11 +1245,9 @@ func (e *Entry) selectingKeyHandler(key *fyne.KeyEvent) bool { switch key.Name { case fyne.KeyBackspace, fyne.KeyDelete: // clears the selection -- return handled - e.propertyLock.Lock() e.eraseSelectionAndUpdate() content := e.Text cb := e.OnChanged - e.propertyLock.Unlock() e.validate() if cb != nil { @@ -1346,19 +1267,15 @@ func (e *Entry) selectingKeyHandler(key *fyne.KeyEvent) bool { switch key.Name { case fyne.KeyLeft: // seek to the start of the selection -- return handled - e.propertyLock.Lock() selectStart, _ := e.selection() e.CursorRow, e.CursorColumn = e.rowColFromTextPos(selectStart) e.selecting = false - e.propertyLock.Unlock() return true case fyne.KeyRight: // seek to the end of the selection -- return handled _, selectEnd := e.selection() - e.propertyLock.Lock() e.CursorRow, e.CursorColumn = e.rowColFromTextPos(selectEnd) e.selecting = false - e.propertyLock.Unlock() return true case fyne.KeyUp, fyne.KeyDown, fyne.KeyEnd, fyne.KeyHome, fyne.KeyPageUp, fyne.KeyPageDown: // cursor movement without left or right shift -- clear selection and return unhandled @@ -1470,8 +1387,6 @@ func (e *Entry) textWrap() fyne.TextWrap { } func (e *Entry) updateCursorAndSelection() { - e.propertyLock.Lock() - defer e.propertyLock.Unlock() e.CursorRow, e.CursorColumn = e.truncatePosition(e.CursorRow, e.CursorColumn) e.selectRow, e.selectColumn = e.truncatePosition(e.selectRow, e.selectColumn) } @@ -1512,7 +1427,6 @@ func (e *Entry) truncatePosition(row, col int) (int, int) { func (e *Entry) updateMousePointer(p fyne.Position, rightClick bool) { row, col := e.getRowCol(p) - e.propertyLock.Lock() if !rightClick || !e.selecting { e.CursorRow = row @@ -1523,7 +1437,6 @@ func (e *Entry) updateMousePointer(p fyne.Position, rightClick bool) { e.selectRow = row e.selectColumn = col } - e.propertyLock.Unlock() r := cache.Renderer(e.content) if r != nil { @@ -1558,13 +1471,11 @@ func (e *Entry) updateText(text string, fromBinding bool) bool { func (e *Entry) updateTextAndRefresh(text string, fromBinding bool) { var callback func(string) - e.propertyLock.Lock() changed := e.updateText(text, fromBinding) if changed { callback = e.OnChanged } - e.propertyLock.Unlock() e.validate() if callback != nil { @@ -1590,11 +1501,9 @@ func (e *Entry) writeData(data binding.DataItem) { } func (e *Entry) typedKeyReturn(provider *RichText, multiLine bool) { - e.propertyLock.RLock() onSubmitted := e.OnSubmitted selectDown := e.selectKeyDown text := e.Text - e.propertyLock.RUnlock() if !multiLine { // Single line doesn't support newline. @@ -1608,7 +1517,6 @@ func (e *Entry) typedKeyReturn(provider *RichText, multiLine bool) { onSubmitted(text) return } - e.propertyLock.Lock() s := []rune("\n") pos := e.cursorTextPos() provider.insertAt(pos, s) @@ -1618,14 +1526,12 @@ func (e *Entry) typedKeyReturn(provider *RichText, multiLine bool) { }) e.CursorColumn = 0 e.CursorRow++ - e.propertyLock.Unlock() } // Selects the row where the CursorColumn is currently positioned // Do not call while holding the proeprtyLock func (e *Entry) selectCurrentRow() { provider := e.textProvider() - e.propertyLock.Lock() e.selectRow = e.CursorRow e.selectColumn = 0 if e.MultiLine { @@ -1633,14 +1539,11 @@ func (e *Entry) selectCurrentRow() { } else { e.CursorColumn = provider.len() } - e.propertyLock.Unlock() e.Refresh() } func (e *Entry) setFieldsAndRefresh(f func()) { - e.propertyLock.Lock() f() - e.propertyLock.Unlock() impl := e.super() if impl == nil { @@ -1723,10 +1626,8 @@ func (r *entryRenderer) Layout(size fyne.Size) { entrySize := size.Subtract(fyne.NewSize(r.trailingInset(), inputBorder*2)) entryPos := fyne.NewPos(0, inputBorder) - r.entry.propertyLock.Lock() textPos := r.entry.textPosFromRowCol(r.entry.CursorRow, r.entry.CursorColumn) selectPos := r.entry.textPosFromRowCol(r.entry.selectRow, r.entry.selectColumn) - r.entry.propertyLock.Unlock() if r.entry.Wrapping == fyne.TextWrapOff && r.entry.Scroll == widget.ScrollNone { r.entry.content.Resize(entrySize) r.entry.content.Move(entryPos) @@ -1735,9 +1636,7 @@ func (r *entryRenderer) Layout(size fyne.Size) { r.scroll.Move(entryPos) } - r.entry.propertyLock.Lock() resizedTextPos := r.entry.textPosFromRowCol(r.entry.CursorRow, r.entry.CursorColumn) - r.entry.propertyLock.Unlock() if textPos != resizedTextPos { r.entry.setFieldsAndRefresh(func() { r.entry.CursorRow, r.entry.CursorColumn = r.entry.rowColFromTextPos(textPos) @@ -1792,19 +1691,14 @@ func (r *entryRenderer) MinSize() fyne.Size { } func (r *entryRenderer) Objects() []fyne.CanvasObject { - r.entry.propertyLock.RLock() - defer r.entry.propertyLock.RUnlock() - return r.objects } func (r *entryRenderer) Refresh() { - r.entry.propertyLock.RLock() content := r.entry.content focusedAppearance := r.entry.focused && !r.entry.disabled.Load() scroll := r.entry.Scroll wrapping := r.entry.Wrapping - r.entry.propertyLock.RUnlock() r.entry.syncSegments() r.entry.text.updateRowBounds() @@ -1899,8 +1793,6 @@ type entryContent struct { func (e *entryContent) CreateRenderer() fyne.WidgetRenderer { e.ExtendBaseWidget(e) - e.entry.propertyLock.Lock() - defer e.entry.propertyLock.Unlock() provider := e.entry.textProvider() placeholder := e.entry.placeholderProvider() if provider.len() != 0 { @@ -1965,8 +1857,6 @@ func (r *entryContentRenderer) MinSize() fyne.Size { } func (r *entryContentRenderer) Objects() []fyne.CanvasObject { - r.content.entry.propertyLock.RLock() - defer r.content.entry.propertyLock.RUnlock() // Objects are generated dynamically force selection rectangles to appear underneath the text if r.content.entry.selecting { objs := make([]fyne.CanvasObject, 0, len(r.selection)+len(r.objects)) @@ -1977,14 +1867,12 @@ func (r *entryContentRenderer) Objects() []fyne.CanvasObject { } func (r *entryContentRenderer) Refresh() { - r.content.entry.propertyLock.RLock() provider := r.content.entry.textProvider() placeholder := r.content.entry.placeholderProvider() focused := r.content.entry.focused focusedAppearance := focused && !r.content.entry.disabled.Load() selections := r.selection r.updateScrollDirections() - r.content.entry.propertyLock.RUnlock() if provider.len() == 0 { placeholder.Show() @@ -2029,14 +1917,12 @@ func (r *entryContentRenderer) buildSelection() { v := fyne.CurrentApp().Settings().ThemeVariant() textSize := th.Size(theme.SizeNameText) - r.content.entry.propertyLock.RLock() cursorRow, cursorCol := r.content.entry.CursorRow, r.content.entry.CursorColumn selectRow, selectCol := -1, -1 if r.content.entry.selecting { selectRow = r.content.entry.selectRow selectCol = r.content.entry.selectColumn } - r.content.entry.propertyLock.RUnlock() if selectRow == -1 || (cursorRow == selectRow && cursorCol == selectCol) { r.selection = r.selection[:0] @@ -2078,8 +1964,6 @@ func (r *entryContentRenderer) buildSelection() { r.selection = r.selection[:rowCount] } - r.content.entry.propertyLock.Lock() - defer r.content.entry.propertyLock.Unlock() // build a rectangle for each row and add it to r.selection for i := 0; i < rowCount; i++ { if len(r.selection) <= i { @@ -2151,22 +2035,18 @@ func (r *entryContentRenderer) moveCursor() { th := r.content.entry.Theme() textSize := th.Size(theme.SizeNameText) - r.content.entry.propertyLock.RLock() provider := r.content.entry.textProvider() innerPad := th.Size(theme.SizeNameInnerPadding) inputBorder := th.Size(theme.SizeNameInputBorder) size := provider.lineSizeToColumn(r.content.entry.CursorColumn, r.content.entry.CursorRow, textSize, innerPad) xPos := size.Width yPos := size.Height * float32(r.content.entry.CursorRow) - r.content.entry.propertyLock.RUnlock() - r.content.entry.propertyLock.Lock() lineHeight := r.content.entry.text.charMinSize(r.content.entry.Password, r.content.entry.TextStyle, textSize).Height r.cursor.Resize(fyne.NewSize(inputBorder, lineHeight)) r.cursor.Move(fyne.NewPos(xPos-(inputBorder/2), yPos+innerPad-inputBorder)) callback := r.content.entry.OnCursorChanged - r.content.entry.propertyLock.Unlock() r.ensureCursorVisible() if callback != nil { diff --git a/widget/entry_password.go b/widget/entry_password.go index 40573a0eef..de98912744 100644 --- a/widget/entry_password.go +++ b/widget/entry_password.go @@ -72,8 +72,6 @@ func (r *passwordRevealerRenderer) MinSize() fyne.Size { func (r *passwordRevealerRenderer) Refresh() { th := r.entry.Theme() - r.entry.propertyLock.RLock() - defer r.entry.propertyLock.RUnlock() if !r.entry.Password { r.icon.Resource = th.Icon(theme.IconNameVisibility) } else { diff --git a/widget/entry_validation.go b/widget/entry_validation.go index fb6eb2c477..5095cd25cd 100644 --- a/widget/entry_validation.go +++ b/widget/entry_validation.go @@ -116,8 +116,6 @@ func (r *validationStatusRenderer) MinSize() fyne.Size { func (r *validationStatusRenderer) Refresh() { th := r.entry.Theme() - r.entry.propertyLock.RLock() - defer r.entry.propertyLock.RUnlock() if r.entry.disabled.Load() { r.icon.Hide() return diff --git a/widget/fileicon.go b/widget/fileicon.go index b2249ca6f5..9cde75d9a6 100644 --- a/widget/fileicon.go +++ b/widget/fileicon.go @@ -67,12 +67,7 @@ func (i *FileIcon) CreateRenderer() fyne.WidgetRenderer { v := fyne.CurrentApp().Settings().ThemeVariant() i.ExtendBaseWidget(i) - i.propertyLock.Lock() i.setURI(i.URI) - i.propertyLock.Unlock() - - i.propertyLock.RLock() - defer i.propertyLock.RUnlock() // TODO remove background when `SetSelected` is gone. background := canvas.NewRectangle(th.Color(theme.ColorNameSelection, v)) @@ -180,9 +175,7 @@ func (s *fileIconRenderer) Refresh() { th := s.file.Theme() v := fyne.CurrentApp().Settings().ThemeVariant() - s.file.propertyLock.Lock() s.file.setURI(s.file.URI) - s.file.propertyLock.Unlock() if s.file.Selected { s.background.Show() @@ -198,7 +191,6 @@ func (s *fileIconRenderer) Refresh() { } } - s.file.propertyLock.RLock() if s.img.Resource != s.file.resource { s.img.Resource = s.file.resource s.img.Refresh() @@ -207,7 +199,6 @@ func (s *fileIconRenderer) Refresh() { s.ext.Text = s.file.extension s.ext.Refresh() } - s.file.propertyLock.RUnlock() canvas.Refresh(s.file.super()) } diff --git a/widget/hyperlink.go b/widget/hyperlink.go index ae1cb7bac6..9d5a3e031f 100644 --- a/widget/hyperlink.go +++ b/widget/hyperlink.go @@ -186,9 +186,7 @@ func (hl *Hyperlink) Resize(size fyne.Size) { // SetText sets the text of the hyperlink func (hl *Hyperlink) SetText(text string) { - hl.propertyLock.Lock() hl.Text = text - hl.propertyLock.Unlock() if len(hl.provider.Segments) == 0 { return // Not initialized yet. @@ -199,9 +197,6 @@ func (hl *Hyperlink) SetText(text string) { // SetURL sets the URL of the hyperlink, taking in a URL type func (hl *Hyperlink) SetURL(url *url.URL) { - hl.propertyLock.Lock() - defer hl.propertyLock.Unlock() - hl.URL = url } @@ -224,9 +219,7 @@ func (hl *Hyperlink) Tapped(e *fyne.PointEvent) { } func (hl *Hyperlink) invokeAction() { - hl.propertyLock.RLock() onTapped := hl.OnTapped - hl.propertyLock.RUnlock() if onTapped != nil { onTapped() @@ -247,9 +240,7 @@ func (hl *Hyperlink) TypedKey(ev *fyne.KeyEvent) { } func (hl *Hyperlink) openURL() { - hl.propertyLock.RLock() url := hl.URL - hl.propertyLock.RUnlock() if url != nil { err := fyne.CurrentApp().OpenURL(url) @@ -262,9 +253,6 @@ func (hl *Hyperlink) openURL() { func (hl *Hyperlink) syncSegments() { th := hl.Theme() - hl.propertyLock.RLock() - defer hl.propertyLock.RUnlock() - hl.provider.Wrapping = hl.Wrapping hl.provider.Truncation = hl.Truncation @@ -311,12 +299,10 @@ func (r *hyperlinkRenderer) Destroy() { func (r *hyperlinkRenderer) Layout(s fyne.Size) { th := r.hl.Theme() - r.hl.propertyLock.RLock() textSize := r.hl.textSize innerPad := th.Size(theme.SizeNameInnerPadding) w := r.hl.focusWidth() xposFocus := r.hl.focusXPos() - r.hl.propertyLock.RUnlock() xposUnderline := xposFocus + innerPad/2 lineCount := float32(len(r.hl.provider.rowBounds)) @@ -341,9 +327,6 @@ func (r *hyperlinkRenderer) Refresh() { th := r.hl.Theme() v := fyne.CurrentApp().Settings().ThemeVariant() - r.hl.propertyLock.RLock() - defer r.hl.propertyLock.RUnlock() - r.focus.StrokeColor = th.Color(theme.ColorNameFocus, v) r.focus.Hidden = !r.hl.focused r.focus.Refresh() diff --git a/widget/icon.go b/widget/icon.go index bd30e413ab..7ab35f18e8 100644 --- a/widget/icon.go +++ b/widget/icon.go @@ -31,14 +31,12 @@ func (i *iconRenderer) Refresh() { return } - i.image.propertyLock.RLock() i.raster.Resource = i.image.Resource i.image.cachedRes = i.image.Resource if i.image.Resource == nil { i.raster.Image = nil // reset the internal caching too... } - i.image.propertyLock.RUnlock() i.raster.Refresh() } @@ -66,8 +64,6 @@ func (i *Icon) MinSize() fyne.Size { // CreateRenderer is a private method to Fyne which links this widget to its renderer func (i *Icon) CreateRenderer() fyne.WidgetRenderer { i.ExtendBaseWidget(i) - i.propertyLock.RLock() - defer i.propertyLock.RUnlock() img := canvas.NewImageFromResource(i.Resource) img.FillMode = canvas.ImageFillContain diff --git a/widget/label.go b/widget/label.go index a587137d36..b0c34a0e17 100644 --- a/widget/label.go +++ b/widget/label.go @@ -105,9 +105,7 @@ func (l *Label) Resize(s fyne.Size) { // SetText sets the text of the label func (l *Label) SetText(text string) { - l.propertyLock.Lock() l.Text = text - l.propertyLock.Unlock() l.Refresh() } @@ -120,9 +118,6 @@ func (l *Label) Unbind() { } func (l *Label) syncSegments() { - l.propertyLock.RLock() - defer l.propertyLock.RUnlock() - var color fyne.ThemeColorName switch l.Importance { case LowImportance: diff --git a/widget/list.go b/widget/list.go index f51d6e3c65..872e8b4022 100644 --- a/widget/list.go +++ b/widget/list.go @@ -146,15 +146,12 @@ func (l *List) RefreshItem(id ListItemID) { // // Since: 2.3 func (l *List) SetItemHeight(id ListItemID, height float32) { - l.propertyLock.Lock() - if l.itemHeights == nil { l.itemHeights = make(map[ListItemID]float32) } refresh := l.itemHeights[id] != height l.itemHeights[id] = height - l.propertyLock.Unlock() if refresh { l.RefreshItem(id) @@ -361,8 +358,6 @@ func (l *List) UnselectAll() { func (l *List) contentMinSize() fyne.Size { separatorThickness := l.Theme().Size(theme.SizeNamePadding) - l.propertyLock.Lock() - defer l.propertyLock.Unlock() if l.Length == nil { return fyne.NewSize(0, 0) } @@ -709,9 +704,7 @@ func (l *listLayout) updateList(newOnly bool) { wasVisible := (*wasVisiblePtr)[:0] wasVisible = append(wasVisible, l.visible...) - l.list.propertyLock.Lock() offY, minRow := l.calculateVisibleRowHeights(l.list.itemMin.Height, length, th) - l.list.propertyLock.Unlock() if len(l.visibleRowHeights) == 0 && length > 0 { // we can't show anything until we have some dimensions l.renderLock.Unlock() // user code should not be locked return diff --git a/widget/progressbarinfinite.go b/widget/progressbarinfinite.go index c7d161a634..da2a3b565a 100644 --- a/widget/progressbarinfinite.go +++ b/widget/progressbarinfinite.go @@ -90,9 +90,6 @@ func (p *infProgressRenderer) Refresh() { // Start the infinite progress bar background thread to update it continuously func (p *infProgressRenderer) start() { - p.progress.propertyLock.Lock() - defer p.progress.propertyLock.Unlock() - p.animation.Duration = time.Second * 3 p.animation.Tick = p.updateBar p.animation.Curve = fyne.AnimationLinear @@ -104,17 +101,12 @@ func (p *infProgressRenderer) start() { // Stop the background thread from updating the infinite progress bar func (p *infProgressRenderer) stop() { - p.progress.propertyLock.Lock() - defer p.progress.propertyLock.Unlock() - p.wasRunning = false p.animation.Stop() } func (p *infProgressRenderer) Destroy() { - p.progress.propertyLock.Lock() p.progress.running = false - p.progress.propertyLock.Unlock() p.stop() } @@ -128,54 +120,40 @@ type ProgressBarInfinite struct { // Show this widget, if it was previously hidden func (p *ProgressBarInfinite) Show() { - p.propertyLock.Lock() p.running = true - p.propertyLock.Unlock() p.BaseWidget.Show() } // Hide this widget, if it was previously visible func (p *ProgressBarInfinite) Hide() { - p.propertyLock.Lock() p.running = false - p.propertyLock.Unlock() p.BaseWidget.Hide() } // Start the infinite progress bar animation func (p *ProgressBarInfinite) Start() { - p.propertyLock.Lock() if p.running { - p.propertyLock.Unlock() return } p.running = true - p.propertyLock.Unlock() - p.BaseWidget.Refresh() } // Stop the infinite progress bar animation func (p *ProgressBarInfinite) Stop() { - p.propertyLock.Lock() if !p.running { - p.propertyLock.Unlock() return } p.running = false - p.propertyLock.Unlock() - p.BaseWidget.Refresh() } // Running returns the current state of the infinite progress animation func (p *ProgressBarInfinite) Running() bool { - p.propertyLock.RLock() - defer p.propertyLock.RUnlock() return p.running } @@ -208,10 +186,7 @@ func (p *ProgressBarInfinite) CreateRenderer() fyne.WidgetRenderer { render.SetObjects([]fyne.CanvasObject{&render.background, &render.bar}) - p.propertyLock.Lock() p.running = true - p.propertyLock.Unlock() - return render } diff --git a/widget/richtext.go b/widget/richtext.go index 8faea43846..4d44203215 100644 --- a/widget/richtext.go +++ b/widget/richtext.go @@ -124,13 +124,10 @@ func (t *RichText) Resize(size fyne.Size) { t.size.Store(size) - t.propertyLock.RLock() - segments := t.Segments skipResize := !t.minCache.IsZero() && size.Width >= t.minCache.Width && size.Height >= t.minCache.Height && t.Wrapping == fyne.TextWrapOff && t.Truncation == fyne.TextTruncateOff - t.propertyLock.RUnlock() if skipResize { - if len(segments) < 2 { // we can simplify :) + if len(t.Segments) < 2 { // we can simplify :) cache.Renderer(t).Layout(size) return } @@ -369,8 +366,6 @@ func (t *RichText) row(row int) []rune { // RowBoundary returns the boundary of the row specified. // The row parameter should be between 0 and t.Rows()-1. func (t *RichText) rowBoundary(row int) *rowBoundary { - t.propertyLock.RLock() - defer t.propertyLock.RUnlock() if row < 0 || row >= t.rows() { return nil } @@ -400,7 +395,6 @@ func (t *RichText) updateRowBounds() { } fitSize.Height -= (innerPadding + t.inset.Height) * 2 - t.propertyLock.RLock() var bounds []rowBoundary maxWidth := t.size.Load().Width - 2*innerPadding + 2*t.inset.Width wrapWidth := maxWidth @@ -493,11 +487,7 @@ func (t *RichText) updateRowBounds() { } iterateSegments(t.Segments) - t.propertyLock.RUnlock() - - t.propertyLock.Lock() t.rowBounds = bounds - t.propertyLock.Unlock() } // RichTextBlock is an extension of a text segment that contains other segments @@ -515,14 +505,12 @@ type textRenderer struct { func (r *textRenderer) Layout(size fyne.Size) { th := r.obj.Theme() - r.obj.propertyLock.RLock() bounds := r.obj.rowBounds objs := r.Objects() if r.obj.scr != nil { r.obj.scr.Resize(size) objs = r.obj.scr.Content.(*fyne.Container).Objects[1].(*fyne.Container).Objects } - r.obj.propertyLock.RUnlock() // Accessing theme here is slow, so we cache the value innerPadding := th.Size(theme.SizeNameInnerPadding) @@ -589,7 +577,6 @@ func (r *textRenderer) Layout(size fyne.Size) { func (r *textRenderer) MinSize() fyne.Size { th := r.obj.Theme() textSize := th.Size(theme.SizeNameText) - r.obj.propertyLock.RLock() innerPad := th.Size(theme.SizeNameInnerPadding) bounds := r.obj.rowBounds @@ -600,7 +587,6 @@ func (r *textRenderer) MinSize() fyne.Size { if r.obj.scr != nil { objs = r.obj.scr.Content.(*fyne.Container).Objects[1].(*fyne.Container).Objects } - r.obj.propertyLock.RUnlock() charMinSize := r.obj.charMinSize(false, fyne.TextStyle{}, textSize) min := r.calculateMin(bounds, wrap, objs, charMinSize, th) @@ -693,10 +679,8 @@ func (r *textRenderer) calculateMin(bounds []rowBoundary, wrap fyne.TextWrap, ob } func (r *textRenderer) Refresh() { - r.obj.propertyLock.RLock() bounds := r.obj.rowBounds scroll := r.obj.Scroll - r.obj.propertyLock.RUnlock() var objs []fyne.CanvasObject for _, bound := range bounds { @@ -739,7 +723,6 @@ func (r *textRenderer) Refresh() { } } - r.obj.propertyLock.Lock() if r.obj.scr != nil { r.obj.scr.Content = &fyne.Container{Layout: layout.NewStackLayout(), Objects: []fyne.CanvasObject{ r.obj.prop, &fyne.Container{Objects: objs}}} @@ -749,7 +732,6 @@ func (r *textRenderer) Refresh() { } else { r.SetObjects(objs) } - r.obj.propertyLock.Unlock() r.Layout(r.obj.Size()) canvas.Refresh(r.obj.super()) diff --git a/widget/select.go b/widget/select.go index 3e776c05d3..b5f04473d4 100644 --- a/widget/select.go +++ b/widget/select.go @@ -88,7 +88,6 @@ func (s *Select) CreateRenderer() fyne.WidgetRenderer { th := s.Theme() v := fyne.CurrentApp().Settings().ThemeVariant() - s.propertyLock.RLock() icon := NewIcon(th.Icon(theme.IconNameArrowDropDown)) if s.PlaceHolder == "" { s.PlaceHolder = defaultPlaceHolder @@ -110,7 +109,6 @@ func (s *Select) CreateRenderer() fyne.WidgetRenderer { background.FillColor = r.bgColor(th, v) background.CornerRadius = th.Size(theme.SizeNameInputRadius) r.updateIcon(th) - s.propertyLock.RUnlock() // updateLabel and some text handling isn't quite right, resolve in text refactor for 2.0 r.updateLabel() return r } @@ -403,9 +401,6 @@ func (s *selectRenderer) MinSize() fyne.Size { th := s.combo.Theme() innerPad := th.Size(theme.SizeNameInnerPadding) - s.combo.propertyLock.RLock() - defer s.combo.propertyLock.RUnlock() - minPlaceholderWidth := fyne.MeasureText(s.combo.PlaceHolder, th.Size(theme.SizeNameText), fyne.TextStyle{}).Width min := s.label.MinSize() min.Width = minPlaceholderWidth @@ -417,12 +412,10 @@ func (s *selectRenderer) Refresh() { th := s.combo.Theme() v := fyne.CurrentApp().Settings().ThemeVariant() - s.combo.propertyLock.RLock() s.updateLabel() s.updateIcon(th) s.background.FillColor = s.bgColor(th, v) s.background.CornerRadius = s.combo.themeWithLock().Size(theme.SizeNameInputRadius) - s.combo.propertyLock.RUnlock() s.Layout(s.combo.Size()) if s.combo.popUp != nil { diff --git a/widget/table.go b/widget/table.go index 1eba170fcf..18c6af40ad 100644 --- a/widget/table.go +++ b/widget/table.go @@ -137,7 +137,6 @@ func NewTableWithHeaders(length func() (rows int, cols int), create func() fyne. func (t *Table) CreateRenderer() fyne.WidgetRenderer { t.ExtendBaseWidget(t) - t.propertyLock.Lock() t.headerSize = t.createHeader().MinSize() if t.columnWidths != nil { if v, ok := t.columnWidths[-1]; ok { @@ -156,7 +155,6 @@ func (t *Table) CreateRenderer() fyne.WidgetRenderer { t.left = newClip(t, &fyne.Container{}) t.corner = newClip(t, &fyne.Container{}) t.dividerLayer = newClip(t, &fyne.Container{}) - t.propertyLock.Unlock() t.dragCol = noCellMatch t.dragRow = noCellMatch @@ -182,13 +180,11 @@ func (t *Table) Cursor() desktop.Cursor { } func (t *Table) Dragged(e *fyne.DragEvent) { - t.propertyLock.Lock() min := t.cellSize col := t.dragCol row := t.dragRow startPos := t.dragStartPos startSize := t.dragStartSize - t.propertyLock.Unlock() if col != noCellMatch { newSize := startSize + (e.Position.X - startPos.X) @@ -296,10 +292,8 @@ func (t *Table) Select(id TableCellID) { // // Since: 1.4.1 func (t *Table) SetColumnWidth(id int, width float32) { - t.propertyLock.Lock() if id < 0 { if t.headerSize.Width == width { - t.propertyLock.Unlock() return } t.headerSize.Width = width @@ -310,12 +304,9 @@ func (t *Table) SetColumnWidth(id int, width float32) { } if set, ok := t.columnWidths[id]; ok && set == width { - t.propertyLock.Unlock() return } t.columnWidths[id] = width - t.propertyLock.Unlock() - t.Refresh() } @@ -325,10 +316,8 @@ func (t *Table) SetColumnWidth(id int, width float32) { // // Since: 2.3 func (t *Table) SetRowHeight(id int, height float32) { - t.propertyLock.Lock() if id < 0 { if t.headerSize.Height == height { - t.propertyLock.Unlock() return } t.headerSize.Height = height @@ -339,12 +328,9 @@ func (t *Table) SetRowHeight(id int, height float32) { } if set, ok := t.rowHeights[id]; ok && set == height { - t.propertyLock.Unlock() return } t.rowHeights[id] = height - t.propertyLock.Unlock() - t.Refresh() } @@ -1042,7 +1028,6 @@ type tableRenderer struct { func (t *tableRenderer) Layout(s fyne.Size) { th := t.t.Theme() - t.t.propertyLock.RLock() t.calculateHeaderSizes(th) off := fyne.NewPos(t.t.stuckWidth, t.t.stuckHeight) @@ -1052,7 +1037,6 @@ func (t *tableRenderer) Layout(s fyne.Size) { if t.t.ShowHeaderColumn { off.X += t.t.headerSize.Width } - t.t.propertyLock.RUnlock() t.t.content.Move(off) t.t.content.Resize(s.SubtractWidthHeight(off.X, off.Y)) @@ -1073,9 +1057,6 @@ func (t *tableRenderer) Layout(s fyne.Size) { func (t *tableRenderer) MinSize() fyne.Size { sep := t.t.Theme().Size(theme.SizeNamePadding) - t.t.propertyLock.RLock() - defer t.t.propertyLock.RUnlock() - min := t.t.content.MinSize().Max(t.t.cellSize) if t.t.ShowHeaderRow { min.Height += t.t.headerSize.Height + sep @@ -1108,7 +1089,6 @@ func (t *tableRenderer) MinSize() fyne.Size { func (t *tableRenderer) Refresh() { th := t.t.Theme() - t.t.propertyLock.Lock() t.t.headerSize = t.t.createHeader().MinSize() if t.t.columnWidths != nil { if v, ok := t.t.columnWidths[-1]; ok { @@ -1122,7 +1102,6 @@ func (t *tableRenderer) Refresh() { } t.t.cellSize = t.t.templateSize() t.calculateHeaderSizes(th) - t.t.propertyLock.Unlock() t.Layout(t.t.Size()) t.t.cells.Refresh() @@ -1208,14 +1187,10 @@ type tableCellsRenderer struct { } func (r *tableCellsRenderer) Layout(fyne.Size) { - r.cells.propertyLock.Lock() r.moveIndicators() - r.cells.propertyLock.Unlock() } func (r *tableCellsRenderer) MinSize() fyne.Size { - r.cells.propertyLock.RLock() - defer r.cells.propertyLock.RUnlock() rows, cols := 0, 0 if f := r.cells.t.Length; f != nil { rows, cols = r.cells.t.Length() @@ -1268,7 +1243,6 @@ func (r *tableCellsRenderer) refreshForID(toDraw TableCellID) { th := r.cells.t.Theme() v := fyne.CurrentApp().Settings().ThemeVariant() - r.cells.propertyLock.Lock() separatorThickness := th.Size(theme.SizeNamePadding) dataRows, dataCols := 0, 0 if f := r.cells.t.Length; f != nil { @@ -1276,12 +1250,10 @@ func (r *tableCellsRenderer) refreshForID(toDraw TableCellID) { } visibleColWidths, offX, minCol, maxCol := r.cells.t.visibleColumnWidths(r.cells.t.cellSize.Width, dataCols) if len(visibleColWidths) == 0 && dataCols > 0 { // we can't show anything until we have some dimensions - r.cells.propertyLock.Unlock() return } visibleRowHeights, offY, minRow, maxRow := r.cells.t.visibleRowHeights(r.cells.t.cellSize.Height, dataRows) if len(visibleRowHeights) == 0 && dataRows > 0 { // we can't show anything until we have some dimensions - r.cells.propertyLock.Unlock() return } @@ -1392,7 +1364,6 @@ func (r *tableCellsRenderer) refreshForID(toDraw TableCellID) { visible := r.visible headers := r.headers - r.cells.propertyLock.Unlock() r.SetObjects(cells) if updateCell != nil { diff --git a/widget/tree.go b/widget/tree.go index 34fa3ebcb6..de48c91339 100644 --- a/widget/tree.go +++ b/widget/tree.go @@ -119,18 +119,14 @@ func NewTreeWithStrings(data map[string][]string) (t *Tree) { // CloseAllBranches closes all branches in the tree. func (t *Tree) CloseAllBranches() { - t.propertyLock.Lock() t.open = make(map[TreeNodeID]bool) - t.propertyLock.Unlock() t.Refresh() } // CloseBranch closes the branch with the given TreeNodeID. func (t *Tree) CloseBranch(uid TreeNodeID) { t.ensureOpenMap() - t.propertyLock.Lock() t.open[uid] = false - t.propertyLock.Unlock() if f := t.OnBranchClosed; f != nil { f(uid) } @@ -161,8 +157,6 @@ func (t *Tree) IsBranchOpen(uid TreeNodeID) bool { return true // Root is always open } t.ensureOpenMap() - t.propertyLock.RLock() - defer t.propertyLock.RUnlock() return t.open[uid] } @@ -217,9 +211,7 @@ func (t *Tree) OpenAllBranches() { t.ensureOpenMap() t.walkAll(func(uid, parent TreeNodeID, branch bool, depth int) { if branch { - t.propertyLock.Lock() t.open[uid] = true - t.propertyLock.Unlock() } }) t.Refresh() @@ -228,9 +220,7 @@ func (t *Tree) OpenAllBranches() { // OpenBranch opens the branch with the given TreeNodeID. func (t *Tree) OpenBranch(uid TreeNodeID) { t.ensureOpenMap() - t.propertyLock.Lock() t.open[uid] = true - t.propertyLock.Unlock() if f := t.OnBranchOpened; f != nil { f(uid) } @@ -433,8 +423,6 @@ func (t *Tree) UnselectAll() { } func (t *Tree) ensureOpenMap() { - t.propertyLock.Lock() - defer t.propertyLock.Unlock() if t.open == nil { t.open = make(map[string]bool) } @@ -620,9 +608,6 @@ type treeContentRenderer struct { func (r *treeContentRenderer) Layout(size fyne.Size) { th := r.treeContent.Theme() - r.treeContent.propertyLock.Lock() - defer r.treeContent.propertyLock.Unlock() - r.objects = nil branches := make(map[string]*branch) leaves := make(map[string]*leaf) @@ -742,8 +727,6 @@ func (r *treeContentRenderer) Layout(size fyne.Size) { func (r *treeContentRenderer) MinSize() (min fyne.Size) { th := r.treeContent.Theme() - r.treeContent.propertyLock.Lock() - defer r.treeContent.propertyLock.Unlock() pad := th.Size(theme.SizeNamePadding) iconSize := th.Size(theme.SizeNameInlineIcon) @@ -788,7 +771,6 @@ func (r *treeContentRenderer) refreshForID(toDraw TreeNodeID) { } else { r.Layout(s) } - r.treeContent.propertyLock.RLock() for id, b := range r.branches { if toDraw != allTreeNodesID && id != toDraw { continue @@ -803,7 +785,6 @@ func (r *treeContentRenderer) refreshForID(toDraw TreeNodeID) { l.Refresh() } - r.treeContent.propertyLock.RUnlock() canvas.Refresh(r.treeContent.super()) } @@ -914,9 +895,7 @@ func (n *treeNode) partialRefresh() { func (n *treeNode) update(uid string, depth int) { n.uid = uid n.depth = depth - n.propertyLock.Lock() n.Hidden = false - n.propertyLock.Unlock() n.partialRefresh() } diff --git a/widget/widget.go b/widget/widget.go index 63b8555633..b899406e78 100644 --- a/widget/widget.go +++ b/widget/widget.go @@ -2,7 +2,6 @@ package widget // import "fyne.io/fyne/v2/widget" import ( - "sync" "sync/atomic" "fyne.io/fyne/v2" @@ -19,9 +18,8 @@ type BaseWidget struct { position async.Position Hidden bool - impl atomic.Pointer[fyne.Widget] - propertyLock sync.RWMutex - themeCache fyne.Theme + impl atomic.Pointer[fyne.Widget] + themeCache fyne.Theme } // ExtendBaseWidget is used by an extending widget to make use of BaseWidget functionality. @@ -82,9 +80,6 @@ func (w *BaseWidget) MinSize() fyne.Size { // Visible returns whether or not this widget should be visible. // Note that this may not mean it is currently visible if a parent has been hidden. func (w *BaseWidget) Visible() bool { - w.propertyLock.RLock() - defer w.propertyLock.RUnlock() - return !w.Hidden } @@ -94,9 +89,7 @@ func (w *BaseWidget) Show() { return } - w.propertyLock.Lock() w.Hidden = false - w.propertyLock.Unlock() impl := w.super() if impl == nil { @@ -111,9 +104,7 @@ func (w *BaseWidget) Hide() { return } - w.propertyLock.Lock() w.Hidden = true - w.propertyLock.Unlock() impl := w.super() if impl == nil { @@ -129,9 +120,7 @@ func (w *BaseWidget) Refresh() { return } - w.propertyLock.Lock() w.themeCache = nil - w.propertyLock.Unlock() render := cache.Renderer(impl) render.Refresh() @@ -142,8 +131,6 @@ func (w *BaseWidget) Refresh() { // // Since: 2.5 func (w *BaseWidget) Theme() fyne.Theme { - w.propertyLock.RLock() - defer w.propertyLock.RUnlock() return w.themeWithLock() } From bd7c521f342065c13300abf9de71699f64da66fe Mon Sep 17 00:00:00 2001 From: Andy Williams Date: Mon, 16 Dec 2024 21:24:50 +0000 Subject: [PATCH 4/9] Fixed missed test updates --- widget/entry_internal_test.go | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/widget/entry_internal_test.go b/widget/entry_internal_test.go index f3ffe6a995..e5e27957fd 100644 --- a/widget/entry_internal_test.go +++ b/widget/entry_internal_test.go @@ -147,15 +147,11 @@ func TestEntry_DragSelectEmpty(t *testing.T) { de = &fyne.DragEvent{PointEvent: *ev1, Dragged: fyne.NewDelta(1, 0)} entry.Dragged(de) - entry.propertyLock.RLock() assert.True(t, entry.selecting) - entry.propertyLock.RUnlock() entry.DragEnd() assert.Equal(t, "", entry.SelectedText()) - entry.propertyLock.RLock() assert.False(t, entry.selecting) - entry.propertyLock.RUnlock() // Test non-empty selection - drag from 'T' to 'g' (empty) ev1 = getClickPosition("", 0) @@ -164,15 +160,11 @@ func TestEntry_DragSelectEmpty(t *testing.T) { de = &fyne.DragEvent{PointEvent: *ev2, Dragged: fyne.NewDelta(1, 0)} entry.Dragged(de) - entry.propertyLock.RLock() assert.True(t, entry.selecting) - entry.propertyLock.RUnlock() entry.DragEnd() assert.Equal(t, "Testing", entry.SelectedText()) - entry.propertyLock.RLock() assert.True(t, entry.selecting) - entry.propertyLock.RUnlock() } func TestEntry_DragSelectWithScroll(t *testing.T) { @@ -292,9 +284,7 @@ func TestEntry_CallbackLocking(t *testing.T) { e := &Entry{} called := 0 e.OnChanged = func(_ string) { - e.propertyLock.Lock() called++ // Just to not have an empty critical section. - e.propertyLock.Unlock() } _ = e.Theme() From 9b720cbd1827d84aa97661da2bea65376780f19a Mon Sep 17 00:00:00 2001 From: Andy Williams Date: Mon, 16 Dec 2024 21:31:10 +0000 Subject: [PATCH 5/9] Fixing GLFW test too --- internal/driver/glfw/canvas_test.go | 6 ------ internal/driver/glfw/driver_test.go | 2 -- internal/driver/glfw/window_test.go | 8 -------- 3 files changed, 16 deletions(-) diff --git a/internal/driver/glfw/canvas_test.go b/internal/driver/glfw/canvas_test.go index 2bdc66a27d..b64e7205e5 100644 --- a/internal/driver/glfw/canvas_test.go +++ b/internal/driver/glfw/canvas_test.go @@ -368,16 +368,12 @@ func TestGlCanvas_PixelCoordinateAtPosition(t *testing.T) { c := w.Canvas().(*glCanvas) pos := fyne.NewPos(4, 4) - c.Lock() c.scale = 2.5 - c.Unlock() x, y := c.PixelCoordinateForPosition(pos) assert.Equal(t, int(10*c.texScale), x) assert.Equal(t, int(10*c.texScale), y) - c.Lock() c.texScale = 2.0 - c.Unlock() x, y = c.PixelCoordinateForPosition(pos) assert.Equal(t, 20, x) assert.Equal(t, 20, y) @@ -503,9 +499,7 @@ func TestGlCanvas_Scale(t *testing.T) { w := createWindow("Test").(*window) c := w.Canvas().(*glCanvas) - c.Lock() c.scale = 2.5 - c.Unlock() assert.Equal(t, 5, int(2*c.Scale())) } diff --git a/internal/driver/glfw/driver_test.go b/internal/driver/glfw/driver_test.go index 01910c3a7e..b2b4249456 100644 --- a/internal/driver/glfw/driver_test.go +++ b/internal/driver/glfw/driver_test.go @@ -40,9 +40,7 @@ func Test_gLDriver_AbsolutePositionForObject(t *testing.T) { // We work around w.SetMainMenu because on MacOS the main menu is a native menu. c := w.canvas movl := buildMenuOverlay(mm, w) - c.Lock() c.setMenuOverlay(movl) - c.Unlock() w.SetContent(content) w.Resize(fyne.NewSize(300, 200)) ensureCanvasSize(t, w, fyne.NewSize(300, 200)) diff --git a/internal/driver/glfw/window_test.go b/internal/driver/glfw/window_test.go index 626739a22e..64b96e963b 100644 --- a/internal/driver/glfw/window_test.go +++ b/internal/driver/glfw/window_test.go @@ -104,9 +104,7 @@ func TestWindow_ToggleMainMenuByKeyboard(t *testing.T) { c := w.canvas m := fyne.NewMainMenu(fyne.NewMenu("File"), fyne.NewMenu("Edit"), fyne.NewMenu("Help")) menuBar := buildMenuOverlay(m, w).(*MenuBar) - c.Lock() c.setMenuOverlay(menuBar) - c.Unlock() w.SetContent(canvas.NewRectangle(color.Black)) altPressingMod := glfw.ModAlt @@ -324,25 +322,19 @@ func TestWindow_HandleOutsideHoverableObject(t *testing.T) { w.mouseMoved(w.viewport, 15, 48) w.WaitForEvents() repaintWindow(w) - w.mouseLock.RLock() assert.NotNil(t, w.mouseOver) - w.mouseLock.RUnlock() test.AssertRendersToMarkup(t, "windows_hover_object.xml", w.Canvas()) w.mouseMoved(w.viewport, 42, 48) w.WaitForEvents() repaintWindow(w) - w.mouseLock.RLock() assert.NotNil(t, w.mouseOver) - w.mouseLock.RUnlock() test.AssertRendersToMarkup(t, "windows_hover_object.xml", w.Canvas()) w.mouseMoved(w.viewport, 42, 100) w.WaitForEvents() repaintWindow(w) - w.mouseLock.RLock() assert.Nil(t, w.mouseOver) - w.mouseLock.RUnlock() test.AssertRendersToMarkup(t, "windows_no_hover_outside_object.xml", w.Canvas()) } From dceb7232c682d98517ab045cf814aa60ff56327d Mon Sep 17 00:00:00 2001 From: Andy Williams Date: Tue, 17 Dec 2024 12:44:38 +0000 Subject: [PATCH 6/9] Fix deadlocking on Linux clipboard test --- internal/driver/glfw/clipboard.go | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/internal/driver/glfw/clipboard.go b/internal/driver/glfw/clipboard.go index cb0bfb3fa0..37cbda2713 100644 --- a/internal/driver/glfw/clipboard.go +++ b/internal/driver/glfw/clipboard.go @@ -39,11 +39,7 @@ func (c clipboard) Content() string { } func (c clipboard) content() string { - content := "" - runOnMain(func() { - content = glfw.GetClipboardString() - }) - return content + return glfw.GetClipboardString() } // SetContent sets the clipboard content @@ -64,7 +60,5 @@ func (c clipboard) SetContent(content string) { } func (c clipboard) setContent(content string) { - runOnMain(func() { - glfw.SetClipboardString(content) - }) + glfw.SetClipboardString(content) } From f0bf159daafdb8c956bd63850c33e5771f5b1ad3 Mon Sep 17 00:00:00 2001 From: Andy Williams Date: Tue, 17 Dec 2024 13:14:19 +0000 Subject: [PATCH 7/9] Fix deadlocking on Linux clipboard test (2) --- internal/driver/glfw/window.go | 12 ++++-------- internal/driver/glfw/window_test.go | 2 +- 2 files changed, 5 insertions(+), 9 deletions(-) diff --git a/internal/driver/glfw/window.go b/internal/driver/glfw/window.go index 08e04eae9b..12432b153f 100644 --- a/internal/driver/glfw/window.go +++ b/internal/driver/glfw/window.go @@ -203,17 +203,13 @@ func (w *window) Close() { // trigger callbacks - early so window still exists if w.onClosed != nil { - w.QueueEvent(w.onClosed) + w.onClosed() } - // set w.closing flag inside draw thread to ensure we can free textures - runOnMainWithContext(w, func() { - w.closing = true - w.viewport.SetShouldClose(true) - - cache.RangeTexturesFor(w.canvas, w.canvas.Painter().Free) - }) + w.closing = true + w.viewport.SetShouldClose(true) + cache.RangeTexturesFor(w.canvas, w.canvas.Painter().Free) w.canvas.WalkTrees(nil, func(node *common.RenderCacheNode, _ fyne.Position) { if wid, ok := node.Obj().(fyne.Widget); ok { cache.DestroyRenderer(wid) diff --git a/internal/driver/glfw/window_test.go b/internal/driver/glfw/window_test.go index 64b96e963b..03ff71b450 100644 --- a/internal/driver/glfw/window_test.go +++ b/internal/driver/glfw/window_test.go @@ -1668,7 +1668,7 @@ func TestWindow_CloseInterception(t *testing.T) { w.SetCloseIntercept(func() { onIntercepted = true }) w.SetOnClosed(func() { onClosed = true }) w.Close() - w.WaitForEvents() + assert.False(t, onIntercepted, "the interceptor should not have been called") assert.True(t, onClosed, "the on closed handler should have been called") assert.True(t, w.viewport.ShouldClose()) // For #2694 From ddc5df1685238c3b2ad2aa6ca1daebe4188c6089 Mon Sep 17 00:00:00 2001 From: Andy Williams Date: Tue, 17 Dec 2024 13:23:43 +0000 Subject: [PATCH 8/9] Fix deadlocking on Linux clipboard test (3) --- internal/driver/glfw/window.go | 4 ++-- internal/driver/glfw/window_test.go | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/internal/driver/glfw/window.go b/internal/driver/glfw/window.go index 12432b153f..d09459cfd0 100644 --- a/internal/driver/glfw/window.go +++ b/internal/driver/glfw/window.go @@ -253,11 +253,11 @@ func (w *window) Canvas() fyne.Canvas { func (w *window) processClosed() { if w.onCloseIntercepted != nil { - w.QueueEvent(w.onCloseIntercepted) + w.onCloseIntercepted() return } - go w.Close() // unsure which thread this comes from, so don't block + w.Close() } // destroy this window and, if it's the last window quit the app diff --git a/internal/driver/glfw/window_test.go b/internal/driver/glfw/window_test.go index 03ff71b450..b7d69dd57d 100644 --- a/internal/driver/glfw/window_test.go +++ b/internal/driver/glfw/window_test.go @@ -1683,7 +1683,7 @@ func TestWindow_CloseInterception(t *testing.T) { closed := make(chan bool, 1) w.SetOnClosed(func() { closed <- true }) w.closed(w.viewport) - w.WaitForEvents() + assert.True(t, onIntercepted, "the interceptor should have been called") select { case <-closed: @@ -1700,7 +1700,7 @@ func TestWindow_CloseInterception(t *testing.T) { closed := make(chan bool, 1) w.SetOnClosed(func() { closed <- true }) w.closed(w.viewport) - w.WaitForEvents() + select { case <-closed: case <-time.After(20 * time.Millisecond): From 017e0850359b12ba587967cf69cb5612f1d7dfa2 Mon Sep 17 00:00:00 2001 From: Andy Williams Date: Tue, 17 Dec 2024 14:09:40 +0000 Subject: [PATCH 9/9] Remove event queue and process inline --- internal/driver/common/window.go | 43 ------------ internal/driver/glfw/driver.go | 2 +- internal/driver/glfw/loop.go | 1 - internal/driver/glfw/menu_darwin.go | 2 +- internal/driver/glfw/window.go | 80 ++++++++++------------ internal/driver/glfw/window_desktop.go | 10 +-- internal/driver/glfw/window_test.go | 91 +------------------------- internal/driver/glfw/window_wasm.go | 3 - internal/driver/mobile/driver.go | 20 +++--- internal/driver/mobile/window.go | 15 +---- 10 files changed, 53 insertions(+), 214 deletions(-) diff --git a/internal/driver/common/window.go b/internal/driver/common/window.go index ab5e499e74..afa8946f13 100644 --- a/internal/driver/common/window.go +++ b/internal/driver/common/window.go @@ -4,49 +4,6 @@ import ( "fyne.io/fyne/v2/internal/async" ) -// Window defines common functionality for windows. -type Window struct { - eventQueue *async.UnboundedFuncChan -} - -// DestroyEventQueue destroys the event queue. -func (w *Window) DestroyEventQueue() { - w.eventQueue.Close() -} - -// InitEventQueue initializes the event queue. -func (w *Window) InitEventQueue() { - // This channel should be closed when the window is closed. - w.eventQueue = async.NewUnboundedFuncChan() -} - -// QueueEvent uses this method to queue up a callback that handles an event. This ensures -// user interaction events for a given window are processed in order. -func (w *Window) QueueEvent(fn func()) { - w.eventQueue.In() <- fn -} - -// ProcessEventQueue runs all the items in the event queue, returning once it is empty again. -func (w *Window) ProcessEventQueue() { - for { - select { - case fn := <-w.eventQueue.Out(): - fn() - default: - return - } - } -} - -// WaitForEvents wait for all the events. -func (w *Window) WaitForEvents() { - done := DonePool.Get() - defer DonePool.Put(done) - - w.eventQueue.In() <- func() { done <- struct{}{} } - <-done -} - var DonePool = async.Pool[chan struct{}]{ New: func() chan struct{} { return make(chan struct{}) diff --git a/internal/driver/glfw/driver.go b/internal/driver/glfw/driver.go index d9c930ad91..23d28dbef5 100644 --- a/internal/driver/glfw/driver.go +++ b/internal/driver/glfw/driver.go @@ -89,7 +89,7 @@ func (d *gLDriver) Device() fyne.Device { func (d *gLDriver) Quit() { if curWindow != nil { if f := fyne.CurrentApp().Lifecycle().(*intapp.Lifecycle).OnExitedForeground(); f != nil { - curWindow.QueueEvent(f) + f() } curWindow = nil if d.trayStop != nil { diff --git a/internal/driver/glfw/loop.go b/internal/driver/glfw/loop.go index ca51b0bd9f..acf2a30526 100644 --- a/internal/driver/glfw/loop.go +++ b/internal/driver/glfw/loop.go @@ -126,7 +126,6 @@ func (d *gLDriver) runGL() { if w.viewport == nil { continue } - w.ProcessEventQueue() if w.viewport.ShouldClose() { windowsToRemove++ diff --git a/internal/driver/glfw/menu_darwin.go b/internal/driver/glfw/menu_darwin.go index c6a4b8bc95..aa5eef93ce 100644 --- a/internal/driver/glfw/menu_darwin.go +++ b/internal/driver/glfw/menu_darwin.go @@ -246,7 +246,7 @@ func registerCallback(w *window, item *fyne.MenuItem, nextItemID int) int { callbacks = append(callbacks, &menuCallbacks{ action: func() { if item.Action != nil { - w.QueueEvent(item.Action) + item.Action() } }, enabled: func() bool { diff --git a/internal/driver/glfw/window.go b/internal/driver/glfw/window.go index d09459cfd0..d60c7169ce 100644 --- a/internal/driver/glfw/window.go +++ b/internal/driver/glfw/window.go @@ -269,7 +269,6 @@ func (w *window) destroy(d *gLDriver) { } else if runtime.GOOS == "darwin" { go d.focusPreviousWindow() } - w.DestroyEventQueue() } func (w *window) processMoved(x, y int) { @@ -386,7 +385,7 @@ func (w *window) processMouseMoved(xpos float64, ypos float64) { if hovered, ok := obj.(desktop.Hoverable); ok { if hovered == mouseOver { - w.QueueEvent(func() { hovered.MouseMoved(ev) }) + hovered.MouseMoved(ev) } else { w.mouseOut() w.mouseIn(hovered, ev) @@ -419,7 +418,7 @@ func (w *window) processMouseMoved(xpos float64, ypos float64) { ev.Position = mousePos.Subtract(w.mouseDraggedOffset).Add(draggedObjDelta) ev.Dragged = fyne.NewDelta(mousePos.X-mouseDragPos.X, mousePos.Y-mouseDragPos.Y) wd := mouseDragged - w.QueueEvent(func() { wd.Dragged(ev) }) + wd.Dragged(ev) } w.mouseDragStarted = true @@ -436,22 +435,18 @@ func (w *window) objIsDragged(obj any) bool { } func (w *window) mouseIn(obj desktop.Hoverable, ev *desktop.MouseEvent) { - w.QueueEvent(func() { - if obj != nil { - obj.MouseIn(ev) - } - w.mouseOver = obj - }) + if obj != nil { + obj.MouseIn(ev) + } + w.mouseOver = obj } func (w *window) mouseOut() { - w.QueueEvent(func() { - mouseOver := w.mouseOver - if mouseOver != nil { - mouseOver.MouseOut() - w.mouseOver = nil - } - }) + mouseOver := w.mouseOver + if mouseOver != nil { + mouseOver.MouseOut() + w.mouseOver = nil + } } func (w *window) processMouseClicked(button desktop.MouseButton, action action, modifiers fyne.KeyModifier) { @@ -523,7 +518,7 @@ func (w *window) processMouseClicked(button desktop.MouseButton, action action, if action == release && mouseDragged != nil { if mouseDragStarted { - w.QueueEvent(mouseDragged.DragEnd) + mouseDragged.DragEnd() w.mouseDragStarted = false } if shouldMouseOut { @@ -540,7 +535,7 @@ func (w *window) processMouseClicked(button desktop.MouseButton, action action, } else if action == release { if co == mousePressed { if button == desktop.MouseButtonSecondary && altTap { - w.QueueEvent(func() { secondary.TappedSecondary(ev) }) + secondary.TappedSecondary(ev) } } } @@ -555,18 +550,18 @@ func (w *window) processMouseClicked(button desktop.MouseButton, action action, func (w *window) mouseClickedHandleMouseable(mev *desktop.MouseEvent, action action, wid desktop.Mouseable) { mousePos := mev.AbsolutePosition if action == press { - w.QueueEvent(func() { wid.MouseDown(mev) }) + wid.MouseDown(mev) } else if action == release { mouseDragged := w.mouseDragged mouseDraggedOffset := w.mouseDraggedOffset if mouseDragged == nil { - w.QueueEvent(func() { wid.MouseUp(mev) }) + wid.MouseUp(mev) } else { if dragged, ok := mouseDragged.(desktop.Mouseable); ok { mev.Position = mousePos.Subtract(mouseDraggedOffset) - w.QueueEvent(func() { dragged.MouseUp(mev) }) + dragged.MouseUp(mev) } else { - w.QueueEvent(func() { wid.MouseUp(mev) }) + wid.MouseUp(mev) } } } @@ -585,7 +580,7 @@ func (w *window) mouseClickedHandleTapDoubleTap(co fyne.CanvasObject, ev *fyne.P go w.waitForDoubleTap(co, ev) } else { if wid, ok := co.(fyne.Tappable); ok && co == w.mousePressed { - w.QueueEvent(func() { wid.Tapped(ev) }) + wid.Tapped(ev) } w.mousePressed = nil } @@ -600,11 +595,11 @@ func (w *window) waitForDoubleTap(co fyne.CanvasObject, ev *fyne.PointEvent) { if w.mouseClickCount == 2 && w.mouseLastClick == co { if wid, ok := co.(fyne.DoubleTappable); ok { - w.QueueEvent(func() { wid.DoubleTapped(ev) }) + wid.DoubleTapped(ev) } } else if co == w.mousePressed { if wid, ok := co.(fyne.Tappable); ok { - w.QueueEvent(func() { wid.Tapped(ev) }) + wid.Tapped(ev) } } @@ -646,10 +641,10 @@ func (w *window) capturesTab(modifier fyne.KeyModifier) bool { if !captures { switch modifier { case 0: - w.QueueEvent(w.canvas.FocusNext) + w.canvas.FocusNext() return false case fyne.KeyModifierShift: - w.QueueEvent(w.canvas.FocusPrevious) + w.canvas.FocusPrevious() return false } } @@ -679,10 +674,10 @@ func (w *window) processKeyPressed(keyName fyne.KeyName, keyASCII fyne.KeyName, if w.canvas.Focused() != nil { if focused, ok := w.canvas.Focused().(desktop.Keyable); ok { - w.QueueEvent(func() { focused.KeyUp(keyEvent) }) + focused.KeyUp(keyEvent) } } else if w.canvas.onKeyUp != nil { - w.QueueEvent(func() { w.canvas.onKeyUp(keyEvent) }) + w.canvas.onKeyUp(keyEvent) } return // ignore key up in other core events case press: @@ -697,10 +692,10 @@ func (w *window) processKeyPressed(keyName fyne.KeyName, keyASCII fyne.KeyName, } if w.canvas.Focused() != nil { if focused, ok := w.canvas.Focused().(desktop.Keyable); ok { - w.QueueEvent(func() { focused.KeyDown(keyEvent) }) + focused.KeyDown(keyEvent) } } else if w.canvas.onKeyDown != nil { - w.QueueEvent(func() { w.canvas.onKeyDown(keyEvent) }) + w.canvas.onKeyDown(keyEvent) } default: // key repeat will fall through to TypedKey and TypedShortcut @@ -717,9 +712,9 @@ func (w *window) processKeyPressed(keyName fyne.KeyName, keyASCII fyne.KeyName, // No shortcut detected, pass down to TypedKey focused := w.canvas.Focused() if focused != nil { - w.QueueEvent(func() { focused.TypedKey(keyEvent) }) + focused.TypedKey(keyEvent) } else if w.canvas.onTypedKey != nil { - w.QueueEvent(func() { w.canvas.onTypedKey(keyEvent) }) + w.canvas.onTypedKey(keyEvent) } } @@ -729,9 +724,9 @@ func (w *window) processKeyPressed(keyName fyne.KeyName, keyASCII fyne.KeyName, // Characters do not map 1:1 to physical keys, as a key may produce zero, one or more characters. func (w *window) processCharInput(char rune) { if focused := w.canvas.Focused(); focused != nil { - w.QueueEvent(func() { focused.TypedRune(char) }) + focused.TypedRune(char) } else if w.canvas.onTypedRune != nil { - w.QueueEvent(func() { w.canvas.onTypedRune(char) }) + w.canvas.onTypedRune(char) } } @@ -739,13 +734,13 @@ func (w *window) processFocused(focus bool) { if focus { if curWindow == nil { if f := fyne.CurrentApp().Lifecycle().(*app.Lifecycle).OnEnteredForeground(); f != nil { - w.QueueEvent(f) + f() } } curWindow = w - w.QueueEvent(w.canvas.FocusGained) + w.canvas.FocusGained() } else { - w.QueueEvent(w.canvas.FocusLost) + w.canvas.FocusLost() w.mousePos = fyne.Position{} go func() { // check whether another window was focused or not @@ -756,7 +751,7 @@ func (w *window) processFocused(focus bool) { curWindow = nil if f := fyne.CurrentApp().Lifecycle().(*app.Lifecycle).OnExitedForeground(); f != nil { - w.QueueEvent(f) + f() } }() } @@ -841,11 +836,11 @@ func (w *window) triggersShortcut(localizedKeyName fyne.KeyName, key fyne.KeyNam shouldRunShortcut = shortcut.ShortcutName() == "Copy" } if shouldRunShortcut { - w.QueueEvent(func() { focused.TypedShortcut(shortcut) }) + focused.TypedShortcut(shortcut) } return shouldRunShortcut } - w.QueueEvent(func() { w.canvas.TypedShortcut(shortcut) }) + w.canvas.TypedShortcut(shortcut) return true } @@ -924,9 +919,6 @@ func (d *gLDriver) createWindow(title string, decorate bool) fyne.Window { d.initGLFW() ret = &window{title: title, decorate: decorate, driver: d} - // This queue is destroyed when the window is closed. - ret.InitEventQueue() - ret.canvas = newCanvas() ret.canvas.context = ret ret.SetIcon(ret.icon) diff --git a/internal/driver/glfw/window_desktop.go b/internal/driver/glfw/window_desktop.go index b9dca89968..3aae611b8f 100644 --- a/internal/driver/glfw/window_desktop.go +++ b/internal/driver/glfw/window_desktop.go @@ -15,7 +15,6 @@ import ( "fyne.io/fyne/v2/container" "fyne.io/fyne/v2/driver/desktop" "fyne.io/fyne/v2/internal/build" - "fyne.io/fyne/v2/internal/driver/common" "fyne.io/fyne/v2/internal/painter" "fyne.io/fyne/v2/internal/painter/gl" "fyne.io/fyne/v2/internal/scale" @@ -61,8 +60,6 @@ func initCursors() { var _ fyne.Window = (*window)(nil) type window struct { - common.Window - viewport *glfw.Window createLock sync.Once decorate bool @@ -124,7 +121,8 @@ func (w *window) SetFullScreen(full bool) { w.viewport.SetMonitor(monitor, 0, 0, mode.Width, mode.Height, mode.RefreshRate) } else { if w.width == 0 && w.height == 0 { // if we were fullscreen on creation... - w.width, w.height = w.screenSize(w.canvas.Size()) + s := w.canvas.Size().Max(w.canvas.MinSize()) + w.width, w.height = w.screenSize(s) } w.viewport.SetMonitor(nil, w.xpos, w.ypos, w.width, w.height, 0) } @@ -155,9 +153,7 @@ func (w *window) SetOnDropped(dropped func(pos fyne.Position, items []fyne.URI)) uris[i] = storage.NewFileURI(name) } - w.QueueEvent(func() { - dropped(w.mousePos, uris) - }) + dropped(w.mousePos, uris) }) }) } diff --git a/internal/driver/glfw/window_test.go b/internal/driver/glfw/window_test.go index b7d69dd57d..e18d5d960d 100644 --- a/internal/driver/glfw/window_test.go +++ b/internal/driver/glfw/window_test.go @@ -271,21 +271,18 @@ func TestWindow_HandleHoverable(t *testing.T) { require.Equal(t, fyne.NewPos(14, 0), h2.Position()) w.mouseMoved(w.viewport, 9, 9) - w.WaitForEvents() assert.Equal(t, &desktop.MouseEvent{PointEvent: fyne.PointEvent{Position: fyne.NewPos(5, 5), AbsolutePosition: fyne.NewPos(9, 9)}}, h1.popMouseInEvent()) assert.Nil(t, h1.popMouseMovedEvent()) assert.Nil(t, h1.popMouseOutEvent()) w.mouseMoved(w.viewport, 9, 8) - w.WaitForEvents() assert.Nil(t, h1.popMouseInEvent()) assert.Equal(t, &desktop.MouseEvent{PointEvent: fyne.PointEvent{Position: fyne.NewPos(5, 4), AbsolutePosition: fyne.NewPos(9, 8)}}, h1.popMouseMovedEvent()) assert.Nil(t, h1.popMouseOutEvent()) w.mouseMoved(w.viewport, 23, 11) - w.WaitForEvents() assert.Nil(t, h1.popMouseInEvent()) assert.Nil(t, h1.popMouseMovedEvent()) assert.NotNil(t, h1.popMouseOutEvent()) @@ -295,7 +292,6 @@ func TestWindow_HandleHoverable(t *testing.T) { assert.Nil(t, h2.popMouseOutEvent()) w.mouseMoved(w.viewport, 23, 10) - w.WaitForEvents() assert.Nil(t, h2.popMouseInEvent()) assert.Equal(t, &desktop.MouseEvent{PointEvent: fyne.PointEvent{Position: fyne.NewPos(5, 6), AbsolutePosition: fyne.NewPos(23, 10)}}, h2.popMouseMovedEvent()) @@ -320,19 +316,16 @@ func TestWindow_HandleOutsideHoverableObject(t *testing.T) { repaintWindow(w) w.mouseMoved(w.viewport, 15, 48) - w.WaitForEvents() repaintWindow(w) assert.NotNil(t, w.mouseOver) test.AssertRendersToMarkup(t, "windows_hover_object.xml", w.Canvas()) w.mouseMoved(w.viewport, 42, 48) - w.WaitForEvents() repaintWindow(w) assert.NotNil(t, w.mouseOver) test.AssertRendersToMarkup(t, "windows_hover_object.xml", w.Canvas()) w.mouseMoved(w.viewport, 42, 100) - w.WaitForEvents() repaintWindow(w) assert.Nil(t, w.mouseOver) test.AssertRendersToMarkup(t, "windows_no_hover_outside_object.xml", w.Canvas()) @@ -352,67 +345,56 @@ func TestWindow_HandleDragging(t *testing.T) { // no drag event in simple move w.mouseMoved(w.viewport, 9, 9) - w.WaitForEvents() assert.Nil(t, d1.popDragEvent()) assert.Nil(t, d2.popDragEvent()) // no drag event on secondary mouseDown w.mouseClicked(w.viewport, glfw.MouseButton2, glfw.Press, 0) - w.WaitForEvents() assert.Nil(t, d1.popDragEvent()) assert.Nil(t, d2.popDragEvent()) // no drag start and no drag event with pressed secondary mouse button w.mouseMoved(w.viewport, 8, 8) - w.WaitForEvents() assert.Nil(t, d1.popDragEvent()) assert.Nil(t, d2.popDragEvent()) // no drag end event on secondary mouseUp w.mouseClicked(w.viewport, glfw.MouseButton2, glfw.Release, 0) - w.WaitForEvents() assert.Nil(t, d1.popDragEndEvent()) assert.Nil(t, d2.popDragEndEvent()) // no drag event in simple move w.mouseMoved(w.viewport, 9, 9) - w.WaitForEvents() assert.Nil(t, d1.popDragEvent()) assert.Nil(t, d2.popDragEvent()) // no drag event on secondary mouseDown w.mouseClicked(w.viewport, glfw.MouseButton2, glfw.Press, 0) - w.WaitForEvents() assert.Nil(t, d1.popDragEvent()) assert.Nil(t, d2.popDragEvent()) // no drag start and no drag event with pressed secondary mouse button w.mouseMoved(w.viewport, 8, 8) - w.WaitForEvents() assert.Nil(t, d1.popDragEvent()) assert.Nil(t, d2.popDragEvent()) // no drag end event on secondary mouseUp w.mouseClicked(w.viewport, glfw.MouseButton2, glfw.Release, 0) - w.WaitForEvents() assert.Nil(t, d1.popDragEndEvent()) assert.Nil(t, d2.popDragEndEvent()) // no drag event in simple move w.mouseMoved(w.viewport, 10, 10) - w.WaitForEvents() assert.Nil(t, d1.popDragEvent()) assert.Nil(t, d2.popDragEvent()) // no drag event on mouseDown w.mouseClicked(w.viewport, glfw.MouseButton1, glfw.Press, 0) - w.WaitForEvents() assert.Nil(t, d1.popDragEvent()) assert.Nil(t, d2.popDragEvent()) // drag start and drag event with pressed mouse button w.mouseMoved(w.viewport, 8, 8) - w.WaitForEvents() assert.Equal(t, &fyne.DragEvent{ PointEvent: fyne.PointEvent{Position: fyne.NewPos(4, 4), @@ -426,7 +408,6 @@ func TestWindow_HandleDragging(t *testing.T) { // drag event going outside the widget's area w.mouseMoved(w.viewport, 16, 8) - w.WaitForEvents() assert.Equal(t, &fyne.DragEvent{ PointEvent: fyne.PointEvent{Position: fyne.NewPos(12, 4), @@ -440,7 +421,6 @@ func TestWindow_HandleDragging(t *testing.T) { // drag event entering a _different_ widget's area still for the widget dragged initially w.mouseMoved(w.viewport, 22, 6) - w.WaitForEvents() assert.Equal(t, &fyne.DragEvent{ PointEvent: fyne.PointEvent{Position: fyne.NewPos(18, 2), @@ -453,26 +433,22 @@ func TestWindow_HandleDragging(t *testing.T) { // drag end event on mouseUp w.mouseClicked(w.viewport, glfw.MouseButton1, glfw.Release, 0) - w.WaitForEvents() assert.Nil(t, d1.popDragEvent()) assert.NotNil(t, d1.popDragEndEvent()) assert.Nil(t, d2.popDragEvent()) // no drag event on further mouse move w.mouseMoved(w.viewport, 22, 6) - w.WaitForEvents() assert.Nil(t, d1.popDragEvent()) assert.Nil(t, d2.popDragEvent()) // no drag event on mouseDown w.mouseClicked(w.viewport, glfw.MouseButton1, glfw.Press, 0) - w.WaitForEvents() assert.Nil(t, d1.popDragEvent()) assert.Nil(t, d2.popDragEvent()) // drag event for other widget w.mouseMoved(w.viewport, 26, 9) - w.WaitForEvents() assert.Nil(t, d1.popDragEvent()) assert.Equal(t, &fyne.DragEvent{ @@ -497,7 +473,6 @@ func TestWindow_DragObjectThatMoves(t *testing.T) { w.mouseMoved(w.viewport, 12, 12) w.mouseClicked(w.viewport, glfw.MouseButton1, glfw.Press, 0) w.mouseMoved(w.viewport, 10, 10) - w.WaitForEvents() assert.Equal(t, &fyne.DragEvent{ PointEvent: fyne.PointEvent{Position: fyne.NewPos(6, 6), @@ -513,7 +488,6 @@ func TestWindow_DragObjectThatMoves(t *testing.T) { // drag again -> position is relative to new element position w.mouseMoved(w.viewport, 12, 12) - w.WaitForEvents() assert.Equal(t, &fyne.DragEvent{ PointEvent: fyne.PointEvent{Position: fyne.NewPos(9, 9), @@ -540,7 +514,6 @@ func TestWindow_DragIntoNewObjectKeepingFocus(t *testing.T) { w.mouseClicked(w.viewport, glfw.MouseButton1, glfw.Press, 0) w.mouseMoved(w.viewport, 21, 11) w.mouseClicked(w.viewport, glfw.MouseButton1, glfw.Release, 0) - w.WaitForEvents() // we should only have 2 mouse events on d1 assert.Equal(t, @@ -577,7 +550,6 @@ func TestWindow_NoDragEndWithoutDraggedEvent(t *testing.T) { w.mouseClicked(w.viewport, glfw.MouseButton1, glfw.Press, 0) // mouse release without move (not really a drag) w.mouseClicked(w.viewport, glfw.MouseButton1, glfw.Release, 0) - w.WaitForEvents() assert.Nil(t, do.popDragEvent(), "no drag event without move") assert.Nil(t, do.popDragEndEvent(), "no drag end event without drag event") @@ -592,7 +564,6 @@ func TestWindow_HoverableOnDragging(t *testing.T) { repaintWindow(w) w.mouseMoved(w.viewport, 10, 10) - w.WaitForEvents() assert.Equal(t, &desktop.MouseEvent{PointEvent: fyne.PointEvent{Position: fyne.NewPos(6, 6), AbsolutePosition: fyne.NewPos(10, 10)}}, @@ -600,7 +571,6 @@ func TestWindow_HoverableOnDragging(t *testing.T) { ) w.mouseClicked(w.viewport, glfw.MouseButton1, glfw.Press, 0) w.mouseMoved(w.viewport, 12, 12) - w.WaitForEvents() assert.Equal(t, &fyne.DragEvent{ PointEvent: fyne.PointEvent{Position: fyne.NewPos(8, 8), @@ -612,7 +582,6 @@ func TestWindow_HoverableOnDragging(t *testing.T) { // drag event going outside the widget's area w.mouseMoved(w.viewport, 20, 12) - w.WaitForEvents() assert.Equal(t, &fyne.DragEvent{ PointEvent: fyne.PointEvent{Position: fyne.NewPos(16, 8), @@ -626,7 +595,6 @@ func TestWindow_HoverableOnDragging(t *testing.T) { // drag event going inside the widget's area again w.mouseMoved(w.viewport, 12, 12) - w.WaitForEvents() assert.Equal(t, &fyne.DragEvent{ PointEvent: fyne.PointEvent{Position: fyne.NewPos(8, 8), @@ -640,7 +608,6 @@ func TestWindow_HoverableOnDragging(t *testing.T) { // no hover events on end of drag event w.mouseClicked(w.viewport, glfw.MouseButton1, glfw.Release, 0) - w.WaitForEvents() assert.Nil(t, dh.popMouseInEvent()) assert.Nil(t, dh.popMouseMovedEvent()) assert.Nil(t, dh.popMouseOutEvent()) @@ -650,7 +617,6 @@ func TestWindow_HoverableOnDragging(t *testing.T) { w.mouseClicked(w.viewport, glfw.MouseButton1, glfw.Press, 0) w.mouseMoved(w.viewport, 28, 12) // outside the 20x20 object w.mouseClicked(w.viewport, glfw.MouseButton1, glfw.Release, 0) - w.WaitForEvents() assert.NotNil(t, dh.popMouseOutEvent()) } @@ -677,7 +643,6 @@ func TestWindow_HoverableUnderDraggable(t *testing.T) { // - no events by draggableObject // - no events by draggableHoverableObject w.mouseMoved(w.viewport, 7, 7) - w.WaitForEvents() assert.Equal(t, &desktop.MouseEvent{PointEvent: fyne.PointEvent{Position: fyne.NewPos(3, 3), AbsolutePosition: fyne.NewPos(7, 7)}}, h.popMouseInEvent()) assert.Nil(t, h.popMouseMovedEvent()) @@ -696,7 +661,6 @@ func TestWindow_HoverableUnderDraggable(t *testing.T) { // - no events by draggableHoverableObject w.mouseClicked(w.viewport, glfw.MouseButton1, glfw.Press, 0) w.mouseMoved(w.viewport, 8, 8) - w.WaitForEvents() assert.Nil(t, h.popMouseInEvent()) assert.Equal(t, &desktop.MouseEvent{PointEvent: fyne.PointEvent{Position: fyne.NewPos(4, 4), AbsolutePosition: fyne.NewPos(8, 8)}, Button: 1, Modifier: 0}, h.popMouseMovedEvent()) @@ -715,7 +679,6 @@ func TestWindow_HoverableUnderDraggable(t *testing.T) { // - no events by draggableObject // - no events by draggableHoverableObject w.mouseMoved(w.viewport, 16, 16) - w.WaitForEvents() assert.Nil(t, h.popMouseInEvent()) assert.Equal(t, &desktop.MouseEvent{PointEvent: fyne.PointEvent{Position: fyne.NewPos(12, 12), AbsolutePosition: fyne.NewPos(16, 16)}}, h.popMouseMovedEvent()) @@ -734,7 +697,6 @@ func TestWindow_HoverableUnderDraggable(t *testing.T) { // - no events by draggableHoverableObject w.mouseClicked(w.viewport, glfw.MouseButton1, glfw.Press, 0) w.mouseMoved(w.viewport, 18, 18) - w.WaitForEvents() assert.Nil(t, h.popMouseInEvent()) assert.Equal(t, &desktop.MouseEvent{PointEvent: fyne.PointEvent{Position: fyne.NewPos(14, 14), AbsolutePosition: fyne.NewPos(18, 18)}, Button: 1, Modifier: 0}, h.popMouseMovedEvent()) @@ -753,7 +715,6 @@ func TestWindow_HoverableUnderDraggable(t *testing.T) { // - drag end by draggableObject // - no events by draggableHoverableObject w.mouseClicked(w.viewport, glfw.MouseButton1, glfw.Release, 0) - w.WaitForEvents() assert.Nil(t, h.popMouseInEvent()) assert.Nil(t, h.popMouseMovedEvent()) assert.Nil(t, h.popMouseOutEvent()) @@ -770,7 +731,6 @@ func TestWindow_HoverableUnderDraggable(t *testing.T) { // - no events by draggableObject // - mouseIn by draggableHoverableObject w.mouseMoved(w.viewport, 27, 27) - w.WaitForEvents() assert.Nil(t, h.popMouseInEvent()) assert.Nil(t, h.popMouseMovedEvent()) assert.NotNil(t, h.popMouseOutEvent()) @@ -788,7 +748,6 @@ func TestWindow_HoverableUnderDraggable(t *testing.T) { // - no events by draggableObject // - mouseOut by draggableHoverableObject w.mouseMoved(w.viewport, 37, 37) - w.WaitForEvents() assert.Equal(t, &desktop.MouseEvent{PointEvent: fyne.PointEvent{Position: fyne.NewPos(33, 33), AbsolutePosition: fyne.NewPos(37, 37)}}, h.popMouseInEvent()) assert.Nil(t, h.popMouseMovedEvent()) @@ -806,7 +765,6 @@ func TestWindow_HoverableUnderDraggable(t *testing.T) { // - no events by draggableObject // - no events by draggableHoverableObject w.mouseMoved(w.viewport, 47, 47) - w.WaitForEvents() assert.Nil(t, h.popMouseInEvent()) assert.Equal(t, &desktop.MouseEvent{PointEvent: fyne.PointEvent{Position: fyne.NewPos(43, 43), AbsolutePosition: fyne.NewPos(47, 47)}}, h.popMouseMovedEvent()) @@ -823,7 +781,6 @@ func TestWindow_HoverableUnderDraggable(t *testing.T) { // - no events by draggableObject // - no events by draggableHoverableObject w.mouseMoved(w.viewport, 57, 57) - w.WaitForEvents() assert.Nil(t, h.popMouseInEvent()) assert.Nil(t, h.popMouseMovedEvent()) assert.NotNil(t, h.popMouseOutEvent()) @@ -851,7 +808,6 @@ func TestWindow_HoverableUnderDraggable_DragAcross(t *testing.T) { dh.Move(fyne.NewPos(20, 20)) w.SetContent(c) - repaintWindow(w) // 1. drag across hoverable @@ -859,7 +815,6 @@ func TestWindow_HoverableUnderDraggable_DragAcross(t *testing.T) { // - no events by draggableObject // - no events by draggableHoverableObject w.mouseMoved(w.viewport, 16, 16) - w.WaitForEvents() assert.Equal(t, &desktop.MouseEvent{PointEvent: fyne.PointEvent{Position: fyne.NewPos(12, 12), AbsolutePosition: fyne.NewPos(16, 16)}}, h.popMouseInEvent()) assert.Nil(t, h.popMouseMovedEvent()) @@ -878,7 +833,6 @@ func TestWindow_HoverableUnderDraggable_DragAcross(t *testing.T) { // - no events by draggableHoverableObject w.mouseClicked(w.viewport, glfw.MouseButton1, glfw.Press, 0) w.mouseMoved(w.viewport, 18, 18) - w.WaitForEvents() assert.Nil(t, h.popMouseInEvent()) assert.Equal(t, &desktop.MouseEvent{PointEvent: fyne.PointEvent{Position: fyne.NewPos(14, 14), AbsolutePosition: fyne.NewPos(18, 18)}, Button: 1, Modifier: 0}, h.popMouseMovedEvent()) @@ -897,7 +851,6 @@ func TestWindow_HoverableUnderDraggable_DragAcross(t *testing.T) { // - drag events by draggableObject // - moveIn by draggableHoverableObject w.mouseMoved(w.viewport, 27, 27) - w.WaitForEvents() assert.Nil(t, h.popMouseInEvent()) assert.Nil(t, h.popMouseMovedEvent()) assert.NotNil(t, h.popMouseOutEvent()) @@ -916,7 +869,6 @@ func TestWindow_HoverableUnderDraggable_DragAcross(t *testing.T) { // - drag event by draggableObject // - mouseOut by draggableHoverableObject w.mouseMoved(w.viewport, 37, 37) - w.WaitForEvents() assert.Equal(t, &desktop.MouseEvent{PointEvent: fyne.PointEvent{Position: fyne.NewPos(33, 33), AbsolutePosition: fyne.NewPos(37, 37)}, Button: 1, Modifier: 0}, h.popMouseInEvent()) assert.Nil(t, h.popMouseMovedEvent()) @@ -935,7 +887,6 @@ func TestWindow_HoverableUnderDraggable_DragAcross(t *testing.T) { // - drag end by draggableObject // - no events by draggableHoverableObject w.mouseClicked(w.viewport, glfw.MouseButton1, glfw.Release, 0) - w.WaitForEvents() assert.Nil(t, h.popMouseInEvent()) assert.Nil(t, h.popMouseMovedEvent()) assert.Nil(t, h.popMouseOutEvent()) @@ -963,7 +914,6 @@ func TestWindow_HoverableUnderDraggable_Drag_draggableHoverable(t *testing.T) { dh.Move(fyne.NewPos(20, 20)) w.SetContent(c) - repaintWindow(w) // 1. drag of draggableHoverable @@ -971,7 +921,6 @@ func TestWindow_HoverableUnderDraggable_Drag_draggableHoverable(t *testing.T) { // - no event by draggableObject // - moveIn event by draggableHoverableObject w.mouseMoved(w.viewport, 28, 28) - w.WaitForEvents() assert.Nil(t, h.popMouseInEvent()) assert.Nil(t, h.popMouseMovedEvent()) assert.Nil(t, h.popMouseOutEvent()) @@ -990,7 +939,6 @@ func TestWindow_HoverableUnderDraggable_Drag_draggableHoverable(t *testing.T) { // - drag begin by draggableHoverableObject w.mouseClicked(w.viewport, glfw.MouseButton1, glfw.Press, 0) w.mouseMoved(w.viewport, 30, 30) - w.WaitForEvents() assert.Nil(t, h.popMouseInEvent()) assert.Nil(t, h.popMouseMovedEvent()) assert.Nil(t, h.popMouseOutEvent()) @@ -1008,7 +956,6 @@ func TestWindow_HoverableUnderDraggable_Drag_draggableHoverable(t *testing.T) { // - no events by draggableObject // - drag and moveOut by draggableHoverableObject w.mouseMoved(w.viewport, 47, 47) - w.WaitForEvents() assert.Equal(t, &desktop.MouseEvent{PointEvent: fyne.PointEvent{Position: fyne.NewPos(43, 43), AbsolutePosition: fyne.NewPos(47, 47)}, Button: 1, Modifier: 0}, h.popMouseInEvent()) assert.Nil(t, h.popMouseMovedEvent()) @@ -1027,7 +974,6 @@ func TestWindow_HoverableUnderDraggable_Drag_draggableHoverable(t *testing.T) { // - no events by draggableObject // - drag end by draggableHoverableObject w.mouseClicked(w.viewport, glfw.MouseButton1, glfw.Release, 0) - w.WaitForEvents() assert.Nil(t, h.popMouseInEvent()) assert.Nil(t, h.popMouseMovedEvent()) assert.Nil(t, h.popMouseOutEvent()) @@ -1054,14 +1000,11 @@ func TestWindow_DragEndWithoutTappedEvent(t *testing.T) { w.mouseMoved(w.viewport, 10, 10) // Less than drag threshold w.mouseClicked(w.viewport, glfw.MouseButton1, glfw.Release, 0) - w.WaitForEvents() assert.NotNil(t, do.popTapEvent()) // it was slight drag, so call it a tap w.mouseMoved(w.viewport, 7, 7) w.mouseClicked(w.viewport, glfw.MouseButton1, glfw.Release, 0) - w.WaitForEvents() - assert.Nil(t, do.popTapEvent()) } @@ -1093,7 +1036,6 @@ func TestWindow_Tapped(t *testing.T) { w.mousePos = fyne.NewPos(50, 160) w.mouseClicked(w.viewport, glfw.MouseButton1, glfw.Press, 0) w.mouseClicked(w.viewport, glfw.MouseButton1, glfw.Release, 0) - w.WaitForEvents() assert.Nil(t, o.popSecondaryTapEvent(), "no secondary tap") if e, _ := o.popTapEvent().(*fyne.PointEvent); assert.NotNil(t, e, "tapped") { @@ -1112,7 +1054,6 @@ func TestWindow_TappedSecondary(t *testing.T) { w.mousePos = fyne.NewPos(50, 60) w.mouseClicked(w.viewport, glfw.MouseButton2, glfw.Press, 0) w.mouseClicked(w.viewport, glfw.MouseButton2, glfw.Release, 0) - w.WaitForEvents() assert.Nil(t, o.popTapEvent(), "no primary tap") if e, _ := o.popSecondaryTapEvent().(*fyne.PointEvent); assert.NotNil(t, e, "tapped secondary") { @@ -1134,13 +1075,11 @@ func TestWindow_TappedSecondary_OnPrimaryOnlyTarget(t *testing.T) { w.mousePos = fyne.NewPos(10, 25) w.mouseClicked(w.viewport, glfw.MouseButton2, glfw.Press, 0) w.mouseClicked(w.viewport, glfw.MouseButton2, glfw.Release, 0) - w.WaitForEvents() assert.False(t, tapped) w.mouseClicked(w.viewport, glfw.MouseButton1, glfw.Press, 0) w.mouseClicked(w.viewport, glfw.MouseButton1, glfw.Release, 0) - w.WaitForEvents() assert.True(t, tapped) } @@ -1169,16 +1108,12 @@ func TestWindow_TappedIgnoresScrollerClip(t *testing.T) { w.mouseClicked(w.viewport, glfw.MouseButton1, glfw.Press, 0) w.mouseClicked(w.viewport, glfw.MouseButton1, glfw.Release, 0) - w.WaitForEvents() - assert.False(t, tapped, "Tapped button that was clipped") w.mousePos = fyne.NewPos(10, 120) w.mouseClicked(w.viewport, glfw.MouseButton1, glfw.Press, 0) w.mouseClicked(w.viewport, glfw.MouseButton1, glfw.Release, 0) - w.WaitForEvents() - assert.True(t, tapped, "Tapped button that was clipped") } @@ -1193,8 +1128,6 @@ func TestWindow_TappedIgnoredWhenMovedOffOfTappable(t *testing.T) { w.mouseClicked(w.viewport, glfw.MouseButton1, glfw.Press, 0) w.mouseClicked(w.viewport, glfw.MouseButton1, glfw.Release, 0) - w.WaitForEvents() - assert.Equal(t, 1, tapped, "Button 1 should be tapped") tapped = 0 @@ -1202,15 +1135,11 @@ func TestWindow_TappedIgnoredWhenMovedOffOfTappable(t *testing.T) { w.mouseMoved(w.viewport, 17, 59) w.mouseClicked(w.viewport, glfw.MouseButton1, glfw.Release, 0) - w.WaitForEvents() - assert.Equal(t, 0, tapped, "button was tapped without mouse press & release on it %d", tapped) w.mouseClicked(w.viewport, glfw.MouseButton1, glfw.Press, 0) w.mouseClicked(w.viewport, glfw.MouseButton1, glfw.Release, 0) - w.WaitForEvents() - assert.Equal(t, 2, tapped, "Button 2 should be tapped") } @@ -1235,7 +1164,6 @@ func TestWindow_TappedAndDoubleTapped(t *testing.T) { w.mouseClicked(w.viewport, glfw.MouseButton1, glfw.Release, 0) <-waitSingleTapped - w.WaitForEvents() time.Sleep(500 * time.Millisecond) assert.Equal(t, int32(1), tapped.Load(), "Single tap should have fired") @@ -1247,7 +1175,6 @@ func TestWindow_TappedAndDoubleTapped(t *testing.T) { w.mouseClicked(w.viewport, glfw.MouseButton1, glfw.Release, 0) <-waitDoubleTapped - w.WaitForEvents() time.Sleep(500 * time.Millisecond) assert.Equal(t, int32(2), tapped.Load(), "Double tap should have fired") @@ -1263,7 +1190,6 @@ func TestWindow_MouseEventContainsModifierKeys(t *testing.T) { ensureCanvasSize(t, w, minSize.AddWidthHeight(theme.Padding()*2, theme.Padding()*2)) w.mouseMoved(w.viewport, 7, 7) - w.WaitForEvents() // On OS X a Ctrl+Click is normally translated into a Right-Click. // The well-known Ctrl+Click for extending a selection is a Cmd+Click there. @@ -1349,7 +1275,7 @@ func TestWindow_MouseEventContainsModifierKeys(t *testing.T) { t.Run(name, func(t *testing.T) { require.Nil(t, m.popMouseEvent(), "no initial mouse event") w.mouseClicked(w.viewport, glfw.MouseButton1, glfw.Press, tt.modifier) - w.WaitForEvents() + me, _ := m.popMouseEvent().(*desktop.MouseEvent) if assert.NotNil(t, me, "mouse event triggered") { assert.Equal(t, tt.expectedEventModifier, me.Modifier, "expect modifier to be correct") @@ -1485,12 +1411,10 @@ func TestWindow_Focus(t *testing.T) { w.charInput(w.viewport, 'c') w.charInput(w.viewport, 'd') w.keyPressed(w.viewport, glfw.KeyTab, 0, glfw.Press, 0) - w.WaitForEvents() w.keyPressed(w.viewport, glfw.KeyTab, 0, glfw.Release, 0) w.charInput(w.viewport, 'e') w.charInput(w.viewport, 'f') - w.WaitForEvents() assert.Equal(t, "abcd", e1.Text) assert.Equal(t, "ef", e2.Text) @@ -1512,8 +1436,6 @@ func TestWindow_CaptureTypedShortcut(t *testing.T) { w.keyPressed(nil, glfw.KeyLeftControl, 0, glfw.Release, glfw.ModControl) w.keyPressed(nil, glfw.KeyF, 0, glfw.Release, glfw.ModControl) - w.WaitForEvents() - assert.Equal(t, 1, len(content.capturedShortcuts)) assert.Equal(t, "CustomDesktop:Control+F", content.capturedShortcuts[0].ShortcutName()) } @@ -1530,11 +1452,9 @@ func TestWindow_OnlyTabAndShiftTabToCapturesTab(t *testing.T) { // Tab and Shift-Tab are passed to capturesTab w.keyPressed(nil, glfw.KeyTab, 0, glfw.Press, glfw.ModShift) w.keyPressed(nil, glfw.KeyTab, 0, glfw.Release, glfw.ModShift) - w.WaitForEvents() assert.Equal(t, 1, content.acceptTabCallCount) w.keyPressed(nil, glfw.KeyTab, 0, glfw.Press, 0) w.keyPressed(nil, glfw.KeyTab, 0, glfw.Release, 0) - w.WaitForEvents() assert.Equal(t, 2, content.acceptTabCallCount) // Tab with ctrl or alt is not passed @@ -1542,7 +1462,6 @@ func TestWindow_OnlyTabAndShiftTabToCapturesTab(t *testing.T) { w.keyPressed(nil, glfw.KeyTab, 0, glfw.Release, glfw.ModControl) w.keyPressed(nil, glfw.KeyTab, 0, glfw.Press, glfw.ModControl|glfw.ModShift) w.keyPressed(nil, glfw.KeyTab, 0, glfw.Release, glfw.ModControl|glfw.ModShift) - w.WaitForEvents() assert.Equal(t, 2, content.acceptTabCallCount) } @@ -1561,7 +1480,6 @@ func TestWindow_TabWithModifierToTriggersShortcut(t *testing.T) { w.keyPressed(nil, glfw.KeyTab, 0, glfw.Press, 0) w.keyPressed(nil, glfw.KeyTab, 0, glfw.Release, 0) - w.WaitForEvents() assert.Equal(t, 0, len(content.capturedShortcuts)) @@ -1570,7 +1488,6 @@ func TestWindow_TabWithModifierToTriggersShortcut(t *testing.T) { w.keyPressed(nil, glfw.KeyTab, 0, glfw.Release, glfw.ModControl) w.keyPressed(nil, glfw.KeyTab, 0, glfw.Press, glfw.ModControl|glfw.ModShift) w.keyPressed(nil, glfw.KeyTab, 0, glfw.Release, glfw.ModControl|glfw.ModShift) - w.WaitForEvents() assert.Equal(t, 2, len(content.capturedShortcuts)) assert.Equal(t, "CustomDesktop:Control+Tab", content.capturedShortcuts[0].ShortcutName()) assert.Equal(t, "CustomDesktop:Shift+Control+Tab", content.capturedShortcuts[1].ShortcutName()) @@ -1586,13 +1503,11 @@ func TestWindow_ManualFocus(t *testing.T) { w.mouseMoved(w.viewport, 9, 9) w.mouseClicked(w.viewport, glfw.MouseButton1, glfw.Press, 0) w.mouseClicked(w.viewport, glfw.MouseButton1, glfw.Release, 0) - w.WaitForEvents() assert.Equal(t, 1, content.focusedTimes) assert.Equal(t, 0, content.unfocusedTimes) w.mouseClicked(w.viewport, glfw.MouseButton1, glfw.Press, 0) w.mouseClicked(w.viewport, glfw.MouseButton1, glfw.Release, 0) - w.WaitForEvents() assert.Equal(t, 1, content.focusedTimes) assert.Equal(t, 0, content.unfocusedTimes) @@ -1610,7 +1525,6 @@ func TestWindow_ManualFocus(t *testing.T) { assert.Equal(t, 1, content.unfocusedTimes) w.mouseClicked(w.viewport, glfw.MouseButton1, glfw.Press, 0) - w.WaitForEvents() assert.Equal(t, 1, content.focusedTimes) assert.Equal(t, 1, content.unfocusedTimes) } @@ -1632,7 +1546,6 @@ func TestWindow_ClipboardCopy_DisabledEntry(t *testing.T) { ctrlMod = glfw.ModSuper } w.keyPressed(nil, glfw.KeyC, 0, glfw.Repeat, ctrlMod) - w.WaitForEvents() assert.Equal(t, "Testing", NewClipboard().Content()) @@ -1642,14 +1555,12 @@ func TestWindow_ClipboardCopy_DisabledEntry(t *testing.T) { // any other shortcut should be forbidden (Cut) w.keyPressed(nil, glfw.KeyX, 0, glfw.Repeat, ctrlMod) - w.WaitForEvents() assert.Equal(t, "Testing2", e.Text) assert.Equal(t, "Testing", NewClipboard().Content()) // any other shortcut should be forbidden (Paste) w.keyPressed(nil, glfw.KeyV, 0, glfw.Repeat, ctrlMod) - w.WaitForEvents() assert.Equal(t, "Testing2", e.Text) assert.Equal(t, "Testing", NewClipboard().Content()) diff --git a/internal/driver/glfw/window_wasm.go b/internal/driver/glfw/window_wasm.go index 25068a1495..c33a2cd97d 100644 --- a/internal/driver/glfw/window_wasm.go +++ b/internal/driver/glfw/window_wasm.go @@ -11,7 +11,6 @@ import ( "fyne.io/fyne/v2" "fyne.io/fyne/v2/container" "fyne.io/fyne/v2/driver/desktop" - "fyne.io/fyne/v2/internal/driver/common" "fyne.io/fyne/v2/internal/painter/gl" "fyne.io/fyne/v2/internal/scale" @@ -45,8 +44,6 @@ var cursorMap map[desktop.Cursor]*Cursor var _ fyne.Window = (*window)(nil) type window struct { - common.Window - viewport *glfw.Window viewLock sync.RWMutex createLock sync.Once diff --git a/internal/driver/mobile/driver.go b/internal/driver/mobile/driver.go index 96315c873b..bba05f363b 100644 --- a/internal/driver/mobile/driver.go +++ b/internal/driver/mobile/driver.go @@ -74,7 +74,6 @@ func init() { func (d *driver) CreateWindow(title string) fyne.Window { c := newCanvas(fyne.CurrentDevice()).(*canvas) // silence lint ret := &window{title: title, canvas: c, isChild: len(d.windows) > 0} - ret.InitEventQueue() c.setContent(&fynecanvas.Rectangle{FillColor: theme.Color(theme.ColorNameBackground)}) c.SetPainter(pgl.NewPainter(c, ret)) d.windows = append(d.windows, ret) @@ -177,7 +176,6 @@ func (d *driver) Run() { if current == nil { continue } - current.ProcessEventQueue() c := current.Canvas().(*canvas) switch e := a.Filter(e).(type) { @@ -252,7 +250,7 @@ func (d *driver) handleLifecycle(e lifecycle.Event, w *window) { switch e.Crosses(lifecycle.StageFocused) { case lifecycle.CrossOn: // foregrounding if f := fyne.CurrentApp().Lifecycle().(*intapp.Lifecycle).OnEnteredForeground(); f != nil { - w.QueueEvent(f) + f() } case lifecycle.CrossOff: // will enter background if runtime.GOOS == "darwin" || runtime.GOOS == "ios" { @@ -265,7 +263,7 @@ func (d *driver) handleLifecycle(e lifecycle.Event, w *window) { d.app.Publish() } if f := fyne.CurrentApp().Lifecycle().(*intapp.Lifecycle).OnExitedForeground(); f != nil { - w.QueueEvent(f) + f() } } } @@ -388,7 +386,7 @@ func (d *driver) tapMoveCanvas(w *window, x, y float32, tapID touch.Sequence) { pos := fyne.NewPos(tapX, tapY+tapYOffset) w.canvas.tapMove(pos, int(tapID), func(wid fyne.Draggable, ev *fyne.DragEvent) { - w.QueueEvent(func() { wid.Dragged(ev) }) + wid.Dragged(ev) }) } @@ -398,14 +396,14 @@ func (d *driver) tapUpCanvas(w *window, x, y float32, tapID touch.Sequence) { pos := fyne.NewPos(tapX, tapY+tapYOffset) w.canvas.tapUp(pos, int(tapID), func(wid fyne.Tappable, ev *fyne.PointEvent) { - w.QueueEvent(func() { wid.Tapped(ev) }) + wid.Tapped(ev) }, func(wid fyne.SecondaryTappable, ev *fyne.PointEvent) { - w.QueueEvent(func() { wid.TappedSecondary(ev) }) + wid.TappedSecondary(ev) }, func(wid fyne.DoubleTappable, ev *fyne.PointEvent) { - w.QueueEvent(func() { wid.DoubleTapped(ev) }) + wid.DoubleTapped(ev) }, func(wid fyne.Draggable, ev *fyne.DragEvent) { if math.Abs(float64(ev.Dragged.DX)) <= tapMoveEndThreshold && math.Abs(float64(ev.Dragged.DY)) <= tapMoveEndThreshold { - w.QueueEvent(wid.DragEnd) + wid.DragEnd() return } @@ -418,11 +416,11 @@ func (d *driver) tapUpCanvas(w *window, x, y float32, tapID touch.Sequence) { ev.Dragged.DY *= tapMoveDecay } - w.QueueEvent(func() { wid.Dragged(ev) }) + wid.Dragged(ev) time.Sleep(time.Millisecond * 16) } - w.QueueEvent(wid.DragEnd) + wid.DragEnd() }() }) } diff --git a/internal/driver/mobile/window.go b/internal/driver/mobile/window.go index b119429cae..85cdf095db 100644 --- a/internal/driver/mobile/window.go +++ b/internal/driver/mobile/window.go @@ -11,8 +11,6 @@ import ( ) type window struct { - common.Window - title string visible bool onClosed func() @@ -142,7 +140,7 @@ func (w *window) Hide() { func (w *window) tryClose() { if w.onCloseIntercepted != nil { - w.QueueEvent(w.onCloseIntercepted) + w.onCloseIntercepted() return } @@ -168,16 +166,7 @@ func (w *window) Close() { cache.DestroyRenderer(wid) } }) - - w.QueueEvent(func() { - cache.CleanCanvas(w.canvas) - }) - - // Call this in a go routine, because this function could be called - // inside a button which callback would be queued in this event queue - // and it will lead to a deadlock if this is performed in the same go - // routine. - go w.DestroyEventQueue() + cache.CleanCanvas(w.canvas) if w.onClosed != nil { w.onClosed()