Skip to content

perf(legacy): dispatch events without per-event allocations - #603

Open
palmoni5 wants to merge 1 commit into
leanflutter:mainfrom
palmoni5:upstream/legacy-dispatch
Open

palmoni5 wants to merge 1 commit into
leanflutter:mainfrom
palmoni5:upstream/legacy-dispatch

Conversation

@palmoni5

@palmoni5 palmoni5 commented Nov 10, 2026 •

Copy link
Copy Markdown

Problem

Move and resize events arrive many times per second while the user drags a window. For each event the 0.5.x bridge (package:window_manager/legacy.dart) copies the listener list, and for each listener it builds a map of fifteen callback tear-offs just to call one of them.

Change

  • Delivery iterates a listener snapshot that is rebuilt only when listeners are added or removed.
  • The named callback is called through a switch instead of a per-listener map.
  • _emit returns early without listeners.

Delivery semantics are unchanged: listeners added by a callback join from the next event, removed ones are skipped immediately, and listeners still returns a copy.

Tests

New test/legacy_dispatch_test.dart (driven through close() with prevent-close, which needs no window): the named callback follows onWindowEvent once per event, removing a listener during delivery does not starve later listeners, a listener added during delivery joins the next event only, and listeners returns a copy. These pin the existing semantics, so they pass before and after the change.

dart format --set-exit-if-changed ., flutter analyze (package and example) and flutter test (package and example) pass locally (Flutter 3.47.7, Windows), and the full CI workflow passes on the identical commit in my fork.

Related

Part of a set of independent PRs, each based on main and mergeable on its own: widgets #598, #599, #600, #601; legacy bridge #602, #603 (this), #604, #605, #606.

Merges cleanly with the other legacy PRs (#602, #604, #605, #606).

Move and resize events arrive many times per second while the user drags
a window. For each event the bridge copied the listener list, and for
each listener it built a map of fifteen callback tear-offs just to call
one of them.

Delivery now iterates a listener snapshot that is rebuilt only when
listeners are added or removed, and calls the named callback through a
switch. It returns early without listeners. Delivery semantics are
unchanged: listeners added by a callback join from the next event, and
removed ones are skipped immediately.
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.

1 participant