From 12fda2fc13426799bd4376c1fbd99b179c685559 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pedro=20J=2E=20Est=C3=A9banez?= Date: Tue, 30 Apr 2024 14:31:43 +0200 Subject: [PATCH] Windows: Fix WINDOW_EVENT_FOCUS_IN not delivered in some cases --- platform/windows/display_server_windows.cpp | 46 +++++++++++++-------- platform/windows/display_server_windows.h | 4 +- 2 files changed, 32 insertions(+), 18 deletions(-) diff --git a/platform/windows/display_server_windows.cpp b/platform/windows/display_server_windows.cpp index dbba9b43083a..d268ac485402 100644 --- a/platform/windows/display_server_windows.cpp +++ b/platform/windows/display_server_windows.cpp @@ -3740,8 +3740,13 @@ LRESULT DisplayServerWindows::WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARA } } break; case WM_ACTIVATE: { - _process_activate_event(window_id, wParam, lParam); - return 0; // Return to the message loop. + // Activation can happen just after the window has been created, even before the callbacks are set. + // Therefore, it's safer to defer the delivery of the event. + if (!windows[window_id].activate_timer_id) { + windows[window_id].activate_timer_id = SetTimer(windows[window_id].hWnd, 1, USER_TIMER_MINIMUM, (TIMERPROC) nullptr); + } + windows[window_id].activate_state = GET_WM_ACTIVATE_STATE(wParam, lParam); + return 0; } break; case WM_GETMINMAXINFO: { if (windows[window_id].resizable && !windows[window_id].fullscreen) { @@ -3864,11 +3869,13 @@ LRESULT DisplayServerWindows::WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARA return 0; } } break; - case WM_CLOSE: // Did we receive a close message? - { + case WM_CLOSE: { + if (windows[window_id].activate_timer_id) { + KillTimer(windows[window_id].hWnd, windows[window_id].activate_timer_id); + windows[window_id].activate_timer_id = 0; + } _send_window_event(windows[window_id], WINDOW_EVENT_CLOSE_REQUEST); - - return 0; // Jump back. + return 0; } case WM_MOUSELEAVE: { if (window_mouseover_id == window_id) { @@ -4637,6 +4644,10 @@ LRESULT DisplayServerWindows::WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARA if (!Main::is_iterating()) { Main::iteration(); } + } else if (wParam == windows[window_id].activate_timer_id) { + _process_activate_event(window_id); + KillTimer(windows[window_id].hWnd, windows[window_id].activate_timer_id); + windows[window_id].activate_timer_id = 0; } } break; case WM_SYSKEYUP: @@ -4840,31 +4851,32 @@ LRESULT CALLBACK WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) { } } -void DisplayServerWindows::_process_activate_event(WindowID p_window_id, WPARAM wParam, LPARAM lParam) { - if (LOWORD(wParam) == WA_ACTIVE || LOWORD(wParam) == WA_CLICKACTIVE) { +void DisplayServerWindows::_process_activate_event(WindowID p_window_id) { + WindowData &wd = windows[p_window_id]; + if (wd.activate_state == WA_ACTIVE || wd.activate_state == WA_CLICKACTIVE) { last_focused_window = p_window_id; alt_mem = false; control_mem = false; shift_mem = false; gr_mem = false; _set_mouse_mode_impl(mouse_mode); - if (!IsIconic(windows[p_window_id].hWnd)) { - SetFocus(windows[p_window_id].hWnd); + if (!IsIconic(wd.hWnd)) { + SetFocus(wd.hWnd); } - windows[p_window_id].window_focused = true; - _send_window_event(windows[p_window_id], WINDOW_EVENT_FOCUS_IN); + wd.window_focused = true; + _send_window_event(wd, WINDOW_EVENT_FOCUS_IN); } else { // WM_INACTIVE. Input::get_singleton()->release_pressed_events(); - track_mouse_leave_event(windows[p_window_id].hWnd); + track_mouse_leave_event(wd.hWnd); // Release capture unconditionally because it can be set due to dragging, in addition to captured mode. ReleaseCapture(); alt_mem = false; - windows[p_window_id].window_focused = false; - _send_window_event(windows[p_window_id], WINDOW_EVENT_FOCUS_OUT); + wd.window_focused = false; + _send_window_event(wd, WINDOW_EVENT_FOCUS_OUT); } - if ((tablet_get_current_driver() == "wintab") && wintab_available && windows[p_window_id].wtctx) { - wintab_WTEnable(windows[p_window_id].wtctx, GET_WM_ACTIVATE_STATE(wParam, lParam)); + if ((tablet_get_current_driver() == "wintab") && wintab_available && wd.wtctx) { + wintab_WTEnable(wd.wtctx, wd.activate_state); } } diff --git a/platform/windows/display_server_windows.h b/platform/windows/display_server_windows.h index 12350d6b34ee..40c10d594f96 100644 --- a/platform/windows/display_server_windows.h +++ b/platform/windows/display_server_windows.h @@ -389,6 +389,7 @@ class DisplayServerWindows : public DisplayServer { bool borderless = false; bool resizable = true; bool window_focused = false; + int activate_state = 0; bool was_maximized = false; bool always_on_top = false; bool no_focus = false; @@ -402,6 +403,7 @@ class DisplayServerWindows : public DisplayServer { // Timers. uint32_t move_timer_id = 0U; + uint32_t activate_timer_id = 0U; HANDLE wtctx; LOGCONTEXTW wtlc; @@ -508,7 +510,7 @@ class DisplayServerWindows : public DisplayServer { WindowID _get_focused_window_or_popup() const; void _register_raw_input_devices(WindowID p_target_window); - void _process_activate_event(WindowID p_window_id, WPARAM wParam, LPARAM lParam); + void _process_activate_event(WindowID p_window_id); void _process_key_events(); static void _dispatch_input_events(const Ref &p_event);