From f21b5eb1df39b00631492c7c8cb2c802fa50ca74 Mon Sep 17 00:00:00 2001 From: Elias Naur Date: Sun, 31 Mar 2019 13:36:24 +0200 Subject: [PATCH] ui/app,apps/gophers,apps/hello: replace CreateWindow with NewWindow Gio doesn't support multiple windows anyway, so get rid of the app.Windows channel and use NewWindow call for the mobile platforms as well. Signed-off-by: Elias Naur --- apps/go.mod | 2 ++ apps/go.sum | 2 -- apps/gophers/main.go | 25 ++++++++------------ apps/hello/hello.go | 54 ++++++++++++++++++++------------------------ ui/app/app.go | 13 +++++------ ui/app/os_android.go | 6 +++-- ui/app/os_ios.go | 8 ++++--- ui/app/os_macos.go | 35 ++++++++++++---------------- ui/app/os_wayland.go | 10 ++++---- ui/app/os_windows.go | 19 +++++++++------- 10 files changed, 81 insertions(+), 93 deletions(-) diff --git a/apps/go.mod b/apps/go.mod index ff90edba..dad10aa3 100644 --- a/apps/go.mod +++ b/apps/go.mod @@ -2,6 +2,8 @@ module gioui.org/apps go 1.12 +replace gioui.org/ui => ../ui + require ( gioui.org/ui v0.0.0-20190331090026-ca5204fcb8b3 github.com/google/go-github/v24 v24.0.1 diff --git a/apps/go.sum b/apps/go.sum index a645078a..10eb2054 100644 --- a/apps/go.sum +++ b/apps/go.sum @@ -1,6 +1,4 @@ cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= -gioui.org/ui v0.0.0-20190331090026-ca5204fcb8b3 h1:+iSMCchOrM75QcNH8czjwCXVbwYLofiPeKHl/8Nxxck= -gioui.org/ui v0.0.0-20190331090026-ca5204fcb8b3/go.mod h1:FBjAd/bO8PFxAPY49SiMXkF7Mj677k+KYut4glYlhnM= github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= github.com/golang/protobuf v1.2.0 h1:P3YflyNX/ehuJFLhxviNdFxQPkGK5cDcApsge1SqnvM= github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= diff --git a/apps/gophers/main.go b/apps/gophers/main.go index 06830b0d..f98ce211 100644 --- a/apps/gophers/main.go +++ b/apps/gophers/main.go @@ -119,14 +119,6 @@ func main() { fmt.Println("The quota for anonymous GitHub API access is very low. Specify a token with -token to avoid quota errors.") fmt.Println("See https://help.github.com/en/articles/creating-a-personal-access-token-for-the-command-line.") } - err := app.CreateWindow(app.WindowOptions{ - Width: ui.Dp(400), - Height: ui.Dp(800), - Title: "Gophers", - }) - if err != nil { - log.Fatal(err) - } app.Main() } @@ -147,13 +139,16 @@ func init() { fonts.italic = mustLoadFont(goitalic.TTF) fonts.mono = mustLoadFont(gomono.TTF) go func() { - for w := range app.Windows() { - w := w - go func() { - if err := newApp(w).run(); err != nil { - log.Fatal(err) - } - }() + w, err := app.NewWindow(app.WindowOptions{ + Width: ui.Dp(400), + Height: ui.Dp(800), + Title: "Gophers", + }) + if err != nil { + log.Fatal(err) + } + if err := newApp(w).run(); err != nil { + log.Fatal(err) } }() } diff --git a/apps/hello/hello.go b/apps/hello/hello.go index 351b9e33..0d5cf473 100644 --- a/apps/hello/hello.go +++ b/apps/hello/hello.go @@ -18,26 +18,10 @@ import ( ) func main() { - err := app.CreateWindow(app.WindowOptions{ - Width: ui.Dp(400), - Height: ui.Dp(800), - Title: "Hello World", - }) - if err != nil { - log.Fatal(err) - } app.Main() } func init() { - go func() { - for w := range app.Windows() { - go loop(w) - } - }() -} - -func loop(w *app.Window) { regular, err := sfnt.Parse(goregular.TTF) if err != nil { panic("failed to load font") @@ -45,19 +29,29 @@ func loop(w *app.Window) { var faces measure.Faces black := &image.Uniform{color.Black} face := faces.For(regular, ui.Dp(50)) - for w.IsAlive() { - e := <-w.Events() - switch e := e.(type) { - case app.Draw: - faces.Cfg = e.Config - cs := layout.ExactConstraints(w.Size()) - root, _ := (text.Label{Src: black, Face: face, Text: "Hello, World!"}).Layout(cs) - w.Draw(root) - faces.Frame() + go func() { + w, err := app.NewWindow(app.WindowOptions{ + Width: ui.Dp(400), + Height: ui.Dp(800), + Title: "Hello World", + }) + if err != nil { + log.Fatal(err) } - w.Ack() - } - if w.Err() != nil { - log.Fatal(err) - } + for w.IsAlive() { + e := <-w.Events() + switch e := e.(type) { + case app.Draw: + faces.Cfg = e.Config + cs := layout.ExactConstraints(w.Size()) + root, _ := (text.Label{Src: black, Face: face, Text: "Hello, World!"}).Layout(cs) + w.Draw(root) + faces.Frame() + } + w.Ack() + } + if w.Err() != nil { + log.Fatal(err) + } + }() } diff --git a/ui/app/app.go b/ui/app/app.go index 2cc6940b..35d2f387 100644 --- a/ui/app/app.go +++ b/ui/app/app.go @@ -59,19 +59,18 @@ const ( // Set it with the go tool linker flag -X. var extraArgs string -var windows = make(chan *Window) - -func CreateWindow(opts WindowOptions) error { +// NewWindow creates a new window for a set of window +// options. The options are hints; the platform is free to +// ignore or adjust them. +// If the current program is running on iOS and Android, +// NewWindow the window previously created by the platform. +func NewWindow(opts WindowOptions) (*Window, error) { if opts.Width.V <= 0 || opts.Height.V <= 0 { panic("window width and height must be larger than 0") } return createWindow(opts) } -func Windows() <-chan *Window { - return windows -} - func (l Stage) String() string { switch l { case StageDead: diff --git a/ui/app/os_android.go b/ui/app/os_android.go index b4bc7816..0a391a67 100644 --- a/ui/app/os_android.go +++ b/ui/app/os_android.go @@ -55,6 +55,8 @@ type window struct { var theJVM *C.JavaVM +var windows = make(chan *Window) + var views = make(map[C.jlong]*window) func jniGetMethodID(env *C.JNIEnv, class C.jclass, method, sig string) C.jmethodID { @@ -379,6 +381,6 @@ func Main() { panic("unreachable") } -func createWindow(opts WindowOptions) error { - return errors.New("createWindow not supported") +func createWindow(opts WindowOptions) (*Window, error) { + return <- windows, nil } diff --git a/ui/app/os_ios.go b/ui/app/os_ios.go index 479295a9..4d241829 100644 --- a/ui/app/os_ios.go +++ b/ui/app/os_ios.go @@ -22,10 +22,10 @@ import ( "sync/atomic" "time" + "gioui.org/ui" "gioui.org/ui/f32" "gioui.org/ui/key" "gioui.org/ui/pointer" - "gioui.org/ui" ) type window struct { @@ -42,6 +42,8 @@ var layerFactory func() uintptr var views = make(map[C.CFTypeRef]*window) +var windows = make(chan *Window) + func init() { // Darwin requires UI operations happen on the main thread only. runtime.LockOSThread() @@ -233,8 +235,8 @@ func (w *window) setTextInput(s key.TextInputState) { } } -func createWindow(opts WindowOptions) error { - panic("unsupported") +func createWindow(opts WindowOptions) (*Window, error) { + return <-windows, nil } func Main() { diff --git a/ui/app/os_macos.go b/ui/app/os_macos.go index 4a07b560..e4eb58aa 100644 --- a/ui/app/os_macos.go +++ b/ui/app/os_macos.go @@ -15,7 +15,6 @@ import ( "errors" "image" "runtime" - "sync" "time" "unsafe" @@ -36,13 +35,15 @@ type window struct { stage Stage } -// Only support one main window for now. -var singleWindow struct { - mu sync.Mutex - hasOpts bool - opts WindowOptions +type windowError struct { + window *Window + err error } +var windowOpts = make(chan WindowOptions) + +var windows = make(chan windowError) + var viewFactory func() uintptr var views = make(map[C.CFTypeRef]*window) @@ -162,7 +163,6 @@ func gio_onTerminate(view C.CFTypeRef) { w := views[view] delete(views, view) w.setStage(StageDead) - close(windows) } //export gio_onHide @@ -185,28 +185,23 @@ func gio_onCreate(view C.CFTypeRef) { ow := newWindow(w) w.w = ow views[view] = w - windows <- ow + windows <- windowError{window: ow} } -func createWindow(opts WindowOptions) error { - singleWindow.mu.Lock() - defer singleWindow.mu.Unlock() - if singleWindow.hasOpts { - panic("only one window supported") - } - singleWindow.opts = opts - singleWindow.hasOpts = true - return nil +func createWindow(opts WindowOptions) (*Window, error) { + windowOpts <- opts + werr := <-windows + return werr.window, werr.err } func Main() { view := C.CFTypeRef(viewFactory()) if view == 0 { - // TODO: return this error from CreateWindow. - panic(errors.New("CreateWindow: failed to create view")) + windows <- windowError{err: errors.New("CreateWindow: failed to create view")} + return } cfg := getConfig() - opts := singleWindow.opts + opts := <-windowOpts w := cfg.Pixels(opts.Width) h := cfg.Pixels(opts.Height) title := C.CString(opts.Title) diff --git a/ui/app/os_wayland.go b/ui/app/os_wayland.go index 3fe0dbc0..ef70db8d 100644 --- a/ui/app/os_wayland.go +++ b/ui/app/os_wayland.go @@ -141,30 +141,28 @@ func Main() { <-mainDone } -func createWindow(opts WindowOptions) error { +func createWindow(opts WindowOptions) (*Window, error) { connMu.Lock() defer connMu.Unlock() if len(winMap) > 0 { panic("multiple windows are not supported") } if err := waylandConnect(); err != nil { - return err + return nil, err } w, err := createNativeWindow(opts) if err != nil { conn.destroy() - return err + return nil, err } go func() { - windows <- w.w w.setStage(StageVisible) w.loop() w.destroy() conn.destroy() - close(windows) close(mainDone) }() - return nil + return w.w, nil } func createNativeWindow(opts WindowOptions) (*window, error) { diff --git a/ui/app/os_windows.go b/ui/app/os_windows.go index 10714eea..88fea26f 100644 --- a/ui/app/os_windows.go +++ b/ui/app/os_windows.go @@ -13,10 +13,10 @@ import ( syscall "golang.org/x/sys/windows" + "gioui.org/ui" "gioui.org/ui/f32" "gioui.org/ui/key" "gioui.org/ui/pointer" - "gioui.org/ui" ) var winMap = make(map[syscall.Handle]*window) @@ -157,34 +157,37 @@ func Main() { <-mainDone } -func createWindow(opts WindowOptions) error { +func createWindow(opts WindowOptions) (*Window, error) { onceMu.Lock() defer onceMu.Unlock() if len(winMap) > 0 { panic("multiple windows are not supported") } - cerr := make(chan error, 1) + type windowError struct { + window *Window + err error + } + cerr := make(chan windowError) go func() { // Call win32 API from a single OS thread. runtime.LockOSThread() w, err := createNativeWindow(opts) if err != nil { - cerr <- err + cerr <- windowError{err: err} return } defer w.destroy() - cerr <- nil - windows <- w.w + cerr <- windowError{w.w, nil} showWindow(w.hwnd, _SW_SHOWDEFAULT) setForegroundWindow(w.hwnd) setFocus(w.hwnd) if err := w.loop(); err != nil { panic(err) } - close(windows) close(mainDone) }() - return <-cerr + werr := <-cerr + return werr.window, werr.err } func createNativeWindow(opts WindowOptions) (*window, error) {