On 28/12/2021 18:15, Henri Verbeet wrote:
On Mon, 27 Dec 2021 at 15:32, Gabriel Ivăncescu gabrielopcode@gmail.com wrote:
This is a regression from last year but I completely forgot about it. Last time, it got no reviews, unfortunately, so it would be nice to have it fixed during this year's code freeze.
I think this got deferred during code freeze last year, because window handling is simply very sensitive. It was then never resubmitted after code freeze.
Ah, I did resend it in this form (the old form sent during code freeze was wrong), and now that I done more tests it does seem slightly off as well but more details below.
- if ((cooplevel & DDSCL_NOWINDOWCHANGES) || window != GetActiveWindow())
swapchain_desc.flags |= WINED3D_SWAPCHAIN_NO_WINDOW_CHANGES;
That said, I also remember thinking that doing the GetActiveWindow() check here seems somewhat suspicious. The expected place for that kind of check would be in wined3d_swapchain_state_setup_fullscreen(), and the tests don't seem to provide a justification for doing it here instead. Of course doing it in wined3d_swapchain_state_setup_fullscreen() would raise the question of how this is supposed to behave in other D3D versions, but that seems a question worth raising anyway.
Okay so I wrote tests for the different D3D versions and it seems it's somewhat version-specific, but the main problem is that I don't know how to fix it in wined3d side, because of the acquire_focus_window which changes the focus *before* the swapchain sets fullscreen. But first, here's roughly the results of how each version works:
ddraw: If it's not active when entering fullscreen, WS_EX_TOPMOST is not set (i.e. doesn't do window changes). This check is done only when entering fullscreen; if the coop level is reset again after to fullscreen while active, even while already being fullscreen, it will set WS_EX_TOPMOST, i.e. it does not "persist".
d3d9: Same as ddraw, where creating the device while not active will not make it topmost. Resetting the device while not active won't make it topmost either, but doing so while active (even if it was created inactive) will.
d3d8: Similar to d3d9, except that it persists. If it's created inactive, it will never set WS_EX_TOPMOST after that during any resets, even if it's active while it's being reset back to fullscreen.
dxgi: Doesn't care about inactive at all, always sets topmost (so current behavior is correct).
This leads me to think a solution outside of wined3d is preferable. However, there's more reasons to it. The problem, as stated, is wined3d_device_acquire_focus_window. This is done before the swapchain is created/sets fullscreen (during reset). And it focuses the window, which means that any checks during setup_fullscreen will always see it active/focused, making them pointless.
Checking whether it's active before acquire_focus_window is easy enough outside of wined3d, but would be pretty ugly in wined3d, having to track extra state and all.
Then there's the difference between versions, where it's easy enough to handle that outside of wined3d, while requiring some sort of new flags (?) for wined3d, especially given that dxgi's current behavior is correct and needs no changes at all.