Skip to content

Send WM_SIZING during resize for grid-snapping apps#723

Open
andrewachen wants to merge 2 commits intoRamonUnch:mainfrom
andrewachen:wm-sizing
Open

Send WM_SIZING during resize for grid-snapping apps#723
andrewachen wants to merge 2 commits intoRamonUnch:mainfrom
andrewachen:wm-sizing

Conversation

@andrewachen
Copy link
Copy Markdown
Contributor

@andrewachen andrewachen commented Apr 1, 2026

Summary

  • Fix buffer overrun in EnumSnappedWindows: snwnds.it[snwnds.num].flag was written before ListAppend allocated the slot, causing a write past the buffer when full. Now stores the flag in a local and writes it after ListAppend, matching the safe pattern in EnumStackedWindowsProc.

  • Send WM_SIZING before SetWindowPos during resize: Terminal emulators (mintty, PuTTY, etc.) and other apps that snap to a character-cell grid need WM_SIZING to adjust the proposed rect to their grid boundaries. AltSnap was calling SetWindowPos directly, bypassing this. There was already commented-out code attempting this.

    Sends WM_SIZING via SendMessageTimeout (SMTO_ABORTIFHUNG, 32ms) before SetWindowPos when resizing. The app-adjusted rect is read back and used for the final positioning. A lookup table maps the current resize direction (state.resize.x/y) to the correct WMSZ_* edge constant. Respects the existing SSizeMove blacklist. Apps that don't handle WM_SIZING are unaffected.

Co-Authored-By: Claude Opus 4.6 (1M context) noreply@anthropic.com
Sponsored-By: Netflix

andrewachen and others added 2 commits April 1, 2026 15:53
The flag field was written to snwnds.it[snwnds.num] before ListAppend
allocated the slot, causing a write past the end of the buffer when
the list was full. Store the flag in a local variable and write it
to new_wnd->flag after ListAppend, matching the safe pattern used
in EnumStackedWindowsProc.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Sponsored-By: Netflix
Terminal emulators (mintty, PuTTY, etc.) and other apps that snap to a
character-cell grid need WM_SIZING to adjust the proposed rect to their
grid boundaries. AltSnap was calling SetWindowPos directly, bypassing
this. There was already commented-out code attempting this.

Send WM_SIZING via SendMessageTimeout (SMTO_ABORTIFHUNG, 32ms) before
SetWindowPos when resizing. The app-adjusted rect is read back and used
for the final SetWindowPos. A lookup table maps the current resize
direction (state.resize.x/y) to the correct WMSZ_* edge constant.
Respects the existing SSizeMove blacklist.

Apps that don't handle WM_SIZING are unaffected.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Sponsored-By: Netflix
@andrewachen andrewachen marked this pull request as ready for review April 1, 2026 22:59
@RamonUnch
Copy link
Copy Markdown
Owner

RamonUnch commented Apr 2, 2026

???

You are sending with WM_SIZING message to another process with a pointer to your own memory? This is not possible because since we run in protected mode on Win32 every process has its own address space.

I will have a look about the ListAppend problem

Have you even tested the code?
Please review what AI tells you before doing a PR.

Also sending a WM_SIZING message is not a documented way of resizing a window,, the Win32 API gust guarenties that you will receive it while resizing. I would not rely on it even if it were to work.

@RamonUnch RamonUnch closed this Apr 2, 2026
@andrewachen
Copy link
Copy Markdown
Contributor Author

Thanks for the review and for taking the time to look at this!

On the cross-process pointer concern: That's a reasonable worry, but it turns out WM_SIZING (0x0214) falls in the system message range (below WM_USER at 0x0400), which means the OS handles the pointer marshalling for us automatically. From the SendMessageTimeout documentation:

The system only does marshalling for system messages (those in the range 0 to (WM_USER-1)). To send other messages (those >= WM_USER) to another process, you must do custom marshalling.

So the RECT* gets copied into the target process's address space and back by Windows itself — no shared memory issues here.

On WM_SIZING not being a documented resize API: That's a fair point — the docs do describe it as "sent to a window that the user is resizing," so it's a notification rather than a command. But since AltSnap already synthesizes WM_ENTERSIZEMOVE / WM_EXITSIZEMOVE to simulate a user drag session, sending WM_SIZING between those bookends felt like the natural completion of that simulation — and it matches what DefWindowProc does during a real drag.

I have been testing this locally and it fixes the grid-snapping issue for both Windows Terminal and wsltty. Apps that don't handle WM_SIZING are unaffected since we only use the adjusted rect if SendMessageTimeout succeeds.

Happy to hear if you have other concerns or suggestions for a better approach!

@andrewachen
Copy link
Copy Markdown
Contributor Author

@RamonUnch -- would it be ok to reopen this PR given the above information?

@RamonUnch RamonUnch reopened this Apr 2, 2026
@RamonUnch
Copy link
Copy Markdown
Owner

RamonUnch commented Apr 2, 2026

this is true for WM_ENTER/WM_EXITSIZEMOVE, they are optional and are a legacy of original AltDarg, also they require no marshaling.

I thought the list of system message that were actually marshaled were very little.

@RamonUnch
Copy link
Copy Markdown
Owner

Sorr ignore the above I misred your changes

@RamonUnch
Copy link
Copy Markdown
Owner

I will try it myself and see what happens, then

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.

2 participants