From 45da52cee7aaa828d793733be0c9c6c4adaaa77b Mon Sep 17 00:00:00 2001 From: Elias Naur Date: Sun, 29 Aug 2021 22:00:16 +0200 Subject: [PATCH] app: merge app/internal/wm into package app The app and app/internal/wm packages are tightly coupled, requiring quite a bit of forwarding types, values and constants from the internal package to export it. Further, no other package imports package wm. This change merges the two packages. While here, drop the pre-Go 1.14 SIGPIPE workaround. Signed-off-by: Elias Naur --- app/{internal/wm => }/Gio.java | 0 app/{internal/wm => }/GioActivity.java | 0 app/{internal/wm => }/GioView.java | 0 app/app.go | 10 +- app/app_android.go | 18 --- app/{internal/wm => }/d3d11_windows.go | 6 +- app/datadir_android.go | 42 ------ app/{internal/wm => }/egl_android.go | 16 +- app/{internal/wm => }/egl_wayland.go | 16 +- app/{internal/wm => }/egl_windows.go | 4 +- app/{internal/wm => }/egl_x11.go | 4 +- app/{internal/wm => }/framework_ios.h | 0 app/{internal/wm => }/gl_ios.go | 2 +- app/{internal/wm => }/gl_ios.m | 0 app/{internal/wm => }/gl_js.go | 24 +-- app/{internal/wm => }/gl_macos.go | 24 +-- app/{internal/wm => }/gl_macos.m | 0 app/loop.go | 7 +- app/{internal/wm => }/metal_darwin.go | 4 +- app/{internal/wm => }/metal_ios.go | 2 +- app/{internal/wm => }/metal_macos.go | 2 +- app/{internal/wm/window.go => os.go} | 76 +++++----- app/{internal/wm => }/os_android.go | 75 ++++++--- app/{internal/wm => }/os_darwin.go | 4 +- app/{internal/wm => }/os_darwin.m | 0 app/{internal/wm => }/os_ios.go | 14 +- app/{internal/wm => }/os_ios.m | 0 app/{internal/wm => }/os_js.go | 38 ++--- app/{internal/wm => }/os_macos.go | 34 ++--- app/{internal/wm => }/os_macos.m | 0 app/{internal/wm => }/os_unix.go | 10 +- app/{internal/wm => }/os_wayland.c | 0 app/{internal/wm => }/os_wayland.go | 28 ++-- app/{internal/wm => }/os_windows.go | 64 ++++---- app/{internal/wm => }/os_x11.go | 34 ++--- app/{internal/wm => }/runmain.go | 2 +- app/sigpipe_darwin.go | 19 --- app/{internal/wm => }/wayland_text_input.c | 0 app/{internal/wm => }/wayland_text_input.h | 0 .../wm => }/wayland_xdg_decoration.c | 0 .../wm => }/wayland_xdg_decoration.h | 0 app/{internal/wm => }/wayland_xdg_shell.c | 0 app/{internal/wm => }/wayland_xdg_shell.h | 0 app/window.go | 142 +++++++++--------- cmd/gogio/androidbuild.go | 2 +- cmd/gogio/iosbuild.go | 2 +- 46 files changed, 325 insertions(+), 400 deletions(-) rename app/{internal/wm => }/Gio.java (100%) rename app/{internal/wm => }/GioActivity.java (100%) rename app/{internal/wm => }/GioView.java (100%) delete mode 100644 app/app_android.go rename app/{internal/wm => }/d3d11_windows.go (97%) delete mode 100644 app/datadir_android.go rename app/{internal/wm => }/egl_android.go (70%) rename app/{internal/wm => }/egl_wayland.go (83%) rename app/{internal/wm => }/egl_windows.go (94%) rename app/{internal/wm => }/egl_x11.go (94%) rename app/{internal/wm => }/framework_ios.h (100%) rename app/{internal/wm => }/gl_ios.go (99%) rename app/{internal/wm => }/gl_ios.m (100%) rename app/{internal/wm => }/gl_js.go (67%) rename app/{internal/wm => }/gl_macos.go (79%) rename app/{internal/wm => }/gl_macos.m (100%) rename app/{internal/wm => }/metal_darwin.go (98%) rename app/{internal/wm => }/metal_ios.go (98%) rename app/{internal/wm => }/metal_macos.go (98%) rename app/{internal/wm/window.go => os.go} (61%) rename app/{internal/wm => }/os_android.go (93%) rename app/{internal/wm => }/os_darwin.go (99%) rename app/{internal/wm => }/os_darwin.m (100%) rename app/{internal/wm => }/os_ios.go (97%) rename app/{internal/wm => }/os_ios.m (100%) rename app/{internal/wm => }/os_js.go (96%) rename app/{internal/wm => }/os_macos.go (96%) rename app/{internal/wm => }/os_macos.m (100%) rename app/{internal/wm => }/os_unix.go (85%) rename app/{internal/wm => }/os_wayland.c (100%) rename app/{internal/wm => }/os_wayland.go (98%) rename app/{internal/wm => }/os_windows.go (94%) rename app/{internal/wm => }/os_x11.go (97%) rename app/{internal/wm => }/runmain.go (98%) delete mode 100644 app/sigpipe_darwin.go rename app/{internal/wm => }/wayland_text_input.c (100%) rename app/{internal/wm => }/wayland_text_input.h (100%) rename app/{internal/wm => }/wayland_xdg_decoration.c (100%) rename app/{internal/wm => }/wayland_xdg_decoration.h (100%) rename app/{internal/wm => }/wayland_xdg_shell.c (100%) rename app/{internal/wm => }/wayland_xdg_shell.h (100%) diff --git a/app/internal/wm/Gio.java b/app/Gio.java similarity index 100% rename from app/internal/wm/Gio.java rename to app/Gio.java diff --git a/app/internal/wm/GioActivity.java b/app/GioActivity.java similarity index 100% rename from app/internal/wm/GioActivity.java rename to app/GioActivity.java diff --git a/app/internal/wm/GioView.java b/app/GioView.java similarity index 100% rename from app/internal/wm/GioView.java rename to app/GioView.java diff --git a/app/app.go b/app/app.go index 240b9452..e00298a3 100644 --- a/app/app.go +++ b/app/app.go @@ -5,16 +5,8 @@ package app import ( "os" "strings" - - "gioui.org/app/internal/wm" ) -// ViewEvent carries the platform specific window handles for -// a Window. -// -// ViewEvent is implemented for Android, macOS, Windows. -type ViewEvent = wm.ViewEvent - // extraArgs contains extra arguments to append to // os.Args. The arguments are separated with |. // Useful for running programs on mobiles where the @@ -50,5 +42,5 @@ func DataDir() (string, error) { // require control of the main thread of the program for // running windows. func Main() { - wm.Main() + osMain() } diff --git a/app/app_android.go b/app/app_android.go deleted file mode 100644 index 30a6c675..00000000 --- a/app/app_android.go +++ /dev/null @@ -1,18 +0,0 @@ -// SPDX-License-Identifier: Unlicense OR MIT - -package app - -import ( - "gioui.org/app/internal/wm" -) - -// JavaVM returns the global JNI JavaVM. -func JavaVM() uintptr { - return wm.JavaVM() -} - -// AppContext returns the global Application context as a JNI -// jobject. -func AppContext() uintptr { - return wm.AppContext() -} diff --git a/app/internal/wm/d3d11_windows.go b/app/d3d11_windows.go similarity index 97% rename from app/internal/wm/d3d11_windows.go rename to app/d3d11_windows.go index 2b89c1f2..8324ed67 100644 --- a/app/internal/wm/d3d11_windows.go +++ b/app/d3d11_windows.go @@ -1,6 +1,6 @@ // SPDX-License-Identifier: Unlicense OR MIT -package wm +package app import ( "fmt" @@ -25,7 +25,7 @@ const debug = false func init() { drivers = append(drivers, gpuAPI{ priority: 1, - initializer: func(w *window) (Context, error) { + initializer: func(w *window) (context, error) { hwnd, _, _ := w.HWND() var flags uint32 if debug { @@ -70,7 +70,7 @@ func (c *d3d11Context) Present() error { // Ignore return nil case d3d11.DXGI_ERROR_DEVICE_RESET, d3d11.DXGI_ERROR_DEVICE_REMOVED, d3d11.D3DDDIERR_DEVICEREMOVED: - return ErrDeviceLost + return errDeviceLost } } return err diff --git a/app/datadir_android.go b/app/datadir_android.go deleted file mode 100644 index c4739e02..00000000 --- a/app/datadir_android.go +++ /dev/null @@ -1,42 +0,0 @@ -// SPDX-License-Identifier: Unlicense OR MIT - -//go:build android -// +build android - -package app - -import "C" - -import ( - "os" - "path/filepath" - "sync" - - "gioui.org/app/internal/wm" -) - -var ( - dataDirOnce sync.Once - dataPath string -) - -func dataDir() (string, error) { - dataDirOnce.Do(func() { - dataPath = wm.GetDataDir() - // Set XDG_CACHE_HOME to make os.UserCacheDir work. - if _, exists := os.LookupEnv("XDG_CACHE_HOME"); !exists { - cachePath := filepath.Join(dataPath, "cache") - os.Setenv("XDG_CACHE_HOME", cachePath) - } - // Set XDG_CONFIG_HOME to make os.UserConfigDir work. - if _, exists := os.LookupEnv("XDG_CONFIG_HOME"); !exists { - cfgPath := filepath.Join(dataPath, "config") - os.Setenv("XDG_CONFIG_HOME", cfgPath) - } - // Set HOME to make os.UserHomeDir work. - if _, exists := os.LookupEnv("HOME"); !exists { - os.Setenv("HOME", dataPath) - } - }) - return dataPath, nil -} diff --git a/app/internal/wm/egl_android.go b/app/egl_android.go similarity index 70% rename from app/internal/wm/egl_android.go rename to app/egl_android.go index 759620a7..f1f2abc2 100644 --- a/app/internal/wm/egl_android.go +++ b/app/egl_android.go @@ -1,6 +1,6 @@ // SPDX-License-Identifier: Unlicense OR MIT -package wm +package app /* #include @@ -14,27 +14,27 @@ import ( "gioui.org/internal/egl" ) -type context struct { +type androidContext struct { win *window *egl.Context } -func (w *window) NewContext() (Context, error) { +func (w *window) NewContext() (context, error) { ctx, err := egl.NewContext(nil) if err != nil { return nil, err } - return &context{win: w, Context: ctx}, nil + return &androidContext{win: w, Context: ctx}, nil } -func (c *context) Release() { +func (c *androidContext) Release() { if c.Context != nil { c.Context.Release() c.Context = nil } } -func (c *context) Refresh() error { +func (c *androidContext) Refresh() error { c.Context.ReleaseSurface() var ( win *C.ANativeWindow @@ -48,10 +48,10 @@ func (c *context) Refresh() error { return c.Context.CreateSurface(eglSurf, width, height) } -func (c *context) Lock() error { +func (c *androidContext) Lock() error { return c.Context.MakeCurrent() } -func (c *context) Unlock() { +func (c *androidContext) Unlock() { c.Context.ReleaseCurrent() } diff --git a/app/internal/wm/egl_wayland.go b/app/egl_wayland.go similarity index 83% rename from app/internal/wm/egl_wayland.go rename to app/egl_wayland.go index abd92770..05a5fe79 100644 --- a/app/internal/wm/egl_wayland.go +++ b/app/egl_wayland.go @@ -3,7 +3,7 @@ //go:build (linux && !android && !nowayland) || freebsd // +build linux,!android,!nowayland freebsd -package wm +package app import ( "errors" @@ -23,22 +23,22 @@ import ( */ import "C" -type context struct { +type wlContext struct { win *window *egl.Context eglWin *C.struct_wl_egl_window } -func (w *window) NewContext() (Context, error) { +func (w *window) NewContext() (context, error) { disp := egl.NativeDisplayType(unsafe.Pointer(w.display())) ctx, err := egl.NewContext(disp) if err != nil { return nil, err } - return &context{Context: ctx, win: w}, nil + return &wlContext{Context: ctx, win: w}, nil } -func (c *context) Release() { +func (c *wlContext) Release() { if c.Context != nil { c.Context.Release() c.Context = nil @@ -49,7 +49,7 @@ func (c *context) Release() { } } -func (c *context) Refresh() error { +func (c *wlContext) Refresh() error { c.Context.ReleaseSurface() if c.eglWin != nil { C.wl_egl_window_destroy(c.eglWin) @@ -68,10 +68,10 @@ func (c *context) Refresh() error { return c.Context.CreateSurface(eglSurf, width, height) } -func (c *context) Lock() error { +func (c *wlContext) Lock() error { return c.Context.MakeCurrent() } -func (c *context) Unlock() { +func (c *wlContext) Unlock() { c.Context.ReleaseCurrent() } diff --git a/app/internal/wm/egl_windows.go b/app/egl_windows.go similarity index 94% rename from app/internal/wm/egl_windows.go rename to app/egl_windows.go index b2b66ecc..3a95450e 100644 --- a/app/internal/wm/egl_windows.go +++ b/app/egl_windows.go @@ -1,6 +1,6 @@ // SPDX-License-Identifier: Unlicense OR MIT -package wm +package app import ( "golang.org/x/sys/windows" @@ -16,7 +16,7 @@ type glContext struct { func init() { drivers = append(drivers, gpuAPI{ priority: 2, - initializer: func(w *window) (Context, error) { + initializer: func(w *window) (context, error) { disp := egl.NativeDisplayType(w.HDC()) ctx, err := egl.NewContext(disp) if err != nil { diff --git a/app/internal/wm/egl_x11.go b/app/egl_x11.go similarity index 94% rename from app/internal/wm/egl_x11.go rename to app/egl_x11.go index b16ebd7a..763bd965 100644 --- a/app/internal/wm/egl_x11.go +++ b/app/egl_x11.go @@ -3,7 +3,7 @@ //go:build (linux && !android && !nox11) || freebsd || openbsd // +build linux,!android,!nox11 freebsd openbsd -package wm +package app import ( "unsafe" @@ -16,7 +16,7 @@ type x11Context struct { *egl.Context } -func (w *x11Window) NewContext() (Context, error) { +func (w *x11Window) NewContext() (context, error) { disp := egl.NativeDisplayType(unsafe.Pointer(w.display())) ctx, err := egl.NewContext(disp) if err != nil { diff --git a/app/internal/wm/framework_ios.h b/app/framework_ios.h similarity index 100% rename from app/internal/wm/framework_ios.h rename to app/framework_ios.h diff --git a/app/internal/wm/gl_ios.go b/app/gl_ios.go similarity index 99% rename from app/internal/wm/gl_ios.go rename to app/gl_ios.go index 9cf772e9..98c98330 100644 --- a/app/internal/wm/gl_ios.go +++ b/app/gl_ios.go @@ -3,7 +3,7 @@ //go:build darwin && ios && nometal // +build darwin,ios,nometal -package wm +package app /* @import UIKit; diff --git a/app/internal/wm/gl_ios.m b/app/gl_ios.m similarity index 100% rename from app/internal/wm/gl_ios.m rename to app/gl_ios.m diff --git a/app/internal/wm/gl_js.go b/app/gl_js.go similarity index 67% rename from app/internal/wm/gl_js.go rename to app/gl_js.go index 56227235..d76f5bbb 100644 --- a/app/internal/wm/gl_js.go +++ b/app/gl_js.go @@ -1,6 +1,6 @@ // SPDX-License-Identifier: Unlicense OR MIT -package wm +package app import ( "errors" @@ -10,12 +10,12 @@ import ( "gioui.org/internal/gl" ) -type context struct { +type glContext struct { ctx js.Value cnv js.Value } -func newContext(w *window) (*context, error) { +func newContext(w *window) (*glContext, error) { args := map[string]interface{}{ // Enable low latency rendering. // See https://developers.google.com/web/updates/2019/05/desynchronized. @@ -29,41 +29,41 @@ func newContext(w *window) (*context, error) { if ctx.IsNull() { return nil, errors.New("app: webgl is not supported") } - c := &context{ + c := &glContext{ ctx: ctx, cnv: w.cnv, } return c, nil } -func (c *context) RenderTarget() gpu.RenderTarget { +func (c *glContext) RenderTarget() gpu.RenderTarget { return gpu.OpenGLRenderTarget{} } -func (c *context) API() gpu.API { +func (c *glContext) API() gpu.API { return gpu.OpenGL{Context: gl.Context(c.ctx)} } -func (c *context) Release() { +func (c *glContext) Release() { } -func (c *context) Present() error { +func (c *glContext) Present() error { if c.ctx.Call("isContextLost").Bool() { return errors.New("context lost") } return nil } -func (c *context) Lock() error { +func (c *glContext) Lock() error { return nil } -func (c *context) Unlock() {} +func (c *glContext) Unlock() {} -func (c *context) Refresh() error { +func (c *glContext) Refresh() error { return nil } -func (w *window) NewContext() (Context, error) { +func (w *window) NewContext() (context, error) { return newContext(w) } diff --git a/app/internal/wm/gl_macos.go b/app/gl_macos.go similarity index 79% rename from app/internal/wm/gl_macos.go rename to app/gl_macos.go index ad78360c..b6c5924d 100644 --- a/app/internal/wm/gl_macos.go +++ b/app/gl_macos.go @@ -3,7 +3,7 @@ //go:build darwin && !ios && nometal // +build darwin,!ios,nometal -package wm +package app import ( "errors" @@ -28,35 +28,35 @@ __attribute__ ((visibility ("hidden"))) void gio_unlockContext(CFTypeRef ctxRef) */ import "C" -type context struct { +type glContext struct { c *gl.Functions ctx C.CFTypeRef view C.CFTypeRef } -func newContext(w *window) (*context, error) { +func newContext(w *window) (*glContext, error) { view := w.contextView() ctx := C.gio_createGLContext() if ctx == 0 { return nil, errors.New("gl: failed to create NSOpenGLContext") } C.gio_setContextView(ctx, view) - c := &context{ + c := &glContext{ ctx: ctx, view: view, } return c, nil } -func (c *context) RenderTarget() gpu.RenderTarget { +func (c *glContext) RenderTarget() gpu.RenderTarget { return gpu.OpenGLRenderTarget{} } -func (c *context) API() gpu.API { +func (c *glContext) API() gpu.API { return gpu.OpenGL{} } -func (c *context) Release() { +func (c *glContext) Release() { if c.ctx != 0 { C.gio_clearCurrentContext() C.CFRelease(c.ctx) @@ -64,28 +64,28 @@ func (c *context) Release() { } } -func (c *context) Present() error { +func (c *glContext) Present() error { return nil } -func (c *context) Lock() error { +func (c *glContext) Lock() error { C.gio_lockContext(c.ctx) C.gio_makeCurrentContext(c.ctx) return nil } -func (c *context) Unlock() { +func (c *glContext) Unlock() { C.gio_clearCurrentContext() C.gio_unlockContext(c.ctx) } -func (c *context) Refresh() error { +func (c *glContext) Refresh() error { c.Lock() defer c.Unlock() C.gio_updateContext(c.ctx) return nil } -func (w *window) NewContext() (Context, error) { +func (w *window) NewContext() (context, error) { return newContext(w) } diff --git a/app/internal/wm/gl_macos.m b/app/gl_macos.m similarity index 100% rename from app/internal/wm/gl_macos.m rename to app/gl_macos.m diff --git a/app/loop.go b/app/loop.go index 1d388b62..b72a6230 100644 --- a/app/loop.go +++ b/app/loop.go @@ -7,7 +7,6 @@ import ( "image/color" "runtime" - "gioui.org/app/internal/wm" "gioui.org/gpu" "gioui.org/op" ) @@ -17,7 +16,7 @@ type renderLoop struct { drawing bool err error - ctx wm.Context + ctx context frames chan frame results chan frameResult ack chan struct{} @@ -35,7 +34,7 @@ type frameResult struct { err error } -func newLoop(ctx wm.Context) (*renderLoop, error) { +func newLoop(ctx context) (*renderLoop, error) { l := &renderLoop{ ctx: ctx, frames: make(chan frame), @@ -52,7 +51,7 @@ func newLoop(ctx wm.Context) (*renderLoop, error) { return l, nil } -func (l *renderLoop) renderLoop(ctx wm.Context) error { +func (l *renderLoop) renderLoop(ctx context) error { // GL Operations must happen on a single OS thread, so // pass initialization result through a channel. initErr := make(chan error) diff --git a/app/internal/wm/metal_darwin.go b/app/metal_darwin.go similarity index 98% rename from app/internal/wm/metal_darwin.go rename to app/metal_darwin.go index 327a60cc..2dced328 100644 --- a/app/internal/wm/metal_darwin.go +++ b/app/metal_darwin.go @@ -3,7 +3,7 @@ //go:build !nometal // +build !nometal -package wm +package app import ( "errors" @@ -169,6 +169,6 @@ func (c *mtlContext) Refresh() error { return nil } -func (w *window) NewContext() (Context, error) { +func (w *window) NewContext() (context, error) { return newMtlContext(w) } diff --git a/app/internal/wm/metal_ios.go b/app/metal_ios.go similarity index 98% rename from app/internal/wm/metal_ios.go rename to app/metal_ios.go index 5b66136b..860ba1aa 100644 --- a/app/internal/wm/metal_ios.go +++ b/app/metal_ios.go @@ -3,7 +3,7 @@ //go:build !nometal // +build !nometal -package wm +package app /* #cgo CFLAGS: -Werror -xobjective-c -fmodules -fobjc-arc diff --git a/app/internal/wm/metal_macos.go b/app/metal_macos.go similarity index 98% rename from app/internal/wm/metal_macos.go rename to app/metal_macos.go index 570cc84e..7db06a99 100644 --- a/app/internal/wm/metal_macos.go +++ b/app/metal_macos.go @@ -3,7 +3,7 @@ //go:build darwin && !ios && !nometal // +build darwin,!ios,!nometal -package wm +package app /* #cgo CFLAGS: -Werror -xobjective-c -fmodules -fobjc-arc diff --git a/app/internal/wm/window.go b/app/os.go similarity index 61% rename from app/internal/wm/window.go rename to app/os.go index da30a8fb..75d0e03d 100644 --- a/app/internal/wm/window.go +++ b/app/os.go @@ -1,8 +1,8 @@ // SPDX-License-Identifier: Unlicense OR MIT -// package wm implements platform specific windows +// package app implements platform specific windows // and GPU contexts. -package wm +package app import ( "errors" @@ -11,58 +11,52 @@ import ( "gioui.org/io/key" "gioui.org/gpu" - "gioui.org/io/event" "gioui.org/io/pointer" "gioui.org/io/system" "gioui.org/unit" ) -type Size struct { +type size struct { Width unit.Value Height unit.Value } -type Options struct { - Size *Size - MinSize *Size - MaxSize *Size +type config struct { + Size *size + MinSize *size + MaxSize *size Title *string - WindowMode *WindowMode + WindowMode *windowMode StatusColor *color.NRGBA NavigationColor *color.NRGBA - Orientation *Orientation + Orientation *orientation CustomRenderer bool } -type WakeupEvent struct{} +type wakeupEvent struct{} -type WindowMode uint8 +type windowMode uint8 const ( - Windowed WindowMode = iota - Fullscreen + windowed windowMode = iota + fullscreen ) -type Orientation uint8 +type orientation uint8 const ( - AnyOrientation Orientation = iota - LandscapeOrientation - PortraitOrientation + anyOrientation orientation = iota + landscapeOrientation + portraitOrientation ) -type FrameEvent struct { +type frameEvent struct { system.FrameEvent Sync bool } -type Callbacks interface { - SetDriver(d Driver) - Event(e event.Event) -} - -type Context interface { +type context interface { API() gpu.API RenderTarget() gpu.RenderTarget Present() error @@ -72,14 +66,14 @@ type Context interface { Unlock() } -// ErrDeviceLost is returned from Context.Present when +// errDeviceLost is returned from Context.Present when // the underlying GPU device is gone and should be // recreated. -var ErrDeviceLost = errors.New("GPU device lost") +var errDeviceLost = errors.New("GPU device lost") // Driver is the interface for the platform implementation // of a window. -type Driver interface { +type driver interface { // SetAnimating sets the animation flag. When the window is animating, // FrameEvents are delivered as fast as the display can handle them. SetAnimating(anim bool) @@ -89,15 +83,15 @@ type Driver interface { SetInputHint(mode key.InputHint) - NewContext() (Context, error) + NewContext() (context, error) // ReadClipboard requests the clipboard content. ReadClipboard() // WriteClipboard requests a clipboard write. WriteClipboard(s string) - // Option processes option changes. - Option(opts *Options) + // Configure the window. + Configure(cnf *config) // SetCursor updates the current cursor to name. SetCursor(name pointer.CursorName) @@ -109,25 +103,25 @@ type Driver interface { } type windowRendezvous struct { - in chan windowAndOptions - out chan windowAndOptions + in chan windowAndConfig + out chan windowAndConfig errs chan error } -type windowAndOptions struct { - window Callbacks - opts *Options +type windowAndConfig struct { + window *callbacks + cnf *config } func newWindowRendezvous() *windowRendezvous { wr := &windowRendezvous{ - in: make(chan windowAndOptions), - out: make(chan windowAndOptions), + in: make(chan windowAndConfig), + out: make(chan windowAndConfig), errs: make(chan error), } go func() { - var main windowAndOptions - var out chan windowAndOptions + var main windowAndConfig + var out chan windowAndConfig for { select { case w := <-wr.in: @@ -145,4 +139,4 @@ func newWindowRendezvous() *windowRendezvous { return wr } -func (_ WakeupEvent) ImplementsEvent() {} +func (_ wakeupEvent) ImplementsEvent() {} diff --git a/app/internal/wm/os_android.go b/app/os_android.go similarity index 93% rename from app/internal/wm/os_android.go rename to app/os_android.go index 0230c0ac..abca7b3f 100644 --- a/app/internal/wm/os_android.go +++ b/app/os_android.go @@ -1,6 +1,6 @@ // SPDX-License-Identifier: Unlicense OR MIT -package wm +package app /* #cgo CFLAGS: -Werror @@ -111,6 +111,8 @@ import ( "fmt" "image" "image/color" + "os" + "path/filepath" "reflect" "runtime" "runtime/debug" @@ -130,7 +132,7 @@ import ( ) type window struct { - callbacks Callbacks + callbacks *callbacks view C.jobject @@ -195,13 +197,38 @@ var android struct { // view maps from GioView JNI refenreces to windows. var views = make(map[C.jlong]*window) -// windows maps from Callbacks to windows -var windows = make(map[Callbacks]*window) +var windows = make(map[*callbacks]*window) var mainWindow = newWindowRendezvous() var mainFuncs = make(chan func(env *C.JNIEnv), 1) +var ( + dataDirOnce sync.Once + dataPath string +) + +func dataDir() (string, error) { + dataDirOnce.Do(func() { + dataPath = <-dataDirChan + // Set XDG_CACHE_HOME to make os.UserCacheDir work. + if _, exists := os.LookupEnv("XDG_CACHE_HOME"); !exists { + cachePath := filepath.Join(dataPath, "cache") + os.Setenv("XDG_CACHE_HOME", cachePath) + } + // Set XDG_CONFIG_HOME to make os.UserConfigDir work. + if _, exists := os.LookupEnv("XDG_CONFIG_HOME"); !exists { + cfgPath := filepath.Join(dataPath, "config") + os.Setenv("XDG_CONFIG_HOME", cfgPath) + } + // Set HOME to make os.UserHomeDir work. + if _, exists := os.LookupEnv("HOME"); !exists { + os.Setenv("HOME", dataPath) + } + }) + return dataPath, nil +} + func getMethodID(env *C.JNIEnv, class C.jclass, method, sig string) C.jmethodID { m := C.CString(method) defer C.free(unsafe.Pointer(m)) @@ -254,6 +281,7 @@ func initJVM(env *C.JNIEnv, gio C.jclass, ctx C.jobject) { android.mwakeupMainThread = getStaticMethodID(env, gio, "wakeupMainThread", "()V") } +// JavaVM returns the global JNI JavaVM. func JavaVM() uintptr { jvm := javaVM() return uintptr(unsafe.Pointer(jvm)) @@ -265,16 +293,13 @@ func javaVM() *C.JavaVM { return android.jvm } +// AppContext returns the global Application context as a JNI jobject. func AppContext() uintptr { android.mu.Lock() defer android.mu.Unlock() return uintptr(android.appCtx) } -func GetDataDir() string { - return <-dataDirChan -} - //export Java_org_gioui_GioView_onCreateView func Java_org_gioui_GioView_onCreateView(env *C.JNIEnv, class C.jclass, view C.jobject) C.jlong { gioView.once.Do(func() { @@ -305,7 +330,7 @@ func Java_org_gioui_GioView_onCreateView(env *C.JNIEnv, class C.jclass, view C.j handle := C.jlong(view) views[handle] = w w.loadConfig(env, class) - w.Option(wopts.opts) + w.Configure(wopts.cnf) w.setStage(system.StagePaused) w.callbacks.Event(ViewEvent{View: uintptr(view)}) return handle @@ -476,7 +501,7 @@ func (w *window) draw(sync bool) { } const inchPrDp = 1.0 / 160 ppdp := float32(w.dpi) * inchPrDp - w.callbacks.Event(FrameEvent{ + w.callbacks.Event(frameEvent{ FrameEvent: system.FrameEvent{ Now: time.Now(), Size: image.Point{ @@ -723,11 +748,11 @@ func goString(env *C.JNIEnv, str C.jstring) string { return string(utf8) } -func Main() { +func osMain() { } -func NewWindow(window Callbacks, opts *Options) error { - mainWindow.in <- windowAndOptions{window, opts} +func newWindow(window *callbacks, cnf *config) error { + mainWindow.in <- windowAndConfig{window, cnf} return <-mainWindow.errs } @@ -751,18 +776,18 @@ func (w *window) ReadClipboard() { }) } -func (w *window) Option(opts *Options) { +func (w *window) Configure(cnf *config) { runInJVM(javaVM(), func(env *C.JNIEnv) { - if o := opts.Orientation; o != nil { + if o := cnf.Orientation; o != nil { setOrientation(env, w.view, *o) } - if o := opts.NavigationColor; o != nil { + if o := cnf.NavigationColor; o != nil { setNavigationColor(env, w.view, *o) } - if o := opts.StatusColor; o != nil { + if o := cnf.StatusColor; o != nil { setStatusColor(env, w.view, *o) } - if o := opts.WindowMode; o != nil { + if o := cnf.WindowMode; o != nil { setWindowMode(env, w.view, *o) } }) @@ -776,7 +801,7 @@ func (w *window) SetCursor(name pointer.CursorName) { func (w *window) Wakeup() { runOnMain(func(env *C.JNIEnv) { - w.callbacks.Event(WakeupEvent{}) + w.callbacks.Event(wakeupEvent{}) }) } @@ -803,18 +828,18 @@ func setCursor(env *C.JNIEnv, view C.jobject, name pointer.CursorName) { callVoidMethod(env, view, gioView.setCursor, jvalue(curID)) } -func setOrientation(env *C.JNIEnv, view C.jobject, mode Orientation) { +func setOrientation(env *C.JNIEnv, view C.jobject, mode orientation) { var ( id int idFallback int // Used only for SDK 17 or older. ) // Constants defined at https://developer.android.com/reference/android/content/pm/ActivityInfo. switch mode { - case AnyOrientation: + case anyOrientation: id, idFallback = 2, 2 // SCREEN_ORIENTATION_USER - case LandscapeOrientation: + case landscapeOrientation: id, idFallback = 11, 0 // SCREEN_ORIENTATION_USER_LANDSCAPE (or SCREEN_ORIENTATION_LANDSCAPE) - case PortraitOrientation: + case portraitOrientation: id, idFallback = 12, 1 // SCREEN_ORIENTATION_USER_PORTRAIT (or SCREEN_ORIENTATION_PORTRAIT) } callVoidMethod(env, view, gioView.setOrientation, jvalue(id), jvalue(idFallback)) @@ -834,9 +859,9 @@ func setNavigationColor(env *C.JNIEnv, view C.jobject, color color.NRGBA) { ) } -func setWindowMode(env *C.JNIEnv, view C.jobject, mode WindowMode) { +func setWindowMode(env *C.JNIEnv, view C.jobject, mode windowMode) { switch mode { - case Fullscreen: + case fullscreen: callVoidMethod(env, view, gioView.setFullscreen, C.JNI_TRUE) default: callVoidMethod(env, view, gioView.setFullscreen, C.JNI_FALSE) diff --git a/app/internal/wm/os_darwin.go b/app/os_darwin.go similarity index 99% rename from app/internal/wm/os_darwin.go rename to app/os_darwin.go index 7c170f15..c0554db3 100644 --- a/app/internal/wm/os_darwin.go +++ b/app/os_darwin.go @@ -1,6 +1,6 @@ // SPDX-License-Identifier: Unlicense OR MIT -package wm +package app /* #include @@ -232,6 +232,6 @@ func windowSetCursor(from, to pointer.CursorName) pointer.CursorName { func (w *window) Wakeup() { runOnMain(func() { - w.w.Event(WakeupEvent{}) + w.w.Event(wakeupEvent{}) }) } diff --git a/app/internal/wm/os_darwin.m b/app/os_darwin.m similarity index 100% rename from app/internal/wm/os_darwin.m rename to app/os_darwin.m diff --git a/app/internal/wm/os_ios.go b/app/os_ios.go similarity index 97% rename from app/internal/wm/os_ios.go rename to app/os_ios.go index efe0d23f..7d34b904 100644 --- a/app/internal/wm/os_ios.go +++ b/app/os_ios.go @@ -3,7 +3,7 @@ //go:build darwin && ios // +build darwin,ios -package wm +package app /* #cgo CFLAGS: -DGLES_SILENCE_DEPRECATION -Werror -Wno-deprecated-declarations -fmodules -fobjc-arc -x objective-c @@ -90,7 +90,7 @@ type ViewEvent struct{} type window struct { view C.CFTypeRef - w Callbacks + w *callbacks displayLink *displayLink visible bool @@ -144,7 +144,7 @@ func (w *window) draw(sync bool) { w.w.Event(system.StageEvent{Stage: system.StageRunning}) } const inchPrDp = 1.0 / 163 - w.w.Event(FrameEvent{ + w.w.Event(frameEvent{ FrameEvent: system.FrameEvent{ Now: time.Now(), Size: image.Point{ @@ -268,7 +268,7 @@ func (w *window) WriteClipboard(s string) { C.writeClipboard(chars, C.NSUInteger(len(u16))) } -func (w *window) Option(opts *Options) {} +func (w *window) Configure(cnf *config) {} func (w *window) SetAnimating(anim bool) { v := w.view @@ -329,12 +329,12 @@ func (w *window) SetInputHint(_ key.InputHint) {} // Close the window. Not implemented for iOS. func (w *window) Close() {} -func NewWindow(win Callbacks, opts *Options) error { - mainWindow.in <- windowAndOptions{win, opts} +func newWindow(win *callbacks, cnf *config) error { + mainWindow.in <- windowAndConfig{win, cnf} return <-mainWindow.errs } -func Main() { +func osMain() { } //export gio_runMain diff --git a/app/internal/wm/os_ios.m b/app/os_ios.m similarity index 100% rename from app/internal/wm/os_ios.m rename to app/os_ios.m diff --git a/app/internal/wm/os_js.go b/app/os_js.go similarity index 96% rename from app/internal/wm/os_js.go rename to app/os_js.go index 48962b70..64aa7b1c 100644 --- a/app/internal/wm/os_js.go +++ b/app/os_js.go @@ -1,6 +1,6 @@ // SPDX-License-Identifier: Unlicense OR MIT -package wm +package app import ( "fmt" @@ -31,7 +31,7 @@ type window struct { clipboard js.Value cnv js.Value tarea js.Value - w Callbacks + w *callbacks redraw js.Func clipboardCallback js.Func requestAnimationFrame js.Value @@ -56,7 +56,7 @@ type window struct { wakeups chan struct{} } -func NewWindow(win Callbacks, opts *Options) error { +func newWindow(win *callbacks, cnf *config) error { doc := js.Global().Get("document") cont := getContainer(doc) cnv := createCanvas(doc) @@ -94,7 +94,7 @@ func NewWindow(win Callbacks, opts *Options) error { }) w.addEventListeners() w.addHistory() - w.Option(opts) + w.Configure(cnf) w.w = win go func() { @@ -107,7 +107,7 @@ func NewWindow(win Callbacks, opts *Options) error { for { select { case <-w.wakeups: - w.w.Event(WakeupEvent{}) + w.w.Event(wakeupEvent{}) case <-w.chanAnimation: w.animCallback() case <-w.chanRedraw: @@ -509,17 +509,17 @@ func (w *window) WriteClipboard(s string) { w.clipboard.Call("writeText", s) } -func (w *window) Option(opts *Options) { - if o := opts.Title; o != nil { +func (w *window) Configure(cnf *config) { + if o := cnf.Title; o != nil { w.document.Set("title", *o) } - if o := opts.WindowMode; o != nil { + if o := cnf.WindowMode; o != nil { w.windowMode(*o) } - if o := opts.NavigationColor; o != nil { + if o := cnf.NavigationColor; o != nil { w.navigationColor(*o) } - if o := opts.Orientation; o != nil { + if o := cnf.Orientation; o != nil { w.orientation(*o) } } @@ -581,7 +581,7 @@ func (w *window) draw(sync bool) { return } - w.w.Event(FrameEvent{ + w.w.Event(frameEvent{ FrameEvent: system.FrameEvent{ Now: time.Now(), Size: image.Point{ @@ -605,9 +605,9 @@ func (w *window) config() (int, int, system.Insets, unit.Metric) { } } -func (w *window) windowMode(mode WindowMode) { +func (w *window) windowMode(mode windowMode) { switch mode { - case Windowed: + case windowed: if !w.document.Get("fullscreenElement").Truthy() { return // Browser is already Windowed. } @@ -615,7 +615,7 @@ func (w *window) windowMode(mode WindowMode) { return // Browser doesn't support such feature. } w.document.Call("exitFullscreen") - case Fullscreen: + case fullscreen: elem := w.document.Get("documentElement") if !elem.Get("requestFullscreen").Truthy() { return // Browser doesn't support such feature. @@ -624,17 +624,17 @@ func (w *window) windowMode(mode WindowMode) { } } -func (w *window) orientation(mode Orientation) { +func (w *window) orientation(mode orientation) { if j := w.screenOrientation; !j.Truthy() || !j.Get("unlock").Truthy() || !j.Get("lock").Truthy() { return // Browser don't support Screen Orientation API. } switch mode { - case AnyOrientation: + case anyOrientation: w.screenOrientation.Call("unlock") - case LandscapeOrientation: + case landscapeOrientation: w.screenOrientation.Call("lock", "landscape").Call("then", w.redraw) - case PortraitOrientation: + case portraitOrientation: w.screenOrientation.Call("lock", "portrait").Call("then", w.redraw) } } @@ -650,7 +650,7 @@ func (w *window) navigationColor(c color.NRGBA) { theme.Set("content", fmt.Sprintf("#%06X", []uint8{rgba.R, rgba.G, rgba.B})) } -func Main() { +func osMain() { select {} } diff --git a/app/internal/wm/os_macos.go b/app/os_macos.go similarity index 96% rename from app/internal/wm/os_macos.go rename to app/os_macos.go index 1ab07d81..d74bbd6f 100644 --- a/app/internal/wm/os_macos.go +++ b/app/os_macos.go @@ -3,7 +3,7 @@ //go:build darwin && !ios // +build darwin,!ios -package wm +package app import ( "errors" @@ -147,13 +147,13 @@ type ViewEvent struct { type window struct { view C.CFTypeRef window C.CFTypeRef - w Callbacks + w *callbacks stage system.Stage displayLink *displayLink cursor pointer.CursorName scale float32 - mode WindowMode + mode windowMode } // viewMap is the mapping from Cocoa NSViews to Go windows. @@ -210,47 +210,47 @@ func (w *window) WriteClipboard(s string) { C.writeClipboard(chars, C.NSUInteger(len(u16))) } -func (w *window) Option(opts *Options) { +func (w *window) Configure(cnf *config) { screenScale := float32(C.getScreenBackingScale()) cfg := configFor(screenScale) val := func(v unit.Value) float32 { return float32(cfg.Px(v)) / screenScale } - if o := opts.Size; o != nil { + if o := cnf.Size; o != nil { width := val(o.Width) height := val(o.Height) if width > 0 || height > 0 { C.setSize(w.window, C.CGFloat(width), C.CGFloat(height)) } } - if o := opts.MinSize; o != nil { + if o := cnf.MinSize; o != nil { width := val(o.Width) height := val(o.Height) if width > 0 || height > 0 { C.setMinSize(w.window, C.CGFloat(width), C.CGFloat(height)) } } - if o := opts.MaxSize; o != nil { + if o := cnf.MaxSize; o != nil { width := val(o.Width) height := val(o.Height) if width > 0 || height > 0 { C.setMaxSize(w.window, C.CGFloat(width), C.CGFloat(height)) } } - if o := opts.Title; o != nil { + if o := cnf.Title; o != nil { title := C.CString(*o) defer C.free(unsafe.Pointer(title)) C.setTitle(w.window, title) } - if o := opts.WindowMode; o != nil { + if o := cnf.WindowMode; o != nil { w.SetWindowMode(*o) } } -func (w *window) SetWindowMode(mode WindowMode) { +func (w *window) SetWindowMode(mode windowMode) { switch mode { case w.mode: - case Windowed, Fullscreen: + case windowed, fullscreen: C.toggleFullScreen(w.window) w.mode = mode } @@ -396,7 +396,7 @@ func (w *window) draw() { height := int(hf*w.scale + .5) cfg := configFor(w.scale) w.setStage(system.StageRunning) - w.w.Event(FrameEvent{ + w.w.Event(frameEvent{ FrameEvent: system.FrameEvent{ Now: time.Now(), Size: image.Point{ @@ -461,11 +461,11 @@ func gio_onFinishLaunching() { close(launched) } -func NewWindow(win Callbacks, opts *Options) error { +func newWindow(win *callbacks, cnf *config) error { <-launched errch := make(chan error) runOnMain(func() { - w, err := newWindow(opts) + w, err := newOSWindow() if err != nil { errch <- err return @@ -474,7 +474,7 @@ func NewWindow(win Callbacks, opts *Options) error { w.w = win w.window = C.gio_createWindow(w.view, nil, 0, 0, 0, 0, 0, 0) win.SetDriver(w) - w.Option(opts) + w.Configure(cnf) if nextTopLeft.x == 0 && nextTopLeft.y == 0 { // cascadeTopLeftFromPoint treats (0, 0) as a no-op, // and just returns the offset we need for the first window. @@ -488,7 +488,7 @@ func NewWindow(win Callbacks, opts *Options) error { return <-errch } -func newWindow(opts *Options) (*window, error) { +func newOSWindow() (*window, error) { view := C.gio_createView() if view == 0 { return nil, errors.New("CreateWindow: failed to create view") @@ -512,7 +512,7 @@ func newWindow(opts *Options) (*window, error) { return w, nil } -func Main() { +func osMain() { C.gio_main() } diff --git a/app/internal/wm/os_macos.m b/app/os_macos.m similarity index 100% rename from app/internal/wm/os_macos.m rename to app/os_macos.m diff --git a/app/internal/wm/os_unix.go b/app/os_unix.go similarity index 85% rename from app/internal/wm/os_unix.go rename to app/os_unix.go index 7f92d026..518f912c 100644 --- a/app/internal/wm/os_unix.go +++ b/app/os_unix.go @@ -3,7 +3,7 @@ //go:build (linux && !android) || freebsd || openbsd // +build linux,!android freebsd openbsd -package wm +package app import ( "errors" @@ -17,23 +17,23 @@ type ViewEvent struct { Window uintptr } -func Main() { +func osMain() { select {} } -type windowDriver func(Callbacks, *Options) error +type windowDriver func(*callbacks, *config) error // Instead of creating files with build tags for each combination of wayland +/- x11 // let each driver initialize these variables with their own version of createWindow. var wlDriver, x11Driver windowDriver -func NewWindow(window Callbacks, opts *Options) error { +func newWindow(window *callbacks, cnf *config) error { var errFirst error for _, d := range []windowDriver{x11Driver, wlDriver} { if d == nil { continue } - err := d(window, opts) + err := d(window, cnf) if err == nil { return nil } diff --git a/app/internal/wm/os_wayland.c b/app/os_wayland.c similarity index 100% rename from app/internal/wm/os_wayland.c rename to app/os_wayland.c diff --git a/app/internal/wm/os_wayland.go b/app/os_wayland.go similarity index 98% rename from app/internal/wm/os_wayland.go rename to app/os_wayland.go index 5d7a0b0a..e3c95829 100644 --- a/app/internal/wm/os_wayland.go +++ b/app/os_wayland.go @@ -3,7 +3,7 @@ //go:build (linux && !android && !nowayland) || freebsd // +build linux,!android,!nowayland freebsd -package wm +package app import ( "bytes" @@ -136,7 +136,7 @@ type repeatState struct { delay time.Duration key uint32 - win Callbacks + win *callbacks stopC chan struct{} start time.Duration @@ -146,7 +146,7 @@ type repeatState struct { } type window struct { - w Callbacks + w *callbacks disp *wlDisplay surf *C.struct_wl_surface wmSurf *C.struct_xdg_surface @@ -222,12 +222,12 @@ func init() { wlDriver = newWLWindow } -func newWLWindow(window Callbacks, opts *Options) error { +func newWLWindow(window *callbacks, cnf *config) error { d, err := newWLDisplay() if err != nil { return err } - w, err := d.createNativeWindow(opts) + w, err := d.createNativeWindow(cnf) if err != nil { d.destroy() return err @@ -289,7 +289,7 @@ func (d *wlDisplay) readClipboard() (io.ReadCloser, error) { return r, nil } -func (d *wlDisplay) createNativeWindow(opts *Options) (*window, error) { +func (d *wlDisplay) createNativeWindow(cnf *config) (*window, error) { if d.compositor == nil { return nil, errors.New("wayland: no compositor available") } @@ -356,7 +356,7 @@ func (d *wlDisplay) createNativeWindow(opts *Options) (*window, error) { C.xdg_surface_add_listener(w.wmSurf, &C.gio_xdg_surface_listener, unsafe.Pointer(w.surf)) C.xdg_toplevel_add_listener(w.topLvl, &C.gio_xdg_toplevel_listener, unsafe.Pointer(w.surf)) - w.setOptions(opts) + w.Configure(cnf) if d.decor != nil { // Request server side decorations. @@ -907,17 +907,13 @@ func (w *window) WriteClipboard(s string) { w.disp.writeClipboard([]byte(s)) } -func (w *window) Option(opts *Options) { - w.setOptions(opts) -} - -func (w *window) setOptions(opts *Options) { +func (w *window) Configure(cnf *config) { _, _, cfg := w.config() - if o := opts.Size; o != nil { + if o := cnf.Size; o != nil { w.width = cfg.Px(o.Width) w.height = cfg.Px(o.Height) } - if o := opts.Title; o != nil { + if o := cnf.Title; o != nil { title := C.CString(*o) C.xdg_toplevel_set_title(w.topLvl, title) C.free(unsafe.Pointer(title)) @@ -1134,7 +1130,7 @@ func (w *window) loop() error { } select { case <-w.wakeups: - w.w.Event(WakeupEvent{}) + w.w.Event(wakeupEvent{}) default: } if w.dead { @@ -1423,7 +1419,7 @@ func (w *window) draw(sync bool) { // Use the surface as listener data for gio_onFrameDone. C.wl_callback_add_listener(w.lastFrameCallback, &C.gio_callback_listener, unsafe.Pointer(w.surf)) } - w.w.Event(FrameEvent{ + w.w.Event(frameEvent{ FrameEvent: system.FrameEvent{ Now: time.Now(), Size: image.Point{ diff --git a/app/internal/wm/os_windows.go b/app/os_windows.go similarity index 94% rename from app/internal/wm/os_windows.go rename to app/os_windows.go index 5c0cfaf6..2fcf62a4 100644 --- a/app/internal/wm/os_windows.go +++ b/app/os_windows.go @@ -1,6 +1,6 @@ // SPDX-License-Identifier: Unlicense OR MIT -package wm +package app import ( "errors" @@ -45,7 +45,7 @@ type winDeltas struct { type window struct { hwnd syscall.Handle hdc syscall.Handle - w Callbacks + w *callbacks width int height int stage system.Stage @@ -63,14 +63,14 @@ type window struct { minmax winConstraints deltas winDeltas - opts *Options + cnf *config } const _WM_WAKEUP = windows.WM_USER + iota type gpuAPI struct { priority int - initializer func(w *window) (Context, error) + initializer func(w *window) (context, error) } // drivers is the list of potential Context implementations. @@ -92,11 +92,11 @@ var resources struct { cursor syscall.Handle } -func Main() { +func osMain() { select {} } -func NewWindow(window Callbacks, opts *Options) error { +func newWindow(window *callbacks, cnf *config) error { cerr := make(chan error) go func() { // GetMessage and PeekMessage can filter on a window HWND, but @@ -104,7 +104,7 @@ func NewWindow(window Callbacks, opts *Options) error { // Instead lock the thread so window messages arrive through // unfiltered GetMessage calls. runtime.LockOSThread() - w, err := createNativeWindow(opts) + w, err := createNativeWindow(cnf) if err != nil { cerr <- err return @@ -115,7 +115,7 @@ func NewWindow(window Callbacks, opts *Options) error { w.w = window w.w.SetDriver(w) w.w.Event(ViewEvent{HWND: uintptr(w.hwnd)}) - w.Option(opts) + w.Configure(cnf) windows.ShowWindow(w.hwnd, windows.SW_SHOWDEFAULT) windows.SetForegroundWindow(w.hwnd) windows.SetFocus(w.hwnd) @@ -159,20 +159,20 @@ func initResources() error { return nil } -func getWindowConstraints(cfg unit.Metric, opts *Options) winConstraints { +func getWindowConstraints(cfg unit.Metric, cnf *config) winConstraints { var minmax winConstraints - if o := opts.MinSize; o != nil { + if o := cnf.MinSize; o != nil { minmax.minWidth = int32(cfg.Px(o.Width)) minmax.minHeight = int32(cfg.Px(o.Height)) } - if o := opts.MaxSize; o != nil { + if o := cnf.MaxSize; o != nil { minmax.maxWidth = int32(cfg.Px(o.Width)) minmax.maxHeight = int32(cfg.Px(o.Height)) } return minmax } -func createNativeWindow(opts *Options) (*window, error) { +func createNativeWindow(cnf *config) (*window, error) { var resErr error resources.once.Do(func() { resErr = initResources() @@ -200,8 +200,8 @@ func createNativeWindow(opts *Options) (*window, error) { } w := &window{ hwnd: hwnd, - minmax: getWindowConstraints(cfg, opts), - opts: opts, + minmax: getWindowConstraints(cfg, cnf), + cnf: cnf, } w.hdc, err = windows.GetDC(hwnd) if err != nil { @@ -330,7 +330,7 @@ func windowProc(hwnd syscall.Handle, msg uint32, wParam, lParam uintptr) uintptr return windows.TRUE } case _WM_WAKEUP: - w.w.Event(WakeupEvent{}) + w.w.Event(wakeupEvent{}) } return windows.DefWindowProc(hwnd, msg, wParam, lParam) @@ -458,8 +458,8 @@ func (w *window) draw(sync bool) { } dpi := windows.GetWindowDPI(w.hwnd) cfg := configForDPI(dpi) - w.minmax = getWindowConstraints(cfg, w.opts) - w.w.Event(FrameEvent{ + w.minmax = getWindowConstraints(cfg, w.cnf) + w.w.Event(frameEvent{ FrameEvent: system.FrameEvent{ Now: time.Now(), Size: image.Point{ @@ -472,7 +472,7 @@ func (w *window) draw(sync bool) { }) } -func (w *window) NewContext() (Context, error) { +func (w *window) NewContext() (context, error) { sort.Slice(drivers, func(i, j int) bool { return drivers[i].priority < drivers[j].priority }) @@ -515,9 +515,9 @@ func (w *window) readClipboard() error { return nil } -func (w *window) Option(opts *Options) { - w.opts = opts - if o := opts.Size; o != nil { +func (w *window) Configure(cnf *config) { + w.cnf = cnf + if o := cnf.Size; o != nil { dpi := windows.GetSystemDPI() cfg := configForDPI(dpi) width := int32(cfg.Px(o.Width)) @@ -538,27 +538,27 @@ func (w *window) Option(opts *Options) { w.deltas.width = width - dw w.deltas.height = height - dh - w.opts.Size = o + w.cnf.Size = o windows.MoveWindow(w.hwnd, 0, 0, width, height, true) } - if o := opts.MinSize; o != nil { - w.opts.MinSize = o + if o := cnf.MinSize; o != nil { + w.cnf.MinSize = o } - if o := opts.MaxSize; o != nil { - w.opts.MaxSize = o + if o := cnf.MaxSize; o != nil { + w.cnf.MaxSize = o } - if o := opts.Title; o != nil { - windows.SetWindowText(w.hwnd, *opts.Title) + if o := cnf.Title; o != nil { + windows.SetWindowText(w.hwnd, *cnf.Title) } - if o := opts.WindowMode; o != nil { + if o := cnf.WindowMode; o != nil { w.SetWindowMode(*o) } } -func (w *window) SetWindowMode(mode WindowMode) { +func (w *window) SetWindowMode(mode windowMode) { // https://devblogs.microsoft.com/oldnewthing/20100412-00/?p=14353 switch mode { - case Windowed: + case windowed: if w.placement == nil { return } @@ -570,7 +570,7 @@ func (w *window) SetWindowMode(mode WindowMode) { 0, 0, 0, 0, windows.SWP_NOOWNERZORDER|windows.SWP_FRAMECHANGED, ) - case Fullscreen: + case fullscreen: if w.placement != nil { return } diff --git a/app/internal/wm/os_x11.go b/app/os_x11.go similarity index 97% rename from app/internal/wm/os_x11.go rename to app/os_x11.go index f521d6ba..f3716010 100644 --- a/app/internal/wm/os_x11.go +++ b/app/os_x11.go @@ -3,7 +3,7 @@ //go:build (linux && !android && !nox11) || freebsd || openbsd // +build linux,!android,!nox11 freebsd openbsd -package wm +package app /* #cgo openbsd CFLAGS: -I/usr/X11R6/include -I/usr/local/include @@ -49,7 +49,7 @@ import ( ) type x11Window struct { - w Callbacks + w *callbacks x *C.Display xkb *xkb.Context xkbEventBase C.int @@ -96,7 +96,7 @@ type x11Window struct { content []byte } cursor pointer.CursorName - mode WindowMode + mode windowMode wakeups chan struct{} } @@ -115,14 +115,14 @@ func (w *x11Window) WriteClipboard(s string) { C.XSetSelectionOwner(w.x, w.atoms.clipboard, w.xw, C.CurrentTime) } -func (w *x11Window) Option(opts *Options) { +func (w *x11Window) Configure(cnf *config) { var shints C.XSizeHints - if o := opts.MinSize; o != nil { + if o := cnf.MinSize; o != nil { shints.min_width = C.int(w.cfg.Px(o.Width)) shints.min_height = C.int(w.cfg.Px(o.Height)) shints.flags = C.PMinSize } - if o := opts.MaxSize; o != nil { + if o := cnf.MaxSize; o != nil { shints.max_width = C.int(w.cfg.Px(o.Width)) shints.max_height = C.int(w.cfg.Px(o.Height)) shints.flags = shints.flags | C.PMaxSize @@ -131,12 +131,12 @@ func (w *x11Window) Option(opts *Options) { C.XSetWMNormalHints(w.x, w.xw, &shints) } - if o := opts.Size; o != nil { + if o := cnf.Size; o != nil { C.XResizeWindow(w.x, w.xw, C.uint(w.cfg.Px(o.Width)), C.uint(w.cfg.Px(o.Height))) } var title string - if o := opts.Title; o != nil { + if o := cnf.Title; o != nil { title = *o } ctitle := C.CString(title) @@ -152,7 +152,7 @@ func (w *x11Window) Option(opts *Options) { }, w.atoms.wmName) - if o := opts.WindowMode; o != nil { + if o := cnf.WindowMode; o != nil { w.SetWindowMode(*o) } } @@ -181,13 +181,13 @@ func (w *x11Window) SetCursor(name pointer.CursorName) { C.XDefineCursor(w.x, w.xw, c) } -func (w *x11Window) SetWindowMode(mode WindowMode) { +func (w *x11Window) SetWindowMode(mode windowMode) { switch mode { case w.mode: return - case Windowed: + case windowed: C.XDeleteProperty(w.x, w.xw, w.atoms.wmStateFullscreen) - case Fullscreen: + case fullscreen: C.XChangeProperty(w.x, w.xw, w.atoms.wmState, C.XA_ATOM, 32, C.PropModeReplace, (*C.uchar)(unsafe.Pointer(&w.atoms.wmStateFullscreen)), 1, @@ -322,12 +322,12 @@ loop: } select { case <-w.wakeups: - w.w.Event(WakeupEvent{}) + w.w.Event(wakeupEvent{}) default: } if (anim || syn) && w.width != 0 && w.height != 0 { - w.w.Event(FrameEvent{ + w.w.Event(frameEvent{ FrameEvent: system.FrameEvent{ Now: time.Now(), Size: image.Point{ @@ -582,7 +582,7 @@ func init() { x11Driver = newX11Window } -func newX11Window(gioWin Callbacks, opts *Options) error { +func newX11Window(gioWin *callbacks, cnf *config) error { var err error pipe := make([]int, 2) @@ -632,7 +632,7 @@ func newX11Window(gioWin Callbacks, opts *Options) error { override_redirect: C.False, } var width, height int - if o := opts.Size; o != nil { + if o := cnf.Size; o != nil { width = cfg.Px(o.Width) height = cfg.Px(o.Height) } @@ -683,7 +683,7 @@ func newX11Window(gioWin Callbacks, opts *Options) error { // extensions C.XSetWMProtocols(dpy, win, &w.atoms.evDelWindow, 1) - w.Option(opts) + w.Configure(cnf) // make the window visible on the screen C.XMapWindow(dpy, win) diff --git a/app/internal/wm/runmain.go b/app/runmain.go similarity index 98% rename from app/internal/wm/runmain.go rename to app/runmain.go index 0fa7a6cf..a1c1e3d4 100644 --- a/app/internal/wm/runmain.go +++ b/app/runmain.go @@ -3,7 +3,7 @@ //go:build android || (darwin && ios) // +build android darwin,ios -package wm +package app // Android only supports non-Java programs as c-shared libraries. // Unfortunately, Go does not run a program's main function in diff --git a/app/sigpipe_darwin.go b/app/sigpipe_darwin.go deleted file mode 100644 index 74dd969b..00000000 --- a/app/sigpipe_darwin.go +++ /dev/null @@ -1,19 +0,0 @@ -// SPDX-License-Identifier: Unlicense OR MIT - -//go:build !go1.14 -// +build !go1.14 - -// Work around golang.org/issue/33384, fixed in CL 191785, -// to be released in Go 1.14. - -package app - -import ( - "os" - "os/signal" - "syscall" -) - -func init() { - signal.Notify(make(chan os.Signal), syscall.SIGPIPE) -} diff --git a/app/internal/wm/wayland_text_input.c b/app/wayland_text_input.c similarity index 100% rename from app/internal/wm/wayland_text_input.c rename to app/wayland_text_input.c diff --git a/app/internal/wm/wayland_text_input.h b/app/wayland_text_input.h similarity index 100% rename from app/internal/wm/wayland_text_input.h rename to app/wayland_text_input.h diff --git a/app/internal/wm/wayland_xdg_decoration.c b/app/wayland_xdg_decoration.c similarity index 100% rename from app/internal/wm/wayland_xdg_decoration.c rename to app/wayland_xdg_decoration.c diff --git a/app/internal/wm/wayland_xdg_decoration.h b/app/wayland_xdg_decoration.h similarity index 100% rename from app/internal/wm/wayland_xdg_decoration.h rename to app/wayland_xdg_decoration.h diff --git a/app/internal/wm/wayland_xdg_shell.c b/app/wayland_xdg_shell.c similarity index 100% rename from app/internal/wm/wayland_xdg_shell.c rename to app/wayland_xdg_shell.c diff --git a/app/internal/wm/wayland_xdg_shell.h b/app/wayland_xdg_shell.h similarity index 100% rename from app/internal/wm/wayland_xdg_shell.h rename to app/wayland_xdg_shell.h diff --git a/app/window.go b/app/window.go index 3cbd126b..c7ae5af0 100644 --- a/app/window.go +++ b/app/window.go @@ -18,22 +18,21 @@ import ( "gioui.org/unit" _ "gioui.org/app/internal/log" - "gioui.org/app/internal/wm" ) // Option configures a window. -type Option func(opts *wm.Options) +type Option func(cnf *config) // Window represents an operating system window. type Window struct { - ctx wm.Context + ctx context loop *renderLoop // driverFuncs is a channel of functions to run when // the Window has a valid driver. - driverFuncs chan func(d wm.Driver) + driverFuncs chan func(d driver) // wakeups wakes up the native event loop to send a - // wm.WakeupEvent that flushes driverFuncs. + // WakeupEvent that flushes driverFuncs. wakeups chan struct{} out chan event.Event @@ -62,7 +61,7 @@ type Window struct { type callbacks struct { w *Window - d wm.Driver + d driver } // queue is an event.Queue implementation that distributes system events @@ -73,7 +72,7 @@ type queue struct { // driverEvent is sent when the underlying driver changes. type driverEvent struct { - driver wm.Driver + driver driver } // Pre-allocate the ack event to avoid garbage. @@ -90,13 +89,13 @@ var ackEvent event.Event // Calling NewWindow more than once is not supported on // iOS, Android, WebAssembly. func NewWindow(options ...Option) *Window { - opts := new(wm.Options) + cnf := new(config) // Default options. - Size(unit.Dp(800), unit.Dp(600))(opts) - Title("Gio")(opts) + Size(unit.Dp(800), unit.Dp(600))(cnf) + Title("Gio")(cnf) for _, o := range options { - o(opts) + o(cnf) } w := &Window{ @@ -106,14 +105,14 @@ func NewWindow(options ...Option) *Window { invalidates: make(chan struct{}, 1), frames: make(chan *op.Ops), frameAck: make(chan struct{}), - driverFuncs: make(chan func(d wm.Driver), 1), + driverFuncs: make(chan func(d driver), 1), wakeups: make(chan struct{}, 1), dead: make(chan struct{}), notifyAnimate: make(chan struct{}, 1), - nocontext: opts.CustomRenderer, + nocontext: cnf.CustomRenderer, } w.callbacks.w = w - go w.run(opts) + go w.run(cnf) return w } @@ -122,21 +121,20 @@ func (w *Window) Events() <-chan event.Event { return w.out } -// update updates the wm. Paint operations updates the -// window contents, input operations declare input handlers, -// and so on. The supplied operations list completely replaces -// the window state from previous calls. +// update updates the window contents, input operations declare input handlers, +// and so on. The supplied operations list completely replaces the window state +// from previous calls. func (w *Window) update(frame *op.Ops) { w.frames <- frame <-w.frameAck } -func (w *Window) validateAndProcess(driver wm.Driver, frameStart time.Time, size image.Point, sync bool, frame *op.Ops) error { +func (w *Window) validateAndProcess(d driver, frameStart time.Time, size image.Point, sync bool, frame *op.Ops) error { for { if w.loop != nil { if err := w.loop.Flush(); err != nil { w.destroyGPU() - if err == wm.ErrDeviceLost { + if err == errDeviceLost { continue } return err @@ -145,8 +143,8 @@ func (w *Window) validateAndProcess(driver wm.Driver, frameStart time.Time, size if w.loop == nil && !w.nocontext { var err error if w.ctx == nil { - w.driverRun(func(_ wm.Driver) { - w.ctx, err = driver.NewContext() + w.driverRun(func(_ driver) { + w.ctx, err = d.NewContext() }) if err != nil { return err @@ -160,7 +158,7 @@ func (w *Window) validateAndProcess(driver wm.Driver, frameStart time.Time, size } } if sync && w.ctx != nil { - w.driverRun(func(_ wm.Driver) { + w.driverRun(func(_ driver) { w.ctx.Refresh() }) } @@ -168,7 +166,7 @@ func (w *Window) validateAndProcess(driver wm.Driver, frameStart time.Time, size if sync && w.loop != nil { if err := w.loop.Flush(); err != nil { w.destroyGPU() - if err == wm.ErrDeviceLost { + if err == errDeviceLost { continue } return err @@ -190,12 +188,12 @@ func (w *Window) processFrame(frameStart time.Time, size image.Point, frame *op. w.queue.q.Frame(frame) switch w.queue.q.TextInputState() { case router.TextInputOpen: - go w.driverRun(func(d wm.Driver) { d.ShowTextInput(true) }) + go w.driverRun(func(d driver) { d.ShowTextInput(true) }) case router.TextInputClose: - go w.driverRun(func(d wm.Driver) { d.ShowTextInput(false) }) + go w.driverRun(func(d driver) { d.ShowTextInput(false) }) } if hint, ok := w.queue.q.TextInputHint(); ok { - go w.driverRun(func(d wm.Driver) { d.SetInputHint(hint) }) + go w.driverRun(func(d driver) { d.SetInputHint(hint) }) } if txt, ok := w.queue.q.WriteClipboard(); ok { go w.WriteClipboard(txt) @@ -242,12 +240,12 @@ func (w *Window) Invalidate() { // Option applies the options to the window. func (w *Window) Option(opts ...Option) { - go w.driverRun(func(d wm.Driver) { - o := new(wm.Options) + go w.driverRun(func(d driver) { + c := new(config) for _, opt := range opts { - opt(o) + opt(c) } - d.Option(o) + d.Configure(c) }) } @@ -255,32 +253,32 @@ func (w *Window) Option(opts ...Option) { // of a clipboard.Event. Multiple reads may be coalesced // to a single event. func (w *Window) ReadClipboard() { - go w.driverRun(func(d wm.Driver) { + go w.driverRun(func(d driver) { d.ReadClipboard() }) } // WriteClipboard writes a string to the clipboard. func (w *Window) WriteClipboard(s string) { - go w.driverRun(func(d wm.Driver) { + go w.driverRun(func(d driver) { d.WriteClipboard(s) }) } // SetCursorName changes the current window cursor to name. func (w *Window) SetCursorName(name pointer.CursorName) { - go w.driverRun(func(d wm.Driver) { + go w.driverRun(func(d driver) { d.SetCursor(name) }) } -// Close the wm. The window's event loop should exit when it receives +// Close the window. The window's event loop should exit when it receives // system.DestroyEvent. // // Currently, only macOS, Windows and X11 drivers implement this functionality, // all others are stubbed. func (w *Window) Close() { - go w.driverRun(func(d wm.Driver) { + go w.driverRun(func(d driver) { d.Close() }) } @@ -294,14 +292,14 @@ func (w *Window) Close() { // Note that most programs should not call Run; configuring a Window with // CustomRenderer is a notable exception. func (w *Window) Run(f func()) { - w.driverRun(func(_ wm.Driver) { + w.driverRun(func(_ driver) { f() }) } -func (w *Window) driverRun(f func(d wm.Driver)) { +func (w *Window) driverRun(f func(d driver)) { done := make(chan struct{}) - wrapper := func(d wm.Driver) { + wrapper := func(d driver) { defer close(done) f(d) } @@ -353,7 +351,7 @@ func (w *Window) setNextFrame(at time.Time) { } } -func (c *callbacks) SetDriver(d wm.Driver) { +func (c *callbacks) SetDriver(d driver) { c.d = d c.Event(driverEvent{d}) } @@ -366,7 +364,7 @@ func (c *callbacks) Event(e event.Event) { } } -func (w *Window) runFuncs(d wm.Driver) { +func (w *Window) runFuncs(d driver) { // Don't run driver functions if there's no driver. if d == nil { <-w.ack @@ -446,14 +444,14 @@ func (w *Window) waitFrame() (*op.Ops, bool) { } } -func (w *Window) run(opts *wm.Options) { +func (w *Window) run(cnf *config) { defer close(w.out) defer close(w.dead) - if err := wm.NewWindow(&w.callbacks, opts); err != nil { + if err := newWindow(&w.callbacks, cnf); err != nil { w.out <- system.DestroyEvent{Err: err} return } - var driver wm.Driver + var driver driver for { var wakeups chan struct{} if driver != nil { @@ -487,7 +485,7 @@ func (w *Window) run(opts *wm.Options) { w.updateAnimation() w.out <- e w.waitAck() - case wm.FrameEvent: + case frameEvent: if e2.Size == (image.Point{}) { panic(errors.New("internal error: zero-sized Draw")) } @@ -525,7 +523,7 @@ func (w *Window) run(opts *wm.Options) { case ViewEvent: w.out <- e2 w.waitAck() - case wm.WakeupEvent: + case wakeupEvent: case event.Event: if w.queue.q.Queue(e2) { w.setNextFrame(time.Time{}) @@ -552,42 +550,42 @@ func (q *queue) Events(k event.Tag) []event.Event { var ( // Windowed is the normal window mode with OS specific window decorations. - Windowed Option = windowMode(wm.Windowed) + Windowed Option = modeOption(windowed) // Fullscreen is the full screen window mode. - Fullscreen Option = windowMode(wm.Fullscreen) + Fullscreen Option = modeOption(fullscreen) ) -// windowMode sets the window mode. +// WindowMode sets the window mode. // // Supported platforms are macOS, X11, Windows and JS. -func windowMode(mode wm.WindowMode) Option { - return func(opts *wm.Options) { - opts.WindowMode = &mode +func modeOption(mode windowMode) Option { + return func(cnf *config) { + cnf.WindowMode = &mode } } var ( // AnyOrientation allows the window to be freely orientated. - AnyOrientation Option = orientation(wm.AnyOrientation) + AnyOrientation Option = orientationOption(anyOrientation) // LandscapeOrientation constrains the window to landscape orientations. - LandscapeOrientation Option = orientation(wm.LandscapeOrientation) + LandscapeOrientation Option = orientationOption(landscapeOrientation) // PortraitOrientation constrains the window to portrait orientations. - PortraitOrientation Option = orientation(wm.PortraitOrientation) + PortraitOrientation Option = orientationOption(portraitOrientation) ) // orientation sets the orientation of the app. // // Supported platforms are Android and JS. -func orientation(mode wm.Orientation) Option { - return func(opts *wm.Options) { - opts.Orientation = &mode +func orientationOption(mode orientation) Option { + return func(cnf *config) { + cnf.Orientation = &mode } } // Title sets the title of the window. func Title(t string) Option { - return func(opts *wm.Options) { - opts.Title = &t + return func(cnf *config) { + cnf.Title = &t } } @@ -599,8 +597,8 @@ func Size(w, h unit.Value) Option { if h.V <= 0 { panic("height must be larger than or equal to 0") } - return func(opts *wm.Options) { - opts.Size = &wm.Size{ + return func(cnf *config) { + cnf.Size = &size{ Width: w, Height: h, } @@ -615,8 +613,8 @@ func MaxSize(w, h unit.Value) Option { if h.V <= 0 { panic("height must be larger than or equal to 0") } - return func(opts *wm.Options) { - opts.MaxSize = &wm.Size{ + return func(cnf *config) { + cnf.MaxSize = &size{ Width: w, Height: h, } @@ -631,8 +629,8 @@ func MinSize(w, h unit.Value) Option { if h.V <= 0 { panic("height must be larger than or equal to 0") } - return func(opts *wm.Options) { - opts.MinSize = &wm.Size{ + return func(cnf *config) { + cnf.MinSize = &size{ Width: w, Height: h, } @@ -641,23 +639,23 @@ func MinSize(w, h unit.Value) Option { // StatusColor sets the color of the Android status bar. func StatusColor(color color.NRGBA) Option { - return func(opts *wm.Options) { - opts.StatusColor = &color + return func(cnf *config) { + cnf.StatusColor = &color } } // NavigationColor sets the color of the navigation bar on Android, or the address bar in browsers. func NavigationColor(color color.NRGBA) Option { - return func(opts *wm.Options) { - opts.NavigationColor = &color + return func(cnf *config) { + cnf.NavigationColor = &color } } // CustomRenderer controls whether the the window contents is // rendered by the client. If true, no GPU context is created. func CustomRenderer(custom bool) Option { - return func(opts *wm.Options) { - opts.CustomRenderer = custom + return func(cnf *config) { + cnf.CustomRenderer = custom } } diff --git a/cmd/gogio/androidbuild.go b/cmd/gogio/androidbuild.go index b937c5b6..87486669 100644 --- a/cmd/gogio/androidbuild.go +++ b/cmd/gogio/androidbuild.go @@ -240,7 +240,7 @@ func compileAndroid(tmpDir string, tools *androidTools, bi *buildInfo) (err erro return err }) } - appDir, err := runCmd(exec.Command("go", "list", "-f", "{{.Dir}}", "gioui.org/app/internal/wm")) + appDir, err := runCmd(exec.Command("go", "list", "-f", "{{.Dir}}", "gioui.org/app/")) if err != nil { return err } diff --git a/cmd/gogio/iosbuild.go b/cmd/gogio/iosbuild.go index 858b5697..b75e43cc 100644 --- a/cmd/gogio/iosbuild.go +++ b/cmd/gogio/iosbuild.go @@ -464,7 +464,7 @@ func archiveIOS(tmpDir, target, frameworkRoot string, bi *buildInfo) error { if _, err := runCmd(lipo); err != nil { return err } - appDir, err := runCmd(exec.Command("go", "list", "-f", "{{.Dir}}", "gioui.org/app/internal/wm")) + appDir, err := runCmd(exec.Command("go", "list", "-f", "{{.Dir}}", "gioui.org/app/")) if err != nil { return err }