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