Skip to content

win32: fix cursor coordinates when starting window dragging - #4765

Open
smittie2000 wants to merge 2 commits into
rust-windowing:masterfrom
smittie2000:codex/fix-win32-drag-coordinates
Open

smittie2000 wants to merge 2 commits into
rust-windowing:masterfrom
smittie2000:codex/fix-win32-drag-coordinates

Conversation

@smittie2000

@smittie2000 smittie2000 commented Oct 15, 2026 •

Copy link
Copy Markdown

Microsoft describes lParam for WM_NCLBUTTONDOWN as a POINTS structure,
so using POINTS to hold the coordinates makes sense. The issue is the
conversion at the call site: &points as *const _ as LPARAM passes the
structure's memory address rather than its coordinate values.

The documentation's GET_X_LPARAM and GET_Y_LPARAM examples clarify that
Windows reads the coordinates from the bits of lParam itself. Keeping a
POINTS variable would also work if its fields were packed into LPARAM;
this change packs the coordinates directly, so that intermediate structure
is no longer needed. It fixes the shared path used by drag_window and
drag_resize_window.

The new line is:

let position =
    (u32::from(points.x as u16) | (u32::from(points.y as u16) << 16)) as LPARAM;

Windows expects two signed 16-bit coordinates packed into one value:

bits:    31 ........ 16 | 15 ......... 0
         y coordinate  | x coordinate
  • as u16 keeps each coordinate's lowest 16 bits, preserving negative
    coordinates: -1 becomes 0xffff, which Windows decodes back to -1.
  • u32::from(...) widens each value with zeros in the upper bits, leaving
    room for both coordinates without sign extension overwriting either word.
  • << 16 moves y into the upper word.
  • | combines the two words without overlap. The result is cast to LPARAM.

See Microsoft's WM_NCLBUTTONDOWN documentation
for the coordinate layout and signed decoding.

Validation on Windows 10 x64:

  • Actual posted-message checks for move and southeast resize fail before
    the fix and pass afterward.
  • All 7 backend library tests pass; strict backend Clippy and the backend
    documentation build pass.
  • Nightly formatting passes with LF-normalized sources; git diff --check
    passes.

These checks verify the message payload, not a drag-latency improvement.

@smittie2000 smittie2000 changed the title Fix Win32 cursor coordinates when starting window dragging win32: fix cursor coordinates when starting window dragging Oct 15, 2026
@ogoffart

Copy link
Copy Markdown
Contributor

Looks sensible.
Have you considered using transmute to convert from POINT to LPARAM?

@smittie2000

Copy link
Copy Markdown
Author

I did not think of that.
I am assuming you meant POINTS as POINT holds two 32bit value so transmute to LPARAM will put y in the wrong place for 64bit systems and not compile on 32bit system

Let me know if i change it. Something in the lines of

let position = unsafe { mem::transmute::<POINTS, u32>(points) } as LPARAM;

@smittie2000
smittie2000 force-pushed the codex/fix-win32-drag-coordinates branch from 3d330f0 to 1449a93 Compare October 22, 2026 10:29

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Development

Successfully merging this pull request may close these issues.

2 participants