@@ -81,20 +81,18 @@ void EmbeddedProcess::_notification(int p_what) {
81
81
} break ;
82
82
case NOTIFICATION_APPLICATION_FOCUS_IN: {
83
83
application_has_focus = true ;
84
- if (embedded_process_was_focused) {
85
- embedded_process_was_focused = false ;
86
- // Refocus the embedded process if it was focused when the application lost focus,
87
- // but do not refocus if the embedded process is currently focused (indicating it just lost focus)
88
- // or if the current window is a different popup or secondary window.
89
- if (embedding_completed && current_process_id != focused_process_id && window && window->has_focus ()) {
90
- grab_focus ();
91
- queue_update_embedded_process ();
92
- }
93
- }
84
+ last_application_focus_time = OS::get_singleton ()->get_ticks_msec ();
94
85
} break ;
95
86
case NOTIFICATION_APPLICATION_FOCUS_OUT: {
96
87
application_has_focus = false ;
97
- embedded_process_was_focused = embedding_completed && current_process_id == focused_process_id;
88
+
89
+ // Refocus the current model when focusing the embedded process.
90
+ if (embedding_completed && current_process_id == DisplayServer::get_singleton ()->get_focused_process_id ()) {
91
+ Window *modal_window = _get_current_modal_window ();
92
+ if (modal_window) {
93
+ callable_mp (modal_window, &Window::grab_focus).call_deferred ();
94
+ }
95
+ }
98
96
} break ;
99
97
}
100
98
}
@@ -266,7 +264,6 @@ void EmbeddedProcess::_update_embedded_process() {
266
264
}
267
265
last_updated_embedded_process_focused = focus;
268
266
}
269
-
270
267
DisplayServer::get_singleton ()->embed_process (window->get_window_id (), current_process_id, get_screen_embedded_window_rect (), is_visible_in_tree (), must_grab_focus);
271
268
emit_signal (SNAME (" embedded_process_updated" ));
272
269
}
@@ -287,14 +284,27 @@ void EmbeddedProcess::_check_mouse_over() {
287
284
// This method checks if the mouse is over the embedded process while the current application is focused.
288
285
// The goal is to give focus to the embedded process as soon as the mouse hovers over it,
289
286
// allowing the user to interact with it immediately without needing to click first.
290
- 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)) {
291
288
return ;
292
289
}
293
290
294
- 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
+ }
295
305
296
306
// Not stealing focus from a textfield.
297
- 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 ()) {
298
308
return ;
299
309
}
300
310
@@ -310,14 +320,17 @@ void EmbeddedProcess::_check_mouse_over() {
310
320
return ;
311
321
}
312
322
313
- // When we already have the focus and the user moves the mouse over the embedded process,
314
- // we just need to refocus the process.
315
- if (focused) {
316
- queue_update_embedded_process ();
317
- } else {
318
- grab_focus ();
319
- 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 ;
320
327
}
328
+
329
+ // Force "regrabbing" the game window focus.
330
+ last_updated_embedded_process_focused = false ;
331
+
332
+ grab_focus ();
333
+ queue_redraw ();
321
334
}
322
335
323
336
void EmbeddedProcess::_check_focused_process_id () {
@@ -326,19 +339,41 @@ void EmbeddedProcess::_check_focused_process_id() {
326
339
focused_process_id = process_id;
327
340
if (focused_process_id == current_process_id) {
328
341
// The embedded process got the focus.
329
- emit_signal (SNAME (" embedded_process_focused" ));
330
- if (has_focus ()) {
331
- // Redraw to updated the focus style.
332
- queue_redraw ();
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 ();
333
347
} else {
334
- grab_focus ();
348
+ emit_signal (SNAME (" embedded_process_focused" ));
349
+ if (has_focus ()) {
350
+ // Redraw to updated the focus style.
351
+ queue_redraw ();
352
+ } else {
353
+ grab_focus ();
354
+ }
335
355
}
336
356
} else if (has_focus ()) {
337
357
release_focus ();
338
358
}
339
359
}
340
360
}
341
361
362
+ Window *EmbeddedProcess::_get_current_modal_window () {
363
+ Vector<DisplayServer::WindowID> wl = DisplayServer::get_singleton ()->get_window_list ();
364
+ for (const DisplayServer::WindowID &window_id : wl) {
365
+ Window *w = Window::get_from_id (window_id);
366
+ if (!w) {
367
+ continue ;
368
+ }
369
+
370
+ if (w->is_exclusive ()) {
371
+ return w;
372
+ }
373
+ }
374
+ return nullptr ;
375
+ }
376
+
342
377
void EmbeddedProcess::_bind_methods () {
343
378
ADD_SIGNAL (MethodInfo (" embedding_completed" ));
344
379
ADD_SIGNAL (MethodInfo (" embedding_failed" ));
0 commit comments