@@ -67,20 +67,18 @@ void EmbeddedProcess::_notification(int p_what) {
67
67
} break ;
68
68
case NOTIFICATION_APPLICATION_FOCUS_IN: {
69
69
application_has_focus = true ;
70
- if (embedded_process_was_focused) {
71
- embedded_process_was_focused = false ;
72
- // Refocus the embedded process if it was focused when the application lost focus,
73
- // but do not refocus if the embedded process is currently focused (indicating it just lost focus)
74
- // or if the current window is a different popup or secondary window.
75
- if (embedding_completed && current_process_id != focused_process_id && window && window->has_focus ()) {
76
- grab_focus ();
77
- queue_update_embedded_process ();
78
- }
79
- }
70
+ last_application_focus_time = OS::get_singleton ()->get_ticks_msec ();
80
71
} break ;
81
72
case NOTIFICATION_APPLICATION_FOCUS_OUT: {
82
73
application_has_focus = false ;
83
- embedded_process_was_focused = embedding_completed && current_process_id == focused_process_id;
74
+
75
+ // // Refocus the current model when focusing the embedded process.
76
+ // if (embedding_completed && current_process_id == DisplayServer::get_singleton()->get_focused_process_id()) {
77
+ // Window *modal_window = _get_current_modal_window();
78
+ // if (modal_window) {
79
+ // callable_mp(modal_window, &Window::grab_focus).call_deferred();
80
+ // }
81
+ // }
84
82
} break ;
85
83
}
86
84
}
@@ -286,14 +284,27 @@ void EmbeddedProcess::_check_mouse_over() {
286
284
// This method checks if the mouse is over the embedded process while the current application is focused.
287
285
// The goal is to give focus to the embedded process as soon as the mouse hovers over it,
288
286
// allowing the user to interact with it immediately without needing to click first.
289
- 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)) {
287
+ 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)) {
290
288
return ;
291
289
}
292
290
293
- bool focused = has_focus ();
291
+ // Before checking whether the mouse is truly inside the embedded process, ensure
292
+ // the editor has enough time to re-render. When a breakpoint is hit in the script editor,
293
+ // `_check_mouse_over` may be triggered before the editor hides the game workspace.
294
+ // This prevents the embedded process from regaining focus immediately after the editor has taken it.
295
+ if (OS::get_singleton ()->get_ticks_msec () - last_application_focus_time < 500 ) {
296
+ return ;
297
+ }
298
+
299
+ // Input::is_mouse_button_pressed is not sufficient to detect the mouse button state
300
+ // while the floating game window is being resized.
301
+ BitField<MouseButtonMask> mouse_button_mask = DisplayServer::get_singleton ()->mouse_get_button_state ();
302
+ if (!mouse_button_mask.is_empty ()) {
303
+ return ;
304
+ }
294
305
295
306
// Not stealing focus from a textfield.
296
- if (!focused && get_viewport ()->gui_get_focus_owner () && get_viewport ()->gui_get_focus_owner ()->is_text_field ()) {
307
+ if (get_viewport ()->gui_get_focus_owner () && get_viewport ()->gui_get_focus_owner ()->is_text_field ()) {
297
308
return ;
298
309
}
299
310
@@ -309,14 +320,17 @@ void EmbeddedProcess::_check_mouse_over() {
309
320
return ;
310
321
}
311
322
312
- // When we already have the focus and the user moves the mouse over the embedded process,
313
- // we just need to refocus the process.
314
- if (focused) {
315
- queue_update_embedded_process ();
316
- } else {
317
- grab_focus ();
318
- queue_redraw ();
323
+ // When there's a modal window, we don't want to grab the focus to prevent
324
+ // the game window to go in front of the modal window.
325
+ if (_get_current_modal_window ()) {
326
+ return ;
319
327
}
328
+
329
+ // Force "regrabbing" the game window focus.
330
+ last_updated_embedded_process_focused = false ;
331
+
332
+ grab_focus ();
333
+ queue_redraw ();
320
334
}
321
335
322
336
void EmbeddedProcess::_check_focused_process_id () {
@@ -325,6 +339,14 @@ void EmbeddedProcess::_check_focused_process_id() {
325
339
focused_process_id = process_id;
326
340
if (focused_process_id == current_process_id) {
327
341
// The embedded process got the focus.
342
+
343
+ // Refocus the current model when focusing the embedded process.
344
+ Window *modal_window = _get_current_modal_window ();
345
+ if (modal_window) {
346
+ callable_mp (modal_window, &Window::grab_focus).call_deferred ();
347
+ return ;
348
+ }
349
+
328
350
emit_signal (SNAME (" embedded_process_focused" ));
329
351
if (has_focus ()) {
330
352
// Redraw to updated the focus style.
@@ -336,6 +358,29 @@ void EmbeddedProcess::_check_focused_process_id() {
336
358
release_focus ();
337
359
}
338
360
}
361
+
362
+ // Ensure that the opened modal dialog is refocused when the focused process is the embedded process.
363
+ if (!application_has_focus && focused_process_id == current_process_id) {
364
+ Window *modal_window = _get_current_modal_window ();
365
+ if (modal_window) {
366
+ callable_mp (modal_window, &Window::grab_focus).call_deferred ();
367
+ }
368
+ }
369
+ }
370
+
371
+ Window *EmbeddedProcess::_get_current_modal_window () {
372
+ Vector<DisplayServer::WindowID> wl = DisplayServer::get_singleton ()->get_window_list ();
373
+ for (const DisplayServer::WindowID &window_id : wl) {
374
+ Window *w = Window::get_from_id (window_id);
375
+ if (!w) {
376
+ continue ;
377
+ }
378
+
379
+ if (w->is_exclusive ()) {
380
+ return w;
381
+ }
382
+ }
383
+ return nullptr ;
339
384
}
340
385
341
386
void EmbeddedProcess::_bind_methods () {
0 commit comments