Skip to content

Close the window when Run returns, and fail loudly when Spec.Tray cannot attach - #29

Merged
tannevaled merged 2 commits into
mainfrom
fix/close-backend-and-linux-tray
Oct 5, 2026
Merged

tannevaled merged 2 commits into
mainfrom
fix/close-backend-and-linux-tray

Conversation

@tannevaled

@tannevaled tannevaled commented Oct 5, 2026 •

Copy link
Copy Markdown
Contributor

Fixes #27
Fixes #28

#27: Run never closed the window back-end

A back-end's Run returns when its window is asked to close, and on X11 that leaves the window mapped, frozen, with its connection open, until a GC finalises it. claimward-vpn-app-linux works around it with view.CloseLeftoverWindow, closing the window through the only reference Run left behind (the toolkit clipboard).

Fix: run closes the window when its loop returns (defer closeAfterRun(win)), and restores the toolkit clipboard it installed from the window, which would otherwise outlive it.

Cocoa exception (closedByItsOwnLoop): its loop returns only once the window has already closed, and Close is performed on the main thread. Sent after the loop stopped, it waits in the run-loop queue and gets delivered to the next window's loop. viewCloseNow acts on the active window, so it would close the window an app opens next. Win32's Close after WM_DESTROY is already a no-op (hwnd is 0).

#28: Spec.Tray silently gave no tray on Linux

attachTray swallowed tray.Attach's error, and the Linux (and Windows) tray backends do not implement Attach. Now, when the attach fails, Run closes the window (through a new quit channel run listens on) and returns application: Spec.Tray could not be attached: <err>; errors.Is(err, tray.ErrNoBackend) works. go-widgets/tray#36 implements Attach on Linux and Windows. With that release, Spec.Tray works there; before it, the same code gives this error instead of nothing.

Tests (lifecycle_test.go, via a new openWindow seam and a fake back-end)

  • TestRunClosesTheWindowWhenItsLoopReturns, TestRunPutsTheClipboardBack, TestRunLeavesAWindowThatClosedItselfAlone, TestRunReportsAWindowThatWouldNotOpen, TestRunQuitClosesTheWindow
  • TestRunFailsLoudlyWhenTheTrayCannotAttach: real run, fake window that stays open, attachTray failing. Run must return the wrapped error and close the window.
  • Existing stubs updated for the new run signature. TestAttachTrayDefaultIsHarmless is now TestAttachTrayDefaultReportsAFailure.
  • Coverage gate unchanged and green: 100% outside run (which is now partly exercised too). -race clean on linux and darwin.

Sabotage checks (each sabotaged tree passes go vet):

  • no closeAfterRun -> "the window was closed 0 times after its loop returned, want 1"
  • clipboard not restored -> "after run the toolkit clipboard is *application.clipWindow"
  • attach error swallowed again -> "a tray that could not attach left the window running and Run returning nothing"

Live check on Ubuntu 24.04 arm64 (Xvfb + openbox + a D-Bus session). A probe calls application.Run, closes the window with wmctrl -c (WM_DELETE_WINDOW, as the close button sends), and checks xdotool search --onlyvisible 2 s after Run returns:

application tray window gone after Run? Spec.Tray
origin/main v0.13.0 (released) no, still on screen no tray on the bus, Run returns nil
this PR v0.13.0 (released) yes Run returns "Spec.Tray could not be attached: tray: no backend for this platform"
origin/main tray#36 no tray on the bus
this PR tray#36 yes tray on the bus, Run returns nil

Not verified

  • macOS: the Cocoa path is unchanged by design (no Close after the loop). The hazard it avoids was then observed on macOS: in Show, Hide and Raise an open window window#135, a Close queued after one window's loop closed the next window the moment it opened. That PR fixes the hazard in the window itself (the main-thread handlers check the receiving view). Once a window release has it, closedByItsOwnLoop is only belt-and-braces. application.Run itself was not run on macOS.
  • Windows: not run (no Windows machine); Win32 Close after the loop is a no-op by reading.

Release order

  1. Linux: the dbusmenu tree behind a lock, and Attach on Linux and Windows tray#36 -> release (minor, v0.14.0 proposed).
  2. Bump this PR's github.com/go-widgets/tray to that release (go get github.com/go-widgets/tray@v0.14.0 && go mod tidy) before merging, so Spec.Tray works on Linux/Windows instead of failing. The PR builds as it is against the released tray (go.mod untouched), and failing loudly there is still correct.
  3. Merge and release this one.

go-widgets/window#135 (Show/Hide/Raise) is independent: this PR neither needs nor uses it.

Semver: minor (v0.x+1.0). There is no new exported identifier, but Run now returns an error where it used to return nil (a Spec.Tray that cannot attach), and callers can see that.

🤖 Generated with Claude Code

tannevaled and others added 2 commits October 5, 2026 16:04
…ut a tray

Run never closed its window back-end. A back-end's Run returns when the
window is asked to close, and on X11 that leaves the window mapped, frozen,
with its connection open, until a garbage collection finalises it.
claimward-vpn-app-linux closed it through the only reference Run left, the
toolkit clipboard. run now closes the window when its loop returns, and
restores the toolkit clipboard it installed from it. Cocoa is the exception:
its loop has already closed the window, and a Close sent afterwards is
queued on the main run loop and delivered to the next window's loop instead.

Spec.Tray silently gave no tray where the tray backend cannot attach (Linux
and Windows, before go-widgets/tray#36): the attach error was swallowed. Run
now closes the window and returns that error, wrapped.

The window is opened through a seam (openWindow), so the lifecycle around
the loop is tested against a fake back-end; run takes a quit channel Run uses
to close the window when the attach fails.

Fixes #27
Fixes #28

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
tray v0.14.0 (go-widgets/tray#36) implements Attach on Linux and Windows,
where it used to return ErrNoBackend. With this, Spec.Tray works there
instead of returning the error #28 now surfaces.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
@tannevaled
tannevaled merged commit 6984fc5 into main Oct 5, 2026
5 checks passed
@tannevaled
tannevaled deleted the fix/close-backend-and-linux-tray branch October 5, 2026 14:14
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Spec.Tray gives no tray on Linux: tray.Attach is not implemented there Run does not close the window backend: on X11 a closed window stays on screen

1 participant