Fix Windows resize handling under DPI scaling - #684
Open
Dkijas wants to merge 1 commit into
Open
Conversation
Two independent problems on the Windows GDI path. First, a resize can be lost before it is applied. sys_event holds a single pending event, but one message retrieval dispatches every sent message before it returns the posted one, so WM_SIZE writes the slot and a later message of the same retrieval overwrites it. Maximizing triggers it because the window grows under the mouse pointer and Windows follows WM_SIZE with a WM_MOUSEMOVE. The loading screen can also replay a resize it stored earlier, applying an obsolete size after the real one. WM_SIZE now keeps only the newest client size, GetEvents() hands it to the slot as soon as the slot is free, and queue_event() drops already queued resizes. Second, WindowSize mixes units. dr_os_open fills it from MaxSize, which is scaled up, and WM_PAINT consumes it as physical client pixels both as the StretchDIBits destination and to recompute the framebuffer height, but dr_textur_resize stored the logical size it is passed. At 100% scaling the two are the same number; above it every repaint after a resize painted into a rectangle smaller than the client area and rewrote biHeight too small. With a 3440x1369 client at 150%, WindowSize held 2304x912. Reported for Simutrans in forum topic 23805; the same symptom appears here. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
This fixes two independent Windows resize problems on the GDI path:
WindowSizewas produced in logical pixels but consumed asphysical ones, so the window was repainted at the wrong size after a resize.
They are independent: the second one is invisible at 100 % scaling, the first one is not.
Related to the behaviour reported in forum topic
23805.
Resize event loss
sys_eventholds a single pending event, but one message retrieval dispatches every sent messagebefore it returns the posted one, so
WM_SIZEwrites the slot and a later message of the sameretrieval overwrites it. Maximizing triggers it because the window grows under the mouse pointer
and Windows follows
WM_SIZEwith aWM_MOUSEMOVE. Separately, the loading screen stores theresizes it consumes and flushes them back, so an obsolete size could be applied after the real one.
WM_SIZEnow keeps only the newest client size,GetEvents()hands it to the slot as soon as theslot is free, and
queue_event()drops already queuedSYSTEM_RESIZEevents.DPI unit mismatch
dr_os_openfillsWindowSizefromMaxSize, which is scaled up, andWM_PAINTconsumes it asphysical client pixels — both as the
StretchDIBitsdestination and to recomputeAllDib->bmiHeader.biHeight. Butdr_textur_resizestored the logical size it is passed.At 100 % scaling the two are the same number and nothing shows. Above it, every repaint after a
resize painted into a rectangle smaller than the client area: with a 3440x1369 client at 150 %,
WindowSizeheld 2304x912.Extended-specific implementation
This is not a copy of the Simutrans Standard patch.
sys_event.new_window_sizeis ascr_sizehere, so the fields are
.w/.h, and sincescr_coord_valissint32the pending state needs nocast — Standard's
uint16fields do. The change was derived and measured against this code base.Validation
Measured on this branch's base, at 150 % and 100 % screen scaling, with a lab-only trace of the
producer/consumer contract and negative controls that remove each half separately:
WindowSizeholding the logical sizeWindowSize= 3456x1368 for a 3440x1369 clientthe unpatched baseline
Scope
Only
simevent.ccandsys/simsys_w.cc.sys/simsys_w.ccis Windows/GDI only;simevent.ccisshared by every backend, which is why SDL2 is included above. No savegame format change, no pak
format change, no new dependencies, nothing unrelated.