Tk Source Code

View Ticket
Login
Ticket UUID: 90f5cd3f212cbb1aca7c51cb0a6aa17edde15bd0
Title: Windows ConfigureNotify uses stale WINDOWPOS x/y when SWP_NOMOVE is set
Type: Bug Version: Python 3.13.5
Submitter: anonymous Created on: 2026-09-18 20:35:37
Subsystem: 68. Win Window Operations Assigned To: nobody
Priority: 5 Medium Severity: Minor
Status: Closed Last Modified: 2026-10-19 15:30:42
Resolution: Fixed Closed By: nemethi
    Closed on: 2026-10-19 15:30:42
Description:

On Windows, ConfigureTopLevel(WINDOWPOS *pos) in win/tkWinWm.c appears to use pos->x and pos->y unconditionally when handling WM_WINDOWPOSCHANGED, even when pos->flags contains SWP_NOMOVE.

Microsoft documents SWP_NOMOVE as meaning that the current position should be retained and the x and y members ignored.

Tk currently does approximately:

winPtr->changes.x = pos->x;
winPtr->changes.y = pos->y;
...
GenerateConfigureNotify(winPtr);
The function does test SWP_NOMOVE later, but by then the stale coordinates have already been copied into winPtr->changes and exposed through ConfigureNotify.

I encountered this while implementing native Windows window movement from a Tk application. Aero Shake provides an unusually reliable reproduction.

During a restore shake I recorded the raw WM_WINDOWPOSCHANGED traffic and the resulting Tk <Configure> events.

A normal final movement looked like:

WINDOWPOS: (486, 177), flags=18453
Configure: (486, 177)
Immediately afterward Windows sent:
WINDOWPOS: (113, 19), flags=6163
6163 == 0x1813, which contains SWP_NOMOVE.

The physical HWND correctly remained at (486, 177), but Tk generated another Configure event reporting (113, 19). Those coordinates were from the WINDOWPOS structure that Windows had explicitly marked as not representing a move.

This can leave Tk's reported geometry inconsistent with the actual HWND position and causes dependent windows which follow <Configure> events to move to the wrong location.

The likely fix is for ConfigureTopLevel() to preserve the existing winPtr->changes.x/y whenever pos->flags & SWP_NOMOVE, analogous to how size handling respects SWP_NOSIZE.

For example:

if (!(pos->flags & SWP_NOMOVE)) {
    winPtr->changes.x = pos->x;
    winPtr->changes.y = pos->y;
}
before generating the ConfigureNotify.

This was reproduced through Python/Tkinter, but the fault appears to be in Tk's Windows window-manager code rather than _tkinter.

User Comments: nemethi (claiming to be Csaba Nemethi) added on 2026-10-19 15:30:42:

Merged into main, core-9-0-branch, and core-8-6-branch by commits [722bc576] (Jan), [64869de0], and [1cc77361]. Closing the ticket.


serhiy.storchaka added on 2026-09-22 06:29:42:

Added test winWm-11.1 in [267c29b292]. It uses a new test command testwindowposchanged (win/tkWinTest.c) which sends a WM_WINDOWPOSCHANGED message with the given WINDOWPOS fields to the toplevel, since a real SetWindowPos() call with SWP_NOMOVE arrives with the position already corrected by Windows and cannot reproduce the bug. Before the fix the test gives "+1111+2222" for the window position.

The branch for [564897] also changes win/tkWinTest.c and tests/constraints.tcl (a different command); merging both will conflict there, and both additions should be kept.


serhiy.storchaka added on 2026-09-20 07:34:57:

Confirmed. When SWP_NOMOVE or SWP_NOSIZE is set, the actual position and size of the window are now used instead of the stale values in WINDOWPOS. Fixed in [070b63854e] (branch win-configure-nomove).