diff --git a/app/app.go b/app/app.go index ef4a0fe2..53355f40 100644 --- a/app/app.go +++ b/app/app.go @@ -120,18 +120,6 @@ func DataDir() (string, error) { return dataDir() } -// Main must be called last from the program main function. -// On most platforms Main blocks forever, for Android and -// iOS it returns immediately to give control of the main -// thread back to the system. -// -// Calling Main is necessary because some operating systems -// require control of the main thread of the program for -// running windows. -func Main() { - osMain() -} - func (FrameEvent) ImplementsEvent() {} func init() { diff --git a/app/doc.go b/app/doc.go index e510253d..485b9f3e 100644 --- a/app/doc.go +++ b/app/doc.go @@ -33,28 +33,12 @@ For example: A program must keep receiving events from the event channel until [DestroyEvent] is received. -# Main +# Main Thread -The Main function must be called from a program's main function, to hand over -control of the main thread to operating systems that need it. - -Because Main is also blocking on some platforms, the event loop of a Window must run in a goroutine. - -For example, to display a blank but otherwise functional window: - - package main - - import "gioui.org/app" - - func main() { - go func() { - w := app.NewWindow() - for { - w.Event() - } - }() - app.Main() - } +Some GUI platform need access to the main thread of the program. To avoid a +deadlock on such platforms, at least one Window must have its Event method +called by the main goroutine. It doesn't have to be any particular Window; +even a destroyed Window suffices. # Permissions diff --git a/app/os_android.go b/app/os_android.go index a18bd083..a7a4772a 100644 --- a/app/os_android.go +++ b/app/os_android.go @@ -1317,9 +1317,6 @@ func findClass(env *C.JNIEnv, name string) C.jclass { return C.jni_FindClass(env, cn) } -func osMain() { -} - func newWindow(window *callbacks, options []Option) { mainWindow.in <- windowAndConfig{window, options} <-mainWindow.windows diff --git a/app/os_ios.go b/app/os_ios.go index d2880b62..9200b766 100644 --- a/app/os_ios.go +++ b/app/os_ios.go @@ -388,9 +388,6 @@ func newWindow(win *callbacks, options []Option) { <-mainWindow.windows } -func osMain() { -} - //export gio_runMain func gio_runMain() { runMain() diff --git a/app/os_js.go b/app/os_js.go index 79e02783..bc80dbc2 100644 --- a/app/os_js.go +++ b/app/os_js.go @@ -741,10 +741,6 @@ func (w *window) navigationColor(c color.NRGBA) { theme.Set("content", fmt.Sprintf("#%06X", []uint8{rgba.R, rgba.G, rgba.B})) } -func osMain() { - select {} -} - func translateKey(k string) (key.Name, bool) { var n key.Name diff --git a/app/os_macos.go b/app/os_macos.go index 707cb2ac..f85e6177 100644 --- a/app/os_macos.go +++ b/app/os_macos.go @@ -1012,15 +1012,6 @@ func (w *window) init() error { return nil } -func osMain() { - C.gio_initApp() - close(launched) - for { - C.dispatchEvent() - gio_dispatchMainFuncs() - } -} - func convertKey(k rune) (key.Name, bool) { var n key.Name switch k { diff --git a/app/os_unix.go b/app/os_unix.go index b91cf89a..d0f51af1 100644 --- a/app/os_unix.go +++ b/app/os_unix.go @@ -33,10 +33,6 @@ type WaylandViewEvent struct { func (WaylandViewEvent) implementsViewEvent() {} func (WaylandViewEvent) ImplementsEvent() {} -func osMain() { - select {} -} - type windowDriver func(*callbacks, []Option) error // Instead of creating files with build tags for each combination of wayland +/- x11 diff --git a/app/os_windows.go b/app/os_windows.go index 72489270..bf4e92aa 100644 --- a/app/os_windows.go +++ b/app/os_windows.go @@ -85,10 +85,6 @@ var resources struct { cursor syscall.Handle } -func osMain() { - select {} -} - func newWindow(win *callbacks, options []Option) { done := make(chan struct{}) go func() { diff --git a/app/runmain.go b/app/runmain.go index a1c1e3d4..d01d85a6 100644 --- a/app/runmain.go +++ b/app/runmain.go @@ -25,6 +25,6 @@ func runMain() { // Indirect call, since the linker does not know the address of main when // laying down this package. fn := mainMain - fn() + go fn() }) } diff --git a/app/window.go b/app/window.go index 61da5b58..29b7cdab 100644 --- a/app/window.go +++ b/app/window.go @@ -684,6 +684,13 @@ func (w *Window) processEvent(e event.Event) bool { // Event blocks until an event is received from the window, such as // [FrameEvent], or until [Invalidate] is called. +// +// Note: if more than one Window is active, at least one must have +// its Event called from the main goroutine that runs the main +// function. This is necessary because some operating system GUI +// implementations require control of the main thread. +// For this reason, it is allowed to call Event even after a +// DestroyEvent has been received. func (w *Window) Event() event.Event { w.init() return w.basic.Event()