app: [API] remove StageEvent and Stage

StageEvent served only redundant purposes:

- To detect whether the window has focus. That is covered by
  key.FocusEvent.
- To detect whether the window is currently visible. That is covered by
  the absence or presence of FrameEvents.
- To detect when the window native handle is valid. That is
  covered by ViewEvent.

Signed-off-by: Elias Naur <mail@eliasnaur.com>
This commit is contained in:
Elias Naur
2023-12-15 16:45:02 -06:00
parent f3fc0d62b8
commit d58d386b9b
9 changed files with 41 additions and 162 deletions
+11 -23
View File
@@ -161,7 +161,7 @@ type window struct {
fontScale float32 fontScale float32
insets pixelInsets insets pixelInsets
stage Stage visible bool
started bool started bool
animating bool animating bool
@@ -509,11 +509,11 @@ func Java_org_gioui_GioView_onCreateView(env *C.JNIEnv, class C.jclass, view C.j
w.detach(env) w.detach(env)
} }
w.view = view w.view = view
w.visible = false
w.handle = cgo.NewHandle(w) w.handle = cgo.NewHandle(w)
w.loadConfig(env, class) w.loadConfig(env, class)
w.setConfig(env, cnf) w.setConfig(env, cnf)
w.SetInputHint(w.inputHint) w.SetInputHint(w.inputHint)
w.setStage(StagePaused)
w.processEvent(AndroidViewEvent{View: uintptr(view)}) w.processEvent(AndroidViewEvent{View: uintptr(view)})
return C.jlong(w.handle) return C.jlong(w.handle)
} }
@@ -528,7 +528,7 @@ func Java_org_gioui_GioView_onDestroyView(env *C.JNIEnv, class C.jclass, handle
func Java_org_gioui_GioView_onStopView(env *C.JNIEnv, class C.jclass, handle C.jlong) { func Java_org_gioui_GioView_onStopView(env *C.JNIEnv, class C.jclass, handle C.jlong) {
w := cgo.Handle(handle).Value().(*window) w := cgo.Handle(handle).Value().(*window)
w.started = false w.started = false
w.setStage(StagePaused) w.visible = false
} }
//export Java_org_gioui_GioView_onStartView //export Java_org_gioui_GioView_onStartView
@@ -544,7 +544,7 @@ func Java_org_gioui_GioView_onStartView(env *C.JNIEnv, class C.jclass, handle C.
func Java_org_gioui_GioView_onSurfaceDestroyed(env *C.JNIEnv, class C.jclass, handle C.jlong) { func Java_org_gioui_GioView_onSurfaceDestroyed(env *C.JNIEnv, class C.jclass, handle C.jlong) {
w := cgo.Handle(handle).Value().(*window) w := cgo.Handle(handle).Value().(*window)
w.win = nil w.win = nil
w.setStage(StagePaused) w.visible = false
} }
//export Java_org_gioui_GioView_onSurfaceChanged //export Java_org_gioui_GioView_onSurfaceChanged
@@ -566,9 +566,7 @@ func Java_org_gioui_GioView_onLowMemory(env *C.JNIEnv, class C.jclass) {
func Java_org_gioui_GioView_onConfigurationChanged(env *C.JNIEnv, class C.jclass, view C.jlong) { func Java_org_gioui_GioView_onConfigurationChanged(env *C.JNIEnv, class C.jclass, view C.jlong) {
w := cgo.Handle(view).Value().(*window) w := cgo.Handle(view).Value().(*window)
w.loadConfig(env, class) w.loadConfig(env, class)
if w.stage >= StageInactive { w.draw(env, true)
w.draw(env, true)
}
} }
//export Java_org_gioui_GioView_onFrameCallback //export Java_org_gioui_GioView_onFrameCallback
@@ -577,10 +575,7 @@ func Java_org_gioui_GioView_onFrameCallback(env *C.JNIEnv, class C.jclass, view
if !exist { if !exist {
return return
} }
if w.stage < StageInactive { if w.visible && w.animating {
return
}
if w.animating {
w.draw(env, false) w.draw(env, false)
callVoidMethod(env, w.view, gioView.postFrameCallback) callVoidMethod(env, w.view, gioView.postFrameCallback)
} }
@@ -610,9 +605,7 @@ func Java_org_gioui_GioView_onWindowInsets(env *C.JNIEnv, class C.jclass, view C
left: int(left), left: int(left),
right: int(right), right: int(right),
} }
if w.stage >= StageInactive { w.draw(env, true)
w.draw(env, true)
}
} }
//export Java_org_gioui_GioView_initializeAccessibilityNodeInfo //export Java_org_gioui_GioView_initializeAccessibilityNodeInfo
@@ -816,18 +809,10 @@ func (w *window) setVisible(env *C.JNIEnv) {
if width == 0 || height == 0 { if width == 0 || height == 0 {
return return
} }
w.setStage(StageRunning) w.visible = true
w.draw(env, true) w.draw(env, true)
} }
func (w *window) setStage(stage Stage) {
if stage == w.stage {
return
}
w.stage = stage
w.processEvent(StageEvent{stage})
}
func (w *window) setVisual(visID int) error { func (w *window) setVisual(visID int) error {
if C.ANativeWindow_setBuffersGeometry(w.win, 0, 0, C.int32_t(visID)) != 0 { if C.ANativeWindow_setBuffersGeometry(w.win, 0, 0, C.int32_t(visID)) != 0 {
return errors.New("ANativeWindow_setBuffersGeometry failed") return errors.New("ANativeWindow_setBuffersGeometry failed")
@@ -864,6 +849,9 @@ func (w *window) SetAnimating(anim bool) {
} }
func (w *window) draw(env *C.JNIEnv, sync bool) { func (w *window) draw(env *C.JNIEnv, sync bool) {
if !w.visible {
return
}
size := image.Pt(int(C.ANativeWindow_getWidth(w.win)), int(C.ANativeWindow_getHeight(w.win))) size := image.Pt(int(C.ANativeWindow_getWidth(w.win)), int(C.ANativeWindow_getHeight(w.win)))
if size != w.config.Size { if size != w.config.Size {
w.config.Size = size w.config.Size = size
-3
View File
@@ -138,7 +138,6 @@ func onCreate(view, controller C.CFTypeRef) {
w.displayLink = dl w.displayLink = dl
C.gio_viewSetHandle(view, C.uintptr_t(cgo.NewHandle(w))) C.gio_viewSetHandle(view, C.uintptr_t(cgo.NewHandle(w)))
w.Configure(wopts.options) w.Configure(wopts.options)
w.ProcessEvent(StageEvent{Stage: StageRunning})
w.ProcessEvent(UIKitViewEvent{ViewController: uintptr(controller)}) w.ProcessEvent(UIKitViewEvent{ViewController: uintptr(controller)})
} }
@@ -189,14 +188,12 @@ func (w *window) draw(sync bool) {
func onStop(h C.uintptr_t) { func onStop(h C.uintptr_t) {
w := viewFor(h) w := viewFor(h)
w.hidden = true w.hidden = true
w.ProcessEvent(StageEvent{Stage: StagePaused})
} }
//export onStart //export onStart
func onStart(h C.uintptr_t) { func onStart(h C.uintptr_t) {
w := viewFor(h) w := viewFor(h)
w.hidden = false w.hidden = false
w.ProcessEvent(StageEvent{Stage: StageRunning})
w.draw(true) w.draw(true)
} }
-12
View File
@@ -115,7 +115,6 @@ func newWindow(win *callbacks, options []Option) {
w.Configure(options) w.Configure(options)
w.blur() w.blur()
w.processEvent(JSViewEvent{Element: cont}) w.processEvent(JSViewEvent{Element: cont})
w.processEvent(StageEvent{Stage: StageRunning})
w.resize() w.resize()
w.draw(true) w.draw(true)
} }
@@ -195,17 +194,6 @@ func (w *window) addEventListeners() {
} }
return w.browserHistory.Call("back") return w.browserHistory.Call("back")
}) })
w.addEventListener(w.document, "visibilitychange", func(this js.Value, args []js.Value) interface{} {
ev := StageEvent{}
switch w.document.Get("visibilityState").String() {
case "hidden", "prerender", "unloaded":
ev.Stage = StagePaused
default:
ev.Stage = StageRunning
}
w.processEvent(ev)
return nil
})
w.addEventListener(w.cnv, "mousemove", func(this js.Value, args []js.Value) interface{} { w.addEventListener(w.cnv, "mousemove", func(this js.Value, args []js.Value) interface{} {
w.pointerEvent(pointer.Move, 0, 0, args[0]) w.pointerEvent(pointer.Move, 0, 0, args[0])
return nil return nil
+16 -22
View File
@@ -309,7 +309,8 @@ type AppKitViewEvent struct {
type window struct { type window struct {
view C.CFTypeRef view C.CFTypeRef
w *callbacks w *callbacks
stage Stage anim bool
visible bool
displayLink *displayLink displayLink *displayLink
// redraw is a single entry channel for making sure only one // redraw is a single entry channel for making sure only one
// display link redraw request is in flight. // display link redraw request is in flight.
@@ -507,7 +508,8 @@ func (w *window) ShowTextInput(show bool) {}
func (w *window) SetInputHint(_ key.InputHint) {} func (w *window) SetInputHint(_ key.InputHint) {}
func (w *window) SetAnimating(anim bool) { func (w *window) SetAnimating(anim bool) {
if anim { w.anim = anim
if w.anim && w.visible {
w.displayLink.Start() w.displayLink.Start()
} else { } else {
w.displayLink.Stop() w.displayLink.Stop()
@@ -524,14 +526,6 @@ func (w *window) runOnMain(f func()) {
}) })
} }
func (w *window) setStage(stage Stage) {
if stage == w.stage {
return
}
w.stage = stage
w.ProcessEvent(StageEvent{Stage: stage})
}
//export gio_onKeys //export gio_onKeys
func gio_onKeys(h C.uintptr_t, cstr C.CFTypeRef, ti C.double, mods C.NSUInteger, keyDown C.bool) { func gio_onKeys(h C.uintptr_t, cstr C.CFTypeRef, ti C.double, mods C.NSUInteger, keyDown C.bool) {
str := nsstringToString(cstr) str := nsstringToString(cstr)
@@ -619,13 +613,6 @@ func gio_onDraw(h C.uintptr_t) {
func gio_onFocus(h C.uintptr_t, focus C.int) { func gio_onFocus(h C.uintptr_t, focus C.int) {
w := windowFor(h) w := windowFor(h)
w.ProcessEvent(key.FocusEvent{Focus: focus == 1}) w.ProcessEvent(key.FocusEvent{Focus: focus == 1})
if w.stage >= StageInactive {
if focus == 0 {
w.setStage(StageInactive)
} else {
w.setStage(StageRunning)
}
}
w.SetCursor(w.cursor) w.SetCursor(w.cursor)
} }
@@ -804,6 +791,10 @@ func (w *window) draw() {
case <-w.redraw: case <-w.redraw:
default: default:
} }
w.visible = true
if w.anim {
w.SetAnimating(w.anim)
}
w.scale = float32(C.getViewBackingScale(w.view)) w.scale = float32(C.getViewBackingScale(w.view))
wf, hf := float32(C.viewWidth(w.view)), float32(C.viewHeight(w.view)) wf, hf := float32(C.viewWidth(w.view)), float32(C.viewHeight(w.view))
sz := image.Point{ sz := image.Point{
@@ -818,7 +809,6 @@ func (w *window) draw() {
return return
} }
cfg := configFor(w.scale) cfg := configFor(w.scale)
w.setStage(StageRunning)
w.ProcessEvent(frameEvent{ w.ProcessEvent(frameEvent{
FrameEvent: FrameEvent{ FrameEvent: FrameEvent{
Now: time.Now(), Now: time.Now(),
@@ -865,7 +855,8 @@ func gio_onAttached(h C.uintptr_t, attached C.int) {
w.ProcessEvent(AppKitViewEvent{View: uintptr(w.view), Layer: uintptr(layer)}) w.ProcessEvent(AppKitViewEvent{View: uintptr(w.view), Layer: uintptr(layer)})
} else { } else {
w.ProcessEvent(AppKitViewEvent{}) w.ProcessEvent(AppKitViewEvent{})
w.setStage(StagePaused) w.visible = false
w.SetAnimating(w.anim)
} }
} }
@@ -882,13 +873,14 @@ func gio_onDestroy(h C.uintptr_t) {
//export gio_onHide //export gio_onHide
func gio_onHide(h C.uintptr_t) { func gio_onHide(h C.uintptr_t) {
w := windowFor(h) w := windowFor(h)
w.setStage(StagePaused) w.visible = false
w.SetAnimating(w.anim)
} }
//export gio_onShow //export gio_onShow
func gio_onShow(h C.uintptr_t) { func gio_onShow(h C.uintptr_t) {
w := windowFor(h) w := windowFor(h)
w.setStage(StageRunning) w.draw()
} }
//export gio_onFullscreen //export gio_onFullscreen
@@ -956,7 +948,9 @@ func (w *window) init() error {
return return
} }
w.runOnMain(func() { w.runOnMain(func() {
C.setNeedsDisplay(w.view) if w.visible {
C.setNeedsDisplay(w.view)
}
}) })
}) })
w.displayLink = dl w.displayLink = dl
+6 -14
View File
@@ -199,7 +199,7 @@ type window struct {
dir f32.Point dir f32.Point
} }
stage Stage configured bool
lastFrameCallback *C.struct_wl_callback lastFrameCallback *C.struct_wl_callback
animating bool animating bool
@@ -549,7 +549,7 @@ func gio_onXdgSurfaceConfigure(data unsafe.Pointer, wmSurf *C.struct_xdg_surface
w := callbackLoad(data).(*window) w := callbackLoad(data).(*window)
w.serial = serial w.serial = serial
C.xdg_surface_ack_configure(wmSurf, serial) C.xdg_surface_ack_configure(wmSurf, serial)
w.setStage(StageRunning) w.configured = true
w.draw(true) w.draw(true)
} }
@@ -1738,10 +1738,7 @@ func (w *window) updateOutputs() {
C.wl_surface_set_buffer_scale(w.surf, C.int32_t(w.scale)) C.wl_surface_set_buffer_scale(w.surf, C.int32_t(w.scale))
w.draw(true) w.draw(true)
} }
if !found { if found {
w.setStage(StagePaused)
} else {
w.setStage(StageRunning)
w.draw(true) w.draw(true)
} }
} }
@@ -1755,6 +1752,9 @@ func (w *window) getConfig() (image.Point, unit.Metric) {
} }
func (w *window) draw(sync bool) { func (w *window) draw(sync bool) {
if !w.configured {
return
}
w.flushScroll() w.flushScroll()
size, cfg := w.getConfig() size, cfg := w.getConfig()
if cfg == (unit.Metric{}) { if cfg == (unit.Metric{}) {
@@ -1785,14 +1785,6 @@ func (w *window) draw(sync bool) {
}) })
} }
func (w *window) setStage(s Stage) {
if s == w.stage {
return
}
w.stage = s
w.ProcessEvent(StageEvent{Stage: s})
}
func (w *window) display() *C.struct_wl_display { func (w *window) display() *C.struct_wl_display {
return w.disp.disp return w.disp.disp
} }
-19
View File
@@ -39,7 +39,6 @@ type window struct {
hwnd syscall.Handle hwnd syscall.Handle
hdc syscall.Handle hdc syscall.Handle
w *callbacks w *callbacks
stage Stage
pointerBtns pointer.Buttons pointerBtns pointer.Buttons
// cursorIn tracks whether the cursor was inside the window according // cursorIn tracks whether the cursor was inside the window according
@@ -275,14 +274,6 @@ func windowProc(hwnd syscall.Handle, msg uint32, wParam, lParam uintptr) uintptr
case windows.WM_KILLFOCUS: case windows.WM_KILLFOCUS:
w.focused = false w.focused = false
w.ProcessEvent(key.FocusEvent{Focus: false}) w.ProcessEvent(key.FocusEvent{Focus: false})
case windows.WM_NCACTIVATE:
if w.stage >= StageInactive {
if wParam == windows.TRUE {
w.setStage(StageRunning)
} else {
w.setStage(StageInactive)
}
}
case windows.WM_NCHITTEST: case windows.WM_NCHITTEST:
if w.config.Decorated { if w.config.Decorated {
// Let the system handle it. // Let the system handle it.
@@ -348,15 +339,12 @@ func windowProc(hwnd syscall.Handle, msg uint32, wParam, lParam uintptr) uintptr
switch wParam { switch wParam {
case windows.SIZE_MINIMIZED: case windows.SIZE_MINIMIZED:
w.config.Mode = Minimized w.config.Mode = Minimized
w.setStage(StagePaused)
case windows.SIZE_MAXIMIZED: case windows.SIZE_MAXIMIZED:
w.config.Mode = Maximized w.config.Mode = Maximized
w.setStage(StageRunning)
case windows.SIZE_RESTORED: case windows.SIZE_RESTORED:
if w.config.Mode != Fullscreen { if w.config.Mode != Fullscreen {
w.config.Mode = Windowed w.config.Mode = Windowed
} }
w.setStage(StageRunning)
} }
case windows.WM_GETMINMAXINFO: case windows.WM_GETMINMAXINFO:
mm := (*windows.MinMaxInfo)(unsafe.Pointer(lParam)) mm := (*windows.MinMaxInfo)(unsafe.Pointer(lParam))
@@ -645,13 +633,6 @@ func (w *window) wakeup() {
} }
} }
func (w *window) setStage(s Stage) {
if s != w.stage {
w.stage = s
w.ProcessEvent(StageEvent{Stage: s})
}
}
func (w *window) draw(sync bool) { func (w *window) draw(sync bool) {
if w.config.Size.X == 0 || w.config.Size.Y == 0 { if w.config.Size.X == 0 || w.config.Size.Y == 0 {
return return
-10
View File
@@ -95,7 +95,6 @@ type x11Window struct {
// _NET_WM_STATE_MAXIMIZED_VERT // _NET_WM_STATE_MAXIMIZED_VERT
wmStateMaximizedVert C.Atom wmStateMaximizedVert C.Atom
} }
stage Stage
metric unit.Metric metric unit.Metric
notify struct { notify struct {
read, write int read, write int
@@ -437,14 +436,6 @@ func (w *x11Window) window() (C.Window, int, int) {
return w.xw, w.config.Size.X, w.config.Size.Y return w.xw, w.config.Size.X, w.config.Size.Y
} }
func (w *x11Window) setStage(s Stage) {
if s == w.stage {
return
}
w.stage = s
w.ProcessEvent(StageEvent{Stage: s})
}
func (w *x11Window) dispatch() { func (w *x11Window) dispatch() {
if w.x == nil { if w.x == nil {
// Only Invalidate can wake us up. // Only Invalidate can wake us up.
@@ -879,7 +870,6 @@ func newX11Window(gioWin *callbacks, options []Option) error {
C.XMapWindow(dpy, win) C.XMapWindow(dpy, win)
w.Configure(options) w.Configure(options)
w.ProcessEvent(X11ViewEvent{Display: unsafe.Pointer(dpy), Window: uintptr(win)}) w.ProcessEvent(X11ViewEvent{Display: unsafe.Pointer(dpy), Window: uintptr(win)})
w.setStage(StageRunning)
return nil return nil
} }
-36
View File
@@ -10,40 +10,4 @@ type DestroyEvent struct {
Err error Err error
} }
// A StageEvent is generated whenever the stage of a
// Window changes.
type StageEvent struct {
Stage Stage
}
// Stage of a Window.
type Stage uint8
const (
// StagePaused is the stage for windows that have no on-screen representation.
// Paused windows don't receive frames.
StagePaused Stage = iota
// StageInactive is the stage for windows that are visible, but not active.
// Inactive windows receive frames.
StageInactive
// StageRunning is for active and visible Windows.
// Running windows receive frames.
StageRunning
)
// String implements fmt.Stringer.
func (l Stage) String() string {
switch l {
case StagePaused:
return "StagePaused"
case StageInactive:
return "StageInactive"
case StageRunning:
return "StageRunning"
default:
panic("unexpected Stage value")
}
}
func (StageEvent) ImplementsEvent() {}
func (DestroyEvent) ImplementsEvent() {} func (DestroyEvent) ImplementsEvent() {}
+8 -23
View File
@@ -7,6 +7,7 @@ import (
"fmt" "fmt"
"image" "image"
"image/color" "image/color"
"reflect"
"runtime" "runtime"
"sync" "sync"
"time" "time"
@@ -53,7 +54,6 @@ type Window struct {
update chan time.Time update chan time.Time
} }
stage Stage
animating bool animating bool
hasNextFrame bool hasNextFrame bool
nextFrame time.Time nextFrame time.Time
@@ -109,7 +109,6 @@ type eventSummary struct {
cfg *ConfigEvent cfg *ConfigEvent
view *ViewEvent view *ViewEvent
frame *frameEvent frame *frameEvent
stage *StageEvent
destroy *DestroyEvent destroy *DestroyEvent
} }
@@ -328,7 +327,7 @@ func (w *Window) updateAnimation() {
return return
} }
animate := false animate := false
if w.stage >= StageInactive && w.hasNextFrame { if w.hasNextFrame {
if dt := time.Until(w.nextFrame); dt <= 0 { if dt := time.Until(w.nextFrame); dt <= 0 {
animate = true animate = true
} else { } else {
@@ -566,10 +565,6 @@ func (c *callbacks) nextEvent() (event.Event, bool) {
e := *s.cfg e := *s.cfg
s.cfg = nil s.cfg = nil
return e, true return e, true
case s.stage != nil:
e := *s.stage
s.stage = nil
return e, true
case s.frame != nil: case s.frame != nil:
e := *s.frame e := *s.frame
s.frame = nil s.frame = nil
@@ -582,28 +577,12 @@ func (c *callbacks) nextEvent() (event.Event, bool) {
func (w *Window) processEvent(e event.Event) bool { func (w *Window) processEvent(e event.Event) bool {
switch e2 := e.(type) { switch e2 := e.(type) {
case StageEvent:
if e2.Stage < StageInactive {
if w.gpu != nil {
w.ctx.Lock()
w.gpu.Release()
w.gpu = nil
w.ctx.Unlock()
}
}
w.stage = e2.Stage
w.updateAnimation()
w.coalesced.stage = &e2
case wakeupEvent: case wakeupEvent:
w.coalesced.wakeup = true w.coalesced.wakeup = true
case frameEvent: case frameEvent:
if e2.Size == (image.Point{}) { if e2.Size == (image.Point{}) {
panic(errors.New("internal error: zero-sized Draw")) panic(errors.New("internal error: zero-sized Draw"))
} }
if w.stage < StageInactive {
// No drawing if not visible.
break
}
w.metric = e2.Metric w.metric = e2.Metric
w.hasNextFrame = false w.hasNextFrame = false
e2.Frame = w.driver.Frame e2.Frame = w.driver.Frame
@@ -643,6 +622,12 @@ func (w *Window) processEvent(e event.Event) bool {
} }
w.coalesced.destroy = &e2 w.coalesced.destroy = &e2
case ViewEvent: case ViewEvent:
if reflect.ValueOf(e2).IsZero() && w.gpu != nil {
w.ctx.Lock()
w.gpu.Release()
w.gpu = nil
w.ctx.Unlock()
}
w.coalesced.view = &e2 w.coalesced.view = &e2
case ConfigEvent: case ConfigEvent:
w.decorations.Config = e2.Config w.decorations.Config = e2.Config