Skip to content

fix(window): stop forwarding surface mouse messages to Explorer - #199

Open
arshcaria wants to merge 1 commit into
CodeZeno:mainfrom
arshcaria:fix/explorer-hang-mouse-activate
Open

arshcaria wants to merge 1 commit into
CodeZeno:mainfrom
arshcaria:fix/explorer-hang-mouse-activate

Conversation

@arshcaria

Copy link
Copy Markdown
Contributor

Summary

Fixes #198.

A taskbar-hosted surface is a child of Shell_TrayWnd. DefWindowProc forwards several mouse messages from a child window to its parent with a synchronous SendMessage, so the widget was making blocking calls into Explorer's taskbar thread:

  • WM_MOUSEACTIVATE on every button press. A hang dump of explorer.exe showed the Taskbar thread stuck in UI Automation while handling exactly this message (sent to Shell_TrayWnd from a right-button press). The monitor's UI thread waited on it until the hang watchdog relaunched the widget, or Windows restarted Explorer.
  • WM_SETCURSOR on every mouse move over a non-clickable area, through the set_surface_cursor(...) == false fallback.
  • Wheel and WM_APPCOMMAND messages.

Changes:

  • Both surface window procedures return MA_NOACTIVATE for WM_MOUSEACTIVATE. The surfaces are WS_EX_NOACTIVATE and never activate, and the click itself is still delivered.
  • set_surface_cursor always sets a cursor (hand over clickable layers, arrow elsewhere), and WM_SETCURSOR returns TRUE without DefWindowProc.
  • WM_MOUSEWHEEL, WM_MOUSEHWHEEL, WM_APPCOMMAND and WM_CONTEXTMENU are consumed by the surfaces, which have no handlers for them.
  • The widget tooltip is now owned by the controller instead of the surface. A popup owned by a child window is owned by that child's top-level ancestor, which put the tooltip in Explorer's Shell_TrayWnd owner chain.

Testing

  • cargo fmt --all -- --check: passes
  • cargo test --locked: 603 passed, 6 ignored. The run includes a new regression test, hosted_surface_never_forwards_mouse_messages_to_its_parent. It first confirms that DefWindowProc forwards WM_MOUSEACTIVATE to a recording parent, then checks that the surface wnd_proc forwards none of these messages.
  • cargo build --locked --release: succeeds
  • Manual check: confirmed at runtime that the tooltip's owner is the controller window (GetWindow(GW_OWNER)), not Shell_TrayWnd. The hang is intermittent and appeared roughly once per handful of right-clicks over an evening on the affected machine. I am running this build there now and will report back on the issue.

Checklist

  • I have read CONTRIBUTING.md and CODE_OF_CONDUCT.md.
  • The change is focused and contains no credentials or sensitive data.
  • I have added or updated relevant documentation and tests, where applicable.
  • I have left changelog and version changes to maintainers unless requested.

🤖 Generated with Claude Code

A taskbar-hosted surface is a child of Shell_TrayWnd, and DefWindowProc
forwards several mouse messages from a child to its parent with a
synchronous SendMessage. Every button press on the widget therefore sent
WM_MOUSEACTIVATE into Explorer's taskbar thread, and every mouse move over
a non-clickable area sent WM_SETCURSOR.

A hang dump of explorer.exe taken after a right-click on the widget showed
the Taskbar thread stuck inside UI Automation while handling
WM_MOUSEACTIVATE (hit test HTCLIENT, mouse message WM_RBUTTONDOWN) sent to
Shell_TrayWnd. The monitor's UI thread waited on that call until the hang
watchdog relaunched it; on other occasions Windows restarted Explorer.

The surfaces now answer these messages themselves:
- WM_MOUSEACTIVATE returns MA_NOACTIVATE (the surface is WS_EX_NOACTIVATE
  and never activates; the click is still delivered).
- WM_SETCURSOR always sets the hand or arrow cursor and returns TRUE.
- WM_MOUSEWHEEL, WM_MOUSEHWHEEL, WM_APPCOMMAND and WM_CONTEXTMENU are
  consumed, since the surface has no handler for them.

The widget tooltip is also owned by the controller instead of the surface:
a popup owned by a child is owned by its top-level ancestor, which put the
tooltip in Explorer's Shell_TrayWnd owner chain.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
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.

Right-clicking the taskbar widget can hang explorer.exe (WM_MOUSEACTIVATE forwarded to Shell_TrayWnd)

1 participant