diff --git a/go/display/webkit/window_helpers.go b/go/display/webkit/window_helpers.go index 0564ac9..d20c7a5 100644 --- a/go/display/webkit/window_helpers.go +++ b/go/display/webkit/window_helpers.go @@ -185,5 +185,13 @@ func WindowExists(c *core.Core, name string) bool { return false } r := c.QUERY(window.QueryWindowByName{Name: name}) - return r.OK && r.Value != nil + if !r.OK { + return false + } + // The query answers a miss with a typed-nil *WindowInfo inside the + // Result, and a typed nil still passes an interface nil-check — so + // trusting r.Value != nil made every name exist, and callers took + // warm-window paths against windows that were never created. + info, ok := r.Value.(*window.WindowInfo) + return ok && info != nil } diff --git a/go/display/webkit/window_helpers_behaviour_test.go b/go/display/webkit/window_helpers_behaviour_test.go index 6dbe50f..63e39cb 100644 --- a/go/display/webkit/window_helpers_behaviour_test.go +++ b/go/display/webkit/window_helpers_behaviour_test.go @@ -82,3 +82,19 @@ func TestWindowHelpersBehaviour_WindowExists_Bad(t *core.T) { core.AssertFalse(t, WindowExists(c, "chat")) core.AssertFalse(t, HideWindow(c, "chat")) } + +// A window service that answers the query but misses returns a TYPED nil +// *WindowInfo inside the Result — which an interface nil-check passes. +// WindowExists must unwrap the value, or every name "exists" and callers +// take warm-window paths against windows that were never created. +func TestWindowHelpersBehaviour_WindowExists_Ugly(t *core.T) { + c := core.New(core.WithServiceLock()) + c.RegisterQuery(func(_ *core.Core, q core.Query) core.Result { + if _, ok := q.(window.QueryWindowByName); ok { + return core.Result{Value: (*window.WindowInfo)(nil), OK: true} + } + return core.Result{} + }) + + core.AssertFalse(t, WindowExists(c, "never-created")) +}