Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Windows: Fix WINDOW_EVENT_FOCUS_IN not delivered in some cases #91361

Merged
merged 1 commit into from
May 7, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
46 changes: 29 additions & 17 deletions platform/windows/display_server_windows.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand Down Expand Up @@ -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) {
Expand Down Expand Up @@ -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:
Expand Down Expand Up @@ -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);
}
}

Expand Down
4 changes: 3 additions & 1 deletion platform/windows/display_server_windows.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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;
Expand Down Expand Up @@ -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<InputEvent> &p_event);
Expand Down
Loading