Signed-off-by: Gabriel Ivăncescu gabrielopcode@gmail.com --- dlls/wined3d/swapchain.c | 49 ++++++++++++++++++++++------------ dlls/wined3d/wined3d_private.h | 1 + 2 files changed, 33 insertions(+), 17 deletions(-)
diff --git a/dlls/wined3d/swapchain.c b/dlls/wined3d/swapchain.c index 6270c36..8741ed2 100644 --- a/dlls/wined3d/swapchain.c +++ b/dlls/wined3d/swapchain.c @@ -1763,7 +1763,6 @@ void wined3d_swapchain_activate(struct wined3d_swapchain *swapchain, BOOL activa { struct wined3d_device *device = swapchain->device; HWND window = swapchain->state.device_window; - struct wined3d_output_desc output_desc; unsigned int screensaver_active; struct wined3d_output *output; BOOL focus_messages, filter; @@ -1790,22 +1789,7 @@ void wined3d_swapchain_activate(struct wined3d_swapchain *swapchain, BOOL activa if ((device->restore_screensaver = !!screensaver_active)) SystemParametersInfoW(SPI_SETSCREENSAVEACTIVE, FALSE, NULL, 0);
- if (!(device->create_parms.flags & WINED3DCREATE_NOWINDOWCHANGES)) - { - /* The d3d versions do not agree on the exact messages here. D3d8 restores - * the window but leaves the size untouched, d3d9 sets the size on an - * invisible window, generates messages but doesn't change the window - * properties. The implementation follows d3d9. - * - * Guild Wars 1 wants a WINDOWPOSCHANGED message on the device window to - * resume drawing after a focus loss. */ - if (SUCCEEDED(hr = wined3d_output_get_desc(output, &output_desc))) - SetWindowPos(window, NULL, output_desc.desktop_rect.left, - output_desc.desktop_rect.top, swapchain->state.desc.backbuffer_width, - swapchain->state.desc.backbuffer_height, SWP_NOACTIVATE | SWP_NOZORDER); - else - ERR("Failed to get output description, hr %#x.\n", hr); - } + wined3d_swapchain_update_window_size(swapchain);
if (device->wined3d->flags & WINED3D_RESTORE_MODE_ON_ACTIVATE) { @@ -1849,6 +1833,37 @@ void wined3d_swapchain_activate(struct wined3d_swapchain *swapchain, BOOL activa wined3d_filter_messages(window, filter); }
+void wined3d_swapchain_update_window_size(struct wined3d_swapchain *swapchain) +{ + struct wined3d_output_desc output_desc; + struct wined3d_output *output; + HRESULT hr; + + if (swapchain->device->create_parms.flags & WINED3DCREATE_NOWINDOWCHANGES) + return; + + output = wined3d_swapchain_get_output(swapchain); + if (!output) + { + ERR("Failed to get output from swapchain %p.\n", swapchain); + return; + } + + /* The d3d versions do not agree on the exact messages here. D3d8 restores + * the window but leaves the size untouched, d3d9 sets the size on an + * invisible window, generates messages but doesn't change the window + * properties. The implementation follows d3d9. + * + * Guild Wars 1 wants a WINDOWPOSCHANGED message on the device window to + * resume drawing after a focus loss. */ + if (SUCCEEDED(hr = wined3d_output_get_desc(output, &output_desc))) + SetWindowPos(swapchain->state.device_window, NULL, output_desc.desktop_rect.left, + output_desc.desktop_rect.top, swapchain->state.desc.backbuffer_width, + swapchain->state.desc.backbuffer_height, SWP_NOACTIVATE | SWP_NOZORDER); + else + ERR("Failed to get output description, hr %#x.\n", hr); +} + HRESULT CDECL wined3d_swapchain_resize_buffers(struct wined3d_swapchain *swapchain, unsigned int buffer_count, unsigned int width, unsigned int height, enum wined3d_format_id format_id, enum wined3d_multisample_type multisample_type, unsigned int multisample_quality) diff --git a/dlls/wined3d/wined3d_private.h b/dlls/wined3d/wined3d_private.h index c44c4ea..e9acc0a 100644 --- a/dlls/wined3d/wined3d_private.h +++ b/dlls/wined3d/wined3d_private.h @@ -5106,6 +5106,7 @@ struct wined3d_swapchain
void wined3d_swapchain_activate(struct wined3d_swapchain *swapchain, BOOL activate) DECLSPEC_HIDDEN; void wined3d_swapchain_cleanup(struct wined3d_swapchain *swapchain) DECLSPEC_HIDDEN; +void wined3d_swapchain_update_window_size(struct wined3d_swapchain *swapchain) DECLSPEC_HIDDEN; struct wined3d_output * wined3d_swapchain_get_output(const struct wined3d_swapchain *swapchain) DECLSPEC_HIDDEN; void swapchain_update_draw_bindings(struct wined3d_swapchain *swapchain) DECLSPEC_HIDDEN; void swapchain_set_max_frame_latency(struct wined3d_swapchain *swapchain,
Fixes a regression introduced by commit 82c6ec3a32f44e8b3e0cc88b7f10e0c0d7fa1b89, which caused the WM_ACTIVATEAPP to be sent while the window is minimized, if it has been clicked on in the taskbar to be restored. The behavior is correct wrt Windows, but some games expect the window pos change messages to be sent while they are unminimized, but we only sent it during the WM_ACTIVATEAPP hook.
Signed-off-by: Gabriel Ivăncescu gabrielopcode@gmail.com --- dlls/wined3d/device.c | 11 ++++++++--- dlls/wined3d/swapchain.c | 3 ++- 2 files changed, 10 insertions(+), 4 deletions(-)
diff --git a/dlls/wined3d/device.c b/dlls/wined3d/device.c index 754dd76..e76eaa5 100644 --- a/dlls/wined3d/device.c +++ b/dlls/wined3d/device.c @@ -5818,6 +5818,8 @@ void device_invalidate_state(const struct wined3d_device *device, unsigned int s LRESULT device_process_message(struct wined3d_device *device, HWND window, BOOL unicode, UINT message, WPARAM wparam, LPARAM lparam, WNDPROC proc) { + unsigned int i; + if (message == WM_DESTROY) { TRACE("unregister window %p.\n", window); @@ -5832,13 +5834,11 @@ LRESULT device_process_message(struct wined3d_device *device, HWND window, BOOL } else if (message == WM_ACTIVATEAPP) { - unsigned int i = device->swapchain_count; - /* Deactivating the implicit swapchain may cause the application * (e.g. Deus Ex: GOTY) to destroy the device, so take care to * deactivate the implicit swapchain last, and to avoid accessing the * "device" pointer afterwards. */ - while (i--) + for (i = device->swapchain_count; i--;) wined3d_swapchain_activate(device->swapchains[i], wparam); } else if (message == WM_SYSCOMMAND) @@ -5849,6 +5849,11 @@ LRESULT device_process_message(struct wined3d_device *device, HWND window, BOOL DefWindowProcW(window, message, wparam, lparam); else DefWindowProcA(window, message, wparam, lparam); + + /* Heroes of Might and Magic V depends on this being + done after the window has been unminimized. */ + for (i = device->swapchain_count; i--;) + wined3d_swapchain_update_window_size(device->swapchains[i]); } }
diff --git a/dlls/wined3d/swapchain.c b/dlls/wined3d/swapchain.c index 8741ed2..dad795a 100644 --- a/dlls/wined3d/swapchain.c +++ b/dlls/wined3d/swapchain.c @@ -1839,7 +1839,8 @@ void wined3d_swapchain_update_window_size(struct wined3d_swapchain *swapchain) struct wined3d_output *output; HRESULT hr;
- if (swapchain->device->create_parms.flags & WINED3DCREATE_NOWINDOWCHANGES) + if (swapchain->device->create_parms.flags & WINED3DCREATE_NOWINDOWCHANGES || + (GetWindowLongW(swapchain->state.device_window, GWL_STYLE) & WS_MINIMIZE)) return;
output = wined3d_swapchain_get_output(swapchain);
On Tue, 29 Sep 2020 at 19:16, Gabriel Ivăncescu gabrielopcode@gmail.com wrote:
Fixes a regression introduced by commit 82c6ec3a32f44e8b3e0cc88b7f10e0c0d7fa1b89, which caused the WM_ACTIVATEAPP to be sent while the window is minimized, if it has been clicked on in the taskbar to be restored. The behavior is correct wrt Windows, but some games expect the window pos change messages to be sent while they are unminimized, but we only sent it during the WM_ACTIVATEAPP hook.
It's not entirely clear to me what we're fixing here. (E.g., is the issue about the order of the messages, or the state of the window? Which version of Direct3D does this affect?) Do you have a test to reproduce the issue?
On 30/09/2020 14:53, Henri Verbeet wrote:
On Tue, 29 Sep 2020 at 19:16, Gabriel Ivăncescu gabrielopcode@gmail.com wrote:
Fixes a regression introduced by commit 82c6ec3a32f44e8b3e0cc88b7f10e0c0d7fa1b89, which caused the WM_ACTIVATEAPP to be sent while the window is minimized, if it has been clicked on in the taskbar to be restored. The behavior is correct wrt Windows, but some games expect the window pos change messages to be sent while they are unminimized, but we only sent it during the WM_ACTIVATEAPP hook.
It's not entirely clear to me what we're fixing here. (E.g., is the issue about the order of the messages, or the state of the window? Which version of Direct3D does this affect?) Do you have a test to reproduce the issue?
The issue is that HOMM V relies on the SetWindowPos messages to be received when it is unminimized, otherwise it remains a black screen when restored. Prior to that patch, we sent them during WM_ACTIVATEAPP, which happened when the game was not minimized (because WM_SYSCOMMAND SC_RESTORE was the reason the WM_ACTIVATEAPP was sent in the first place).
That patch is needed to fix games like Project CARS, though, and it is correct according to Zhiyi's commit message. I also tested it and it does appear to be correct: WM_ACTIVATE and WM_ACTIVATEAPP are sent before the SC_RESTORE message, if it's clicked on the taskbar to restore it, while the WM_WINDOWPOSCHANGING/WM_WINDOWPOSCHANGED are sent after it.
I'm not entirely sure how to add a test since it requires clicking on the taskbar (when the game is minimized after alt-tab) for this to happen. But if you launch HOMM V, alt-tab to minimize the game, and then click on the taskbar to restore it, it will remain a black screen without this patch (and reverting that commit also fixes it, but breaks Project CARS; that commit + this patch fixes both).
With this patch, it only handles this specific case of restoring it by clicking on the taskbar: where WM_ACTIVATEAPP has the window still minimized (so SetWindowPos is not called), and SC_RESTORE happens after.