Skip to content

Commit

Permalink
Merge pull request #5420 from Jacalz/last-big-lock.cleanup
Browse files Browse the repository at this point in the history
  • Loading branch information
Jacalz authored Jan 16, 2025
2 parents 817fbd8 + 13f72ed commit 5a4731e
Show file tree
Hide file tree
Showing 20 changed files with 98 additions and 160 deletions.
12 changes: 7 additions & 5 deletions dialog/color_channel.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ package dialog

import (
"strconv"
"sync/atomic"

"fyne.io/fyne/v2"
"fyne.io/fyne/v2/canvas"
Expand Down Expand Up @@ -152,7 +151,7 @@ func (e *colorChannelEntry) MinSize() fyne.Size {

type userChangeEntry struct {
widget.Entry
userTyped atomic.Bool
userTyped bool
}

func newUserChangeEntry(text string) *userChangeEntry {
Expand All @@ -164,9 +163,12 @@ func newUserChangeEntry(text string) *userChangeEntry {

func (e *userChangeEntry) setOnChanged(onChanged func(s string)) {
e.Entry.OnChanged = func(text string) {
if !e.userTyped.CompareAndSwap(true, false) {
if !e.userTyped {
return
}

e.userTyped = false

if onChanged != nil {
onChanged(text)
}
Expand All @@ -175,11 +177,11 @@ func (e *userChangeEntry) setOnChanged(onChanged func(s string)) {
}

func (e *userChangeEntry) TypedRune(r rune) {
e.userTyped.Store(true)
e.userTyped = true
e.Entry.TypedRune(r)
}

func (e *userChangeEntry) TypedKey(ev *fyne.KeyEvent) {
e.userTyped.Store(true)
e.userTyped = true
e.Entry.TypedKey(ev)
}
7 changes: 3 additions & 4 deletions internal/animation/animation.go
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
package animation

import (
"sync/atomic"
"time"

"fyne.io/fyne/v2"
Expand All @@ -14,7 +13,7 @@ type anim struct {
reverse bool
start time.Time
total int64
stopped atomic.Bool
stopped bool
}

func newAnim(a *fyne.Animation) *anim {
Expand All @@ -25,9 +24,9 @@ func newAnim(a *fyne.Animation) *anim {
}

func (a *anim) setStopped() {
a.stopped.Store(true)
a.stopped = true
}

func (a *anim) isStopped() bool {
return a.stopped.Load()
return a.stopped
}
49 changes: 16 additions & 33 deletions internal/app/lifecycle.go
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
package app

import (
"sync/atomic"

"fyne.io/fyne/v2"
"fyne.io/fyne/v2/internal/async"
)
Expand All @@ -13,10 +11,10 @@ var _ fyne.Lifecycle = (*Lifecycle)(nil)
//
// Since: 2.1
type Lifecycle struct {
onForeground atomic.Pointer[func()]
onBackground atomic.Pointer[func()]
onStarted atomic.Pointer[func()]
onStopped atomic.Pointer[func()]
onForeground func()
onBackground func()
onStarted func()
onStopped func()

onStoppedHookExecuted func()

Expand All @@ -31,75 +29,60 @@ func (l *Lifecycle) SetOnStoppedHookExecuted(f func()) {

// SetOnEnteredForeground hooks into the app becoming foreground.
func (l *Lifecycle) SetOnEnteredForeground(f func()) {
l.onForeground.Store(&f)
l.onForeground = f
}

// SetOnExitedForeground hooks into the app having moved to the background.
// Depending on the platform it may still be visible but will not receive keyboard events.
// On some systems hover or desktop mouse move events may still occur.
func (l *Lifecycle) SetOnExitedForeground(f func()) {
l.onBackground.Store(&f)
l.onBackground = f
}

// SetOnStarted hooks into an event that says the app is now running.
func (l *Lifecycle) SetOnStarted(f func()) {
l.onStarted.Store(&f)
l.onStarted = f
}

// SetOnStopped hooks into an event that says the app is no longer running.
func (l *Lifecycle) SetOnStopped(f func()) {
l.onStopped.Store(&f)
l.onStopped = f
}

// OnEnteredForeground returns the focus gained hook, if one is registered.
func (l *Lifecycle) OnEnteredForeground() func() {
f := l.onForeground.Load()
if f == nil {
return nil
}

return *f
return l.onForeground
}

// OnExitedForeground returns the focus lost hook, if one is registered.
func (l *Lifecycle) OnExitedForeground() func() {
f := l.onBackground.Load()
if f == nil {
return nil
}

return *f
return l.onBackground
}

// OnStarted returns the started hook, if one is registered.
func (l *Lifecycle) OnStarted() func() {
f := l.onStarted.Load()
if f == nil {
return nil
}

return *f
return l.onStarted
}

// OnStopped returns the stopped hook, if one is registered.
func (l *Lifecycle) OnStopped() func() {
stopped := l.onStopped.Load()
stopped := l.onStopped
stopHook := l.onStoppedHookExecuted
if (stopped == nil || *stopped == nil) && stopHook == nil {
if stopped == nil && stopHook == nil {
return nil
}

if stopHook == nil {
return *stopped
return stopped
}

if stopped == nil || *stopped == nil {
if stopped == nil {
return stopHook
}

// we have a stopped handle and the onStoppedHook
return func() {
(*stopped)()
stopped()
stopHook()
}
}
Expand Down
6 changes: 6 additions & 0 deletions internal/build/menu_integrated.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
//go:build !darwin || no_native_menus

package build

// HasNativeMenu is true if the app is built with support for native menu.
const HasNativeMenu = false
6 changes: 6 additions & 0 deletions internal/build/menu_native.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
//go:build darwin && !no_native_menus

package build

// HasNativeMenu is true if the app is built with support for native menu.
const HasNativeMenu = true
27 changes: 3 additions & 24 deletions internal/cache/base.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ package cache

import (
"os"
"sync/atomic"
"time"

"fyne.io/fyne/v2"
Expand Down Expand Up @@ -175,35 +174,15 @@ func matchesACanvas(cinfo *canvasInfo, canvases []fyne.Canvas) bool {
}

type expiringCache struct {
expires atomic.Pointer[time.Time]
}

// isExpired check if the cache data is expired.
func (c *expiringCache) isExpired(now time.Time) bool {
t := c.expires.Load()
if t == nil {
return (time.Time{}).Before(now)
}
return (*t).Before(now)
}

// setAlive updates expiration time.
func (c *expiringCache) setAlive() {
time := timeNow().Add(cacheDuration)
c.expires.Store(&time)
}

type expiringCacheNoLock struct {
expires time.Time
}

// isExpired check if the cache data is expired.
func (c *expiringCacheNoLock) isExpired(now time.Time) bool {
func (c *expiringCache) isExpired(now time.Time) bool {
return c.expires.Before(now)
}

// setAlive updates expiration time.
func (c *expiringCacheNoLock) setAlive() {
t := timeNow().Add(cacheDuration)
c.expires = t
func (c *expiringCache) setAlive() {
c.expires = timeNow().Add(cacheDuration)
}
22 changes: 1 addition & 21 deletions internal/cache/base_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -192,23 +192,6 @@ func Test_expiringCache(t *testing.T) {
assert.True(t, c.isExpired(tm.now))
}

func Test_expiringCacheNoLock(t *testing.T) {
tm := &timeMock{}
tm.setTime(10, 10)

c := &expiringCacheNoLock{}
assert.True(t, c.isExpired(tm.now))

c.setAlive()

tm.setTime(10, 20)
assert.False(t, c.isExpired(tm.now))

tm.setTime(10, 11)
tm.now = tm.now.Add(cacheDuration)
assert.True(t, c.isExpired(tm.now))
}

type dummyCanvas struct {
fyne.Canvas
}
Expand Down Expand Up @@ -265,10 +248,7 @@ func (t *timeMock) setTime(min, sec int) {
func testClearAll() {
skippedCleanWithCanvasRefresh = false
canvases = make(map[fyne.CanvasObject]*canvasInfo, 1024)
svgs.Range(func(key string, _ *svgInfo) bool {
svgs.Delete(key)
return true
})
svgs.Clear()
textTextures.Clear()
objectTextures.Clear()
renderers.Clear()
Expand Down
2 changes: 0 additions & 2 deletions internal/cache/svg.go
Original file line number Diff line number Diff line change
Expand Up @@ -37,8 +37,6 @@ func SetSvg(name string, o fyne.CanvasObject, pix *image.NRGBA, w int, h int) {
}

type svgInfo struct {
// An svgInfo can be accessed from different goroutines, e.g., systray.
// Use expiringCache instead of expiringCacheNoLock.
expiringCache
pix *image.NRGBA
w, h int
Expand Down
8 changes: 4 additions & 4 deletions internal/cache/texture_common.go
Original file line number Diff line number Diff line change
Expand Up @@ -87,17 +87,17 @@ func DeleteTextTexturesFor(canvas fyne.Canvas) {

// SetTextTexture sets cached texture for a text run.
func SetTextTexture(ent FontCacheEntry, texture TextureType, canvas fyne.Canvas, free func()) {
tinfo := prepareTexture(ent, texture, canvas, free)
tinfo := prepareTexture(texture, canvas, free)
textTextures.Store(ent, tinfo)
}

// SetTexture sets cached texture.
func SetTexture(obj fyne.CanvasObject, texture TextureType, canvas fyne.Canvas) {
tinfo := prepareTexture(obj, texture, canvas, nil)
tinfo := prepareTexture(texture, canvas, nil)
objectTextures.Store(obj, tinfo)
}

func prepareTexture(obj any, texture TextureType, canvas fyne.Canvas, free func()) *textureInfo {
func prepareTexture(texture TextureType, canvas fyne.Canvas, free func()) *textureInfo {
tinfo := &textureInfo{texture: texture, textFree: free}
tinfo.canvas = canvas
tinfo.setAlive()
Expand All @@ -106,6 +106,6 @@ func prepareTexture(obj any, texture TextureType, canvas fyne.Canvas, free func(

// textureCacheBase defines base texture cache object.
type textureCacheBase struct {
expiringCacheNoLock
expiringCache
canvas fyne.Canvas
}
9 changes: 5 additions & 4 deletions internal/driver/common/canvas.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ package common
import (
"image/color"
"reflect"
"sync/atomic"

"fyne.io/fyne/v2"
"fyne.io/fyne/v2/canvas"
Expand Down Expand Up @@ -46,7 +45,7 @@ type Canvas struct {
// the refreshQueue is an unbounded queue which is able to cache
// arbitrary number of fyne.CanvasObject for the rendering.
refreshQueue *async.CanvasObjectQueue
dirty atomic.Bool
dirty bool

mWindowHeadTree, contentTree, menuTree *renderCacheTree
}
Expand Down Expand Up @@ -342,12 +341,14 @@ func (c *Canvas) SetContentTreeAndFocusMgr(content fyne.CanvasObject) {
// CheckDirtyAndClear returns true if the canvas is dirty and
// clears the dirty state atomically.
func (c *Canvas) CheckDirtyAndClear() bool {
return c.dirty.Swap(false)
wasDirty := c.dirty
c.dirty = false
return wasDirty
}

// SetDirty sets canvas dirty flag atomically.
func (c *Canvas) SetDirty() {
c.dirty.Store(true)
c.dirty = true
}

// SetMenuTreeAndFocusMgr sets menu tree and focus manager.
Expand Down
2 changes: 1 addition & 1 deletion internal/driver/glfw/canvas.go
Original file line number Diff line number Diff line change
Expand Up @@ -198,7 +198,7 @@ func (c *glCanvas) buildMenu(w *window, m *fyne.MainMenu) {
if m == nil {
return
}
if hasNativeMenu() {
if build.HasNativeMenu {
setupNativeMenu(w, m)
} else {
c.setMenuOverlay(buildMenuOverlay(m, w))
Expand Down
3 changes: 2 additions & 1 deletion internal/driver/glfw/canvas_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import (
"fyne.io/fyne/v2/canvas"
"fyne.io/fyne/v2/container"
"fyne.io/fyne/v2/internal/async"
"fyne.io/fyne/v2/internal/build"
internalTest "fyne.io/fyne/v2/internal/test"
"fyne.io/fyne/v2/theme"
"fyne.io/fyne/v2/widget"
Expand Down Expand Up @@ -531,7 +532,7 @@ func TestGlCanvas_Scale(t *testing.T) {
func TestGlCanvas_SetContent(t *testing.T) {
fyne.CurrentApp().Settings().SetTheme(internalTest.DarkTheme(theme.DefaultTheme()))
var menuHeight float32
if hasNativeMenu() {
if build.HasNativeMenu {
menuHeight = 0
} else {
menuHeight = NewMenuBar(fyne.NewMainMenu(fyne.NewMenu("Test", fyne.NewMenuItem("Empty", func() {}))), nil).MinSize().Height
Expand Down
8 changes: 5 additions & 3 deletions internal/driver/glfw/driver_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -115,9 +115,11 @@ func Test_gLDriver_AbsolutePositionForObject(t *testing.T) {
}
for name, tt := range tests {
t.Run(name, func(t *testing.T) {
pos := d.AbsolutePositionForObject(tt.object)
assert.Equal(t, tt.wantX, int(pos.X))
assert.Equal(t, tt.wantY, int(pos.Y))
runOnMain(func() {
pos := d.AbsolutePositionForObject(tt.object)
assert.Equal(t, tt.wantX, int(pos.X))
assert.Equal(t, tt.wantY, int(pos.Y))
})
})
}
}
Loading

0 comments on commit 5a4731e

Please sign in to comment.