Skip to content

fix(core): purge Rust event listeners when window/webview is destroyed - #15617

Merged
Legend-Master merged 5 commits into
tauri-apps:devfrom
tenderdeve:fix/15613-rust-listener-cleanup
Jul 22, 2026
Merged

fix(core): purge Rust event listeners when window/webview is destroyed#15617
Legend-Master merged 5 commits into
tauri-apps:devfrom
tenderdeve:fix/15613-rust-listener-cleanup

Conversation

@tenderdeve

Copy link
Copy Markdown
Contributor

Closes #15613 (Rust-side follow-up to the listener-leak discussion in #15583).

Rust-side listeners registered via listen/once on a Window, Webview or WebviewWindow were never removed when that target was destroyed, so the handlers leaked for the lifetime of the app.

Change

  • Add Listeners::remove_listeners_for_label, which retains only handlers whose EventTarget is not bound to the destroyed label. It follows the existing try_lock + Pending queue convention so it stays safe if called mid-emit.
  • Wire it into AppManager::on_window_close (window label + each child webview label) and on_webview_close.

App, Any and AnyLabel listeners are kept — only Window/Webview/WebviewWindow targets matching the closed label are dropped.

Open question

I left AnyLabel { label } listeners intact, treating them as explicit cross-target subscriptions rather than something owned by a single window/webview. Happy to also purge those on matching label if you think that fits the intended semantics better.

This is scoped to the native (handlers) map only; the JS-side js_event_listeners cleanup is a separate concern.

Test

Added remove_listeners_for_label_drops_only_owned_targets verifying that Window/Webview/WebviewWindow listeners for the closed label are removed while unrelated-label, App, Any and AnyLabel listeners survive.

@tenderdeve
tenderdeve requested a review from a team as a code owner June 30, 2026 12:16
@Legend-Master

Copy link
Copy Markdown
Contributor

Please sign your commits and rebase .

@tenderdeve
tenderdeve force-pushed the fix/15613-rust-listener-cleanup branch from fdbe62e to 5baef04 Compare July 20, 2026 11:10
@tenderdeve

Copy link
Copy Markdown
Contributor Author

@Legend-Master rebased on dev and signed — commit 5baef0420 is now Verified and the PR is mergeable.

The rebase conflicted with the JS-listener cleanup from #15604 (now on dev). Resolved it by keeping both: remove_webview_js_listeners (JS map) and remove_listeners_for_label (Rust handlers) run on window/webview destroy. They clean different maps — remove_listeners_for_label only touches the Rust handlers map, so #15604’s JS cleanup is preserved, not replaced. cargo check/fmt clean, listener tests pass.

@github-actions

github-actions Bot commented Jul 20, 2026

Copy link
Copy Markdown
Contributor

Package Changes Through dd47d3a

There are 14 changes which include tauri with minor, tauri-cli with minor, @tauri-apps/cli with minor, tauri-runtime with minor, tauri-runtime-wry with minor, tauri-utils with minor, tauri-bundler with minor, tauri-build with minor, tauri-macos-sign with minor, tauri-codegen with minor, tauri-macros with minor, tauri-plugin with minor, tauri-driver with minor, @tauri-apps/api with minor

Planned Package Versions

The following package releases are the planned based on the context of changes in this pull request.

package current next
@tauri-apps/api 2.11.1 2.12.0
tauri-utils 2.9.3 2.10.0
tauri-macos-sign 2.3.4 2.4.0
tauri-bundler 2.9.4 2.10.0
tauri-runtime 2.11.3 2.12.0
tauri-runtime-wry 2.11.4 2.12.0
tauri-codegen 2.6.3 2.7.0
tauri-macros 2.6.3 2.7.0
tauri-plugin 2.6.3 2.7.0
tauri-build 2.6.3 2.7.0
tauri 2.11.5 2.12.0
@tauri-apps/cli 2.11.4 2.12.0
tauri-cli 2.11.4 2.12.0
tauri-driver 2.0.6 2.1.0

Add another change file through the GitHub UI by following this link.


Read about change files or the docs at github.com/jbolda/covector

Comment thread crates/tauri/src/event/listener.rs Outdated
Comment thread crates/tauri/src/event/listener.rs Outdated
Rust-side listeners registered via listen/once on a Window, Webview or
WebviewWindow were never removed when that target was destroyed, leaking
handlers for the lifetime of the app.

Add Listeners::remove_listeners_for_target, wired into on_window_close and
on_webview_close, which drops handlers whose target exactly matches the
destroyed one. Matching on the full EventTarget (kind + label) instead of the
label alone keeps window and webview listeners distinct in multi-webview mode,
where a window and its webviews can share a label. App, Any and AnyLabel
listeners are preserved. Follows the existing try_lock + Pending convention so
it is safe during emit.

closes tauri-apps#15613
@tenderdeve
tenderdeve force-pushed the fix/15613-rust-listener-cleanup branch from 5baef04 to 7249658 Compare July 21, 2026 12:27
@tenderdeve

Copy link
Copy Markdown
Contributor Author

@Legend-Master addressed both, pushed in 724965882 (rebased on dev, signed/Verified):

  1. Store the event target, not the labelPending::RemoveForLabel(String) is now Pending::RemoveForTarget(EventTarget), and the removal matches on the full EventTarget (kind + label) via equality instead of a bare label string.

  2. Multi-webview labels — because matching is now exact-target, a Window and a Webview that happen to share a label are treated as distinct. on_window_close removes the Window + WebviewWindow targets and, per child webview, the exact Webview target; on_webview_close removes only that Webview target. So closing one webview no longer touches the window's (or a sibling webview's) listeners.

Dropped the old target_bound_to_label helper and updated the unit test to assert same-label-different-kind targets survive. cargo test -p tauri event::listener green (6/6).

@Legend-Master
Legend-Master merged commit 1771775 into tauri-apps:dev Jul 22, 2026
23 checks passed
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.

[bug] event listeners are not cleaned up when its EventTarget is destroyed

2 participants