mirror of
https://git.sr.ht/~eliasnaur/gio
synced 2026-07-01 07:35:40 +00:00
app,internal/window: extract native window code to separate package
Signed-off-by: Elias Naur <mail@eliasnaur.com>
This commit is contained in:
+2
-83
@@ -3,37 +3,10 @@
|
||||
package app
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"math"
|
||||
"os"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"gioui.org/unit"
|
||||
)
|
||||
|
||||
type windowRendezvous struct {
|
||||
in chan windowAndOptions
|
||||
out chan windowAndOptions
|
||||
errs chan error
|
||||
}
|
||||
|
||||
type windowAndOptions struct {
|
||||
window *Window
|
||||
opts *windowOptions
|
||||
}
|
||||
|
||||
const (
|
||||
inchPrDp = 1.0 / 160
|
||||
mmPrDp = 25.4 / 160
|
||||
// monitorScale is the extra scale applied to
|
||||
// monitor outputs to compensate for the extra
|
||||
// viewing distance compared to phone and tables.
|
||||
monitorScale = 1.20
|
||||
// minDensity is the minimum pixels per dp to
|
||||
// ensure font and ui legibility on low-dpi
|
||||
// screens.
|
||||
minDensity = 1.25
|
||||
"gioui.org/app/internal/window"
|
||||
)
|
||||
|
||||
// extraArgs contains extra arguments to append to
|
||||
@@ -69,59 +42,5 @@ func DataDir() (string, error) {
|
||||
// require control of the main thread of the program for
|
||||
// running windows.
|
||||
func Main() {
|
||||
main()
|
||||
}
|
||||
|
||||
// config implements the system.Config interface.
|
||||
type config struct {
|
||||
// Device pixels per dp.
|
||||
pxPerDp float32
|
||||
// Device pixels per sp.
|
||||
pxPerSp float32
|
||||
now time.Time
|
||||
}
|
||||
|
||||
func (c *config) Now() time.Time {
|
||||
return c.now
|
||||
}
|
||||
|
||||
func (c *config) Px(v unit.Value) int {
|
||||
var r float32
|
||||
switch v.U {
|
||||
case unit.UnitPx:
|
||||
r = v.V
|
||||
case unit.UnitDp:
|
||||
r = c.pxPerDp * v.V
|
||||
case unit.UnitSp:
|
||||
r = c.pxPerSp * v.V
|
||||
default:
|
||||
panic("unknown unit")
|
||||
}
|
||||
return int(math.Round(float64(r)))
|
||||
}
|
||||
|
||||
func newWindowRendezvous() *windowRendezvous {
|
||||
wr := &windowRendezvous{
|
||||
in: make(chan windowAndOptions),
|
||||
out: make(chan windowAndOptions),
|
||||
errs: make(chan error),
|
||||
}
|
||||
go func() {
|
||||
var main windowAndOptions
|
||||
var out chan windowAndOptions
|
||||
for {
|
||||
select {
|
||||
case w := <-wr.in:
|
||||
var err error
|
||||
if main.window != nil {
|
||||
err = errors.New("multiple windows are not supported")
|
||||
}
|
||||
wr.errs <- err
|
||||
main = w
|
||||
out = wr.out
|
||||
case out <- main:
|
||||
}
|
||||
}
|
||||
}()
|
||||
return wr
|
||||
window.Main()
|
||||
}
|
||||
|
||||
@@ -5,21 +5,21 @@
|
||||
package app
|
||||
|
||||
import "C"
|
||||
import "sync"
|
||||
|
||||
import (
|
||||
"sync"
|
||||
|
||||
"gioui.org/app/internal/window"
|
||||
)
|
||||
|
||||
var (
|
||||
dataDirOnce sync.Once
|
||||
dataDirChan = make(chan string, 1)
|
||||
dataPath string
|
||||
)
|
||||
|
||||
func dataDir() (string, error) {
|
||||
dataDirOnce.Do(func() {
|
||||
dataPath = <-dataDirChan
|
||||
dataPath = window.GetDataDir()
|
||||
})
|
||||
return dataPath, nil
|
||||
}
|
||||
|
||||
func setDataDir(dir string) {
|
||||
dataDirChan <- dir
|
||||
}
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
// +build linux windows
|
||||
|
||||
package app
|
||||
package window
|
||||
|
||||
import (
|
||||
"errors"
|
||||
@@ -1,6 +1,6 @@
|
||||
// SPDX-License-Identifier: Unlicense OR MIT
|
||||
|
||||
package app
|
||||
package window
|
||||
|
||||
/*
|
||||
#include <EGL/egl.h>
|
||||
@@ -1,6 +1,6 @@
|
||||
// SPDX-License-Identifier: Unlicense OR MIT
|
||||
|
||||
package app
|
||||
package window
|
||||
|
||||
/*
|
||||
#cgo LDFLAGS: -lEGL
|
||||
@@ -13,6 +13,8 @@ package app
|
||||
*/
|
||||
import "C"
|
||||
|
||||
import "gioui.org/app/internal/gl"
|
||||
|
||||
type (
|
||||
_EGLint = C.EGLint
|
||||
_EGLDisplay = C.EGLDisplay
|
||||
@@ -93,3 +95,7 @@ func eglCreateWindowSurface(disp _EGLDisplay, conf _EGLConfig, win _EGLNativeWin
|
||||
eglSurf := C.eglCreateWindowSurface(disp, conf, win, &attribs[0])
|
||||
return eglSurf
|
||||
}
|
||||
|
||||
func (w *window) NewContext() (gl.Context, error) {
|
||||
return newContext(w)
|
||||
}
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
// +build linux,!android
|
||||
|
||||
package app
|
||||
package window
|
||||
|
||||
import (
|
||||
"errors"
|
||||
@@ -1,6 +1,6 @@
|
||||
// SPDX-License-Identifier: Unlicense OR MIT
|
||||
|
||||
package app
|
||||
package window
|
||||
|
||||
import (
|
||||
"os"
|
||||
@@ -154,3 +154,7 @@ func (w *window) eglWindow(visID int) (_EGLNativeWindowType, int, int, error) {
|
||||
hwnd, width, height := w.HWND()
|
||||
return _EGLNativeWindowType(hwnd), width, height, nil
|
||||
}
|
||||
|
||||
func (w *window) NewContext() (gl.Context, error) {
|
||||
return newContext(w)
|
||||
}
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
// +build darwin,ios
|
||||
|
||||
package app
|
||||
package window
|
||||
|
||||
/*
|
||||
#cgo CFLAGS: -fmodules -fobjc-arc -x objective-c
|
||||
@@ -122,3 +122,7 @@ func (c *context) MakeCurrent() error {
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (w *window) NewContext() (gl.Context, error) {
|
||||
return newContext(w)
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
// SPDX-License-Identifier: Unlicense OR MIT
|
||||
|
||||
package app
|
||||
package window
|
||||
|
||||
import (
|
||||
"errors"
|
||||
@@ -89,3 +89,7 @@ func (c *context) MakeCurrent() error {
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (w *window) NewContext() (gl.Context, error) {
|
||||
return newContext(w)
|
||||
}
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
// +build darwin,!ios
|
||||
|
||||
package app
|
||||
package window
|
||||
|
||||
import (
|
||||
"gioui.org/app/internal/gl"
|
||||
@@ -72,3 +72,7 @@ func (c *context) MakeCurrent() error {
|
||||
C.gio_makeCurrentContext(c.ctx)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (w *window) NewContext() (gl.Context, error) {
|
||||
return newContext(w)
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
// SPDX-License-Identifier: Unlicense OR MIT
|
||||
|
||||
package app
|
||||
package window
|
||||
|
||||
/*
|
||||
#cgo LDFLAGS: -landroid
|
||||
@@ -32,7 +32,7 @@ import (
|
||||
)
|
||||
|
||||
type window struct {
|
||||
*Window
|
||||
callbacks Callbacks
|
||||
|
||||
view C.jobject
|
||||
|
||||
@@ -55,6 +55,8 @@ type window struct {
|
||||
mpostFrameCallbackOnMainThread C.jmethodID
|
||||
}
|
||||
|
||||
var dataDirChan = make(chan string, 1)
|
||||
|
||||
var theJVM *C.JavaVM
|
||||
|
||||
var views = make(map[C.jlong]*window)
|
||||
@@ -85,11 +87,15 @@ func runGoMain(env *C.JNIEnv, class C.jclass, jdataDir C.jbyteArray) {
|
||||
}
|
||||
n := C.gio_jni_GetArrayLength(env, jdataDir)
|
||||
dataDir := C.GoStringN((*C.char)(unsafe.Pointer(dirBytes)), n)
|
||||
setDataDir(dataDir)
|
||||
dataDirChan <- dataDir
|
||||
C.gio_jni_ReleaseByteArrayElements(env, jdataDir, dirBytes)
|
||||
runMain()
|
||||
}
|
||||
|
||||
func GetDataDir() string {
|
||||
return <-dataDirChan
|
||||
}
|
||||
|
||||
//export setJVM
|
||||
func setJVM(vm *C.JavaVM) {
|
||||
theJVM = vm
|
||||
@@ -108,8 +114,8 @@ func onCreateView(env *C.JNIEnv, class C.jclass, view C.jobject) C.jlong {
|
||||
mpostFrameCallbackOnMainThread: jniGetMethodID(env, class, "postFrameCallbackOnMainThread", "()V"),
|
||||
}
|
||||
wopts := <-mainWindow.out
|
||||
w.Window = wopts.window
|
||||
w.Window.setDriver(w)
|
||||
w.callbacks = wopts.window
|
||||
w.callbacks.SetDriver(w)
|
||||
handle := C.jlong(view)
|
||||
views[handle] = w
|
||||
w.loadConfig(env, class)
|
||||
@@ -120,7 +126,7 @@ func onCreateView(env *C.JNIEnv, class C.jclass, view C.jobject) C.jlong {
|
||||
//export onDestroyView
|
||||
func onDestroyView(env *C.JNIEnv, class C.jclass, handle C.jlong) {
|
||||
w := views[handle]
|
||||
w.setDriver(nil)
|
||||
w.callbacks.SetDriver(nil)
|
||||
delete(views, handle)
|
||||
C.gio_jni_DeleteGlobalRef(env, w.view)
|
||||
w.view = 0
|
||||
@@ -201,7 +207,7 @@ func onFrameCallback(env *C.JNIEnv, class C.jclass, view C.jlong, nanos C.jlong)
|
||||
func onBack(env *C.JNIEnv, class C.jclass, view C.jlong) C.jboolean {
|
||||
w := views[view]
|
||||
ev := &system.CommandEvent{Type: system.CommandBack}
|
||||
w.event(ev)
|
||||
w.callbacks.Event(ev)
|
||||
if ev.Cancel {
|
||||
return C.JNI_TRUE
|
||||
}
|
||||
@@ -211,7 +217,7 @@ func onBack(env *C.JNIEnv, class C.jclass, view C.jlong) C.jboolean {
|
||||
//export onFocusChange
|
||||
func onFocusChange(env *C.JNIEnv, class C.jclass, view C.jlong, focus C.jboolean) {
|
||||
w := views[view]
|
||||
w.event(key.FocusEvent{Focus: focus == C.JNI_TRUE})
|
||||
w.callbacks.Event(key.FocusEvent{Focus: focus == C.JNI_TRUE})
|
||||
}
|
||||
|
||||
//export onWindowInsets
|
||||
@@ -243,7 +249,7 @@ func (w *window) setStage(stage system.Stage) {
|
||||
return
|
||||
}
|
||||
w.stage = stage
|
||||
w.event(system.StageEvent{stage})
|
||||
w.callbacks.Event(system.StageEvent{stage})
|
||||
}
|
||||
|
||||
func (w *window) nativeWindow(visID int) (*C.ANativeWindow, int, int) {
|
||||
@@ -279,7 +285,7 @@ func (w *window) loadConfig(env *C.JNIEnv, class C.jclass) {
|
||||
}
|
||||
}
|
||||
|
||||
func (w *window) setAnimating(anim bool) {
|
||||
func (w *window) SetAnimating(anim bool) {
|
||||
w.mu.Lock()
|
||||
w.animating = anim
|
||||
w.mu.Unlock()
|
||||
@@ -297,7 +303,7 @@ func (w *window) draw(sync bool) {
|
||||
return
|
||||
}
|
||||
ppdp := float32(w.dpi) * inchPrDp
|
||||
w.event(frameEvent{
|
||||
w.callbacks.Event(FrameEvent{
|
||||
FrameEvent: system.FrameEvent{
|
||||
Size: image.Point{
|
||||
X: int(width),
|
||||
@@ -310,7 +316,7 @@ func (w *window) draw(sync bool) {
|
||||
now: time.Now(),
|
||||
},
|
||||
},
|
||||
sync: sync,
|
||||
Sync: sync,
|
||||
})
|
||||
}
|
||||
|
||||
@@ -364,10 +370,10 @@ func convertKeyCode(code C.jint) (rune, bool) {
|
||||
func onKeyEvent(env *C.JNIEnv, class C.jclass, handle C.jlong, keyCode, r C.jint, t C.jlong) {
|
||||
w := views[handle]
|
||||
if n, ok := convertKeyCode(keyCode); ok {
|
||||
w.event(key.Event{Name: n})
|
||||
w.callbacks.Event(key.Event{Name: n})
|
||||
}
|
||||
if r != 0 {
|
||||
w.event(key.EditEvent{Text: string(rune(r))})
|
||||
w.callbacks.Event(key.EditEvent{Text: string(rune(r))})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -396,7 +402,7 @@ func onTouchEvent(env *C.JNIEnv, class C.jclass, handle C.jlong, action, pointer
|
||||
default:
|
||||
return
|
||||
}
|
||||
w.event(pointer.Event{
|
||||
w.callbacks.Event(pointer.Event{
|
||||
Type: typ,
|
||||
Source: src,
|
||||
PointerID: pointer.ID(pointerID),
|
||||
@@ -405,7 +411,7 @@ func onTouchEvent(env *C.JNIEnv, class C.jclass, handle C.jlong, action, pointer
|
||||
})
|
||||
}
|
||||
|
||||
func (w *window) showTextInput(show bool) {
|
||||
func (w *window) ShowTextInput(show bool) {
|
||||
if w.view == 0 {
|
||||
return
|
||||
}
|
||||
@@ -418,10 +424,10 @@ func (w *window) showTextInput(show bool) {
|
||||
})
|
||||
}
|
||||
|
||||
func main() {
|
||||
func Main() {
|
||||
}
|
||||
|
||||
func createWindow(window *Window, opts *windowOptions) error {
|
||||
func NewWindow(window Callbacks, opts *Options) error {
|
||||
mainWindow.in <- windowAndOptions{window, opts}
|
||||
return <-mainWindow.errs
|
||||
}
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
// +build darwin,ios
|
||||
|
||||
package app
|
||||
package window
|
||||
|
||||
/*
|
||||
#cgo CFLAGS: -fmodules -fobjc-arc -x objective-c
|
||||
@@ -31,7 +31,7 @@ import (
|
||||
|
||||
type window struct {
|
||||
view C.CFTypeRef
|
||||
w *Window
|
||||
w Callbacks
|
||||
|
||||
layer C.CFTypeRef
|
||||
visible atomic.Value
|
||||
@@ -57,12 +57,12 @@ func onCreate(view C.CFTypeRef) {
|
||||
}
|
||||
wopts := <-mainWindow.out
|
||||
w.w = wopts.window
|
||||
w.w.setDriver(w)
|
||||
w.w.SetDriver(w)
|
||||
w.visible.Store(false)
|
||||
w.layer = C.CFTypeRef(layerFactory())
|
||||
C.gio_addLayerToView(view, w.layer)
|
||||
views[view] = w
|
||||
w.w.event(system.StageEvent{Stage: system.StagePaused})
|
||||
w.w.Event(system.StageEvent{Stage: system.StagePaused})
|
||||
}
|
||||
|
||||
//export onDraw
|
||||
@@ -75,13 +75,13 @@ func onDraw(view C.CFTypeRef, dpi, sdpi, width, height C.CGFloat, sync C.int, to
|
||||
w.visible.Store(true)
|
||||
C.gio_updateView(view, w.layer)
|
||||
if !wasVisible {
|
||||
w.w.event(system.StageEvent{Stage: system.StageRunning})
|
||||
w.w.Event(system.StageEvent{Stage: system.StageRunning})
|
||||
}
|
||||
isSync := false
|
||||
if sync != 0 {
|
||||
isSync = true
|
||||
}
|
||||
w.w.event(frameEvent{
|
||||
w.w.Event(FrameEvent{
|
||||
FrameEvent: system.FrameEvent{
|
||||
Size: image.Point{
|
||||
X: int(width + .5),
|
||||
@@ -99,7 +99,7 @@ func onDraw(view C.CFTypeRef, dpi, sdpi, width, height C.CGFloat, sync C.int, to
|
||||
now: time.Now(),
|
||||
},
|
||||
},
|
||||
sync: isSync,
|
||||
Sync: isSync,
|
||||
})
|
||||
}
|
||||
|
||||
@@ -107,14 +107,14 @@ func onDraw(view C.CFTypeRef, dpi, sdpi, width, height C.CGFloat, sync C.int, to
|
||||
func onStop(view C.CFTypeRef) {
|
||||
w := views[view]
|
||||
w.visible.Store(false)
|
||||
w.w.event(system.StageEvent{Stage: system.StagePaused})
|
||||
w.w.Event(system.StageEvent{Stage: system.StagePaused})
|
||||
}
|
||||
|
||||
//export onDestroy
|
||||
func onDestroy(view C.CFTypeRef) {
|
||||
w := views[view]
|
||||
delete(views, view)
|
||||
w.w.event(system.DestroyEvent{})
|
||||
w.w.Event(system.DestroyEvent{})
|
||||
C.gio_removeLayer(w.layer)
|
||||
C.CFRelease(w.layer)
|
||||
w.layer = 0
|
||||
@@ -124,7 +124,7 @@ func onDestroy(view C.CFTypeRef) {
|
||||
//export onFocus
|
||||
func onFocus(view C.CFTypeRef, focus int) {
|
||||
w := views[view]
|
||||
w.w.event(key.FocusEvent{Focus: focus != 0})
|
||||
w.w.Event(key.FocusEvent{Focus: focus != 0})
|
||||
}
|
||||
|
||||
//export onLowMemory
|
||||
@@ -161,7 +161,7 @@ func onDeleteBackward(view C.CFTypeRef) {
|
||||
//export onText
|
||||
func onText(view C.CFTypeRef, str *C.char) {
|
||||
w := views[view]
|
||||
w.w.event(key.EditEvent{
|
||||
w.w.Event(key.EditEvent{
|
||||
Text: C.GoString(str),
|
||||
})
|
||||
}
|
||||
@@ -184,7 +184,7 @@ func onTouch(last C.int, view, touchRef C.CFTypeRef, phase C.NSInteger, x, y C.C
|
||||
w := views[view]
|
||||
t := time.Duration(float64(ti) * float64(time.Second))
|
||||
p := f32.Point{X: float32(x), Y: float32(y)}
|
||||
w.w.event(pointer.Event{
|
||||
w.w.Event(pointer.Event{
|
||||
Type: typ,
|
||||
Source: pointer.Touch,
|
||||
PointerID: w.lookupTouch(last != 0, touchRef),
|
||||
@@ -193,7 +193,7 @@ func onTouch(last C.int, view, touchRef C.CFTypeRef, phase C.NSInteger, x, y C.C
|
||||
})
|
||||
}
|
||||
|
||||
func (w *window) setAnimating(anim bool) {
|
||||
func (w *window) SetAnimating(anim bool) {
|
||||
if w.view == 0 {
|
||||
return
|
||||
}
|
||||
@@ -205,7 +205,7 @@ func (w *window) setAnimating(anim bool) {
|
||||
}
|
||||
|
||||
func (w *window) onKeyCommand(name rune) {
|
||||
w.w.event(key.Event{
|
||||
w.w.Event(key.Event{
|
||||
Name: name,
|
||||
})
|
||||
}
|
||||
@@ -238,7 +238,7 @@ func (w *window) isVisible() bool {
|
||||
return w.visible.Load().(bool)
|
||||
}
|
||||
|
||||
func (w *window) showTextInput(show bool) {
|
||||
func (w *window) ShowTextInput(show bool) {
|
||||
if w.view == 0 {
|
||||
return
|
||||
}
|
||||
@@ -249,10 +249,10 @@ func (w *window) showTextInput(show bool) {
|
||||
}
|
||||
}
|
||||
|
||||
func createWindow(win *Window, opts *windowOptions) error {
|
||||
func NewWindow(win Callbacks, opts *Options) error {
|
||||
mainWindow.in <- windowAndOptions{win, opts}
|
||||
return <-mainWindow.errs
|
||||
}
|
||||
|
||||
func main() {
|
||||
func Main() {
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
// SPDX-License-Identifier: Unlicense OR MIT
|
||||
|
||||
package app
|
||||
package window
|
||||
|
||||
import (
|
||||
"image"
|
||||
@@ -18,7 +18,7 @@ type window struct {
|
||||
window js.Value
|
||||
cnv js.Value
|
||||
tarea js.Value
|
||||
w *Window
|
||||
w Callbacks
|
||||
redraw js.Func
|
||||
requestAnimationFrame js.Value
|
||||
cleanfuncs []func()
|
||||
@@ -32,7 +32,7 @@ type window struct {
|
||||
|
||||
var mainDone = make(chan struct{})
|
||||
|
||||
func createWindow(win *Window, opts *windowOptions) error {
|
||||
func NewWindow(win Callbacks, opts *Options) error {
|
||||
doc := js.Global().Get("document")
|
||||
cont := getContainer(doc)
|
||||
cnv := createCanvas(doc)
|
||||
@@ -52,9 +52,9 @@ func createWindow(win *Window, opts *windowOptions) error {
|
||||
w.addEventListeners()
|
||||
w.w = win
|
||||
go func() {
|
||||
w.w.setDriver(w)
|
||||
w.w.SetDriver(w)
|
||||
w.focus()
|
||||
w.w.event(system.StageEvent{Stage: system.StageRunning})
|
||||
w.w.Event(system.StageEvent{Stage: system.StageRunning})
|
||||
w.draw(true)
|
||||
select {}
|
||||
w.cleanup()
|
||||
@@ -156,18 +156,18 @@ func (w *window) addEventListeners() {
|
||||
w.touches[i] = js.Null()
|
||||
}
|
||||
w.touches = w.touches[:0]
|
||||
w.w.event(pointer.Event{
|
||||
w.w.Event(pointer.Event{
|
||||
Type: pointer.Cancel,
|
||||
Source: pointer.Touch,
|
||||
})
|
||||
return nil
|
||||
})
|
||||
w.addEventListener(w.tarea, "focus", func(this js.Value, args []js.Value) interface{} {
|
||||
w.w.event(key.FocusEvent{Focus: true})
|
||||
w.w.Event(key.FocusEvent{Focus: true})
|
||||
return nil
|
||||
})
|
||||
w.addEventListener(w.tarea, "blur", func(this js.Value, args []js.Value) interface{} {
|
||||
w.w.event(key.FocusEvent{Focus: false})
|
||||
w.w.Event(key.FocusEvent{Focus: false})
|
||||
return nil
|
||||
})
|
||||
w.addEventListener(w.tarea, "keydown", func(this js.Value, args []js.Value) interface{} {
|
||||
@@ -195,7 +195,7 @@ func (w *window) addEventListeners() {
|
||||
func (w *window) flushInput() {
|
||||
val := w.tarea.Get("value").String()
|
||||
w.tarea.Set("value", "")
|
||||
w.w.event(key.EditEvent{Text: string(val)})
|
||||
w.w.Event(key.EditEvent{Text: string(val)})
|
||||
}
|
||||
|
||||
func (w *window) blur() {
|
||||
@@ -216,7 +216,7 @@ func (w *window) keyEvent(e js.Value) {
|
||||
if e.Call("getModifierState", "Shift").Bool() {
|
||||
cmd.Modifiers |= key.ModShift
|
||||
}
|
||||
w.w.event(cmd)
|
||||
w.w.Event(cmd)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -239,7 +239,7 @@ func (w *window) touchEvent(typ pointer.Type, e js.Value) {
|
||||
X: float32(x) * scale,
|
||||
Y: float32(y) * scale,
|
||||
}
|
||||
w.w.event(pointer.Event{
|
||||
w.w.Event(pointer.Event{
|
||||
Type: typ,
|
||||
Source: pointer.Touch,
|
||||
Position: pos,
|
||||
@@ -279,7 +279,7 @@ func (w *window) pointerEvent(typ pointer.Type, dx, dy float32, e js.Value) {
|
||||
Y: dy * scale,
|
||||
}
|
||||
t := time.Duration(e.Get("timeStamp").Int()) * time.Millisecond
|
||||
w.w.event(pointer.Event{
|
||||
w.w.Event(pointer.Event{
|
||||
Type: typ,
|
||||
Source: pointer.Mouse,
|
||||
Position: pos,
|
||||
@@ -316,7 +316,7 @@ func (w *window) animCallback() {
|
||||
}
|
||||
}
|
||||
|
||||
func (w *window) setAnimating(anim bool) {
|
||||
func (w *window) SetAnimating(anim bool) {
|
||||
w.mu.Lock()
|
||||
defer w.mu.Unlock()
|
||||
if anim && !w.animating {
|
||||
@@ -325,7 +325,7 @@ func (w *window) setAnimating(anim bool) {
|
||||
w.animating = anim
|
||||
}
|
||||
|
||||
func (w *window) showTextInput(show bool) {
|
||||
func (w *window) ShowTextInput(show bool) {
|
||||
// Run in a goroutine to avoid a deadlock if the
|
||||
// focus change result in an event.
|
||||
go func() {
|
||||
@@ -346,7 +346,7 @@ func (w *window) draw(sync bool) {
|
||||
w.scale = float32(scale)
|
||||
w.mu.Unlock()
|
||||
cfg.now = time.Now()
|
||||
w.w.event(frameEvent{
|
||||
w.w.Event(FrameEvent{
|
||||
FrameEvent: system.FrameEvent{
|
||||
Size: image.Point{
|
||||
X: width,
|
||||
@@ -354,7 +354,7 @@ func (w *window) draw(sync bool) {
|
||||
},
|
||||
Config: &cfg,
|
||||
},
|
||||
sync: sync,
|
||||
Sync: sync,
|
||||
})
|
||||
}
|
||||
|
||||
@@ -377,7 +377,7 @@ func (w *window) config() (int, int, float32, config) {
|
||||
}
|
||||
}
|
||||
|
||||
func main() {
|
||||
func Main() {
|
||||
<-mainDone
|
||||
}
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
// +build darwin,!ios
|
||||
|
||||
package app
|
||||
package window
|
||||
|
||||
import (
|
||||
"errors"
|
||||
@@ -33,7 +33,7 @@ func init() {
|
||||
|
||||
type window struct {
|
||||
view C.CFTypeRef
|
||||
w *Window
|
||||
w Callbacks
|
||||
stage system.Stage
|
||||
ppdp float32
|
||||
scale float32
|
||||
@@ -81,9 +81,9 @@ func (w *window) contextView() C.CFTypeRef {
|
||||
return w.view
|
||||
}
|
||||
|
||||
func (w *window) showTextInput(show bool) {}
|
||||
func (w *window) ShowTextInput(show bool) {}
|
||||
|
||||
func (w *window) setAnimating(anim bool) {
|
||||
func (w *window) SetAnimating(anim bool) {
|
||||
var animb C.BOOL
|
||||
if anim {
|
||||
animb = 1
|
||||
@@ -96,7 +96,7 @@ func (w *window) setStage(stage system.Stage) {
|
||||
return
|
||||
}
|
||||
w.stage = stage
|
||||
w.w.event(system.StageEvent{Stage: stage})
|
||||
w.w.Event(system.StageEvent{Stage: stage})
|
||||
}
|
||||
|
||||
// Use a top level func for onFrameCallback to avoid
|
||||
@@ -129,7 +129,7 @@ func gio_onKeys(view C.CFTypeRef, cstr *C.char, ti C.double, mods C.NSUInteger)
|
||||
w := views[view]
|
||||
for _, k := range str {
|
||||
if n, ok := convertKey(k); ok {
|
||||
w.w.event(key.Event{Name: n, Modifiers: kmods})
|
||||
w.w.Event(key.Event{Name: n, Modifiers: kmods})
|
||||
}
|
||||
}
|
||||
})
|
||||
@@ -140,7 +140,7 @@ func gio_onText(view C.CFTypeRef, cstr *C.char) {
|
||||
str := C.GoString(cstr)
|
||||
viewDo(view, func(views viewMap, view C.CFTypeRef) {
|
||||
w := views[view]
|
||||
w.w.event(key.EditEvent{Text: str})
|
||||
w.w.Event(key.EditEvent{Text: str})
|
||||
})
|
||||
}
|
||||
|
||||
@@ -162,7 +162,7 @@ func gio_onMouse(view C.CFTypeRef, cdir C.int, x, y, dx, dy C.CGFloat, ti C.doub
|
||||
w := views[view]
|
||||
x, y := float32(x)*w.scale, float32(y)*w.scale
|
||||
dx, dy := float32(dx)*w.scale, float32(dy)*w.scale
|
||||
w.w.event(pointer.Event{
|
||||
w.w.Event(pointer.Event{
|
||||
Type: typ,
|
||||
Source: pointer.Mouse,
|
||||
Time: t,
|
||||
@@ -185,7 +185,7 @@ func gio_onDraw(view C.CFTypeRef) {
|
||||
func gio_onFocus(view C.CFTypeRef, focus C.BOOL) {
|
||||
viewDo(view, func(views viewMap, view C.CFTypeRef) {
|
||||
w := views[view]
|
||||
w.w.event(key.FocusEvent{Focus: focus == C.YES})
|
||||
w.w.Event(key.FocusEvent{Focus: focus == C.YES})
|
||||
})
|
||||
}
|
||||
|
||||
@@ -200,7 +200,7 @@ func (w *window) draw(sync bool) {
|
||||
cfg := configFor(w.ppdp, w.scale)
|
||||
cfg.now = time.Now()
|
||||
w.setStage(system.StageRunning)
|
||||
w.w.event(frameEvent{
|
||||
w.w.Event(FrameEvent{
|
||||
FrameEvent: system.FrameEvent{
|
||||
Size: image.Point{
|
||||
X: width,
|
||||
@@ -208,7 +208,7 @@ func (w *window) draw(sync bool) {
|
||||
},
|
||||
Config: &cfg,
|
||||
},
|
||||
sync: sync,
|
||||
Sync: sync,
|
||||
})
|
||||
}
|
||||
|
||||
@@ -234,7 +234,7 @@ func gio_onTerminate(view C.CFTypeRef) {
|
||||
viewDo(view, func(views viewMap, view C.CFTypeRef) {
|
||||
w := views[view]
|
||||
delete(views, view)
|
||||
w.w.event(system.DestroyEvent{})
|
||||
w.w.Event(system.DestroyEvent{})
|
||||
})
|
||||
}
|
||||
|
||||
@@ -265,17 +265,17 @@ func gio_onCreate(view C.CFTypeRef) {
|
||||
}
|
||||
wopts := <-mainWindow.out
|
||||
w.w = wopts.window
|
||||
w.w.setDriver(w)
|
||||
w.w.SetDriver(w)
|
||||
views[view] = w
|
||||
})
|
||||
}
|
||||
|
||||
func createWindow(win *Window, opts *windowOptions) error {
|
||||
func NewWindow(win Callbacks, opts *Options) error {
|
||||
mainWindow.in <- windowAndOptions{win, opts}
|
||||
return <-mainWindow.errs
|
||||
}
|
||||
|
||||
func main() {
|
||||
func Main() {
|
||||
wopts := <-mainWindow.out
|
||||
view := viewFactory()
|
||||
if view == 0 {
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
// +build linux,!android
|
||||
|
||||
package app
|
||||
package window
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
@@ -80,7 +80,7 @@ type repeatState struct {
|
||||
delay time.Duration
|
||||
|
||||
key uint32
|
||||
win *Window
|
||||
win Callbacks
|
||||
stopC chan struct{}
|
||||
|
||||
start time.Duration
|
||||
@@ -90,7 +90,7 @@ type repeatState struct {
|
||||
}
|
||||
|
||||
type window struct {
|
||||
w *Window
|
||||
w Callbacks
|
||||
disp *C.struct_wl_display
|
||||
surf *C.struct_wl_surface
|
||||
wmSurf *C.struct_xdg_surface
|
||||
@@ -153,11 +153,11 @@ var (
|
||||
outputConfig = make(map[*C.struct_wl_output]*wlOutput)
|
||||
)
|
||||
|
||||
func main() {
|
||||
func Main() {
|
||||
<-mainDone
|
||||
}
|
||||
|
||||
func createWindow(window *Window, opts *windowOptions) error {
|
||||
func NewWindow(window Callbacks, opts *Options) error {
|
||||
connMu.Lock()
|
||||
defer connMu.Unlock()
|
||||
if len(winMap) > 0 {
|
||||
@@ -173,7 +173,7 @@ func createWindow(window *Window, opts *windowOptions) error {
|
||||
}
|
||||
w.w = window
|
||||
go func() {
|
||||
w.w.setDriver(w)
|
||||
w.w.SetDriver(w)
|
||||
w.loop()
|
||||
w.destroy()
|
||||
conn.destroy()
|
||||
@@ -182,7 +182,7 @@ func createWindow(window *Window, opts *windowOptions) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func createNativeWindow(opts *windowOptions) (*window, error) {
|
||||
func createNativeWindow(opts *Options) (*window, error) {
|
||||
pipe := make([]int, 2)
|
||||
if err := syscall.Pipe2(pipe, syscall.O_NONBLOCK|syscall.O_CLOEXEC); err != nil {
|
||||
return nil, fmt.Errorf("createNativeWindow: failed to create pipe: %v", err)
|
||||
@@ -449,7 +449,7 @@ func gio_onTouchDown(data unsafe.Pointer, touch *C.struct_wl_touch, serial, t C.
|
||||
X: fromFixed(x) * float32(w.scale),
|
||||
Y: fromFixed(y) * float32(w.scale),
|
||||
}
|
||||
w.w.event(pointer.Event{
|
||||
w.w.Event(pointer.Event{
|
||||
Type: pointer.Press,
|
||||
Source: pointer.Touch,
|
||||
Position: w.lastTouch,
|
||||
@@ -461,7 +461,7 @@ func gio_onTouchDown(data unsafe.Pointer, touch *C.struct_wl_touch, serial, t C.
|
||||
//export gio_onTouchUp
|
||||
func gio_onTouchUp(data unsafe.Pointer, touch *C.struct_wl_touch, serial, t C.uint32_t, id C.int32_t) {
|
||||
w := winMap[touch]
|
||||
w.w.event(pointer.Event{
|
||||
w.w.Event(pointer.Event{
|
||||
Type: pointer.Release,
|
||||
Source: pointer.Touch,
|
||||
Position: w.lastTouch,
|
||||
@@ -477,7 +477,7 @@ func gio_onTouchMotion(data unsafe.Pointer, touch *C.struct_wl_touch, t C.uint32
|
||||
X: fromFixed(x) * float32(w.scale),
|
||||
Y: fromFixed(y) * float32(w.scale),
|
||||
}
|
||||
w.w.event(pointer.Event{
|
||||
w.w.Event(pointer.Event{
|
||||
Type: pointer.Move,
|
||||
Position: w.lastTouch,
|
||||
Source: pointer.Touch,
|
||||
@@ -493,7 +493,7 @@ func gio_onTouchFrame(data unsafe.Pointer, touch *C.struct_wl_touch) {
|
||||
//export gio_onTouchCancel
|
||||
func gio_onTouchCancel(data unsafe.Pointer, touch *C.struct_wl_touch) {
|
||||
w := winMap[touch]
|
||||
w.w.event(pointer.Event{
|
||||
w.w.Event(pointer.Event{
|
||||
Type: pointer.Cancel,
|
||||
Source: pointer.Touch,
|
||||
})
|
||||
@@ -544,7 +544,7 @@ func gio_onPointerButton(data unsafe.Pointer, p *C.struct_wl_pointer, serial, t,
|
||||
}
|
||||
w.flushScroll()
|
||||
w.resetFling()
|
||||
w.w.event(pointer.Event{
|
||||
w.w.Event(pointer.Event{
|
||||
Type: typ,
|
||||
Source: pointer.Mouse,
|
||||
Position: w.lastPos,
|
||||
@@ -645,14 +645,14 @@ func gio_onKeyboardEnter(data unsafe.Pointer, keyboard *C.struct_wl_keyboard, se
|
||||
conn.repeat.Stop(0)
|
||||
w := winMap[surf]
|
||||
winMap[keyboard] = w
|
||||
w.w.event(key.FocusEvent{Focus: true})
|
||||
w.w.Event(key.FocusEvent{Focus: true})
|
||||
}
|
||||
|
||||
//export gio_onKeyboardLeave
|
||||
func gio_onKeyboardLeave(data unsafe.Pointer, keyboard *C.struct_wl_keyboard, serial C.uint32_t, surf *C.struct_wl_surface) {
|
||||
conn.repeat.Stop(0)
|
||||
w := winMap[keyboard]
|
||||
w.w.event(key.FocusEvent{Focus: false})
|
||||
w.w.Event(key.FocusEvent{Focus: false})
|
||||
}
|
||||
|
||||
//export gio_onKeyboardKey
|
||||
@@ -666,7 +666,7 @@ func gio_onKeyboardKey(data unsafe.Pointer, keyboard *C.struct_wl_keyboard, seri
|
||||
}
|
||||
kc := uint32(keyCode)
|
||||
for _, e := range conn.xkb.DispatchKey(kc) {
|
||||
w.w.event(e)
|
||||
w.w.Event(e)
|
||||
}
|
||||
if conn.xkb.IsRepeatKey(kc) {
|
||||
conn.repeat.Start(w, kc, t)
|
||||
@@ -739,7 +739,7 @@ func (r *repeatState) Repeat() {
|
||||
break
|
||||
}
|
||||
for _, e := range conn.xkb.DispatchKey(r.key) {
|
||||
r.win.event(e)
|
||||
r.win.Event(e)
|
||||
}
|
||||
r.last += delay
|
||||
}
|
||||
@@ -773,7 +773,7 @@ loop:
|
||||
break
|
||||
}
|
||||
if w.dead {
|
||||
w.w.event(system.DestroyEvent{Err: w.pendingErr})
|
||||
w.w.Event(system.DestroyEvent{Err: w.pendingErr})
|
||||
break
|
||||
}
|
||||
// Clear poll events.
|
||||
@@ -809,7 +809,7 @@ loop:
|
||||
}
|
||||
}
|
||||
|
||||
func (w *window) setAnimating(anim bool) {
|
||||
func (w *window) SetAnimating(anim bool) {
|
||||
w.mu.Lock()
|
||||
w.animating = anim
|
||||
animating := w.isAnimating()
|
||||
@@ -924,7 +924,7 @@ func (w *window) flushScroll() {
|
||||
if total == (f32.Point{}) {
|
||||
return
|
||||
}
|
||||
w.w.event(pointer.Event{
|
||||
w.w.Event(pointer.Event{
|
||||
Type: pointer.Move,
|
||||
Source: pointer.Mouse,
|
||||
Position: w.lastPos,
|
||||
@@ -945,7 +945,7 @@ func (w *window) onPointerMotion(x, y C.wl_fixed_t, t C.uint32_t) {
|
||||
X: fromFixed(x) * float32(w.scale),
|
||||
Y: fromFixed(y) * float32(w.scale),
|
||||
}
|
||||
w.w.event(pointer.Event{
|
||||
w.w.Event(pointer.Event{
|
||||
Type: pointer.Move,
|
||||
Position: w.lastPos,
|
||||
Source: pointer.Mouse,
|
||||
@@ -1025,7 +1025,7 @@ func (w *window) draw(sync bool) {
|
||||
C.gio_wl_callback_add_listener(w.lastFrameCallback, unsafe.Pointer(w.surf))
|
||||
}
|
||||
cfg.now = time.Now()
|
||||
w.w.event(frameEvent{
|
||||
w.w.Event(FrameEvent{
|
||||
FrameEvent: system.FrameEvent{
|
||||
Size: image.Point{
|
||||
X: width,
|
||||
@@ -1033,7 +1033,7 @@ func (w *window) draw(sync bool) {
|
||||
},
|
||||
Config: &cfg,
|
||||
},
|
||||
sync: sync,
|
||||
Sync: sync,
|
||||
})
|
||||
}
|
||||
|
||||
@@ -1042,7 +1042,7 @@ func (w *window) setStage(s system.Stage) {
|
||||
return
|
||||
}
|
||||
w.stage = s
|
||||
w.w.event(system.StageEvent{s})
|
||||
w.w.Event(system.StageEvent{s})
|
||||
}
|
||||
|
||||
func (w *window) display() *C.struct_wl_display {
|
||||
@@ -1064,7 +1064,7 @@ func (w *window) surface() (*C.struct_wl_surface, int, int) {
|
||||
return w.surf, width * scale, height * scale
|
||||
}
|
||||
|
||||
func (w *window) showTextInput(show bool) {}
|
||||
func (w *window) ShowTextInput(show bool) {}
|
||||
|
||||
// detectFontScale reports current font scale, or 1.0
|
||||
// if it fails.
|
||||
@@ -1,6 +1,6 @@
|
||||
// SPDX-License-Identifier: Unlicense OR MIT
|
||||
|
||||
package app
|
||||
package window
|
||||
|
||||
import (
|
||||
"errors"
|
||||
@@ -58,7 +58,7 @@ type point struct {
|
||||
type window struct {
|
||||
hwnd syscall.Handle
|
||||
hdc syscall.Handle
|
||||
w *Window
|
||||
w Callbacks
|
||||
width int
|
||||
height int
|
||||
stage system.Stage
|
||||
@@ -159,11 +159,11 @@ const _WM_REDRAW = _WM_USER + 0
|
||||
var onceMu sync.Mutex
|
||||
var mainDone = make(chan struct{})
|
||||
|
||||
func main() {
|
||||
func Main() {
|
||||
<-mainDone
|
||||
}
|
||||
|
||||
func createWindow(window *Window, opts *windowOptions) error {
|
||||
func NewWindow(window Callbacks, opts *Options) error {
|
||||
onceMu.Lock()
|
||||
defer onceMu.Unlock()
|
||||
if len(winMap) > 0 {
|
||||
@@ -183,8 +183,8 @@ func createWindow(window *Window, opts *windowOptions) error {
|
||||
winMap[w.hwnd] = w
|
||||
defer delete(winMap, w.hwnd)
|
||||
w.w = window
|
||||
w.w.setDriver(w)
|
||||
defer w.w.event(system.DestroyEvent{})
|
||||
w.w.SetDriver(w)
|
||||
defer w.w.Event(system.DestroyEvent{})
|
||||
showWindow(w.hwnd, _SW_SHOWDEFAULT)
|
||||
setForegroundWindow(w.hwnd)
|
||||
setFocus(w.hwnd)
|
||||
@@ -196,7 +196,7 @@ func createWindow(window *Window, opts *windowOptions) error {
|
||||
return <-cerr
|
||||
}
|
||||
|
||||
func createNativeWindow(opts *windowOptions) (*window, error) {
|
||||
func createNativeWindow(opts *Options) (*window, error) {
|
||||
setProcessDPIAware()
|
||||
screenDC, err := getDC(0)
|
||||
if err != nil {
|
||||
@@ -266,7 +266,7 @@ func windowProc(hwnd syscall.Handle, msg uint32, wParam, lParam uintptr) uintptr
|
||||
fallthrough
|
||||
case _WM_CHAR:
|
||||
if r := rune(wParam); unicode.IsPrint(r) {
|
||||
w.w.event(key.EditEvent{Text: string(r)})
|
||||
w.w.Event(key.EditEvent{Text: string(r)})
|
||||
}
|
||||
// The message is processed.
|
||||
return 1
|
||||
@@ -279,31 +279,31 @@ func windowProc(hwnd syscall.Handle, msg uint32, wParam, lParam uintptr) uintptr
|
||||
if getKeyState(_VK_SHIFT)&0x1000 != 0 {
|
||||
cmd.Modifiers |= key.ModShift
|
||||
}
|
||||
w.w.event(cmd)
|
||||
w.w.Event(cmd)
|
||||
}
|
||||
case _WM_LBUTTONDOWN:
|
||||
setCapture(w.hwnd)
|
||||
x, y := coordsFromlParam(lParam)
|
||||
p := f32.Point{X: float32(x), Y: float32(y)}
|
||||
w.w.event(pointer.Event{
|
||||
w.w.Event(pointer.Event{
|
||||
Type: pointer.Press,
|
||||
Source: pointer.Mouse,
|
||||
Position: p,
|
||||
Time: getMessageTime(),
|
||||
})
|
||||
case _WM_CANCELMODE:
|
||||
w.w.event(pointer.Event{
|
||||
w.w.Event(pointer.Event{
|
||||
Type: pointer.Cancel,
|
||||
})
|
||||
case _WM_SETFOCUS:
|
||||
w.w.event(key.FocusEvent{Focus: true})
|
||||
w.w.Event(key.FocusEvent{Focus: true})
|
||||
case _WM_KILLFOCUS:
|
||||
w.w.event(key.FocusEvent{Focus: false})
|
||||
w.w.Event(key.FocusEvent{Focus: false})
|
||||
case _WM_LBUTTONUP:
|
||||
releaseCapture()
|
||||
x, y := coordsFromlParam(lParam)
|
||||
p := f32.Point{X: float32(x), Y: float32(y)}
|
||||
w.w.event(pointer.Event{
|
||||
w.w.Event(pointer.Event{
|
||||
Type: pointer.Release,
|
||||
Source: pointer.Mouse,
|
||||
Position: p,
|
||||
@@ -312,7 +312,7 @@ func windowProc(hwnd syscall.Handle, msg uint32, wParam, lParam uintptr) uintptr
|
||||
case _WM_MOUSEMOVE:
|
||||
x, y := coordsFromlParam(lParam)
|
||||
p := f32.Point{X: float32(x), Y: float32(y)}
|
||||
w.w.event(pointer.Event{
|
||||
w.w.Event(pointer.Event{
|
||||
Type: pointer.Move,
|
||||
Source: pointer.Mouse,
|
||||
Position: p,
|
||||
@@ -350,7 +350,7 @@ func (w *window) scrollEvent(wParam, lParam uintptr) {
|
||||
screenToClient(w.hwnd, &np)
|
||||
p := f32.Point{X: float32(np.x), Y: float32(np.y)}
|
||||
dist := float32(int16(wParam >> 16))
|
||||
w.w.event(pointer.Event{
|
||||
w.w.Event(pointer.Event{
|
||||
Type: pointer.Move,
|
||||
Source: pointer.Mouse,
|
||||
Position: p,
|
||||
@@ -381,7 +381,7 @@ func (w *window) loop() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (w *window) setAnimating(anim bool) {
|
||||
func (w *window) SetAnimating(anim bool) {
|
||||
w.mu.Lock()
|
||||
w.animating = anim
|
||||
w.mu.Unlock()
|
||||
@@ -398,7 +398,7 @@ func (w *window) postRedraw() {
|
||||
|
||||
func (w *window) setStage(s system.Stage) {
|
||||
w.stage = s
|
||||
w.w.event(system.StageEvent{Stage: s})
|
||||
w.w.Event(system.StageEvent{Stage: s})
|
||||
}
|
||||
|
||||
func (w *window) draw(sync bool) {
|
||||
@@ -408,7 +408,7 @@ func (w *window) draw(sync bool) {
|
||||
w.height = int(r.bottom - r.top)
|
||||
cfg := configForDC(w.hdc)
|
||||
cfg.now = time.Now()
|
||||
w.w.event(frameEvent{
|
||||
w.w.Event(FrameEvent{
|
||||
FrameEvent: system.FrameEvent{
|
||||
Size: image.Point{
|
||||
X: w.width,
|
||||
@@ -416,7 +416,7 @@ func (w *window) draw(sync bool) {
|
||||
},
|
||||
Config: &cfg,
|
||||
},
|
||||
sync: sync,
|
||||
Sync: sync,
|
||||
})
|
||||
}
|
||||
|
||||
@@ -431,7 +431,7 @@ func (w *window) destroy() {
|
||||
}
|
||||
}
|
||||
|
||||
func (w *window) showTextInput(show bool) {}
|
||||
func (w *window) ShowTextInput(show bool) {}
|
||||
|
||||
func (w *window) HDC() syscall.Handle {
|
||||
return w.hdc
|
||||
@@ -1,6 +1,8 @@
|
||||
// SPDX-License-Identifier: Unlicense OR MIT
|
||||
|
||||
// +build android darwin,ios
|
||||
|
||||
package app
|
||||
package window
|
||||
|
||||
// Android only supports non-Java programs as c-shared libraries.
|
||||
// Unfortunately, Go does not run a program's main function in
|
||||
@@ -1,6 +1,8 @@
|
||||
// SPDX-License-Identifier: Unlicense OR MIT
|
||||
|
||||
// +build darwin,ios
|
||||
|
||||
package app
|
||||
package window
|
||||
|
||||
import "C"
|
||||
|
||||
@@ -0,0 +1,121 @@
|
||||
// SPDX-License-Identifier: Unlicense OR MIT
|
||||
|
||||
// Package window implements platform specific windows
|
||||
// and GPU contexts.
|
||||
package window
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"math"
|
||||
"time"
|
||||
|
||||
"gioui.org/app/internal/gl"
|
||||
"gioui.org/io/event"
|
||||
"gioui.org/io/system"
|
||||
"gioui.org/unit"
|
||||
)
|
||||
|
||||
type Options struct {
|
||||
Width, Height unit.Value
|
||||
Title string
|
||||
}
|
||||
|
||||
type FrameEvent struct {
|
||||
system.FrameEvent
|
||||
|
||||
Sync bool
|
||||
}
|
||||
|
||||
type Callbacks interface {
|
||||
SetDriver(d Driver)
|
||||
Event(e event.Event)
|
||||
}
|
||||
|
||||
// Driver is the interface for the platform implementation
|
||||
// of a window.
|
||||
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)
|
||||
// ShowTextInput updates the virtual keyboard state.
|
||||
ShowTextInput(show bool)
|
||||
NewContext() (gl.Context, error)
|
||||
}
|
||||
|
||||
type windowRendezvous struct {
|
||||
in chan windowAndOptions
|
||||
out chan windowAndOptions
|
||||
errs chan error
|
||||
}
|
||||
|
||||
type windowAndOptions struct {
|
||||
window Callbacks
|
||||
opts *Options
|
||||
}
|
||||
|
||||
// config implements the system.Config interface.
|
||||
type config struct {
|
||||
// Device pixels per dp.
|
||||
pxPerDp float32
|
||||
// Device pixels per sp.
|
||||
pxPerSp float32
|
||||
now time.Time
|
||||
}
|
||||
|
||||
func (c *config) Now() time.Time {
|
||||
return c.now
|
||||
}
|
||||
|
||||
func (c *config) Px(v unit.Value) int {
|
||||
var r float32
|
||||
switch v.U {
|
||||
case unit.UnitPx:
|
||||
r = v.V
|
||||
case unit.UnitDp:
|
||||
r = c.pxPerDp * v.V
|
||||
case unit.UnitSp:
|
||||
r = c.pxPerSp * v.V
|
||||
default:
|
||||
panic("unknown unit")
|
||||
}
|
||||
return int(math.Round(float64(r)))
|
||||
}
|
||||
|
||||
func newWindowRendezvous() *windowRendezvous {
|
||||
wr := &windowRendezvous{
|
||||
in: make(chan windowAndOptions),
|
||||
out: make(chan windowAndOptions),
|
||||
errs: make(chan error),
|
||||
}
|
||||
go func() {
|
||||
var main windowAndOptions
|
||||
var out chan windowAndOptions
|
||||
for {
|
||||
select {
|
||||
case w := <-wr.in:
|
||||
var err error
|
||||
if main.window != nil {
|
||||
err = errors.New("multiple windows are not supported")
|
||||
}
|
||||
wr.errs <- err
|
||||
main = w
|
||||
out = wr.out
|
||||
case out <- main:
|
||||
}
|
||||
}
|
||||
}()
|
||||
return wr
|
||||
}
|
||||
|
||||
const (
|
||||
inchPrDp = 1.0 / 160
|
||||
mmPrDp = 25.4 / 160
|
||||
// monitorScale is the extra scale applied to
|
||||
// monitor outputs to compensate for the extra
|
||||
// viewing distance compared to phone and tables.
|
||||
monitorScale = 1.20
|
||||
// minDensity is the minimum pixels per dp to
|
||||
// ensure font and ui legibility on low-dpi
|
||||
// screens.
|
||||
minDensity = 1.25
|
||||
)
|
||||
+28
-41
@@ -10,6 +10,7 @@ import (
|
||||
|
||||
"gioui.org/app/internal/gpu"
|
||||
"gioui.org/app/internal/input"
|
||||
"gioui.org/app/internal/window"
|
||||
"gioui.org/io/event"
|
||||
"gioui.org/io/profile"
|
||||
"gioui.org/io/system"
|
||||
@@ -18,22 +19,11 @@ import (
|
||||
)
|
||||
|
||||
// WindowOption configures a Window.
|
||||
type Option func(opts *windowOptions)
|
||||
|
||||
type windowOptions struct {
|
||||
Width, Height unit.Value
|
||||
Title string
|
||||
}
|
||||
|
||||
type frameEvent struct {
|
||||
system.FrameEvent
|
||||
|
||||
sync bool
|
||||
}
|
||||
type Option func(opts *window.Options)
|
||||
|
||||
// Window represents an operating system window.
|
||||
type Window struct {
|
||||
driver *window
|
||||
driver window.Driver
|
||||
lastFrame time.Time
|
||||
drawStart time.Time
|
||||
gpu *gpu.GPU
|
||||
@@ -51,6 +41,12 @@ type Window struct {
|
||||
delayedDraw *time.Timer
|
||||
|
||||
queue Queue
|
||||
|
||||
callbacks callbacks
|
||||
}
|
||||
|
||||
type callbacks struct {
|
||||
w *Window
|
||||
}
|
||||
|
||||
// Queue is an event.Queue implementation that distributes system events
|
||||
@@ -62,19 +58,9 @@ type Queue struct {
|
||||
// driverEvent is sent when a new native driver
|
||||
// is available for the Window.
|
||||
type driverEvent struct {
|
||||
driver *window
|
||||
driver window.Driver
|
||||
}
|
||||
|
||||
// driver is the interface for the platform implementation
|
||||
// of a Window.
|
||||
var _ 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)
|
||||
// showTextInput updates the virtual keyboard state.
|
||||
showTextInput(show bool)
|
||||
} = (*window)(nil)
|
||||
|
||||
// Pre-allocate the ack event to avoid garbage.
|
||||
var ackEvent event.Event
|
||||
|
||||
@@ -90,7 +76,7 @@ var ackEvent event.Event
|
||||
//
|
||||
// BUG: Calling NewWindow more than once is not yet supported.
|
||||
func NewWindow(options ...Option) *Window {
|
||||
opts := &windowOptions{
|
||||
opts := &window.Options{
|
||||
Width: unit.Dp(800),
|
||||
Height: unit.Dp(600),
|
||||
Title: "Gio",
|
||||
@@ -107,6 +93,7 @@ func NewWindow(options ...Option) *Window {
|
||||
invalidates: make(chan struct{}, 1),
|
||||
frames: make(chan *op.Ops),
|
||||
}
|
||||
w.callbacks.w = w
|
||||
go w.run(opts)
|
||||
return w
|
||||
}
|
||||
@@ -141,9 +128,9 @@ func (w *Window) draw(size image.Point, frame *op.Ops) {
|
||||
now := time.Now()
|
||||
switch w.queue.q.TextInputState() {
|
||||
case input.TextInputOpen:
|
||||
w.driver.showTextInput(true)
|
||||
w.driver.ShowTextInput(true)
|
||||
case input.TextInputClose:
|
||||
w.driver.showTextInput(false)
|
||||
w.driver.ShowTextInput(false)
|
||||
}
|
||||
frameDur := now.Sub(w.lastFrame)
|
||||
frameDur = frameDur.Truncate(100 * time.Microsecond)
|
||||
@@ -186,7 +173,7 @@ func (w *Window) updateAnimation() {
|
||||
}
|
||||
if animate != w.animating {
|
||||
w.animating = animate
|
||||
w.driver.setAnimating(animate)
|
||||
w.driver.SetAnimating(animate)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -197,13 +184,13 @@ func (w *Window) setNextFrame(at time.Time) {
|
||||
}
|
||||
}
|
||||
|
||||
func (w *Window) setDriver(d *window) {
|
||||
w.event(driverEvent{d})
|
||||
func (c *callbacks) SetDriver(d window.Driver) {
|
||||
c.Event(driverEvent{d})
|
||||
}
|
||||
|
||||
func (w *Window) event(e event.Event) {
|
||||
w.in <- e
|
||||
<-w.ack
|
||||
func (c *callbacks) Event(e event.Event) {
|
||||
c.w.in <- e
|
||||
<-c.w.ack
|
||||
}
|
||||
|
||||
func (w *Window) waitAck() {
|
||||
@@ -226,10 +213,10 @@ func (w *Window) destroy(err error) {
|
||||
}
|
||||
}
|
||||
|
||||
func (w *Window) run(opts *windowOptions) {
|
||||
func (w *Window) run(opts *window.Options) {
|
||||
defer close(w.in)
|
||||
defer close(w.out)
|
||||
if err := createWindow(w, opts); err != nil {
|
||||
if err := window.NewWindow(&w.callbacks, opts); err != nil {
|
||||
w.out <- system.DestroyEvent{Err: err}
|
||||
return
|
||||
}
|
||||
@@ -260,7 +247,7 @@ func (w *Window) run(opts *windowOptions) {
|
||||
w.updateAnimation()
|
||||
w.out <- e
|
||||
w.waitAck()
|
||||
case frameEvent:
|
||||
case window.FrameEvent:
|
||||
if e2.Size == (image.Point{}) {
|
||||
panic(errors.New("internal error: zero-sized Draw"))
|
||||
}
|
||||
@@ -280,7 +267,7 @@ func (w *Window) run(opts *windowOptions) {
|
||||
case w.out <- ackEvent:
|
||||
}
|
||||
if w.gpu != nil {
|
||||
if e2.sync {
|
||||
if e2.Sync {
|
||||
w.gpu.Refresh()
|
||||
}
|
||||
if err := w.gpu.Flush(); err != nil {
|
||||
@@ -290,7 +277,7 @@ func (w *Window) run(opts *windowOptions) {
|
||||
return
|
||||
}
|
||||
} else {
|
||||
ctx, err := newContext(w.driver)
|
||||
ctx, err := w.driver.NewContext()
|
||||
if err != nil {
|
||||
w.destroy(err)
|
||||
return
|
||||
@@ -302,7 +289,7 @@ func (w *Window) run(opts *windowOptions) {
|
||||
}
|
||||
}
|
||||
w.draw(e2.Size, frame)
|
||||
if e2.sync {
|
||||
if e2.Sync {
|
||||
if err := w.gpu.Flush(); err != nil {
|
||||
w.gpu.Release()
|
||||
w.gpu = nil
|
||||
@@ -337,7 +324,7 @@ func (q *Queue) Events(k event.Key) []event.Event {
|
||||
|
||||
// Title sets the title of the window.
|
||||
func Title(t string) Option {
|
||||
return func(opts *windowOptions) {
|
||||
return func(opts *window.Options) {
|
||||
opts.Title = t
|
||||
}
|
||||
}
|
||||
@@ -350,7 +337,7 @@ func Size(w, h unit.Value) Option {
|
||||
if h.V <= 0 {
|
||||
panic("height must be larger than or equal to 0")
|
||||
}
|
||||
return func(opts *windowOptions) {
|
||||
return func(opts *window.Options) {
|
||||
opts.Width = w
|
||||
opts.Height = h
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user