This prevents a window from getting reactivated when calling `SetWindowPos` inside the WM_ACTIVATE handler. For now I only was able to reproduce this by triggering a change in the active window from X11 with an alt-tab or by clicking another window, I was not able to write a wine test for this.
This test program works for reproducing it. ```c #include <windows.h>
LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) { if (uMsg == WM_ACTIVATE) { SetWindowPos(hwnd, 0, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE); }
done: return DefWindowProc(hwnd, uMsg, wParam, lParam); }
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PSTR pCmdLine, int nCmdShow) { HWND hwnd; const char CLASS_NAME[] = "class"; WNDCLASSA wc = {}; wc.lpfnWndProc = WindowProc; wc.hInstance = hInstance; wc.lpszClassName = CLASS_NAME;
RegisterClass(&wc);
hwnd = CreateWindowEx(0, CLASS_NAME, "test", 0, 4, 4, 1024, 768, NULL, NULL, hInstance, NULL);
ShowWindow(hwnd, SW_SHOW);
MSG msg; while (TRUE) { GetMessage(&msg, NULL, 0, 0); TranslateMessage(&msg); DispatchMessage(&msg); } } ```
From: Santino Mazza smazza@codeweavers.com
XWayland sets _NET_ACTIVE_WINDOW to 0 if the active window is a Wayland client. Because of this the WM_ACTIVATE message is not sent. --- dlls/winex11.drv/window.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/dlls/winex11.drv/window.c b/dlls/winex11.drv/window.c index 78f8dd0e158..f6439a2d663 100644 --- a/dlls/winex11.drv/window.c +++ b/dlls/winex11.drv/window.c @@ -1729,7 +1729,8 @@ BOOL X11DRV_GetWindowStateUpdates( HWND hwnd, UINT *state_cmd, UINT *swp_flags, !thread_data->net_active_window_serial) { *foreground = hwnd_from_window( thread_data->display, thread_data->current_state.net_active_window ); - if (*foreground == old_foreground) *foreground = 0; + if (!*foreground) *foreground = NtUserGetDesktopWindow(); + else if (*foreground == old_foreground) *foreground = 0; }
if ((data = get_win_data( hwnd )))
From: Santino Mazza smazza@codeweavers.com
This fixes a difference in behavior between Wine and Windows, where in Wine it's possible to immediatly reactivate a window by calling SetWindowPos inside the WM_ACTIVATE handler. In Windows this isn't possible. --- dlls/win32u/window.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/dlls/win32u/window.c b/dlls/win32u/window.c index c5c5d0522c8..2078628a698 100644 --- a/dlls/win32u/window.c +++ b/dlls/win32u/window.c @@ -3909,7 +3909,7 @@ BOOL set_window_pos( WINDOWPOS *winpos, int parent_x, int parent_y ) NtUserShowCaret( winpos->hwnd ); }
- if (!(winpos->flags & (SWP_NOACTIVATE|SWP_HIDEWINDOW))) + if (!(winpos->flags & (SWP_NOACTIVATE|SWP_HIDEWINDOW)) && get_active_window() != winpos->hwnd) { UINT style = get_window_long( winpos->hwnd, GWL_STYLE ); /* child windows get WM_CHILDACTIVATE message */
It's not something that Xwayland does but rather something that the window managers are doing. We cannot use None as an indication of focus loss because some other X11 WM are using it as a transient state when changing focus, and we don't want to translate it into more Win32 side focus changes that would cause additional requests and confusion. The Wayland compositor logic has been changed in the various MR listed in https://gitlab.winehq.org/wine/wine/-/merge_requests/8117.
Rémi Bernon (@rbernon) commented about dlls/win32u/window.c:
NtUserShowCaret( winpos->hwnd ); }
- if (!(winpos->flags & (SWP_NOACTIVATE|SWP_HIDEWINDOW)))
- if (!(winpos->flags & (SWP_NOACTIVATE|SWP_HIDEWINDOW)) && get_active_window() != winpos->hwnd)
Rather than doing that unconditionally, which may not be always correct (it's not because the window is the thread's active window that it's also the current foreground window), I think this should be dependent on what is currently happening.
I understand that the issue exists when WM_ACTIVATE message is being sent, which happens during window activation and deactivation (with different wparam), and we only want to prevent re-activation if the window is being deactivated, not in other cases.
On Fri Nov 7 16:09:35 2025 +0000, Rémi Bernon wrote:
Rather than doing that unconditionally, which may not be always correct (it's not because the window is the thread's active window that it's also the current foreground window), I think this should be dependent on what is currently happening. I understand that the issue exists when WM_ACTIVATE message is being sent, which happens during window activation and deactivation (with different wparam), and we only want to prevent re-activation if the window is being deactivated, not in other cases.
Sorry for the late reply. What would you suggest for keeping track of when the window is being deactivated? Should I add a new flag to the tagWND struct and set it in `set_active_window`?
Also I found that, on Windows, calling SetActiveWindow directly while handling WM_ACTIVATE doesn't work, however calling SetForegroundWindow does work to activate the window, but it doesn't send a `WM_ACTIVATE` message with 0 wparam when it gets deactivated again which is weird.
On Wed Nov 12 17:32:18 2025 +0000, Santino Mazza wrote:
Sorry for the late reply. What would you suggest for keeping track of when the window is being deactivated? Should I add a new flag to the tagWND struct and set it in `set_active_window`? Also I found that, on Windows, calling SetActiveWindow directly while handling WM_ACTIVATE doesn't work, however calling SetForegroundWindow does work to activate the window, but it doesn't send a `WM_ACTIVATE` message with 0 wparam when it gets deactivated again which is weird.
Yes a flag could probably work.