From d58d386b9b39cb3ac5dbddeb7a5bd5d7f8afabfe Mon Sep 17 00:00:00 2001 From: Elias Naur Date: Fri, 15 Dec 2023 16:45:02 -0600 Subject: [PATCH] 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 --- app/os_android.go | 34 +++++++++++----------------------- app/os_ios.go | 3 --- app/os_js.go | 12 ------------ app/os_macos.go | 38 ++++++++++++++++---------------------- app/os_wayland.go | 20 ++++++-------------- app/os_windows.go | 19 ------------------- app/os_x11.go | 10 ---------- app/system.go | 36 ------------------------------------ app/window.go | 31 ++++++++----------------------- 9 files changed, 41 insertions(+), 162 deletions(-) diff --git a/app/os_android.go b/app/os_android.go index 3819d2f8..f16cf934 100644 --- a/app/os_android.go +++ b/app/os_android.go @@ -161,7 +161,7 @@ type window struct { fontScale float32 insets pixelInsets - stage Stage + visible bool started 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.view = view + w.visible = false w.handle = cgo.NewHandle(w) w.loadConfig(env, class) w.setConfig(env, cnf) w.SetInputHint(w.inputHint) - w.setStage(StagePaused) w.processEvent(AndroidViewEvent{View: uintptr(view)}) 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) { w := cgo.Handle(handle).Value().(*window) w.started = false - w.setStage(StagePaused) + w.visible = false } //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) { w := cgo.Handle(handle).Value().(*window) w.win = nil - w.setStage(StagePaused) + w.visible = false } //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) { w := cgo.Handle(view).Value().(*window) w.loadConfig(env, class) - if w.stage >= StageInactive { - w.draw(env, true) - } + w.draw(env, true) } //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 { return } - if w.stage < StageInactive { - return - } - if w.animating { + if w.visible && w.animating { w.draw(env, false) 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), right: int(right), } - if w.stage >= StageInactive { - w.draw(env, true) - } + w.draw(env, true) } //export Java_org_gioui_GioView_initializeAccessibilityNodeInfo @@ -816,18 +809,10 @@ func (w *window) setVisible(env *C.JNIEnv) { if width == 0 || height == 0 { return } - w.setStage(StageRunning) + w.visible = 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 { if C.ANativeWindow_setBuffersGeometry(w.win, 0, 0, C.int32_t(visID)) != 0 { 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) { + if !w.visible { + return + } size := image.Pt(int(C.ANativeWindow_getWidth(w.win)), int(C.ANativeWindow_getHeight(w.win))) if size != w.config.Size { w.config.Size = size diff --git a/app/os_ios.go b/app/os_ios.go index 8df0dfd9..2ce093cb 100644 --- a/app/os_ios.go +++ b/app/os_ios.go @@ -138,7 +138,6 @@ func onCreate(view, controller C.CFTypeRef) { w.displayLink = dl C.gio_viewSetHandle(view, C.uintptr_t(cgo.NewHandle(w))) w.Configure(wopts.options) - w.ProcessEvent(StageEvent{Stage: StageRunning}) w.ProcessEvent(UIKitViewEvent{ViewController: uintptr(controller)}) } @@ -189,14 +188,12 @@ func (w *window) draw(sync bool) { func onStop(h C.uintptr_t) { w := viewFor(h) w.hidden = true - w.ProcessEvent(StageEvent{Stage: StagePaused}) } //export onStart func onStart(h C.uintptr_t) { w := viewFor(h) w.hidden = false - w.ProcessEvent(StageEvent{Stage: StageRunning}) w.draw(true) } diff --git a/app/os_js.go b/app/os_js.go index 352b8413..536a1223 100644 --- a/app/os_js.go +++ b/app/os_js.go @@ -115,7 +115,6 @@ func newWindow(win *callbacks, options []Option) { w.Configure(options) w.blur() w.processEvent(JSViewEvent{Element: cont}) - w.processEvent(StageEvent{Stage: StageRunning}) w.resize() w.draw(true) } @@ -195,17 +194,6 @@ func (w *window) addEventListeners() { } 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.pointerEvent(pointer.Move, 0, 0, args[0]) return nil diff --git a/app/os_macos.go b/app/os_macos.go index f743980d..6be39508 100644 --- a/app/os_macos.go +++ b/app/os_macos.go @@ -309,7 +309,8 @@ type AppKitViewEvent struct { type window struct { view C.CFTypeRef w *callbacks - stage Stage + anim bool + visible bool displayLink *displayLink // redraw is a single entry channel for making sure only one // 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) SetAnimating(anim bool) { - if anim { + w.anim = anim + if w.anim && w.visible { w.displayLink.Start() } else { 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 func gio_onKeys(h C.uintptr_t, cstr C.CFTypeRef, ti C.double, mods C.NSUInteger, keyDown C.bool) { str := nsstringToString(cstr) @@ -619,13 +613,6 @@ func gio_onDraw(h C.uintptr_t) { func gio_onFocus(h C.uintptr_t, focus C.int) { w := windowFor(h) 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) } @@ -804,6 +791,10 @@ func (w *window) draw() { case <-w.redraw: default: } + w.visible = true + if w.anim { + w.SetAnimating(w.anim) + } w.scale = float32(C.getViewBackingScale(w.view)) wf, hf := float32(C.viewWidth(w.view)), float32(C.viewHeight(w.view)) sz := image.Point{ @@ -818,7 +809,6 @@ func (w *window) draw() { return } cfg := configFor(w.scale) - w.setStage(StageRunning) w.ProcessEvent(frameEvent{ FrameEvent: FrameEvent{ 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)}) } else { 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 func gio_onHide(h C.uintptr_t) { w := windowFor(h) - w.setStage(StagePaused) + w.visible = false + w.SetAnimating(w.anim) } //export gio_onShow func gio_onShow(h C.uintptr_t) { w := windowFor(h) - w.setStage(StageRunning) + w.draw() } //export gio_onFullscreen @@ -956,7 +948,9 @@ func (w *window) init() error { return } w.runOnMain(func() { - C.setNeedsDisplay(w.view) + if w.visible { + C.setNeedsDisplay(w.view) + } }) }) w.displayLink = dl diff --git a/app/os_wayland.go b/app/os_wayland.go index a936b731..b3436af5 100644 --- a/app/os_wayland.go +++ b/app/os_wayland.go @@ -199,7 +199,7 @@ type window struct { dir f32.Point } - stage Stage + configured bool lastFrameCallback *C.struct_wl_callback animating bool @@ -549,7 +549,7 @@ func gio_onXdgSurfaceConfigure(data unsafe.Pointer, wmSurf *C.struct_xdg_surface w := callbackLoad(data).(*window) w.serial = serial C.xdg_surface_ack_configure(wmSurf, serial) - w.setStage(StageRunning) + w.configured = 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)) w.draw(true) } - if !found { - w.setStage(StagePaused) - } else { - w.setStage(StageRunning) + if found { w.draw(true) } } @@ -1755,6 +1752,9 @@ func (w *window) getConfig() (image.Point, unit.Metric) { } func (w *window) draw(sync bool) { + if !w.configured { + return + } w.flushScroll() size, cfg := w.getConfig() 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 { return w.disp.disp } diff --git a/app/os_windows.go b/app/os_windows.go index c73793bc..089a305a 100644 --- a/app/os_windows.go +++ b/app/os_windows.go @@ -39,7 +39,6 @@ type window struct { hwnd syscall.Handle hdc syscall.Handle w *callbacks - stage Stage pointerBtns pointer.Buttons // 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: w.focused = 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: if w.config.Decorated { // Let the system handle it. @@ -348,15 +339,12 @@ func windowProc(hwnd syscall.Handle, msg uint32, wParam, lParam uintptr) uintptr switch wParam { case windows.SIZE_MINIMIZED: w.config.Mode = Minimized - w.setStage(StagePaused) case windows.SIZE_MAXIMIZED: w.config.Mode = Maximized - w.setStage(StageRunning) case windows.SIZE_RESTORED: if w.config.Mode != Fullscreen { w.config.Mode = Windowed } - w.setStage(StageRunning) } case windows.WM_GETMINMAXINFO: 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) { if w.config.Size.X == 0 || w.config.Size.Y == 0 { return diff --git a/app/os_x11.go b/app/os_x11.go index 0745e488..32df7407 100644 --- a/app/os_x11.go +++ b/app/os_x11.go @@ -95,7 +95,6 @@ type x11Window struct { // _NET_WM_STATE_MAXIMIZED_VERT wmStateMaximizedVert C.Atom } - stage Stage metric unit.Metric notify struct { 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 } -func (w *x11Window) setStage(s Stage) { - if s == w.stage { - return - } - w.stage = s - w.ProcessEvent(StageEvent{Stage: s}) -} - func (w *x11Window) dispatch() { if w.x == nil { // Only Invalidate can wake us up. @@ -879,7 +870,6 @@ func newX11Window(gioWin *callbacks, options []Option) error { C.XMapWindow(dpy, win) w.Configure(options) w.ProcessEvent(X11ViewEvent{Display: unsafe.Pointer(dpy), Window: uintptr(win)}) - w.setStage(StageRunning) return nil } diff --git a/app/system.go b/app/system.go index e531313b..2c9acc93 100644 --- a/app/system.go +++ b/app/system.go @@ -10,40 +10,4 @@ type DestroyEvent struct { 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() {} diff --git a/app/window.go b/app/window.go index fe2fd664..3ffd953a 100644 --- a/app/window.go +++ b/app/window.go @@ -7,6 +7,7 @@ import ( "fmt" "image" "image/color" + "reflect" "runtime" "sync" "time" @@ -53,7 +54,6 @@ type Window struct { update chan time.Time } - stage Stage animating bool hasNextFrame bool nextFrame time.Time @@ -109,7 +109,6 @@ type eventSummary struct { cfg *ConfigEvent view *ViewEvent frame *frameEvent - stage *StageEvent destroy *DestroyEvent } @@ -328,7 +327,7 @@ func (w *Window) updateAnimation() { return } animate := false - if w.stage >= StageInactive && w.hasNextFrame { + if w.hasNextFrame { if dt := time.Until(w.nextFrame); dt <= 0 { animate = true } else { @@ -566,10 +565,6 @@ func (c *callbacks) nextEvent() (event.Event, bool) { e := *s.cfg s.cfg = nil return e, true - case s.stage != nil: - e := *s.stage - s.stage = nil - return e, true case s.frame != nil: e := *s.frame s.frame = nil @@ -582,28 +577,12 @@ func (c *callbacks) nextEvent() (event.Event, bool) { func (w *Window) processEvent(e event.Event) bool { 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: w.coalesced.wakeup = true case frameEvent: if e2.Size == (image.Point{}) { panic(errors.New("internal error: zero-sized Draw")) } - if w.stage < StageInactive { - // No drawing if not visible. - break - } w.metric = e2.Metric w.hasNextFrame = false e2.Frame = w.driver.Frame @@ -643,6 +622,12 @@ func (w *Window) processEvent(e event.Event) bool { } w.coalesced.destroy = &e2 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 case ConfigEvent: w.decorations.Config = e2.Config