Skip to content

Commit fdd8955

Browse files
authored
Merge branch 'fyne-io:develop' into develop
2 parents ee5c3bc + 310723c commit fdd8955

File tree

335 files changed

+6024
-1808
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

335 files changed

+6024
-1808
lines changed

CHANGELOG.md

+1
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ More detailed release notes can be found on the [releases page](https://github.c
99

1010
* Go 1.17 or later is now required.
1111
* Icons for macOS bundles are now padded and rounded, disable with "-use-raw-icon"
12+
* Focus handling for List/Tree/Table are now at the parent widget not child elements
1213

1314

1415
## 2.3.5 - 6 June 2023

app/app.go

+15-16
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,6 @@ import (
1414
"fyne.io/fyne/v2/internal/app"
1515
intRepo "fyne.io/fyne/v2/internal/repository"
1616
"fyne.io/fyne/v2/storage/repository"
17-
18-
"golang.org/x/sys/execabs"
1917
)
2018

2119
// Declare conformity with App interface
@@ -33,7 +31,6 @@ type fyneApp struct {
3331
prefs fyne.Preferences
3432

3533
running uint32 // atomic, 1 == running, 0 == stopped
36-
exec func(name string, arg ...string) *execabs.Cmd
3734
}
3835

3936
func (a *fyneApp) CloudProvider() fyne.CloudProvider {
@@ -72,7 +69,6 @@ func (a *fyneApp) NewWindow(title string) fyne.Window {
7269
func (a *fyneApp) Run() {
7370
if atomic.CompareAndSwapUint32(&a.running, 0, 1) {
7471
a.driver.Run()
75-
return
7672
}
7773
}
7874

@@ -110,10 +106,10 @@ func (a *fyneApp) Lifecycle() fyne.Lifecycle {
110106
return a.lifecycle
111107
}
112108

113-
func (a *fyneApp) newDefaultPreferences() fyne.Preferences {
114-
p := fyne.Preferences(newPreferences(a))
115-
if pref, ok := p.(interface{ load() }); ok && a.uniqueID != "" {
116-
pref.load()
109+
func (a *fyneApp) newDefaultPreferences() *preferences {
110+
p := newPreferences(a)
111+
if a.uniqueID != "" {
112+
p.load()
117113
}
118114
return p
119115
}
@@ -126,11 +122,8 @@ func New() fyne.App {
126122
return NewWithID(meta.ID)
127123
}
128124

129-
func makeStoreDocs(id string, p fyne.Preferences, s *store) *internal.Docs {
125+
func makeStoreDocs(id string, s *store) *internal.Docs {
130126
if id != "" {
131-
if pref, ok := p.(interface{ load() }); ok {
132-
pref.load()
133-
}
134127
err := os.MkdirAll(s.a.storageRoot(), 0755) // make the space before anyone can use it
135128
if err != nil {
136129
fyne.LogError("Failed to create app storage space", err)
@@ -144,21 +137,27 @@ func makeStoreDocs(id string, p fyne.Preferences, s *store) *internal.Docs {
144137
}
145138

146139
func newAppWithDriver(d fyne.Driver, id string) fyne.App {
147-
newApp := &fyneApp{uniqueID: id, driver: d, exec: execabs.Command, lifecycle: &app.Lifecycle{}}
140+
newApp := &fyneApp{uniqueID: id, driver: d, lifecycle: &app.Lifecycle{}}
148141
fyne.SetCurrentApp(newApp)
149142

150143
newApp.prefs = newApp.newDefaultPreferences()
144+
newApp.lifecycle.(*app.Lifecycle).SetOnStoppedHookExecuted(func() {
145+
if prefs, ok := newApp.prefs.(*preferences); ok {
146+
prefs.forceImmediateSave()
147+
}
148+
})
151149
newApp.settings = loadSettings()
152150
store := &store{a: newApp}
153-
store.Docs = makeStoreDocs(id, newApp.prefs, store)
151+
store.Docs = makeStoreDocs(id, store)
154152
newApp.storage = store
155153

156154
if !d.Device().IsMobile() {
157155
newApp.settings.watchSettings()
158156
}
159157

160-
repository.Register("http", intRepo.NewHTTPRepository())
161-
repository.Register("https", intRepo.NewHTTPRepository())
158+
httpHandler := intRepo.NewHTTPRepository()
159+
repository.Register("http", httpHandler)
160+
repository.Register("https", httpHandler)
162161

163162
return newApp
164163
}

app/app_desktop_darwin.go

+3-1
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,8 @@ import (
1919
"os"
2020
"path/filepath"
2121

22+
"golang.org/x/sys/execabs"
23+
2224
"fyne.io/fyne/v2"
2325
"fyne.io/fyne/v2/theme"
2426
)
@@ -52,7 +54,7 @@ func rootConfigDir() string {
5254
}
5355

5456
func (a *fyneApp) OpenURL(url *url.URL) error {
55-
cmd := a.exec("open", url.String())
57+
cmd := execabs.Command("open", url.String())
5658
cmd.Stdin, cmd.Stdout, cmd.Stderr = os.Stdin, os.Stdout, os.Stderr
5759
return cmd.Run()
5860
}

app/app_test.go

+10-17
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,12 @@
11
package app
22

33
import (
4-
"net/url"
5-
"strings"
64
"testing"
75

86
"github.com/stretchr/testify/assert"
97

108
"fyne.io/fyne/v2"
119
_ "fyne.io/fyne/v2/test"
12-
13-
"golang.org/x/sys/execabs"
1410
)
1511

1612
func TestDummyApp(t *testing.T) {
@@ -37,21 +33,18 @@ func TestFyneApp_UniqueID(t *testing.T) {
3733
assert.Equal(t, meta.ID, app.UniqueID())
3834
}
3935

40-
func TestFyneApp_OpenURL(t *testing.T) {
41-
opened := ""
36+
func TestFyneApp_SetIcon(t *testing.T) {
4237
app := NewWithID("io.fyne.test")
43-
app.(*fyneApp).exec = func(cmd string, arg ...string) *execabs.Cmd {
44-
opened = arg[len(arg)-1]
45-
return execabs.Command("")
46-
}
4738

48-
urlStr := "https://fyne.io"
49-
u, _ := url.Parse(urlStr)
50-
err := app.OpenURL(u)
39+
metaIcon := &fyne.StaticResource{StaticName: "Metadata"}
40+
SetMetadata(fyne.AppMetadata{
41+
Icon: metaIcon,
42+
})
43+
44+
assert.Equal(t, metaIcon, app.Icon())
5145

52-
if err != nil && strings.Contains(err.Error(), "unknown operating system") {
53-
return // when running in CI mode we don't actually open URLs...
54-
}
46+
setIcon := &fyne.StaticResource{StaticName: "Test"}
47+
app.SetIcon(setIcon)
5548

56-
assert.Equal(t, urlStr, opened)
49+
assert.Equal(t, setIcon, app.Icon())
5750
}

app/app_windows.go

+2-3
Original file line numberDiff line numberDiff line change
@@ -11,12 +11,11 @@ import (
1111
"strings"
1212
"syscall"
1313

14+
"golang.org/x/sys/execabs"
1415
"golang.org/x/sys/windows/registry"
1516

1617
"fyne.io/fyne/v2"
1718
"fyne.io/fyne/v2/theme"
18-
19-
"golang.org/x/sys/execabs"
2019
)
2120

2221
const notificationTemplate = `$title = "%s"
@@ -63,7 +62,7 @@ func rootConfigDir() string {
6362
}
6463

6564
func (a *fyneApp) OpenURL(url *url.URL) error {
66-
cmd := a.exec("rundll32", "url.dll,FileProtocolHandler", url.String())
65+
cmd := execabs.Command("rundll32", "url.dll,FileProtocolHandler", url.String())
6766
cmd.Stdin, cmd.Stdout, cmd.Stderr = os.Stdin, os.Stdout, os.Stderr
6867
return cmd.Run()
6968
}

app/app_xdg.go

+2-1
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ import (
1515
"sync"
1616

1717
"github.com/godbus/dbus/v5"
18+
"golang.org/x/sys/execabs"
1819

1920
"fyne.io/fyne/v2"
2021
"fyne.io/fyne/v2/theme"
@@ -27,7 +28,7 @@ func defaultVariant() fyne.ThemeVariant {
2728
}
2829

2930
func (a *fyneApp) OpenURL(url *url.URL) error {
30-
cmd := a.exec("xdg-open", url.String())
31+
cmd := execabs.Command("xdg-open", url.String())
3132
cmd.Stdin, cmd.Stdout, cmd.Stderr = os.Stdin, os.Stdout, os.Stderr
3233
return cmd.Start()
3334
}

app/cloud.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ func (a *fyneApp) transitionCloud(p fyne.CloudProvider) {
3333
a.storage = cloud.CloudStorage(a)
3434
} else {
3535
store := &store{a: a}
36-
store.Docs = makeStoreDocs(a.uniqueID, a.prefs, store)
36+
store.Docs = makeStoreDocs(a.uniqueID, store)
3737
a.storage = store
3838
}
3939

app/preferences.go

+15-1
Original file line numberDiff line numberDiff line change
@@ -19,12 +19,25 @@ type preferences struct {
1919
savedRecently bool
2020
changedDuringSaving bool
2121

22-
app *fyneApp
22+
app *fyneApp
23+
needsSaveBeforeExit bool
2324
}
2425

2526
// Declare conformity with Preferences interface
2627
var _ fyne.Preferences = (*preferences)(nil)
2728

29+
// forceImmediateSave writes preferences to file immediately, ignoring the debouncing
30+
// logic in the change listener. Does nothing if preferences are not backed with a file.
31+
func (p *preferences) forceImmediateSave() {
32+
if !p.needsSaveBeforeExit {
33+
return
34+
}
35+
err := p.save()
36+
if err != nil {
37+
fyne.LogError("Failed on force saving preferences", err)
38+
}
39+
}
40+
2841
func (p *preferences) resetSavedRecently() {
2942
go func() {
3043
time.Sleep(time.Millisecond * 100) // writes are not always atomic. 10ms worked, 100 is safer.
@@ -132,6 +145,7 @@ func newPreferences(app *fyneApp) *preferences {
132145
return p
133146
}
134147

148+
p.needsSaveBeforeExit = true
135149
p.AddChangeListener(func() {
136150
if p != app.prefs {
137151
return

app/settings_desktop_test.go

-8
Original file line numberDiff line numberDiff line change
@@ -6,22 +6,14 @@ package app
66
import (
77
"os"
88
"path/filepath"
9-
"runtime"
109
"testing"
1110
"time"
1211

1312
"github.com/stretchr/testify/assert"
1413

1514
"fyne.io/fyne/v2"
16-
"fyne.io/fyne/v2/theme"
1715
)
1816

19-
func TestDefaultTheme(t *testing.T) {
20-
if runtime.GOOS != "darwin" && runtime.GOOS != "windows" { // system defines default for macOS and Windows
21-
assert.Equal(t, theme.VariantDark, defaultVariant())
22-
}
23-
}
24-
2517
func TestEnsureDir(t *testing.T) {
2618
tmpDir := testPath("fynetest")
2719

app/storage_test.go

+1-3
Original file line numberDiff line numberDiff line change
@@ -4,14 +4,12 @@ import (
44
"testing"
55

66
"github.com/stretchr/testify/assert"
7-
8-
"fyne.io/fyne/v2/internal"
97
)
108

119
func TestStore_RootURI(t *testing.T) {
1210
id := "io.fyne.test"
1311
a := &fyneApp{uniqueID: id}
14-
d := makeStoreDocs(id, &internal.InMemoryPreferences{}, &store{a: a})
12+
d := makeStoreDocs(id, &store{a: a})
1513

1614
w, err := d.Create("test")
1715
assert.Nil(t, err)

canvas/image.go

+8-2
Original file line numberDiff line numberDiff line change
@@ -175,12 +175,18 @@ func (i *Image) Resize(s fyne.Size) {
175175
if s == i.Size() {
176176
return
177177
}
178-
if i.FillMode == ImageFillOriginal && i.size.Height > 2 { // don't refresh original scale images after first draw
178+
i.baseObject.Resize(s)
179+
if i.FillMode == ImageFillOriginal && i.size.Height > 2 { // we can just ask for a GPU redraw to align
180+
Refresh(i)
179181
return
180182
}
181183

182184
i.baseObject.Resize(s)
183-
i.Refresh()
185+
if i.isSVG || i.Image == nil {
186+
i.Refresh() // we need to rasterise at the new size
187+
} else {
188+
Refresh(i) // just re-size using GPU scaling
189+
}
184190
}
185191

186192
// NewImageFromFile creates a new image from a local file.

cmd/fyne/internal/commands/build.go

+15-4
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ import (
99
"runtime"
1010
"strings"
1111

12-
version "github.com/mcuadros/go-version"
12+
"github.com/mcuadros/go-version"
1313
"github.com/urfave/cli/v2"
1414

1515
"fyne.io/fyne/v2"
@@ -414,14 +414,14 @@ func injectMetadataIfPossible(runner runner, srcdir string, app *appData,
414414
return nil, err
415415
}
416416

417-
fyneGoModVersionNormalized := version.Normalize(fyneGoModVersion)
417+
fyneGoModVersion = normaliseVersion(fyneGoModVersion)
418418
fyneGoModVersionConstraint := version.NewConstrainGroupFromString(">=2.2")
419-
if fyneGoModVersion != "master" && !fyneGoModVersionConstraint.Match(fyneGoModVersionNormalized) {
419+
if fyneGoModVersion != "master" && !fyneGoModVersionConstraint.Match(fyneGoModVersion) {
420420
return nil, nil
421421
}
422422

423423
fyneGoModVersionAtLeast2_3 := version.NewConstrainGroupFromString(">=2.3")
424-
if fyneGoModVersionAtLeast2_3.Match(fyneGoModVersionNormalized) {
424+
if fyneGoModVersionAtLeast2_3.Match(fyneGoModVersion) {
425425
app.VersionAtLeast2_3 = true
426426
}
427427

@@ -485,3 +485,14 @@ func extractLdFlags(goFlags string) (string, string) {
485485

486486
return ldflags, newGoFlags
487487
}
488+
489+
func normaliseVersion(str string) string {
490+
if str == "master" {
491+
return str
492+
}
493+
494+
if pos := strings.Index(str, "-0.20"); pos != -1 {
495+
str = str[:pos] + "-dev"
496+
}
497+
return version.Normalize(str)
498+
}

cmd/fyne/internal/commands/build_test.go

+7
Original file line numberDiff line numberDiff line change
@@ -334,3 +334,10 @@ func Test_ExtractLdFlags(t *testing.T) {
334334
assert.Equal(t, test.wantGoFlags, goFlags)
335335
}
336336
}
337+
338+
func Test_NormaliseVersion(t *testing.T) {
339+
assert.Equal(t, "master", normaliseVersion("master"))
340+
assert.Equal(t, "2.3.0.0", normaliseVersion("v2.3"))
341+
assert.Equal(t, "2.4.0.0", normaliseVersion("v2.4.0"))
342+
assert.Equal(t, "2.3.6.0-dev", normaliseVersion("v2.3.6-0.20230711180435-d4b95e1cb1eb"))
343+
}

cmd/fyne/internal/commands/package-unix.go

+10-5
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import (
77
"path/filepath"
88
"strings"
99

10+
"fyne.io/fyne/v2/cmd/fyne/internal/metadata"
1011
"fyne.io/fyne/v2/cmd/fyne/internal/templates"
1112

1213
"golang.org/x/sys/execabs"
@@ -58,16 +59,20 @@ func (p *Packager) packageUNIX() error {
5859
desktop := filepath.Join(appsDir, p.Name+".desktop")
5960
deskFile, _ := os.Create(desktop)
6061

62+
linuxBSD := metadata.LinuxAndBSD{}
63+
if p.linuxAndBSDMetadata != nil {
64+
linuxBSD = *p.linuxAndBSDMetadata
65+
}
6166
tplData := unixData{
6267
Name: p.Name,
6368
Exec: filepath.Base(p.exe),
6469
Icon: p.Name + filepath.Ext(p.icon),
6570
Local: local,
66-
GenericName: p.linuxAndBSDMetadata.GenericName,
67-
Keywords: formatDesktopFileList(p.linuxAndBSDMetadata.Keywords),
68-
Comment: p.linuxAndBSDMetadata.Comment,
69-
Categories: formatDesktopFileList(p.linuxAndBSDMetadata.Categories),
70-
ExecParams: p.linuxAndBSDMetadata.ExecParams,
71+
GenericName: linuxBSD.GenericName,
72+
Keywords: formatDesktopFileList(linuxBSD.Keywords),
73+
Comment: linuxBSD.Comment,
74+
Categories: formatDesktopFileList(linuxBSD.Categories),
75+
ExecParams: linuxBSD.ExecParams,
7176
}
7277
err = templates.DesktopFileUNIX.Execute(deskFile, tplData)
7378
if err != nil {

0 commit comments

Comments
 (0)