From 3879921b8076f7136f49f8cf7e9869e39ce2cc40 Mon Sep 17 00:00:00 2001 From: Elias Naur Date: Fri, 15 Dec 2023 18:14:57 -0600 Subject: [PATCH] app: [API] remove Main All platforms already allow the omission of the call to Main and running Windows on the main goroutine. This change just gets rid of Main, and documents the special requirement on Window.Event. Signed-off-by: Elias Naur --- app/app.go | 12 ------------ app/doc.go | 26 +++++--------------------- app/os_android.go | 3 --- app/os_ios.go | 3 --- app/os_js.go | 4 ---- app/os_macos.go | 9 --------- app/os_unix.go | 4 ---- app/os_windows.go | 4 ---- app/runmain.go | 2 +- app/window.go | 7 +++++++ 10 files changed, 13 insertions(+), 61 deletions(-) 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() -- 2.45.2