On Thu Feb 19 16:05:32 2026 +0000, Rémi Bernon wrote:
`WM_TAKE_FOCUS` reply is delayed when there's a `WM_STATE` change pending. We expect to receive the `WM_STATE` PropertyNotify before we can decide whether to accept or not focus, because it's otherwise possible to have multiple `WM_STATE` changes pending in sequence (either for one window that gets mapped/minimized/mapped in short sequence, or because another window is being mapped at the same time), and we need that sequence to complete before we decide which one wins the focus race or we may trigger more race conditions. This is not delayed wrt. the _NET_ACTIVE_WINDOW requests, so changing the pending_state.active_window or its serial isn't going to make any difference there. The issue might be that the WM sends `WM_TAKE_FOCUS` first, before actually changing the `WM_STATE` property, and doesn't send more `WM_TAKE_FOCUS` requests after that? Note that `handle_wm_state_notify` also tries to explicitly activate the window again for cases like this, so it's unclear why this doesn't work for you. Fwiw window activation works fine with every WM I have tried, Mutter, Kwin, Openbox, Fvwm.
But the point is that the pending_state should be set when we actually have a pending operation on it, not a no-op. I don't understand what sense does it make to have the pending state set to something that we haven't actually requested (and thus isn't pending)??? Sure, it's a bit weird, but that is meant to work with the GetWindowStateUpdates side or things, to delay changes that would make Win32 active window match the X11 one, if we have just requested explicit window activation, or if we're about to map a window. In the latter case ActivateWindow is called before the WindowPosChanged call that will trigger the mapping of the window, this is a bit unfortunate and could perhaps be changed to make it less awkward but it's a bit delicate to get it right. Yes, `handle_wm_state_notify` is exactly what is calling `set_net_active_window` here, with activate set to TRUE / 1. And it doesn't work because of the reason I explained: it returns early since it sees the pending state net_active_window match the one we "skipped" because it was unmapped. I mean this line:
if (data->pending_state.net_active_window == window) return; how can it possibly work then? I've tested this on compiz where it has this problem. -- https://gitlab.winehq.org/wine/wine/-/merge_requests/10133#note_129974