diff --git a/app/app.go b/app/app.go index e4b4e4c6..71bc57be 100644 --- a/app/app.go +++ b/app/app.go @@ -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() } diff --git a/app/datadir_android.go b/app/datadir_android.go index ad0da624..2804247b 100644 --- a/app/datadir_android.go +++ b/app/datadir_android.go @@ -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 -} diff --git a/app/GioActivity.java b/app/internal/window/GioActivity.java similarity index 100% rename from app/GioActivity.java rename to app/internal/window/GioActivity.java diff --git a/app/GioView.java b/app/internal/window/GioView.java similarity index 100% rename from app/GioView.java rename to app/internal/window/GioView.java diff --git a/app/egl.go b/app/internal/window/egl.go similarity index 99% rename from app/egl.go rename to app/internal/window/egl.go index 3c5f2cd6..ee48b602 100644 --- a/app/egl.go +++ b/app/internal/window/egl.go @@ -2,7 +2,7 @@ // +build linux windows -package app +package window import ( "errors" diff --git a/app/egl_android.go b/app/internal/window/egl_android.go similarity index 96% rename from app/egl_android.go rename to app/internal/window/egl_android.go index f12fb8b7..afaa83ee 100644 --- a/app/egl_android.go +++ b/app/internal/window/egl_android.go @@ -1,6 +1,6 @@ // SPDX-License-Identifier: Unlicense OR MIT -package app +package window /* #include diff --git a/app/egl_linux.go b/app/internal/window/egl_linux.go similarity index 95% rename from app/egl_linux.go rename to app/internal/window/egl_linux.go index eac74c30..da83c6e1 100644 --- a/app/egl_linux.go +++ b/app/internal/window/egl_linux.go @@ -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) +} diff --git a/app/egl_wayland.go b/app/internal/window/egl_wayland.go similarity index 99% rename from app/egl_wayland.go rename to app/internal/window/egl_wayland.go index 0fa3774f..0fdb6014 100644 --- a/app/egl_wayland.go +++ b/app/internal/window/egl_wayland.go @@ -2,7 +2,7 @@ // +build linux,!android -package app +package window import ( "errors" diff --git a/app/egl_windows.go b/app/internal/window/egl_windows.go similarity index 98% rename from app/egl_windows.go rename to app/internal/window/egl_windows.go index 89260d62..0e61c42b 100644 --- a/app/egl_windows.go +++ b/app/internal/window/egl_windows.go @@ -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) +} diff --git a/app/framework_ios.h b/app/internal/window/framework_ios.h similarity index 100% rename from app/framework_ios.h rename to app/internal/window/framework_ios.h diff --git a/app/gl_ios.go b/app/internal/window/gl_ios.go similarity index 97% rename from app/gl_ios.go rename to app/internal/window/gl_ios.go index ab509df6..2ad13a3c 100644 --- a/app/gl_ios.go +++ b/app/internal/window/gl_ios.go @@ -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) +} diff --git a/app/gl_ios.h b/app/internal/window/gl_ios.h similarity index 100% rename from app/gl_ios.h rename to app/internal/window/gl_ios.h diff --git a/app/gl_ios.m b/app/internal/window/gl_ios.m similarity index 100% rename from app/gl_ios.m rename to app/internal/window/gl_ios.m diff --git a/app/gl_js.go b/app/internal/window/gl_js.go similarity index 94% rename from app/gl_js.go rename to app/internal/window/gl_js.go index 7256c74c..acb49e27 100644 --- a/app/gl_js.go +++ b/app/internal/window/gl_js.go @@ -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) +} diff --git a/app/gl_macos.go b/app/internal/window/gl_macos.go similarity index 92% rename from app/gl_macos.go rename to app/internal/window/gl_macos.go index 21bc681f..98eee70b 100644 --- a/app/gl_macos.go +++ b/app/internal/window/gl_macos.go @@ -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) +} diff --git a/app/gl_macos.h b/app/internal/window/gl_macos.h similarity index 100% rename from app/gl_macos.h rename to app/internal/window/gl_macos.h diff --git a/app/gl_macos.m b/app/internal/window/gl_macos.m similarity index 100% rename from app/gl_macos.m rename to app/internal/window/gl_macos.m diff --git a/app/os_android.c b/app/internal/window/os_android.c similarity index 100% rename from app/os_android.c rename to app/internal/window/os_android.c diff --git a/app/os_android.go b/app/internal/window/os_android.go similarity index 93% rename from app/os_android.go rename to app/internal/window/os_android.go index 5646cc2f..850b010f 100644 --- a/app/os_android.go +++ b/app/internal/window/os_android.go @@ -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 } diff --git a/app/os_android.h b/app/internal/window/os_android.h similarity index 100% rename from app/os_android.h rename to app/internal/window/os_android.h diff --git a/app/os_ios.go b/app/internal/window/os_ios.go similarity index 88% rename from app/os_ios.go rename to app/internal/window/os_ios.go index 84e2f883..edee8dd0 100644 --- a/app/os_ios.go +++ b/app/internal/window/os_ios.go @@ -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() { } diff --git a/app/os_ios.h b/app/internal/window/os_ios.h similarity index 100% rename from app/os_ios.h rename to app/internal/window/os_ios.h diff --git a/app/os_ios.m b/app/internal/window/os_ios.m similarity index 100% rename from app/os_ios.m rename to app/internal/window/os_ios.m diff --git a/app/os_js.go b/app/internal/window/os_js.go similarity index 94% rename from app/os_js.go rename to app/internal/window/os_js.go index 0432089b..588308fe 100644 --- a/app/os_js.go +++ b/app/internal/window/os_js.go @@ -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 } diff --git a/app/os_macos.go b/app/internal/window/os_macos.go similarity index 93% rename from app/os_macos.go rename to app/internal/window/os_macos.go index 8d125225..17c279dd 100644 --- a/app/os_macos.go +++ b/app/internal/window/os_macos.go @@ -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 { diff --git a/app/os_macos.h b/app/internal/window/os_macos.h similarity index 100% rename from app/os_macos.h rename to app/internal/window/os_macos.h diff --git a/app/os_macos.m b/app/internal/window/os_macos.m similarity index 100% rename from app/os_macos.m rename to app/internal/window/os_macos.m diff --git a/app/os_wayland.c b/app/internal/window/os_wayland.c similarity index 100% rename from app/os_wayland.c rename to app/internal/window/os_wayland.c diff --git a/app/os_wayland.go b/app/internal/window/os_wayland.go similarity index 97% rename from app/os_wayland.go rename to app/internal/window/os_wayland.go index 1019791e..9fbd57d9 100644 --- a/app/os_wayland.go +++ b/app/internal/window/os_wayland.go @@ -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. diff --git a/app/os_wayland.h b/app/internal/window/os_wayland.h similarity index 100% rename from app/os_wayland.h rename to app/internal/window/os_wayland.h diff --git a/app/os_windows.go b/app/internal/window/os_windows.go similarity index 96% rename from app/os_windows.go rename to app/internal/window/os_windows.go index 7520d7ae..b9fcaf89 100644 --- a/app/os_windows.go +++ b/app/internal/window/os_windows.go @@ -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 diff --git a/app/runmain.go b/app/internal/window/runmain.go similarity index 90% rename from app/runmain.go rename to app/internal/window/runmain.go index 7d7eb7be..17d0c8d6 100644 --- a/app/runmain.go +++ b/app/internal/window/runmain.go @@ -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 diff --git a/app/runmain_ios.go b/app/internal/window/runmain_ios.go similarity index 59% rename from app/runmain_ios.go rename to app/internal/window/runmain_ios.go index 02b08df6..461c6977 100644 --- a/app/runmain_ios.go +++ b/app/internal/window/runmain_ios.go @@ -1,6 +1,8 @@ +// SPDX-License-Identifier: Unlicense OR MIT + // +build darwin,ios -package app +package window import "C" diff --git a/app/wayland_text_input.c b/app/internal/window/wayland_text_input.c similarity index 100% rename from app/wayland_text_input.c rename to app/internal/window/wayland_text_input.c diff --git a/app/wayland_text_input.h b/app/internal/window/wayland_text_input.h similarity index 100% rename from app/wayland_text_input.h rename to app/internal/window/wayland_text_input.h diff --git a/app/wayland_xdg_decoration.c b/app/internal/window/wayland_xdg_decoration.c similarity index 100% rename from app/wayland_xdg_decoration.c rename to app/internal/window/wayland_xdg_decoration.c diff --git a/app/wayland_xdg_decoration.h b/app/internal/window/wayland_xdg_decoration.h similarity index 100% rename from app/wayland_xdg_decoration.h rename to app/internal/window/wayland_xdg_decoration.h diff --git a/app/wayland_xdg_shell.c b/app/internal/window/wayland_xdg_shell.c similarity index 100% rename from app/wayland_xdg_shell.c rename to app/internal/window/wayland_xdg_shell.c diff --git a/app/wayland_xdg_shell.h b/app/internal/window/wayland_xdg_shell.h similarity index 100% rename from app/wayland_xdg_shell.h rename to app/internal/window/wayland_xdg_shell.h diff --git a/app/internal/window/window.go b/app/internal/window/window.go new file mode 100644 index 00000000..fd9610ca --- /dev/null +++ b/app/internal/window/window.go @@ -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 +) diff --git a/app/window.go b/app/window.go index 42ac61cd..e2b24f30 100644 --- a/app/window.go +++ b/app/window.go @@ -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 }