app.go 4.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169
  1. // Package app provides app implementations for working with Fyne graphical interfaces.
  2. // The fastest way to get started is to call app.New() which will normally load a new desktop application.
  3. // If the "ci" tag is passed to go (go run -tags ci myapp.go) it will run an in-memory application.
  4. package app // import "fyne.io/fyne/v2/app"
  5. import (
  6. "os"
  7. "strconv"
  8. "sync/atomic"
  9. "time"
  10. "fyne.io/fyne/v2"
  11. "fyne.io/fyne/v2/internal"
  12. "fyne.io/fyne/v2/internal/app"
  13. intRepo "fyne.io/fyne/v2/internal/repository"
  14. "fyne.io/fyne/v2/storage/repository"
  15. )
  16. // Declare conformity with App interface
  17. var _ fyne.App = (*fyneApp)(nil)
  18. type fyneApp struct {
  19. driver fyne.Driver
  20. icon fyne.Resource
  21. uniqueID string
  22. cloud fyne.CloudProvider
  23. lifecycle fyne.Lifecycle
  24. settings *settings
  25. storage fyne.Storage
  26. prefs fyne.Preferences
  27. running uint32 // atomic, 1 == running, 0 == stopped
  28. }
  29. func (a *fyneApp) CloudProvider() fyne.CloudProvider {
  30. return a.cloud
  31. }
  32. func (a *fyneApp) Icon() fyne.Resource {
  33. if a.icon != nil {
  34. return a.icon
  35. }
  36. return a.Metadata().Icon
  37. }
  38. func (a *fyneApp) SetIcon(icon fyne.Resource) {
  39. a.icon = icon
  40. }
  41. func (a *fyneApp) UniqueID() string {
  42. if a.uniqueID != "" {
  43. return a.uniqueID
  44. }
  45. if a.Metadata().ID != "" {
  46. return a.Metadata().ID
  47. }
  48. fyne.LogError("Preferences API requires a unique ID, use app.NewWithID() or the FyneApp.toml ID field", nil)
  49. a.uniqueID = "missing-id-" + strconv.FormatInt(time.Now().Unix(), 10) // This is a fake unique - it just has to not be reused...
  50. return a.uniqueID
  51. }
  52. func (a *fyneApp) NewWindow(title string) fyne.Window {
  53. return a.driver.CreateWindow(title)
  54. }
  55. func (a *fyneApp) Run() {
  56. if atomic.CompareAndSwapUint32(&a.running, 0, 1) {
  57. a.driver.Run()
  58. }
  59. }
  60. func (a *fyneApp) Quit() {
  61. for _, window := range a.driver.AllWindows() {
  62. window.Close()
  63. }
  64. a.driver.Quit()
  65. a.settings.stopWatching()
  66. atomic.StoreUint32(&a.running, 0)
  67. }
  68. func (a *fyneApp) Driver() fyne.Driver {
  69. return a.driver
  70. }
  71. // Settings returns the application settings currently configured.
  72. func (a *fyneApp) Settings() fyne.Settings {
  73. return a.settings
  74. }
  75. func (a *fyneApp) Storage() fyne.Storage {
  76. return a.storage
  77. }
  78. func (a *fyneApp) Preferences() fyne.Preferences {
  79. if a.UniqueID() == "" {
  80. fyne.LogError("Preferences API requires a unique ID, use app.NewWithID() or the FyneApp.toml ID field", nil)
  81. }
  82. return a.prefs
  83. }
  84. func (a *fyneApp) Lifecycle() fyne.Lifecycle {
  85. return a.lifecycle
  86. }
  87. func (a *fyneApp) newDefaultPreferences() *preferences {
  88. p := newPreferences(a)
  89. if a.uniqueID != "" {
  90. p.load()
  91. }
  92. return p
  93. }
  94. // New returns a new application instance with the default driver and no unique ID (unless specified in FyneApp.toml)
  95. func New() fyne.App {
  96. if meta.ID == "" {
  97. internal.LogHint("Applications should be created with a unique ID using app.NewWithID()")
  98. }
  99. return NewWithID(meta.ID)
  100. }
  101. func makeStoreDocs(id string, s *store) *internal.Docs {
  102. if id != "" {
  103. err := os.MkdirAll(s.a.storageRoot(), 0755) // make the space before anyone can use it
  104. if err != nil {
  105. fyne.LogError("Failed to create app storage space", err)
  106. }
  107. root, _ := s.docRootURI()
  108. return &internal.Docs{RootDocURI: root}
  109. } else {
  110. return &internal.Docs{} // an empty impl to avoid crashes
  111. }
  112. }
  113. func newAppWithDriver(d fyne.Driver, id string) fyne.App {
  114. newApp := &fyneApp{uniqueID: id, driver: d, lifecycle: &app.Lifecycle{}}
  115. fyne.SetCurrentApp(newApp)
  116. newApp.prefs = newApp.newDefaultPreferences()
  117. newApp.lifecycle.(*app.Lifecycle).SetOnStoppedHookExecuted(func() {
  118. if prefs, ok := newApp.prefs.(*preferences); ok {
  119. prefs.forceImmediateSave()
  120. }
  121. })
  122. newApp.settings = loadSettings()
  123. store := &store{a: newApp}
  124. store.Docs = makeStoreDocs(id, store)
  125. newApp.storage = store
  126. if !d.Device().IsMobile() {
  127. newApp.settings.watchSettings()
  128. }
  129. httpHandler := intRepo.NewHTTPRepository()
  130. repository.Register("http", httpHandler)
  131. repository.Register("https", httpHandler)
  132. return newApp
  133. }
  134. // marker interface to pass system tray to supporting drivers
  135. type systrayDriver interface {
  136. SetSystemTrayMenu(*fyne.Menu)
  137. SetSystemTrayIcon(resource fyne.Resource)
  138. }