app.go 5.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180
  1. // Copyright 2014 The Go Authors. All rights reserved.
  2. // Use of this source code is governed by a BSD-style
  3. // license that can be found in the LICENSE file.
  4. //go:build linux || darwin || windows
  5. // +build linux darwin windows
  6. package app
  7. import (
  8. "fyne.io/fyne/v2/internal/async"
  9. "fyne.io/fyne/v2/internal/driver/mobile/event/lifecycle"
  10. "fyne.io/fyne/v2/internal/driver/mobile/event/size"
  11. "fyne.io/fyne/v2/internal/driver/mobile/gl"
  12. // Initialize necessary mobile functionality, such as logging.
  13. _ "fyne.io/fyne/v2/internal/driver/mobile/mobileinit"
  14. )
  15. // Main is called by the main.main function to run the mobile application.
  16. //
  17. // It calls f on the App, in a separate goroutine, as some OS-specific
  18. // libraries require being on 'the main thread'.
  19. func Main(f func(App)) {
  20. main(f)
  21. }
  22. // App is how a GUI mobile application interacts with the OS.
  23. type App interface {
  24. // Events returns the events channel. It carries events from the system to
  25. // the app. The type of such events include:
  26. // - lifecycle.Event
  27. // - mouse.Event
  28. // - paint.Event
  29. // - size.Event
  30. // - touch.Event
  31. // from the golang.org/x/mobile/event/etc packages. Other packages may
  32. // define other event types that are carried on this channel.
  33. Events() <-chan interface{}
  34. // Send sends an event on the events channel. It does not block.
  35. Send(event interface{})
  36. // Publish flushes any pending drawing commands, such as OpenGL calls, and
  37. // swaps the back buffer to the screen.
  38. Publish() PublishResult
  39. // TODO: replace filters (and the Events channel) with a NextEvent method?
  40. // Filter calls each registered event filter function in sequence.
  41. Filter(event interface{}) interface{}
  42. // RegisterFilter registers a event filter function to be called by Filter. The
  43. // function can return a different event, or return nil to consume the event,
  44. // but the function can also return its argument unchanged, where its purpose
  45. // is to trigger a side effect rather than modify the event.
  46. RegisterFilter(f func(interface{}) interface{})
  47. ShowVirtualKeyboard(KeyboardType)
  48. HideVirtualKeyboard()
  49. ShowFileOpenPicker(func(string, func()), *FileFilter)
  50. ShowFileSavePicker(func(string, func()), *FileFilter, string)
  51. }
  52. // FileFilter is a filter of files.
  53. type FileFilter struct {
  54. Extensions []string
  55. MimeTypes []string
  56. }
  57. // PublishResult is the result of an App.Publish call.
  58. type PublishResult struct {
  59. // BackBufferPreserved is whether the contents of the back buffer was
  60. // preserved. If false, the contents are undefined.
  61. BackBufferPreserved bool
  62. }
  63. var theApp = &app{
  64. events: async.NewUnboundedInterfaceChan(),
  65. lifecycleStage: lifecycle.StageDead,
  66. publish: make(chan struct{}),
  67. publishResult: make(chan PublishResult),
  68. }
  69. func init() {
  70. theApp.glctx, theApp.worker = gl.NewContext()
  71. }
  72. func (a *app) sendLifecycle(to lifecycle.Stage) {
  73. if a.lifecycleStage == to {
  74. return
  75. }
  76. a.events.In() <- lifecycle.Event{
  77. From: a.lifecycleStage,
  78. To: to,
  79. DrawContext: a.glctx,
  80. }
  81. a.lifecycleStage = to
  82. }
  83. type app struct {
  84. filters []func(interface{}) interface{}
  85. events *async.UnboundedInterfaceChan
  86. lifecycleStage lifecycle.Stage
  87. publish chan struct{}
  88. publishResult chan PublishResult
  89. glctx gl.Context
  90. worker gl.Worker
  91. }
  92. func (a *app) Events() <-chan interface{} {
  93. return a.events.Out()
  94. }
  95. func (a *app) Send(event interface{}) {
  96. a.events.In() <- event
  97. }
  98. func (a *app) Publish() PublishResult {
  99. // gl.Flush is a lightweight (on modern GL drivers) blocking call
  100. // that ensures all GL functions pending in the gl package have
  101. // been passed onto the GL driver before the app package attempts
  102. // to swap the screen buffer.
  103. //
  104. // This enforces that the final receive (for this paint cycle) on
  105. // gl.WorkAvailable happens before the send on endPaint.
  106. a.glctx.Flush()
  107. a.publish <- struct{}{}
  108. return <-a.publishResult
  109. }
  110. func (a *app) Filter(event interface{}) interface{} {
  111. for _, f := range a.filters {
  112. event = f(event)
  113. }
  114. return event
  115. }
  116. func (a *app) RegisterFilter(f func(interface{}) interface{}) {
  117. a.filters = append(a.filters, f)
  118. }
  119. func (a *app) ShowVirtualKeyboard(keyboard KeyboardType) {
  120. driverShowVirtualKeyboard(keyboard)
  121. }
  122. func (a *app) HideVirtualKeyboard() {
  123. driverHideVirtualKeyboard()
  124. }
  125. func (a *app) ShowFileOpenPicker(callback func(string, func()), filter *FileFilter) {
  126. driverShowFileOpenPicker(callback, filter)
  127. }
  128. func (a *app) ShowFileSavePicker(callback func(string, func()), filter *FileFilter, filename string) {
  129. driverShowFileSavePicker(callback, filter, filename)
  130. }
  131. // TODO: do this for all build targets, not just linux (x11 and Android)? If
  132. // so, should package gl instead of this package call RegisterFilter??
  133. //
  134. // TODO: does Android need this?? It seems to work without it (Nexus 7,
  135. // KitKat). If only x11 needs this, should we move this to x11.go??
  136. func (a *app) registerGLViewportFilter() {
  137. a.RegisterFilter(func(e interface{}) interface{} {
  138. if e, ok := e.(size.Event); ok {
  139. a.glctx.Viewport(0, 0, e.WidthPx, e.HeightPx)
  140. }
  141. return e
  142. })
  143. }
  144. func screenOrientation(width, height int) size.Orientation {
  145. if width > height {
  146. return size.OrientationLandscape
  147. }
  148. return size.OrientationPortrait
  149. }