From 4a1b4c26425ecdb03bd0ad7574ca1db130b14337 Mon Sep 17 00:00:00 2001 From: Chris Waldon Date: Thu, 27 Jun 2024 13:56:28 -0400 Subject: [PATCH] app: add cross-platform empty view event detection Custom rendering applications need to be prepared to handle empty view events, as an empty view event is sent during window shutdown. However, the current implementation requires applications to write a platform-specific helper function for each supported platform in order to check whether a received view event is empty. This commit provides a safe, convenient, cross-platform method that applications can use to detect this special view event and respond to it. Signed-off-by: Chris Waldon --- app/app.go | 4 ++++ app/os_android.go | 3 +++ app/os_ios.go | 3 +++ app/os_js.go | 3 +++ app/os_macos.go | 3 +++ app/os_unix.go | 6 ++++++ app/os_windows.go | 3 +++ app/window.go | 3 +-- 8 files changed, 26 insertions(+), 2 deletions(-) diff --git a/app/app.go b/app/app.go index ef4a0fe2..a9bb0614 100644 --- a/app/app.go +++ b/app/app.go @@ -61,6 +61,10 @@ type FrameEvent struct { type ViewEvent interface { implementsViewEvent() ImplementsEvent() + // Valid will return true when the ViewEvent does contains valid handles. + // If a window receives an invalid ViewEvent, it should deinitialize any + // state referring to handles from a previous ViewEvent. + Valid() bool } // Insets is the space taken up by diff --git a/app/os_android.go b/app/os_android.go index a18bd083..3255d5f9 100644 --- a/app/os_android.go +++ b/app/os_android.go @@ -1495,3 +1495,6 @@ func Java_org_gioui_Gio_scheduleMainFuncs(env *C.JNIEnv, cls C.jclass) { func (AndroidViewEvent) implementsViewEvent() {} func (AndroidViewEvent) ImplementsEvent() {} +func (a AndroidViewEvent) Valid() bool { + return a != (AndroidViewEvent{}) +} diff --git a/app/os_ios.go b/app/os_ios.go index 53a22eaf..2a281cb8 100644 --- a/app/os_ios.go +++ b/app/os_ios.go @@ -441,3 +441,6 @@ func gio_runMain() { func (UIKitViewEvent) implementsViewEvent() {} func (UIKitViewEvent) ImplementsEvent() {} +func (u UIKitViewEvent) Valid() bool { + return u != (UIKitViewEvent{}) +} diff --git a/app/os_js.go b/app/os_js.go index 79e02783..66042917 100644 --- a/app/os_js.go +++ b/app/os_js.go @@ -822,3 +822,6 @@ func translateKey(k string) (key.Name, bool) { func (JSViewEvent) implementsViewEvent() {} func (JSViewEvent) ImplementsEvent() {} +func (j JSViewEvent) Valid() bool { + return !(j.Element.IsNull() || j.Element.IsUndefined()) +} diff --git a/app/os_macos.go b/app/os_macos.go index a1142c86..f133ab10 100644 --- a/app/os_macos.go +++ b/app/os_macos.go @@ -1074,3 +1074,6 @@ func convertMods(mods C.NSUInteger) key.Modifiers { func (AppKitViewEvent) implementsViewEvent() {} func (AppKitViewEvent) ImplementsEvent() {} +func (a AppKitViewEvent) Valid() bool { + return a != (AppKitViewEvent{}) +} diff --git a/app/os_unix.go b/app/os_unix.go index 933b8ff5..28181b8f 100644 --- a/app/os_unix.go +++ b/app/os_unix.go @@ -21,6 +21,9 @@ type X11ViewEvent struct { func (X11ViewEvent) implementsViewEvent() {} func (X11ViewEvent) ImplementsEvent() {} +func (x X11ViewEvent) Valid() bool { + return x != (X11ViewEvent{}) +} type WaylandViewEvent struct { // Display is the *wl_display returned by wl_display_connect. @@ -31,6 +34,9 @@ type WaylandViewEvent struct { func (WaylandViewEvent) implementsViewEvent() {} func (WaylandViewEvent) ImplementsEvent() {} +func (w WaylandViewEvent) Valid() bool { + return w != (WaylandViewEvent{}) +} func osMain() { select {} diff --git a/app/os_windows.go b/app/os_windows.go index 888391b7..7c950a5a 100644 --- a/app/os_windows.go +++ b/app/os_windows.go @@ -981,3 +981,6 @@ func configForDPI(dpi int) unit.Metric { func (Win32ViewEvent) implementsViewEvent() {} func (Win32ViewEvent) ImplementsEvent() {} +func (w Win32ViewEvent) Valid() bool { + return w != (Win32ViewEvent{}) +} diff --git a/app/window.go b/app/window.go index f8aee3ea..bf85099a 100644 --- a/app/window.go +++ b/app/window.go @@ -7,7 +7,6 @@ import ( "fmt" "image" "image/color" - "reflect" "runtime" "sync" "time" @@ -643,7 +642,7 @@ func (w *Window) processEvent(e event.Event) bool { } w.coalesced.destroy = &e2 case ViewEvent: - if reflect.ValueOf(e2).IsZero() && w.gpu != nil { + if !e2.Valid() && w.gpu != nil { w.ctx.Lock() w.gpu.Release() w.gpu = nil