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 (
"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()
}
-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
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
-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
package wm
package app
/*
#include <android/native_window_jni.h>
@@ -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()
}
@@ -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()
}
@@ -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 {
@@ -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 {
+1 -1
View File
@@ -3,7 +3,7 @@
//go:build darwin && ios && nometal
// +build darwin,ios,nometal
package wm
package app
/*
@import UIKit;
+12 -12
View File
@@ -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)
}
+12 -12
View File
@@ -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)
}
+3 -4
View File
@@ -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)
@@ -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)
}
@@ -3,7 +3,7 @@
//go:build !nometal
// +build !nometal
package wm
package app
/*
#cgo CFLAGS: -Werror -xobjective-c -fmodules -fobjc-arc
@@ -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
+35 -41
View File
@@ -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() {}
@@ -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)
@@ -1,6 +1,6 @@
// SPDX-License-Identifier: Unlicense OR MIT
package wm
package app
/*
#include <Foundation/Foundation.h>
@@ -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{})
})
}
+7 -7
View File
@@ -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
+19 -19
View File
@@ -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 {}
}
+17 -17
View File
@@ -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()
}
@@ -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
}
@@ -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{
@@ -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
}
+17 -17
View File
@@ -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)
@@ -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
-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/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
}
}
+1 -1
View File
@@ -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
}
+1 -1
View File
@@ -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
}