@@ -73,20 +73,10 @@ void EmbeddedProcess::_notification(int p_what) {
7373 } break ;
7474 case NOTIFICATION_APPLICATION_FOCUS_IN: {
7575 application_has_focus = true ;
76- if (embedded_process_was_focused) {
77- embedded_process_was_focused = false ;
78- // Refocus the embedded process if it was focused when the application lost focus,
79- // but do not refocus if the embedded process is currently focused (indicating it just lost focus)
80- // or if the current window is a different popup or secondary window.
81- if (embedding_completed && current_process_id != focused_process_id && window && window->has_focus ()) {
82- grab_focus ();
83- queue_update_embedded_process ();
84- }
85- }
76+ last_application_focus_time = OS::get_singleton ()->get_ticks_msec ();
8677 } break ;
8778 case NOTIFICATION_APPLICATION_FOCUS_OUT: {
8879 application_has_focus = false ;
89- embedded_process_was_focused = embedding_completed && current_process_id == focused_process_id;
9080 } break ;
9181 }
9282}
@@ -295,14 +285,27 @@ void EmbeddedProcess::_check_mouse_over() {
295285 // This method checks if the mouse is over the embedded process while the current application is focused.
296286 // The goal is to give focus to the embedded process as soon as the mouse hovers over it,
297287 // allowing the user to interact with it immediately without needing to click first.
298- if (!is_visible_in_tree () || !embedding_completed || !application_has_focus || !window || !window->has_focus () || Input::get_singleton ()->is_mouse_button_pressed (MouseButton::LEFT) || Input::get_singleton ()->is_mouse_button_pressed (MouseButton::RIGHT)) {
288+ if (!embedding_completed || !application_has_focus || !window || has_focus () || !is_visible_in_tree () || !window->has_focus () || Input::get_singleton ()->is_mouse_button_pressed (MouseButton::LEFT) || Input::get_singleton ()->is_mouse_button_pressed (MouseButton::RIGHT)) {
289+ return ;
290+ }
291+
292+ // Before checking whether the mouse is truly inside the embedded process, ensure
293+ // the editor has enough time to re-render. When a breakpoint is hit in the script editor,
294+ // `_check_mouse_over` may be triggered before the editor hides the game workspace.
295+ // This prevents the embedded process from regaining focus immediately after the editor has taken it.
296+ if (OS::get_singleton ()->get_ticks_msec () - last_application_focus_time < 500 ) {
299297 return ;
300298 }
301299
302- bool focused = has_focus ();
300+ // Input::is_mouse_button_pressed is not sufficient to detect the mouse button state
301+ // while the floating game window is being resized.
302+ BitField<MouseButtonMask> mouse_button_mask = DisplayServer::get_singleton ()->mouse_get_button_state ();
303+ if (!mouse_button_mask.is_empty ()) {
304+ return ;
305+ }
303306
304307 // Not stealing focus from a textfield.
305- if (!focused && get_viewport ()->gui_get_focus_owner () && get_viewport ()->gui_get_focus_owner ()->is_text_field ()) {
308+ if (get_viewport ()->gui_get_focus_owner () && get_viewport ()->gui_get_focus_owner ()->is_text_field ()) {
306309 return ;
307310 }
308311
@@ -318,14 +321,17 @@ void EmbeddedProcess::_check_mouse_over() {
318321 return ;
319322 }
320323
321- // When we already have the focus and the user moves the mouse over the embedded process,
322- // we just need to refocus the process.
323- if (focused) {
324- queue_update_embedded_process ();
325- } else {
326- grab_focus ();
327- queue_redraw ();
324+ // When there's a modal window, we don't want to grab the focus to prevent
325+ // the game window to go in front of the modal window.
326+ if (_get_current_modal_window ()) {
327+ return ;
328328 }
329+
330+ // Force "regrabbing" the game window focus.
331+ last_updated_embedded_process_focused = false ;
332+
333+ grab_focus ();
334+ queue_redraw ();
329335}
330336
331337void EmbeddedProcess::_check_focused_process_id () {
@@ -334,17 +340,48 @@ void EmbeddedProcess::_check_focused_process_id() {
334340 focused_process_id = process_id;
335341 if (focused_process_id == current_process_id) {
336342 // The embedded process got the focus.
337- emit_signal (SNAME (" embedded_process_focused" ));
338- if (has_focus ()) {
339- // Redraw to updated the focus style.
340- queue_redraw ();
341- } else {
342- grab_focus ();
343+
344+ // Refocus the current model when focusing the embedded process.
345+ Window *modal_window = _get_current_modal_window ();
346+ if (!modal_window) {
347+ emit_signal (SNAME (" embedded_process_focused" ));
348+ if (has_focus ()) {
349+ // Redraw to updated the focus style.
350+ queue_redraw ();
351+ } else {
352+ grab_focus ();
353+ }
343354 }
344355 } else if (has_focus ()) {
345356 release_focus ();
346357 }
347358 }
359+
360+ // Ensure that the opened modal dialog is refocused when the focused process is the embedded process.
361+ if (!application_has_focus && focused_process_id == current_process_id) {
362+ Window *modal_window = _get_current_modal_window ();
363+ if (modal_window) {
364+ if (modal_window->get_mode () == Window::MODE_MINIMIZED) {
365+ modal_window->set_mode (Window::MODE_WINDOWED);
366+ }
367+ callable_mp (modal_window, &Window::grab_focus).call_deferred ();
368+ }
369+ }
370+ }
371+
372+ Window *EmbeddedProcess::_get_current_modal_window () {
373+ Vector<DisplayServer::WindowID> wl = DisplayServer::get_singleton ()->get_window_list ();
374+ for (const DisplayServer::WindowID &window_id : wl) {
375+ Window *w = Window::get_from_id (window_id);
376+ if (!w) {
377+ continue ;
378+ }
379+
380+ if (w->is_exclusive ()) {
381+ return w;
382+ }
383+ }
384+ return nullptr ;
348385}
349386
350387void EmbeddedProcess::_bind_methods () {
0 commit comments