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 <mail@eliasnaur.com>
This commit is contained in:
Elias Naur
2021-08-29 22:00:16 +02:00
parent fe52357141
commit 45da52cee7
46 changed files with 325 additions and 400 deletions
+1 -9
View File
@@ -5,16 +5,8 @@ package app
import ( import (
"os" "os"
"strings" "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 // extraArgs contains extra arguments to append to
// os.Args. The arguments are separated with |. // os.Args. The arguments are separated with |.
// Useful for running programs on mobiles where the // 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 // require control of the main thread of the program for
// running windows. // running windows.
func Main() { func Main() {
wm.Main() osMain()
} }
-18
View File
@@ -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()
}
@@ -1,6 +1,6 @@
// SPDX-License-Identifier: Unlicense OR MIT // SPDX-License-Identifier: Unlicense OR MIT
package wm package app
import ( import (
"fmt" "fmt"
@@ -25,7 +25,7 @@ const debug = false
func init() { func init() {
drivers = append(drivers, gpuAPI{ drivers = append(drivers, gpuAPI{
priority: 1, priority: 1,
initializer: func(w *window) (Context, error) { initializer: func(w *window) (context, error) {
hwnd, _, _ := w.HWND() hwnd, _, _ := w.HWND()
var flags uint32 var flags uint32
if debug { if debug {
@@ -70,7 +70,7 @@ func (c *d3d11Context) Present() error {
// Ignore // Ignore
return nil return nil
case d3d11.DXGI_ERROR_DEVICE_RESET, d3d11.DXGI_ERROR_DEVICE_REMOVED, d3d11.D3DDDIERR_DEVICEREMOVED: case d3d11.DXGI_ERROR_DEVICE_RESET, d3d11.DXGI_ERROR_DEVICE_REMOVED, d3d11.D3DDDIERR_DEVICEREMOVED:
return ErrDeviceLost return errDeviceLost
} }
} }
return err return err
-42
View File
@@ -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
}
@@ -1,6 +1,6 @@
// SPDX-License-Identifier: Unlicense OR MIT // SPDX-License-Identifier: Unlicense OR MIT
package wm package app
/* /*
#include <android/native_window_jni.h> #include <android/native_window_jni.h>
@@ -14,27 +14,27 @@ import (
"gioui.org/internal/egl" "gioui.org/internal/egl"
) )
type context struct { type androidContext struct {
win *window win *window
*egl.Context *egl.Context
} }
func (w *window) NewContext() (Context, error) { func (w *window) NewContext() (context, error) {
ctx, err := egl.NewContext(nil) ctx, err := egl.NewContext(nil)
if err != nil { if err != nil {
return nil, err 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 { if c.Context != nil {
c.Context.Release() c.Context.Release()
c.Context = nil c.Context = nil
} }
} }
func (c *context) Refresh() error { func (c *androidContext) Refresh() error {
c.Context.ReleaseSurface() c.Context.ReleaseSurface()
var ( var (
win *C.ANativeWindow win *C.ANativeWindow
@@ -48,10 +48,10 @@ func (c *context) Refresh() error {
return c.Context.CreateSurface(eglSurf, width, height) return c.Context.CreateSurface(eglSurf, width, height)
} }
func (c *context) Lock() error { func (c *androidContext) Lock() error {
return c.Context.MakeCurrent() return c.Context.MakeCurrent()
} }
func (c *context) Unlock() { func (c *androidContext) Unlock() {
c.Context.ReleaseCurrent() c.Context.ReleaseCurrent()
} }
@@ -3,7 +3,7 @@
//go:build (linux && !android && !nowayland) || freebsd //go:build (linux && !android && !nowayland) || freebsd
// +build linux,!android,!nowayland freebsd // +build linux,!android,!nowayland freebsd
package wm package app
import ( import (
"errors" "errors"
@@ -23,22 +23,22 @@ import (
*/ */
import "C" import "C"
type context struct { type wlContext struct {
win *window win *window
*egl.Context *egl.Context
eglWin *C.struct_wl_egl_window 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())) disp := egl.NativeDisplayType(unsafe.Pointer(w.display()))
ctx, err := egl.NewContext(disp) ctx, err := egl.NewContext(disp)
if err != nil { if err != nil {
return nil, err 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 { if c.Context != nil {
c.Context.Release() c.Context.Release()
c.Context = nil c.Context = nil
@@ -49,7 +49,7 @@ func (c *context) Release() {
} }
} }
func (c *context) Refresh() error { func (c *wlContext) Refresh() error {
c.Context.ReleaseSurface() c.Context.ReleaseSurface()
if c.eglWin != nil { if c.eglWin != nil {
C.wl_egl_window_destroy(c.eglWin) C.wl_egl_window_destroy(c.eglWin)
@@ -68,10 +68,10 @@ func (c *context) Refresh() error {
return c.Context.CreateSurface(eglSurf, width, height) return c.Context.CreateSurface(eglSurf, width, height)
} }
func (c *context) Lock() error { func (c *wlContext) Lock() error {
return c.Context.MakeCurrent() return c.Context.MakeCurrent()
} }
func (c *context) Unlock() { func (c *wlContext) Unlock() {
c.Context.ReleaseCurrent() c.Context.ReleaseCurrent()
} }
@@ -1,6 +1,6 @@
// SPDX-License-Identifier: Unlicense OR MIT // SPDX-License-Identifier: Unlicense OR MIT
package wm package app
import ( import (
"golang.org/x/sys/windows" "golang.org/x/sys/windows"
@@ -16,7 +16,7 @@ type glContext struct {
func init() { func init() {
drivers = append(drivers, gpuAPI{ drivers = append(drivers, gpuAPI{
priority: 2, priority: 2,
initializer: func(w *window) (Context, error) { initializer: func(w *window) (context, error) {
disp := egl.NativeDisplayType(w.HDC()) disp := egl.NativeDisplayType(w.HDC())
ctx, err := egl.NewContext(disp) ctx, err := egl.NewContext(disp)
if err != nil { if err != nil {
@@ -3,7 +3,7 @@
//go:build (linux && !android && !nox11) || freebsd || openbsd //go:build (linux && !android && !nox11) || freebsd || openbsd
// +build linux,!android,!nox11 freebsd openbsd // +build linux,!android,!nox11 freebsd openbsd
package wm package app
import ( import (
"unsafe" "unsafe"
@@ -16,7 +16,7 @@ type x11Context struct {
*egl.Context *egl.Context
} }
func (w *x11Window) NewContext() (Context, error) { func (w *x11Window) NewContext() (context, error) {
disp := egl.NativeDisplayType(unsafe.Pointer(w.display())) disp := egl.NativeDisplayType(unsafe.Pointer(w.display()))
ctx, err := egl.NewContext(disp) ctx, err := egl.NewContext(disp)
if err != nil { if err != nil {
+1 -1
View File
@@ -3,7 +3,7 @@
//go:build darwin && ios && nometal //go:build darwin && ios && nometal
// +build darwin,ios,nometal // +build darwin,ios,nometal
package wm package app
/* /*
@import UIKit; @import UIKit;
+12 -12
View File
@@ -1,6 +1,6 @@
// SPDX-License-Identifier: Unlicense OR MIT // SPDX-License-Identifier: Unlicense OR MIT
package wm package app
import ( import (
"errors" "errors"
@@ -10,12 +10,12 @@ import (
"gioui.org/internal/gl" "gioui.org/internal/gl"
) )
type context struct { type glContext struct {
ctx js.Value ctx js.Value
cnv js.Value cnv js.Value
} }
func newContext(w *window) (*context, error) { func newContext(w *window) (*glContext, error) {
args := map[string]interface{}{ args := map[string]interface{}{
// Enable low latency rendering. // Enable low latency rendering.
// See https://developers.google.com/web/updates/2019/05/desynchronized. // See https://developers.google.com/web/updates/2019/05/desynchronized.
@@ -29,41 +29,41 @@ func newContext(w *window) (*context, error) {
if ctx.IsNull() { if ctx.IsNull() {
return nil, errors.New("app: webgl is not supported") return nil, errors.New("app: webgl is not supported")
} }
c := &context{ c := &glContext{
ctx: ctx, ctx: ctx,
cnv: w.cnv, cnv: w.cnv,
} }
return c, nil return c, nil
} }
func (c *context) RenderTarget() gpu.RenderTarget { func (c *glContext) RenderTarget() gpu.RenderTarget {
return gpu.OpenGLRenderTarget{} return gpu.OpenGLRenderTarget{}
} }
func (c *context) API() gpu.API { func (c *glContext) API() gpu.API {
return gpu.OpenGL{Context: gl.Context(c.ctx)} 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() { if c.ctx.Call("isContextLost").Bool() {
return errors.New("context lost") return errors.New("context lost")
} }
return nil return nil
} }
func (c *context) Lock() error { func (c *glContext) Lock() error {
return nil return nil
} }
func (c *context) Unlock() {} func (c *glContext) Unlock() {}
func (c *context) Refresh() error { func (c *glContext) Refresh() error {
return nil return nil
} }
func (w *window) NewContext() (Context, error) { func (w *window) NewContext() (context, error) {
return newContext(w) return newContext(w)
} }
+12 -12
View File
@@ -3,7 +3,7 @@
//go:build darwin && !ios && nometal //go:build darwin && !ios && nometal
// +build darwin,!ios,nometal // +build darwin,!ios,nometal
package wm package app
import ( import (
"errors" "errors"
@@ -28,35 +28,35 @@ __attribute__ ((visibility ("hidden"))) void gio_unlockContext(CFTypeRef ctxRef)
*/ */
import "C" import "C"
type context struct { type glContext struct {
c *gl.Functions c *gl.Functions
ctx C.CFTypeRef ctx C.CFTypeRef
view C.CFTypeRef view C.CFTypeRef
} }
func newContext(w *window) (*context, error) { func newContext(w *window) (*glContext, error) {
view := w.contextView() view := w.contextView()
ctx := C.gio_createGLContext() ctx := C.gio_createGLContext()
if ctx == 0 { if ctx == 0 {
return nil, errors.New("gl: failed to create NSOpenGLContext") return nil, errors.New("gl: failed to create NSOpenGLContext")
} }
C.gio_setContextView(ctx, view) C.gio_setContextView(ctx, view)
c := &context{ c := &glContext{
ctx: ctx, ctx: ctx,
view: view, view: view,
} }
return c, nil return c, nil
} }
func (c *context) RenderTarget() gpu.RenderTarget { func (c *glContext) RenderTarget() gpu.RenderTarget {
return gpu.OpenGLRenderTarget{} return gpu.OpenGLRenderTarget{}
} }
func (c *context) API() gpu.API { func (c *glContext) API() gpu.API {
return gpu.OpenGL{} return gpu.OpenGL{}
} }
func (c *context) Release() { func (c *glContext) Release() {
if c.ctx != 0 { if c.ctx != 0 {
C.gio_clearCurrentContext() C.gio_clearCurrentContext()
C.CFRelease(c.ctx) C.CFRelease(c.ctx)
@@ -64,28 +64,28 @@ func (c *context) Release() {
} }
} }
func (c *context) Present() error { func (c *glContext) Present() error {
return nil return nil
} }
func (c *context) Lock() error { func (c *glContext) Lock() error {
C.gio_lockContext(c.ctx) C.gio_lockContext(c.ctx)
C.gio_makeCurrentContext(c.ctx) C.gio_makeCurrentContext(c.ctx)
return nil return nil
} }
func (c *context) Unlock() { func (c *glContext) Unlock() {
C.gio_clearCurrentContext() C.gio_clearCurrentContext()
C.gio_unlockContext(c.ctx) C.gio_unlockContext(c.ctx)
} }
func (c *context) Refresh() error { func (c *glContext) Refresh() error {
c.Lock() c.Lock()
defer c.Unlock() defer c.Unlock()
C.gio_updateContext(c.ctx) C.gio_updateContext(c.ctx)
return nil return nil
} }
func (w *window) NewContext() (Context, error) { func (w *window) NewContext() (context, error) {
return newContext(w) return newContext(w)
} }
+3 -4
View File
@@ -7,7 +7,6 @@ import (
"image/color" "image/color"
"runtime" "runtime"
"gioui.org/app/internal/wm"
"gioui.org/gpu" "gioui.org/gpu"
"gioui.org/op" "gioui.org/op"
) )
@@ -17,7 +16,7 @@ type renderLoop struct {
drawing bool drawing bool
err error err error
ctx wm.Context ctx context
frames chan frame frames chan frame
results chan frameResult results chan frameResult
ack chan struct{} ack chan struct{}
@@ -35,7 +34,7 @@ type frameResult struct {
err error err error
} }
func newLoop(ctx wm.Context) (*renderLoop, error) { func newLoop(ctx context) (*renderLoop, error) {
l := &renderLoop{ l := &renderLoop{
ctx: ctx, ctx: ctx,
frames: make(chan frame), frames: make(chan frame),
@@ -52,7 +51,7 @@ func newLoop(ctx wm.Context) (*renderLoop, error) {
return l, nil 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 // GL Operations must happen on a single OS thread, so
// pass initialization result through a channel. // pass initialization result through a channel.
initErr := make(chan error) initErr := make(chan error)
@@ -3,7 +3,7 @@
//go:build !nometal //go:build !nometal
// +build !nometal // +build !nometal
package wm package app
import ( import (
"errors" "errors"
@@ -169,6 +169,6 @@ func (c *mtlContext) Refresh() error {
return nil return nil
} }
func (w *window) NewContext() (Context, error) { func (w *window) NewContext() (context, error) {
return newMtlContext(w) return newMtlContext(w)
} }
@@ -3,7 +3,7 @@
//go:build !nometal //go:build !nometal
// +build !nometal // +build !nometal
package wm package app
/* /*
#cgo CFLAGS: -Werror -xobjective-c -fmodules -fobjc-arc #cgo CFLAGS: -Werror -xobjective-c -fmodules -fobjc-arc
@@ -3,7 +3,7 @@
//go:build darwin && !ios && !nometal //go:build darwin && !ios && !nometal
// +build darwin,!ios,!nometal // +build darwin,!ios,!nometal
package wm package app
/* /*
#cgo CFLAGS: -Werror -xobjective-c -fmodules -fobjc-arc #cgo CFLAGS: -Werror -xobjective-c -fmodules -fobjc-arc
+35 -41
View File
@@ -1,8 +1,8 @@
// SPDX-License-Identifier: Unlicense OR MIT // SPDX-License-Identifier: Unlicense OR MIT
// package wm implements platform specific windows // package app implements platform specific windows
// and GPU contexts. // and GPU contexts.
package wm package app
import ( import (
"errors" "errors"
@@ -11,58 +11,52 @@ import (
"gioui.org/io/key" "gioui.org/io/key"
"gioui.org/gpu" "gioui.org/gpu"
"gioui.org/io/event"
"gioui.org/io/pointer" "gioui.org/io/pointer"
"gioui.org/io/system" "gioui.org/io/system"
"gioui.org/unit" "gioui.org/unit"
) )
type Size struct { type size struct {
Width unit.Value Width unit.Value
Height unit.Value Height unit.Value
} }
type Options struct { type config struct {
Size *Size Size *size
MinSize *Size MinSize *size
MaxSize *Size MaxSize *size
Title *string Title *string
WindowMode *WindowMode WindowMode *windowMode
StatusColor *color.NRGBA StatusColor *color.NRGBA
NavigationColor *color.NRGBA NavigationColor *color.NRGBA
Orientation *Orientation Orientation *orientation
CustomRenderer bool CustomRenderer bool
} }
type WakeupEvent struct{} type wakeupEvent struct{}
type WindowMode uint8 type windowMode uint8
const ( const (
Windowed WindowMode = iota windowed windowMode = iota
Fullscreen fullscreen
) )
type Orientation uint8 type orientation uint8
const ( const (
AnyOrientation Orientation = iota anyOrientation orientation = iota
LandscapeOrientation landscapeOrientation
PortraitOrientation portraitOrientation
) )
type FrameEvent struct { type frameEvent struct {
system.FrameEvent system.FrameEvent
Sync bool Sync bool
} }
type Callbacks interface { type context interface {
SetDriver(d Driver)
Event(e event.Event)
}
type Context interface {
API() gpu.API API() gpu.API
RenderTarget() gpu.RenderTarget RenderTarget() gpu.RenderTarget
Present() error Present() error
@@ -72,14 +66,14 @@ type Context interface {
Unlock() Unlock()
} }
// ErrDeviceLost is returned from Context.Present when // errDeviceLost is returned from Context.Present when
// the underlying GPU device is gone and should be // the underlying GPU device is gone and should be
// recreated. // recreated.
var ErrDeviceLost = errors.New("GPU device lost") var errDeviceLost = errors.New("GPU device lost")
// Driver is the interface for the platform implementation // Driver is the interface for the platform implementation
// of a window. // of a window.
type Driver interface { type driver interface {
// SetAnimating sets the animation flag. When the window is animating, // SetAnimating sets the animation flag. When the window is animating,
// FrameEvents are delivered as fast as the display can handle them. // FrameEvents are delivered as fast as the display can handle them.
SetAnimating(anim bool) SetAnimating(anim bool)
@@ -89,15 +83,15 @@ type Driver interface {
SetInputHint(mode key.InputHint) SetInputHint(mode key.InputHint)
NewContext() (Context, error) NewContext() (context, error)
// ReadClipboard requests the clipboard content. // ReadClipboard requests the clipboard content.
ReadClipboard() ReadClipboard()
// WriteClipboard requests a clipboard write. // WriteClipboard requests a clipboard write.
WriteClipboard(s string) WriteClipboard(s string)
// Option processes option changes. // Configure the window.
Option(opts *Options) Configure(cnf *config)
// SetCursor updates the current cursor to name. // SetCursor updates the current cursor to name.
SetCursor(name pointer.CursorName) SetCursor(name pointer.CursorName)
@@ -109,25 +103,25 @@ type Driver interface {
} }
type windowRendezvous struct { type windowRendezvous struct {
in chan windowAndOptions in chan windowAndConfig
out chan windowAndOptions out chan windowAndConfig
errs chan error errs chan error
} }
type windowAndOptions struct { type windowAndConfig struct {
window Callbacks window *callbacks
opts *Options cnf *config
} }
func newWindowRendezvous() *windowRendezvous { func newWindowRendezvous() *windowRendezvous {
wr := &windowRendezvous{ wr := &windowRendezvous{
in: make(chan windowAndOptions), in: make(chan windowAndConfig),
out: make(chan windowAndOptions), out: make(chan windowAndConfig),
errs: make(chan error), errs: make(chan error),
} }
go func() { go func() {
var main windowAndOptions var main windowAndConfig
var out chan windowAndOptions var out chan windowAndConfig
for { for {
select { select {
case w := <-wr.in: case w := <-wr.in:
@@ -145,4 +139,4 @@ func newWindowRendezvous() *windowRendezvous {
return wr return wr
} }
func (_ WakeupEvent) ImplementsEvent() {} func (_ wakeupEvent) ImplementsEvent() {}
@@ -1,6 +1,6 @@
// SPDX-License-Identifier: Unlicense OR MIT // SPDX-License-Identifier: Unlicense OR MIT
package wm package app
/* /*
#cgo CFLAGS: -Werror #cgo CFLAGS: -Werror
@@ -111,6 +111,8 @@ import (
"fmt" "fmt"
"image" "image"
"image/color" "image/color"
"os"
"path/filepath"
"reflect" "reflect"
"runtime" "runtime"
"runtime/debug" "runtime/debug"
@@ -130,7 +132,7 @@ import (
) )
type window struct { type window struct {
callbacks Callbacks callbacks *callbacks
view C.jobject view C.jobject
@@ -195,13 +197,38 @@ var android struct {
// view maps from GioView JNI refenreces to windows. // view maps from GioView JNI refenreces to windows.
var views = make(map[C.jlong]*window) 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 mainWindow = newWindowRendezvous()
var mainFuncs = make(chan func(env *C.JNIEnv), 1) 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 { func getMethodID(env *C.JNIEnv, class C.jclass, method, sig string) C.jmethodID {
m := C.CString(method) m := C.CString(method)
defer C.free(unsafe.Pointer(m)) 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") android.mwakeupMainThread = getStaticMethodID(env, gio, "wakeupMainThread", "()V")
} }
// JavaVM returns the global JNI JavaVM.
func JavaVM() uintptr { func JavaVM() uintptr {
jvm := javaVM() jvm := javaVM()
return uintptr(unsafe.Pointer(jvm)) return uintptr(unsafe.Pointer(jvm))
@@ -265,16 +293,13 @@ func javaVM() *C.JavaVM {
return android.jvm return android.jvm
} }
// AppContext returns the global Application context as a JNI jobject.
func AppContext() uintptr { func AppContext() uintptr {
android.mu.Lock() android.mu.Lock()
defer android.mu.Unlock() defer android.mu.Unlock()
return uintptr(android.appCtx) return uintptr(android.appCtx)
} }
func GetDataDir() string {
return <-dataDirChan
}
//export Java_org_gioui_GioView_onCreateView //export Java_org_gioui_GioView_onCreateView
func Java_org_gioui_GioView_onCreateView(env *C.JNIEnv, class C.jclass, view C.jobject) C.jlong { func Java_org_gioui_GioView_onCreateView(env *C.JNIEnv, class C.jclass, view C.jobject) C.jlong {
gioView.once.Do(func() { 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) handle := C.jlong(view)
views[handle] = w views[handle] = w
w.loadConfig(env, class) w.loadConfig(env, class)
w.Option(wopts.opts) w.Configure(wopts.cnf)
w.setStage(system.StagePaused) w.setStage(system.StagePaused)
w.callbacks.Event(ViewEvent{View: uintptr(view)}) w.callbacks.Event(ViewEvent{View: uintptr(view)})
return handle return handle
@@ -476,7 +501,7 @@ func (w *window) draw(sync bool) {
} }
const inchPrDp = 1.0 / 160 const inchPrDp = 1.0 / 160
ppdp := float32(w.dpi) * inchPrDp ppdp := float32(w.dpi) * inchPrDp
w.callbacks.Event(FrameEvent{ w.callbacks.Event(frameEvent{
FrameEvent: system.FrameEvent{ FrameEvent: system.FrameEvent{
Now: time.Now(), Now: time.Now(),
Size: image.Point{ Size: image.Point{
@@ -723,11 +748,11 @@ func goString(env *C.JNIEnv, str C.jstring) string {
return string(utf8) return string(utf8)
} }
func Main() { func osMain() {
} }
func NewWindow(window Callbacks, opts *Options) error { func newWindow(window *callbacks, cnf *config) error {
mainWindow.in <- windowAndOptions{window, opts} mainWindow.in <- windowAndConfig{window, cnf}
return <-mainWindow.errs 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) { runInJVM(javaVM(), func(env *C.JNIEnv) {
if o := opts.Orientation; o != nil { if o := cnf.Orientation; o != nil {
setOrientation(env, w.view, *o) setOrientation(env, w.view, *o)
} }
if o := opts.NavigationColor; o != nil { if o := cnf.NavigationColor; o != nil {
setNavigationColor(env, w.view, *o) setNavigationColor(env, w.view, *o)
} }
if o := opts.StatusColor; o != nil { if o := cnf.StatusColor; o != nil {
setStatusColor(env, w.view, *o) setStatusColor(env, w.view, *o)
} }
if o := opts.WindowMode; o != nil { if o := cnf.WindowMode; o != nil {
setWindowMode(env, w.view, *o) setWindowMode(env, w.view, *o)
} }
}) })
@@ -776,7 +801,7 @@ func (w *window) SetCursor(name pointer.CursorName) {
func (w *window) Wakeup() { func (w *window) Wakeup() {
runOnMain(func(env *C.JNIEnv) { 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)) 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 ( var (
id int id int
idFallback int // Used only for SDK 17 or older. idFallback int // Used only for SDK 17 or older.
) )
// Constants defined at https://developer.android.com/reference/android/content/pm/ActivityInfo. // Constants defined at https://developer.android.com/reference/android/content/pm/ActivityInfo.
switch mode { switch mode {
case AnyOrientation: case anyOrientation:
id, idFallback = 2, 2 // SCREEN_ORIENTATION_USER id, idFallback = 2, 2 // SCREEN_ORIENTATION_USER
case LandscapeOrientation: case landscapeOrientation:
id, idFallback = 11, 0 // SCREEN_ORIENTATION_USER_LANDSCAPE (or SCREEN_ORIENTATION_LANDSCAPE) 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) id, idFallback = 12, 1 // SCREEN_ORIENTATION_USER_PORTRAIT (or SCREEN_ORIENTATION_PORTRAIT)
} }
callVoidMethod(env, view, gioView.setOrientation, jvalue(id), jvalue(idFallback)) 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 { switch mode {
case Fullscreen: case fullscreen:
callVoidMethod(env, view, gioView.setFullscreen, C.JNI_TRUE) callVoidMethod(env, view, gioView.setFullscreen, C.JNI_TRUE)
default: default:
callVoidMethod(env, view, gioView.setFullscreen, C.JNI_FALSE) callVoidMethod(env, view, gioView.setFullscreen, C.JNI_FALSE)
@@ -1,6 +1,6 @@
// SPDX-License-Identifier: Unlicense OR MIT // SPDX-License-Identifier: Unlicense OR MIT
package wm package app
/* /*
#include <Foundation/Foundation.h> #include <Foundation/Foundation.h>
@@ -232,6 +232,6 @@ func windowSetCursor(from, to pointer.CursorName) pointer.CursorName {
func (w *window) Wakeup() { func (w *window) Wakeup() {
runOnMain(func() { runOnMain(func() {
w.w.Event(WakeupEvent{}) w.w.Event(wakeupEvent{})
}) })
} }
+7 -7
View File
@@ -3,7 +3,7 @@
//go:build darwin && ios //go:build darwin && ios
// +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 #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 { type window struct {
view C.CFTypeRef view C.CFTypeRef
w Callbacks w *callbacks
displayLink *displayLink displayLink *displayLink
visible bool visible bool
@@ -144,7 +144,7 @@ func (w *window) draw(sync bool) {
w.w.Event(system.StageEvent{Stage: system.StageRunning}) w.w.Event(system.StageEvent{Stage: system.StageRunning})
} }
const inchPrDp = 1.0 / 163 const inchPrDp = 1.0 / 163
w.w.Event(FrameEvent{ w.w.Event(frameEvent{
FrameEvent: system.FrameEvent{ FrameEvent: system.FrameEvent{
Now: time.Now(), Now: time.Now(),
Size: image.Point{ Size: image.Point{
@@ -268,7 +268,7 @@ func (w *window) WriteClipboard(s string) {
C.writeClipboard(chars, C.NSUInteger(len(u16))) 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) { func (w *window) SetAnimating(anim bool) {
v := w.view v := w.view
@@ -329,12 +329,12 @@ func (w *window) SetInputHint(_ key.InputHint) {}
// Close the window. Not implemented for iOS. // Close the window. Not implemented for iOS.
func (w *window) Close() {} func (w *window) Close() {}
func NewWindow(win Callbacks, opts *Options) error { func newWindow(win *callbacks, cnf *config) error {
mainWindow.in <- windowAndOptions{win, opts} mainWindow.in <- windowAndConfig{win, cnf}
return <-mainWindow.errs return <-mainWindow.errs
} }
func Main() { func osMain() {
} }
//export gio_runMain //export gio_runMain
+19 -19
View File
@@ -1,6 +1,6 @@
// SPDX-License-Identifier: Unlicense OR MIT // SPDX-License-Identifier: Unlicense OR MIT
package wm package app
import ( import (
"fmt" "fmt"
@@ -31,7 +31,7 @@ type window struct {
clipboard js.Value clipboard js.Value
cnv js.Value cnv js.Value
tarea js.Value tarea js.Value
w Callbacks w *callbacks
redraw js.Func redraw js.Func
clipboardCallback js.Func clipboardCallback js.Func
requestAnimationFrame js.Value requestAnimationFrame js.Value
@@ -56,7 +56,7 @@ type window struct {
wakeups chan struct{} wakeups chan struct{}
} }
func NewWindow(win Callbacks, opts *Options) error { func newWindow(win *callbacks, cnf *config) error {
doc := js.Global().Get("document") doc := js.Global().Get("document")
cont := getContainer(doc) cont := getContainer(doc)
cnv := createCanvas(doc) cnv := createCanvas(doc)
@@ -94,7 +94,7 @@ func NewWindow(win Callbacks, opts *Options) error {
}) })
w.addEventListeners() w.addEventListeners()
w.addHistory() w.addHistory()
w.Option(opts) w.Configure(cnf)
w.w = win w.w = win
go func() { go func() {
@@ -107,7 +107,7 @@ func NewWindow(win Callbacks, opts *Options) error {
for { for {
select { select {
case <-w.wakeups: case <-w.wakeups:
w.w.Event(WakeupEvent{}) w.w.Event(wakeupEvent{})
case <-w.chanAnimation: case <-w.chanAnimation:
w.animCallback() w.animCallback()
case <-w.chanRedraw: case <-w.chanRedraw:
@@ -509,17 +509,17 @@ func (w *window) WriteClipboard(s string) {
w.clipboard.Call("writeText", s) w.clipboard.Call("writeText", s)
} }
func (w *window) Option(opts *Options) { func (w *window) Configure(cnf *config) {
if o := opts.Title; o != nil { if o := cnf.Title; o != nil {
w.document.Set("title", *o) w.document.Set("title", *o)
} }
if o := opts.WindowMode; o != nil { if o := cnf.WindowMode; o != nil {
w.windowMode(*o) w.windowMode(*o)
} }
if o := opts.NavigationColor; o != nil { if o := cnf.NavigationColor; o != nil {
w.navigationColor(*o) w.navigationColor(*o)
} }
if o := opts.Orientation; o != nil { if o := cnf.Orientation; o != nil {
w.orientation(*o) w.orientation(*o)
} }
} }
@@ -581,7 +581,7 @@ func (w *window) draw(sync bool) {
return return
} }
w.w.Event(FrameEvent{ w.w.Event(frameEvent{
FrameEvent: system.FrameEvent{ FrameEvent: system.FrameEvent{
Now: time.Now(), Now: time.Now(),
Size: image.Point{ 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 { switch mode {
case Windowed: case windowed:
if !w.document.Get("fullscreenElement").Truthy() { if !w.document.Get("fullscreenElement").Truthy() {
return // Browser is already Windowed. return // Browser is already Windowed.
} }
@@ -615,7 +615,7 @@ func (w *window) windowMode(mode WindowMode) {
return // Browser doesn't support such feature. return // Browser doesn't support such feature.
} }
w.document.Call("exitFullscreen") w.document.Call("exitFullscreen")
case Fullscreen: case fullscreen:
elem := w.document.Get("documentElement") elem := w.document.Get("documentElement")
if !elem.Get("requestFullscreen").Truthy() { if !elem.Get("requestFullscreen").Truthy() {
return // Browser doesn't support such feature. 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() { if j := w.screenOrientation; !j.Truthy() || !j.Get("unlock").Truthy() || !j.Get("lock").Truthy() {
return // Browser don't support Screen Orientation API. return // Browser don't support Screen Orientation API.
} }
switch mode { switch mode {
case AnyOrientation: case anyOrientation:
w.screenOrientation.Call("unlock") w.screenOrientation.Call("unlock")
case LandscapeOrientation: case landscapeOrientation:
w.screenOrientation.Call("lock", "landscape").Call("then", w.redraw) w.screenOrientation.Call("lock", "landscape").Call("then", w.redraw)
case PortraitOrientation: case portraitOrientation:
w.screenOrientation.Call("lock", "portrait").Call("then", w.redraw) 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})) theme.Set("content", fmt.Sprintf("#%06X", []uint8{rgba.R, rgba.G, rgba.B}))
} }
func Main() { func osMain() {
select {} select {}
} }
+17 -17
View File
@@ -3,7 +3,7 @@
//go:build darwin && !ios //go:build darwin && !ios
// +build darwin,!ios // +build darwin,!ios
package wm package app
import ( import (
"errors" "errors"
@@ -147,13 +147,13 @@ type ViewEvent struct {
type window struct { type window struct {
view C.CFTypeRef view C.CFTypeRef
window C.CFTypeRef window C.CFTypeRef
w Callbacks w *callbacks
stage system.Stage stage system.Stage
displayLink *displayLink displayLink *displayLink
cursor pointer.CursorName cursor pointer.CursorName
scale float32 scale float32
mode WindowMode mode windowMode
} }
// viewMap is the mapping from Cocoa NSViews to Go windows. // 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))) C.writeClipboard(chars, C.NSUInteger(len(u16)))
} }
func (w *window) Option(opts *Options) { func (w *window) Configure(cnf *config) {
screenScale := float32(C.getScreenBackingScale()) screenScale := float32(C.getScreenBackingScale())
cfg := configFor(screenScale) cfg := configFor(screenScale)
val := func(v unit.Value) float32 { val := func(v unit.Value) float32 {
return float32(cfg.Px(v)) / screenScale return float32(cfg.Px(v)) / screenScale
} }
if o := opts.Size; o != nil { if o := cnf.Size; o != nil {
width := val(o.Width) width := val(o.Width)
height := val(o.Height) height := val(o.Height)
if width > 0 || height > 0 { if width > 0 || height > 0 {
C.setSize(w.window, C.CGFloat(width), C.CGFloat(height)) 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) width := val(o.Width)
height := val(o.Height) height := val(o.Height)
if width > 0 || height > 0 { if width > 0 || height > 0 {
C.setMinSize(w.window, C.CGFloat(width), C.CGFloat(height)) 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) width := val(o.Width)
height := val(o.Height) height := val(o.Height)
if width > 0 || height > 0 { if width > 0 || height > 0 {
C.setMaxSize(w.window, C.CGFloat(width), C.CGFloat(height)) 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) title := C.CString(*o)
defer C.free(unsafe.Pointer(title)) defer C.free(unsafe.Pointer(title))
C.setTitle(w.window, title) C.setTitle(w.window, title)
} }
if o := opts.WindowMode; o != nil { if o := cnf.WindowMode; o != nil {
w.SetWindowMode(*o) w.SetWindowMode(*o)
} }
} }
func (w *window) SetWindowMode(mode WindowMode) { func (w *window) SetWindowMode(mode windowMode) {
switch mode { switch mode {
case w.mode: case w.mode:
case Windowed, Fullscreen: case windowed, fullscreen:
C.toggleFullScreen(w.window) C.toggleFullScreen(w.window)
w.mode = mode w.mode = mode
} }
@@ -396,7 +396,7 @@ func (w *window) draw() {
height := int(hf*w.scale + .5) height := int(hf*w.scale + .5)
cfg := configFor(w.scale) cfg := configFor(w.scale)
w.setStage(system.StageRunning) w.setStage(system.StageRunning)
w.w.Event(FrameEvent{ w.w.Event(frameEvent{
FrameEvent: system.FrameEvent{ FrameEvent: system.FrameEvent{
Now: time.Now(), Now: time.Now(),
Size: image.Point{ Size: image.Point{
@@ -461,11 +461,11 @@ func gio_onFinishLaunching() {
close(launched) close(launched)
} }
func NewWindow(win Callbacks, opts *Options) error { func newWindow(win *callbacks, cnf *config) error {
<-launched <-launched
errch := make(chan error) errch := make(chan error)
runOnMain(func() { runOnMain(func() {
w, err := newWindow(opts) w, err := newOSWindow()
if err != nil { if err != nil {
errch <- err errch <- err
return return
@@ -474,7 +474,7 @@ func NewWindow(win Callbacks, opts *Options) error {
w.w = win w.w = win
w.window = C.gio_createWindow(w.view, nil, 0, 0, 0, 0, 0, 0) w.window = C.gio_createWindow(w.view, nil, 0, 0, 0, 0, 0, 0)
win.SetDriver(w) win.SetDriver(w)
w.Option(opts) w.Configure(cnf)
if nextTopLeft.x == 0 && nextTopLeft.y == 0 { if nextTopLeft.x == 0 && nextTopLeft.y == 0 {
// cascadeTopLeftFromPoint treats (0, 0) as a no-op, // cascadeTopLeftFromPoint treats (0, 0) as a no-op,
// and just returns the offset we need for the first window. // and just returns the offset we need for the first window.
@@ -488,7 +488,7 @@ func NewWindow(win Callbacks, opts *Options) error {
return <-errch return <-errch
} }
func newWindow(opts *Options) (*window, error) { func newOSWindow() (*window, error) {
view := C.gio_createView() view := C.gio_createView()
if view == 0 { if view == 0 {
return nil, errors.New("CreateWindow: failed to create view") return nil, errors.New("CreateWindow: failed to create view")
@@ -512,7 +512,7 @@ func newWindow(opts *Options) (*window, error) {
return w, nil return w, nil
} }
func Main() { func osMain() {
C.gio_main() C.gio_main()
} }
@@ -3,7 +3,7 @@
//go:build (linux && !android) || freebsd || openbsd //go:build (linux && !android) || freebsd || openbsd
// +build linux,!android freebsd openbsd // +build linux,!android freebsd openbsd
package wm package app
import ( import (
"errors" "errors"
@@ -17,23 +17,23 @@ type ViewEvent struct {
Window uintptr Window uintptr
} }
func Main() { func osMain() {
select {} 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 // 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. // let each driver initialize these variables with their own version of createWindow.
var wlDriver, x11Driver windowDriver var wlDriver, x11Driver windowDriver
func NewWindow(window Callbacks, opts *Options) error { func newWindow(window *callbacks, cnf *config) error {
var errFirst error var errFirst error
for _, d := range []windowDriver{x11Driver, wlDriver} { for _, d := range []windowDriver{x11Driver, wlDriver} {
if d == nil { if d == nil {
continue continue
} }
err := d(window, opts) err := d(window, cnf)
if err == nil { if err == nil {
return nil return nil
} }
@@ -3,7 +3,7 @@
//go:build (linux && !android && !nowayland) || freebsd //go:build (linux && !android && !nowayland) || freebsd
// +build linux,!android,!nowayland freebsd // +build linux,!android,!nowayland freebsd
package wm package app
import ( import (
"bytes" "bytes"
@@ -136,7 +136,7 @@ type repeatState struct {
delay time.Duration delay time.Duration
key uint32 key uint32
win Callbacks win *callbacks
stopC chan struct{} stopC chan struct{}
start time.Duration start time.Duration
@@ -146,7 +146,7 @@ type repeatState struct {
} }
type window struct { type window struct {
w Callbacks w *callbacks
disp *wlDisplay disp *wlDisplay
surf *C.struct_wl_surface surf *C.struct_wl_surface
wmSurf *C.struct_xdg_surface wmSurf *C.struct_xdg_surface
@@ -222,12 +222,12 @@ func init() {
wlDriver = newWLWindow wlDriver = newWLWindow
} }
func newWLWindow(window Callbacks, opts *Options) error { func newWLWindow(window *callbacks, cnf *config) error {
d, err := newWLDisplay() d, err := newWLDisplay()
if err != nil { if err != nil {
return err return err
} }
w, err := d.createNativeWindow(opts) w, err := d.createNativeWindow(cnf)
if err != nil { if err != nil {
d.destroy() d.destroy()
return err return err
@@ -289,7 +289,7 @@ func (d *wlDisplay) readClipboard() (io.ReadCloser, error) {
return r, nil return r, nil
} }
func (d *wlDisplay) createNativeWindow(opts *Options) (*window, error) { func (d *wlDisplay) createNativeWindow(cnf *config) (*window, error) {
if d.compositor == nil { if d.compositor == nil {
return nil, errors.New("wayland: no compositor available") 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_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)) 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 { if d.decor != nil {
// Request server side decorations. // Request server side decorations.
@@ -907,17 +907,13 @@ func (w *window) WriteClipboard(s string) {
w.disp.writeClipboard([]byte(s)) w.disp.writeClipboard([]byte(s))
} }
func (w *window) Option(opts *Options) { func (w *window) Configure(cnf *config) {
w.setOptions(opts)
}
func (w *window) setOptions(opts *Options) {
_, _, cfg := w.config() _, _, cfg := w.config()
if o := opts.Size; o != nil { if o := cnf.Size; o != nil {
w.width = cfg.Px(o.Width) w.width = cfg.Px(o.Width)
w.height = cfg.Px(o.Height) w.height = cfg.Px(o.Height)
} }
if o := opts.Title; o != nil { if o := cnf.Title; o != nil {
title := C.CString(*o) title := C.CString(*o)
C.xdg_toplevel_set_title(w.topLvl, title) C.xdg_toplevel_set_title(w.topLvl, title)
C.free(unsafe.Pointer(title)) C.free(unsafe.Pointer(title))
@@ -1134,7 +1130,7 @@ func (w *window) loop() error {
} }
select { select {
case <-w.wakeups: case <-w.wakeups:
w.w.Event(WakeupEvent{}) w.w.Event(wakeupEvent{})
default: default:
} }
if w.dead { if w.dead {
@@ -1423,7 +1419,7 @@ func (w *window) draw(sync bool) {
// Use the surface as listener data for gio_onFrameDone. // Use the surface as listener data for gio_onFrameDone.
C.wl_callback_add_listener(w.lastFrameCallback, &C.gio_callback_listener, unsafe.Pointer(w.surf)) 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{ FrameEvent: system.FrameEvent{
Now: time.Now(), Now: time.Now(),
Size: image.Point{ Size: image.Point{
@@ -1,6 +1,6 @@
// SPDX-License-Identifier: Unlicense OR MIT // SPDX-License-Identifier: Unlicense OR MIT
package wm package app
import ( import (
"errors" "errors"
@@ -45,7 +45,7 @@ type winDeltas struct {
type window struct { type window struct {
hwnd syscall.Handle hwnd syscall.Handle
hdc syscall.Handle hdc syscall.Handle
w Callbacks w *callbacks
width int width int
height int height int
stage system.Stage stage system.Stage
@@ -63,14 +63,14 @@ type window struct {
minmax winConstraints minmax winConstraints
deltas winDeltas deltas winDeltas
opts *Options cnf *config
} }
const _WM_WAKEUP = windows.WM_USER + iota const _WM_WAKEUP = windows.WM_USER + iota
type gpuAPI struct { type gpuAPI struct {
priority int priority int
initializer func(w *window) (Context, error) initializer func(w *window) (context, error)
} }
// drivers is the list of potential Context implementations. // drivers is the list of potential Context implementations.
@@ -92,11 +92,11 @@ var resources struct {
cursor syscall.Handle cursor syscall.Handle
} }
func Main() { func osMain() {
select {} select {}
} }
func NewWindow(window Callbacks, opts *Options) error { func newWindow(window *callbacks, cnf *config) error {
cerr := make(chan error) cerr := make(chan error)
go func() { go func() {
// GetMessage and PeekMessage can filter on a window HWND, but // 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 // Instead lock the thread so window messages arrive through
// unfiltered GetMessage calls. // unfiltered GetMessage calls.
runtime.LockOSThread() runtime.LockOSThread()
w, err := createNativeWindow(opts) w, err := createNativeWindow(cnf)
if err != nil { if err != nil {
cerr <- err cerr <- err
return return
@@ -115,7 +115,7 @@ func NewWindow(window Callbacks, opts *Options) error {
w.w = window w.w = window
w.w.SetDriver(w) w.w.SetDriver(w)
w.w.Event(ViewEvent{HWND: uintptr(w.hwnd)}) w.w.Event(ViewEvent{HWND: uintptr(w.hwnd)})
w.Option(opts) w.Configure(cnf)
windows.ShowWindow(w.hwnd, windows.SW_SHOWDEFAULT) windows.ShowWindow(w.hwnd, windows.SW_SHOWDEFAULT)
windows.SetForegroundWindow(w.hwnd) windows.SetForegroundWindow(w.hwnd)
windows.SetFocus(w.hwnd) windows.SetFocus(w.hwnd)
@@ -159,20 +159,20 @@ func initResources() error {
return nil return nil
} }
func getWindowConstraints(cfg unit.Metric, opts *Options) winConstraints { func getWindowConstraints(cfg unit.Metric, cnf *config) winConstraints {
var minmax winConstraints var minmax winConstraints
if o := opts.MinSize; o != nil { if o := cnf.MinSize; o != nil {
minmax.minWidth = int32(cfg.Px(o.Width)) minmax.minWidth = int32(cfg.Px(o.Width))
minmax.minHeight = int32(cfg.Px(o.Height)) 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.maxWidth = int32(cfg.Px(o.Width))
minmax.maxHeight = int32(cfg.Px(o.Height)) minmax.maxHeight = int32(cfg.Px(o.Height))
} }
return minmax return minmax
} }
func createNativeWindow(opts *Options) (*window, error) { func createNativeWindow(cnf *config) (*window, error) {
var resErr error var resErr error
resources.once.Do(func() { resources.once.Do(func() {
resErr = initResources() resErr = initResources()
@@ -200,8 +200,8 @@ func createNativeWindow(opts *Options) (*window, error) {
} }
w := &window{ w := &window{
hwnd: hwnd, hwnd: hwnd,
minmax: getWindowConstraints(cfg, opts), minmax: getWindowConstraints(cfg, cnf),
opts: opts, cnf: cnf,
} }
w.hdc, err = windows.GetDC(hwnd) w.hdc, err = windows.GetDC(hwnd)
if err != nil { if err != nil {
@@ -330,7 +330,7 @@ func windowProc(hwnd syscall.Handle, msg uint32, wParam, lParam uintptr) uintptr
return windows.TRUE return windows.TRUE
} }
case _WM_WAKEUP: case _WM_WAKEUP:
w.w.Event(WakeupEvent{}) w.w.Event(wakeupEvent{})
} }
return windows.DefWindowProc(hwnd, msg, wParam, lParam) return windows.DefWindowProc(hwnd, msg, wParam, lParam)
@@ -458,8 +458,8 @@ func (w *window) draw(sync bool) {
} }
dpi := windows.GetWindowDPI(w.hwnd) dpi := windows.GetWindowDPI(w.hwnd)
cfg := configForDPI(dpi) cfg := configForDPI(dpi)
w.minmax = getWindowConstraints(cfg, w.opts) w.minmax = getWindowConstraints(cfg, w.cnf)
w.w.Event(FrameEvent{ w.w.Event(frameEvent{
FrameEvent: system.FrameEvent{ FrameEvent: system.FrameEvent{
Now: time.Now(), Now: time.Now(),
Size: image.Point{ 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 { sort.Slice(drivers, func(i, j int) bool {
return drivers[i].priority < drivers[j].priority return drivers[i].priority < drivers[j].priority
}) })
@@ -515,9 +515,9 @@ func (w *window) readClipboard() error {
return nil return nil
} }
func (w *window) Option(opts *Options) { func (w *window) Configure(cnf *config) {
w.opts = opts w.cnf = cnf
if o := opts.Size; o != nil { if o := cnf.Size; o != nil {
dpi := windows.GetSystemDPI() dpi := windows.GetSystemDPI()
cfg := configForDPI(dpi) cfg := configForDPI(dpi)
width := int32(cfg.Px(o.Width)) width := int32(cfg.Px(o.Width))
@@ -538,27 +538,27 @@ func (w *window) Option(opts *Options) {
w.deltas.width = width - dw w.deltas.width = width - dw
w.deltas.height = height - dh w.deltas.height = height - dh
w.opts.Size = o w.cnf.Size = o
windows.MoveWindow(w.hwnd, 0, 0, width, height, true) windows.MoveWindow(w.hwnd, 0, 0, width, height, true)
} }
if o := opts.MinSize; o != nil { if o := cnf.MinSize; o != nil {
w.opts.MinSize = o w.cnf.MinSize = o
} }
if o := opts.MaxSize; o != nil { if o := cnf.MaxSize; o != nil {
w.opts.MaxSize = o w.cnf.MaxSize = o
} }
if o := opts.Title; o != nil { if o := cnf.Title; o != nil {
windows.SetWindowText(w.hwnd, *opts.Title) windows.SetWindowText(w.hwnd, *cnf.Title)
} }
if o := opts.WindowMode; o != nil { if o := cnf.WindowMode; o != nil {
w.SetWindowMode(*o) w.SetWindowMode(*o)
} }
} }
func (w *window) SetWindowMode(mode WindowMode) { func (w *window) SetWindowMode(mode windowMode) {
// https://devblogs.microsoft.com/oldnewthing/20100412-00/?p=14353 // https://devblogs.microsoft.com/oldnewthing/20100412-00/?p=14353
switch mode { switch mode {
case Windowed: case windowed:
if w.placement == nil { if w.placement == nil {
return return
} }
@@ -570,7 +570,7 @@ func (w *window) SetWindowMode(mode WindowMode) {
0, 0, 0, 0, 0, 0, 0, 0,
windows.SWP_NOOWNERZORDER|windows.SWP_FRAMECHANGED, windows.SWP_NOOWNERZORDER|windows.SWP_FRAMECHANGED,
) )
case Fullscreen: case fullscreen:
if w.placement != nil { if w.placement != nil {
return return
} }
+17 -17
View File
@@ -3,7 +3,7 @@
//go:build (linux && !android && !nox11) || freebsd || openbsd //go:build (linux && !android && !nox11) || freebsd || openbsd
// +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 #cgo openbsd CFLAGS: -I/usr/X11R6/include -I/usr/local/include
@@ -49,7 +49,7 @@ import (
) )
type x11Window struct { type x11Window struct {
w Callbacks w *callbacks
x *C.Display x *C.Display
xkb *xkb.Context xkb *xkb.Context
xkbEventBase C.int xkbEventBase C.int
@@ -96,7 +96,7 @@ type x11Window struct {
content []byte content []byte
} }
cursor pointer.CursorName cursor pointer.CursorName
mode WindowMode mode windowMode
wakeups chan struct{} wakeups chan struct{}
} }
@@ -115,14 +115,14 @@ func (w *x11Window) WriteClipboard(s string) {
C.XSetSelectionOwner(w.x, w.atoms.clipboard, w.xw, C.CurrentTime) 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 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_width = C.int(w.cfg.Px(o.Width))
shints.min_height = C.int(w.cfg.Px(o.Height)) shints.min_height = C.int(w.cfg.Px(o.Height))
shints.flags = C.PMinSize 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_width = C.int(w.cfg.Px(o.Width))
shints.max_height = C.int(w.cfg.Px(o.Height)) shints.max_height = C.int(w.cfg.Px(o.Height))
shints.flags = shints.flags | C.PMaxSize shints.flags = shints.flags | C.PMaxSize
@@ -131,12 +131,12 @@ func (w *x11Window) Option(opts *Options) {
C.XSetWMNormalHints(w.x, w.xw, &shints) 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))) C.XResizeWindow(w.x, w.xw, C.uint(w.cfg.Px(o.Width)), C.uint(w.cfg.Px(o.Height)))
} }
var title string var title string
if o := opts.Title; o != nil { if o := cnf.Title; o != nil {
title = *o title = *o
} }
ctitle := C.CString(title) ctitle := C.CString(title)
@@ -152,7 +152,7 @@ func (w *x11Window) Option(opts *Options) {
}, },
w.atoms.wmName) w.atoms.wmName)
if o := opts.WindowMode; o != nil { if o := cnf.WindowMode; o != nil {
w.SetWindowMode(*o) w.SetWindowMode(*o)
} }
} }
@@ -181,13 +181,13 @@ func (w *x11Window) SetCursor(name pointer.CursorName) {
C.XDefineCursor(w.x, w.xw, c) C.XDefineCursor(w.x, w.xw, c)
} }
func (w *x11Window) SetWindowMode(mode WindowMode) { func (w *x11Window) SetWindowMode(mode windowMode) {
switch mode { switch mode {
case w.mode: case w.mode:
return return
case Windowed: case windowed:
C.XDeleteProperty(w.x, w.xw, w.atoms.wmStateFullscreen) 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, C.XChangeProperty(w.x, w.xw, w.atoms.wmState, C.XA_ATOM,
32, C.PropModeReplace, 32, C.PropModeReplace,
(*C.uchar)(unsafe.Pointer(&w.atoms.wmStateFullscreen)), 1, (*C.uchar)(unsafe.Pointer(&w.atoms.wmStateFullscreen)), 1,
@@ -322,12 +322,12 @@ loop:
} }
select { select {
case <-w.wakeups: case <-w.wakeups:
w.w.Event(WakeupEvent{}) w.w.Event(wakeupEvent{})
default: default:
} }
if (anim || syn) && w.width != 0 && w.height != 0 { if (anim || syn) && w.width != 0 && w.height != 0 {
w.w.Event(FrameEvent{ w.w.Event(frameEvent{
FrameEvent: system.FrameEvent{ FrameEvent: system.FrameEvent{
Now: time.Now(), Now: time.Now(),
Size: image.Point{ Size: image.Point{
@@ -582,7 +582,7 @@ func init() {
x11Driver = newX11Window x11Driver = newX11Window
} }
func newX11Window(gioWin Callbacks, opts *Options) error { func newX11Window(gioWin *callbacks, cnf *config) error {
var err error var err error
pipe := make([]int, 2) pipe := make([]int, 2)
@@ -632,7 +632,7 @@ func newX11Window(gioWin Callbacks, opts *Options) error {
override_redirect: C.False, override_redirect: C.False,
} }
var width, height int var width, height int
if o := opts.Size; o != nil { if o := cnf.Size; o != nil {
width = cfg.Px(o.Width) width = cfg.Px(o.Width)
height = cfg.Px(o.Height) height = cfg.Px(o.Height)
} }
@@ -683,7 +683,7 @@ func newX11Window(gioWin Callbacks, opts *Options) error {
// extensions // extensions
C.XSetWMProtocols(dpy, win, &w.atoms.evDelWindow, 1) C.XSetWMProtocols(dpy, win, &w.atoms.evDelWindow, 1)
w.Option(opts) w.Configure(cnf)
// make the window visible on the screen // make the window visible on the screen
C.XMapWindow(dpy, win) C.XMapWindow(dpy, win)
@@ -3,7 +3,7 @@
//go:build android || (darwin && ios) //go:build android || (darwin && ios)
// +build android darwin,ios // +build android darwin,ios
package wm package app
// Android only supports non-Java programs as c-shared libraries. // Android only supports non-Java programs as c-shared libraries.
// Unfortunately, Go does not run a program's main function in // Unfortunately, Go does not run a program's main function in
-19
View File
@@ -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)
}
+70 -72
View File
@@ -18,22 +18,21 @@ import (
"gioui.org/unit" "gioui.org/unit"
_ "gioui.org/app/internal/log" _ "gioui.org/app/internal/log"
"gioui.org/app/internal/wm"
) )
// Option configures a window. // Option configures a window.
type Option func(opts *wm.Options) type Option func(cnf *config)
// Window represents an operating system window. // Window represents an operating system window.
type Window struct { type Window struct {
ctx wm.Context ctx context
loop *renderLoop loop *renderLoop
// driverFuncs is a channel of functions to run when // driverFuncs is a channel of functions to run when
// the Window has a valid driver. // 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 // wakeups wakes up the native event loop to send a
// wm.WakeupEvent that flushes driverFuncs. // WakeupEvent that flushes driverFuncs.
wakeups chan struct{} wakeups chan struct{}
out chan event.Event out chan event.Event
@@ -62,7 +61,7 @@ type Window struct {
type callbacks struct { type callbacks struct {
w *Window w *Window
d wm.Driver d driver
} }
// queue is an event.Queue implementation that distributes system events // 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. // driverEvent is sent when the underlying driver changes.
type driverEvent struct { type driverEvent struct {
driver wm.Driver driver driver
} }
// Pre-allocate the ack event to avoid garbage. // 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 // Calling NewWindow more than once is not supported on
// iOS, Android, WebAssembly. // iOS, Android, WebAssembly.
func NewWindow(options ...Option) *Window { func NewWindow(options ...Option) *Window {
opts := new(wm.Options) cnf := new(config)
// Default options. // Default options.
Size(unit.Dp(800), unit.Dp(600))(opts) Size(unit.Dp(800), unit.Dp(600))(cnf)
Title("Gio")(opts) Title("Gio")(cnf)
for _, o := range options { for _, o := range options {
o(opts) o(cnf)
} }
w := &Window{ w := &Window{
@@ -106,14 +105,14 @@ func NewWindow(options ...Option) *Window {
invalidates: make(chan struct{}, 1), invalidates: make(chan struct{}, 1),
frames: make(chan *op.Ops), frames: make(chan *op.Ops),
frameAck: make(chan struct{}), frameAck: make(chan struct{}),
driverFuncs: make(chan func(d wm.Driver), 1), driverFuncs: make(chan func(d driver), 1),
wakeups: make(chan struct{}, 1), wakeups: make(chan struct{}, 1),
dead: make(chan struct{}), dead: make(chan struct{}),
notifyAnimate: make(chan struct{}, 1), notifyAnimate: make(chan struct{}, 1),
nocontext: opts.CustomRenderer, nocontext: cnf.CustomRenderer,
} }
w.callbacks.w = w w.callbacks.w = w
go w.run(opts) go w.run(cnf)
return w return w
} }
@@ -122,21 +121,20 @@ func (w *Window) Events() <-chan event.Event {
return w.out return w.out
} }
// update updates the wm. Paint operations updates the // update updates the window contents, input operations declare input handlers,
// window contents, input operations declare input handlers, // and so on. The supplied operations list completely replaces the window state
// and so on. The supplied operations list completely replaces // from previous calls.
// the window state from previous calls.
func (w *Window) update(frame *op.Ops) { func (w *Window) update(frame *op.Ops) {
w.frames <- frame w.frames <- frame
<-w.frameAck <-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 { for {
if w.loop != nil { if w.loop != nil {
if err := w.loop.Flush(); err != nil { if err := w.loop.Flush(); err != nil {
w.destroyGPU() w.destroyGPU()
if err == wm.ErrDeviceLost { if err == errDeviceLost {
continue continue
} }
return err return err
@@ -145,8 +143,8 @@ func (w *Window) validateAndProcess(driver wm.Driver, frameStart time.Time, size
if w.loop == nil && !w.nocontext { if w.loop == nil && !w.nocontext {
var err error var err error
if w.ctx == nil { if w.ctx == nil {
w.driverRun(func(_ wm.Driver) { w.driverRun(func(_ driver) {
w.ctx, err = driver.NewContext() w.ctx, err = d.NewContext()
}) })
if err != nil { if err != nil {
return err return err
@@ -160,7 +158,7 @@ func (w *Window) validateAndProcess(driver wm.Driver, frameStart time.Time, size
} }
} }
if sync && w.ctx != nil { if sync && w.ctx != nil {
w.driverRun(func(_ wm.Driver) { w.driverRun(func(_ driver) {
w.ctx.Refresh() w.ctx.Refresh()
}) })
} }
@@ -168,7 +166,7 @@ func (w *Window) validateAndProcess(driver wm.Driver, frameStart time.Time, size
if sync && w.loop != nil { if sync && w.loop != nil {
if err := w.loop.Flush(); err != nil { if err := w.loop.Flush(); err != nil {
w.destroyGPU() w.destroyGPU()
if err == wm.ErrDeviceLost { if err == errDeviceLost {
continue continue
} }
return err return err
@@ -190,12 +188,12 @@ func (w *Window) processFrame(frameStart time.Time, size image.Point, frame *op.
w.queue.q.Frame(frame) w.queue.q.Frame(frame)
switch w.queue.q.TextInputState() { switch w.queue.q.TextInputState() {
case router.TextInputOpen: 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: 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 { 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 { if txt, ok := w.queue.q.WriteClipboard(); ok {
go w.WriteClipboard(txt) go w.WriteClipboard(txt)
@@ -242,12 +240,12 @@ func (w *Window) Invalidate() {
// Option applies the options to the window. // Option applies the options to the window.
func (w *Window) Option(opts ...Option) { func (w *Window) Option(opts ...Option) {
go w.driverRun(func(d wm.Driver) { go w.driverRun(func(d driver) {
o := new(wm.Options) c := new(config)
for _, opt := range opts { 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 // of a clipboard.Event. Multiple reads may be coalesced
// to a single event. // to a single event.
func (w *Window) ReadClipboard() { func (w *Window) ReadClipboard() {
go w.driverRun(func(d wm.Driver) { go w.driverRun(func(d driver) {
d.ReadClipboard() d.ReadClipboard()
}) })
} }
// WriteClipboard writes a string to the clipboard. // WriteClipboard writes a string to the clipboard.
func (w *Window) WriteClipboard(s string) { func (w *Window) WriteClipboard(s string) {
go w.driverRun(func(d wm.Driver) { go w.driverRun(func(d driver) {
d.WriteClipboard(s) d.WriteClipboard(s)
}) })
} }
// SetCursorName changes the current window cursor to name. // SetCursorName changes the current window cursor to name.
func (w *Window) SetCursorName(name pointer.CursorName) { func (w *Window) SetCursorName(name pointer.CursorName) {
go w.driverRun(func(d wm.Driver) { go w.driverRun(func(d driver) {
d.SetCursor(name) 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. // system.DestroyEvent.
// //
// Currently, only macOS, Windows and X11 drivers implement this functionality, // Currently, only macOS, Windows and X11 drivers implement this functionality,
// all others are stubbed. // all others are stubbed.
func (w *Window) Close() { func (w *Window) Close() {
go w.driverRun(func(d wm.Driver) { go w.driverRun(func(d driver) {
d.Close() d.Close()
}) })
} }
@@ -294,14 +292,14 @@ func (w *Window) Close() {
// Note that most programs should not call Run; configuring a Window with // Note that most programs should not call Run; configuring a Window with
// CustomRenderer is a notable exception. // CustomRenderer is a notable exception.
func (w *Window) Run(f func()) { func (w *Window) Run(f func()) {
w.driverRun(func(_ wm.Driver) { w.driverRun(func(_ driver) {
f() f()
}) })
} }
func (w *Window) driverRun(f func(d wm.Driver)) { func (w *Window) driverRun(f func(d driver)) {
done := make(chan struct{}) done := make(chan struct{})
wrapper := func(d wm.Driver) { wrapper := func(d driver) {
defer close(done) defer close(done)
f(d) 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.d = d
c.Event(driverEvent{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. // Don't run driver functions if there's no driver.
if d == nil { if d == nil {
<-w.ack <-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.out)
defer close(w.dead) 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} w.out <- system.DestroyEvent{Err: err}
return return
} }
var driver wm.Driver var driver driver
for { for {
var wakeups chan struct{} var wakeups chan struct{}
if driver != nil { if driver != nil {
@@ -487,7 +485,7 @@ func (w *Window) run(opts *wm.Options) {
w.updateAnimation() w.updateAnimation()
w.out <- e w.out <- e
w.waitAck() w.waitAck()
case wm.FrameEvent: case frameEvent:
if e2.Size == (image.Point{}) { if e2.Size == (image.Point{}) {
panic(errors.New("internal error: zero-sized Draw")) panic(errors.New("internal error: zero-sized Draw"))
} }
@@ -525,7 +523,7 @@ func (w *Window) run(opts *wm.Options) {
case ViewEvent: case ViewEvent:
w.out <- e2 w.out <- e2
w.waitAck() w.waitAck()
case wm.WakeupEvent: case wakeupEvent:
case event.Event: case event.Event:
if w.queue.q.Queue(e2) { if w.queue.q.Queue(e2) {
w.setNextFrame(time.Time{}) w.setNextFrame(time.Time{})
@@ -552,42 +550,42 @@ func (q *queue) Events(k event.Tag) []event.Event {
var ( var (
// Windowed is the normal window mode with OS specific window decorations. // 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 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. // Supported platforms are macOS, X11, Windows and JS.
func windowMode(mode wm.WindowMode) Option { func modeOption(mode windowMode) Option {
return func(opts *wm.Options) { return func(cnf *config) {
opts.WindowMode = &mode cnf.WindowMode = &mode
} }
} }
var ( var (
// AnyOrientation allows the window to be freely orientated. // 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 constrains the window to landscape orientations.
LandscapeOrientation Option = orientation(wm.LandscapeOrientation) LandscapeOrientation Option = orientationOption(landscapeOrientation)
// PortraitOrientation constrains the window to portrait orientations. // PortraitOrientation constrains the window to portrait orientations.
PortraitOrientation Option = orientation(wm.PortraitOrientation) PortraitOrientation Option = orientationOption(portraitOrientation)
) )
// orientation sets the orientation of the app. // orientation sets the orientation of the app.
// //
// Supported platforms are Android and JS. // Supported platforms are Android and JS.
func orientation(mode wm.Orientation) Option { func orientationOption(mode orientation) Option {
return func(opts *wm.Options) { return func(cnf *config) {
opts.Orientation = &mode cnf.Orientation = &mode
} }
} }
// Title sets the title of the window. // Title sets the title of the window.
func Title(t string) Option { func Title(t string) Option {
return func(opts *wm.Options) { return func(cnf *config) {
opts.Title = &t cnf.Title = &t
} }
} }
@@ -599,8 +597,8 @@ func Size(w, h unit.Value) Option {
if h.V <= 0 { if h.V <= 0 {
panic("height must be larger than or equal to 0") panic("height must be larger than or equal to 0")
} }
return func(opts *wm.Options) { return func(cnf *config) {
opts.Size = &wm.Size{ cnf.Size = &size{
Width: w, Width: w,
Height: h, Height: h,
} }
@@ -615,8 +613,8 @@ func MaxSize(w, h unit.Value) Option {
if h.V <= 0 { if h.V <= 0 {
panic("height must be larger than or equal to 0") panic("height must be larger than or equal to 0")
} }
return func(opts *wm.Options) { return func(cnf *config) {
opts.MaxSize = &wm.Size{ cnf.MaxSize = &size{
Width: w, Width: w,
Height: h, Height: h,
} }
@@ -631,8 +629,8 @@ func MinSize(w, h unit.Value) Option {
if h.V <= 0 { if h.V <= 0 {
panic("height must be larger than or equal to 0") panic("height must be larger than or equal to 0")
} }
return func(opts *wm.Options) { return func(cnf *config) {
opts.MinSize = &wm.Size{ cnf.MinSize = &size{
Width: w, Width: w,
Height: h, Height: h,
} }
@@ -641,23 +639,23 @@ func MinSize(w, h unit.Value) Option {
// StatusColor sets the color of the Android status bar. // StatusColor sets the color of the Android status bar.
func StatusColor(color color.NRGBA) Option { func StatusColor(color color.NRGBA) Option {
return func(opts *wm.Options) { return func(cnf *config) {
opts.StatusColor = &color cnf.StatusColor = &color
} }
} }
// NavigationColor sets the color of the navigation bar on Android, or the address bar in browsers. // NavigationColor sets the color of the navigation bar on Android, or the address bar in browsers.
func NavigationColor(color color.NRGBA) Option { func NavigationColor(color color.NRGBA) Option {
return func(opts *wm.Options) { return func(cnf *config) {
opts.NavigationColor = &color cnf.NavigationColor = &color
} }
} }
// CustomRenderer controls whether the the window contents is // CustomRenderer controls whether the the window contents is
// rendered by the client. If true, no GPU context is created. // rendered by the client. If true, no GPU context is created.
func CustomRenderer(custom bool) Option { func CustomRenderer(custom bool) Option {
return func(opts *wm.Options) { return func(cnf *config) {
opts.CustomRenderer = custom cnf.CustomRenderer = custom
} }
} }
+1 -1
View File
@@ -240,7 +240,7 @@ func compileAndroid(tmpDir string, tools *androidTools, bi *buildInfo) (err erro
return err 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 { if err != nil {
return err return err
} }
+1 -1
View File
@@ -464,7 +464,7 @@ func archiveIOS(tmpDir, target, frameworkRoot string, bi *buildInfo) error {
if _, err := runCmd(lipo); err != nil { if _, err := runCmd(lipo); err != nil {
return err 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 { if err != nil {
return err return err
} }