mirror of
https://git.sr.ht/~eliasnaur/gio
synced 2026-07-01 07:35:40 +00:00
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:
+1
-9
@@ -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()
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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
|
||||||
@@ -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 {
|
||||||
@@ -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;
|
||||||
@@ -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)
|
||||||
}
|
}
|
||||||
@@ -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
@@ -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
|
||||||
@@ -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{})
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@@ -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
|
||||||
@@ -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 {}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -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
|
||||||
}
|
}
|
||||||
@@ -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
|
||||||
@@ -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
@@ -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
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user