app: allow app.Main to return on Windows

Fixes golang/go#49499

Change-Id: Ia65b61b9e0707321439ea85d06bac5ed507b58c7
Reviewed-on: https://go-review.googlesource.com/c/mobile/+/369196
Reviewed-by: Hyang-Ah Hana Kim <hyangah@gmail.com>
Trust: Hyang-Ah Hana Kim <hyangah@gmail.com>
Trust: Dmitri Shuralyov <dmitshur@golang.org>
Run-TryBot: Changkun Ou <mail@changkun.de>
TryBot-Result: Gopher Robot <gobot@golang.org>
diff --git a/app/android.go b/app/android.go
index 123502e..08a6e05 100644
--- a/app/android.go
+++ b/app/android.go
@@ -287,8 +287,12 @@
 
 	donec := make(chan struct{})
 	go func() {
+		// close the donec channel in a defer statement
+		// so that we could still be able to return even
+		// if mainUserFn panics.
+		defer close(donec)
+
 		mainUserFn(theApp)
-		close(donec)
 	}()
 
 	var pixelsPerPt float32
diff --git a/app/shiny.go b/app/shiny.go
index cffb84b..dd1722a 100644
--- a/app/shiny.go
+++ b/app/shiny.go
@@ -38,10 +38,23 @@
 			}
 		}()
 
-		go f(theApp)
+		donec := make(chan struct{})
+		go func() {
+			// close the donec channel in a defer statement
+			// so that we could still be able to return even
+			// if f panics.
+			defer close(donec)
+
+			f(theApp)
+		}()
 
 		for {
-			theApp.Send(convertEvent(w.NextEvent()))
+			select {
+			case <-donec:
+				return
+			default:
+				theApp.Send(convertEvent(w.NextEvent()))
+			}
 		}
 	})
 }
diff --git a/app/x11.go b/app/x11.go
index 49d1dea..ec8c90a 100644
--- a/app/x11.go
+++ b/app/x11.go
@@ -52,8 +52,12 @@
 
 	donec := make(chan struct{})
 	go func() {
+		// close the donec channel in a defer statement
+		// so that we could still be able to return even
+		// if f panics.
+		defer close(donec)
+
 		f(theApp)
-		close(donec)
 	}()
 
 	// TODO: can we get the actual vsync signal?