From a3d03717c0862825bab8c4acdeb889345cd04760 Mon Sep 17 00:00:00 2001 From: Hilderin <81109165+Hilderin@users.noreply.github.com> Date: Wed, 5 Feb 2025 19:51:30 -0500 Subject: [PATCH] Fix Floating Window request close when a dialog is opened --- editor/plugins/embedded_process.cpp | 6 ++++++ editor/plugins/embedded_process.h | 1 + editor/plugins/game_view_plugin.cpp | 9 +++++---- platform/linuxbsd/x11/display_server_x11.cpp | 16 +++++++++++++++- platform/linuxbsd/x11/display_server_x11.h | 1 + platform/windows/display_server_windows.cpp | 16 +++++++++++++++- platform/windows/display_server_windows.h | 1 + servers/display_server.cpp | 5 +++++ servers/display_server.h | 1 + 9 files changed, 50 insertions(+), 6 deletions(-) diff --git a/editor/plugins/embedded_process.cpp b/editor/plugins/embedded_process.cpp index 1638c437125..72c87bfc1c6 100644 --- a/editor/plugins/embedded_process.cpp +++ b/editor/plugins/embedded_process.cpp @@ -200,6 +200,12 @@ void EmbeddedProcess::reset() { queue_redraw(); } +void EmbeddedProcess::request_close() { + if (current_process_id != 0 && embedding_completed) { + DisplayServer::get_singleton()->request_close_embedded_process(current_process_id); + } +} + void EmbeddedProcess::_try_embed_process() { bool is_visible = is_visible_in_tree(); Error err = DisplayServer::get_singleton()->embed_process(window->get_window_id(), current_process_id, get_screen_embedded_window_rect(), is_visible, is_visible && application_has_focus && embedding_grab_focus); diff --git a/editor/plugins/embedded_process.h b/editor/plugins/embedded_process.h index 3e800923a75..abd2c0f36e2 100644 --- a/editor/plugins/embedded_process.h +++ b/editor/plugins/embedded_process.h @@ -76,6 +76,7 @@ protected: public: void embed_process(OS::ProcessID p_pid); void reset(); + void request_close(); void set_window_size(const Size2i p_window_size); void set_keep_aspect(bool p_keep_aspect); diff --git a/editor/plugins/game_view_plugin.cpp b/editor/plugins/game_view_plugin.cpp index a6d73cf9e15..3b8a91c5fc3 100644 --- a/editor/plugins/game_view_plugin.cpp +++ b/editor/plugins/game_view_plugin.cpp @@ -798,16 +798,17 @@ void GameView::_window_close_request() { // Before the parent window closed, we close the embedded game. That prevents // the embedded game to be seen without a parent window for a fraction of second. if (EditorRunBar::get_singleton()->is_playing() && (embedded_process->is_embedding_completed() || embedded_process->is_embedding_in_progress())) { - // Try to gracefully close the window. That way, the NOTIFICATION_WM_CLOSE_REQUEST - // notification should be propagated in the game process. - embedded_process->reset(); - // When the embedding is not complete, we need to kill the process. // If the game is paused, the close request will not be processed by the game, so it's better to kill the process. if (paused || embedded_process->is_embedding_in_progress()) { + embedded_process->reset(); // Call deferred to prevent the _stop_pressed callback to be executed before the wrapper window // actually closes. callable_mp(EditorRunBar::get_singleton(), &EditorRunBar::stop_playing).call_deferred(); + } else { + // Try to gracefully close the window. That way, the NOTIFICATION_WM_CLOSE_REQUEST + // notification should be propagated in the game process. + embedded_process->request_close(); } } } diff --git a/platform/linuxbsd/x11/display_server_x11.cpp b/platform/linuxbsd/x11/display_server_x11.cpp index 95181a1c817..cbf963c59a0 100644 --- a/platform/linuxbsd/x11/display_server_x11.cpp +++ b/platform/linuxbsd/x11/display_server_x11.cpp @@ -5926,7 +5926,7 @@ Error DisplayServerX11::embed_process(WindowID p_window, OS::ProcessID p_pid, co return OK; } -Error DisplayServerX11::remove_embedded_process(OS::ProcessID p_pid) { +Error DisplayServerX11::request_close_embedded_process(OS::ProcessID p_pid) { _THREAD_SAFE_METHOD_ if (!embedded_processes.has(p_pid)) { @@ -5956,6 +5956,20 @@ Error DisplayServerX11::remove_embedded_process(OS::ProcessID p_pid) { // Restore default error handler. XSetErrorHandler(oldHandler); + return OK; +} + +Error DisplayServerX11::remove_embedded_process(OS::ProcessID p_pid) { + _THREAD_SAFE_METHOD_ + + if (!embedded_processes.has(p_pid)) { + return ERR_DOES_NOT_EXIST; + } + + EmbeddedProcessData *ep = embedded_processes.get(p_pid); + + request_close_embedded_process(p_pid); + embedded_processes.erase(p_pid); memdelete(ep); diff --git a/platform/linuxbsd/x11/display_server_x11.h b/platform/linuxbsd/x11/display_server_x11.h index edd70d454da..b21d9024627 100644 --- a/platform/linuxbsd/x11/display_server_x11.h +++ b/platform/linuxbsd/x11/display_server_x11.h @@ -540,6 +540,7 @@ public: virtual void window_start_resize(WindowResizeEdge p_edge, WindowID p_window) override; virtual Error embed_process(WindowID p_window, OS::ProcessID p_pid, const Rect2i &p_rect, bool p_visible, bool p_grab_focus) override; + virtual Error request_close_embedded_process(OS::ProcessID p_pid) override; virtual Error remove_embedded_process(OS::ProcessID p_pid) override; virtual OS::ProcessID get_focused_process_id() override; diff --git a/platform/windows/display_server_windows.cpp b/platform/windows/display_server_windows.cpp index d0ddac4b7f9..6f92cc0d621 100644 --- a/platform/windows/display_server_windows.cpp +++ b/platform/windows/display_server_windows.cpp @@ -3004,7 +3004,7 @@ Error DisplayServerWindows::embed_process(WindowID p_window, OS::ProcessID p_pid return OK; } -Error DisplayServerWindows::remove_embedded_process(OS::ProcessID p_pid) { +Error DisplayServerWindows::request_close_embedded_process(OS::ProcessID p_pid) { _THREAD_SAFE_METHOD_ if (!embedded_processes.has(p_pid)) { @@ -3016,6 +3016,20 @@ Error DisplayServerWindows::remove_embedded_process(OS::ProcessID p_pid) { // Send a close message to gracefully close the process. PostMessage(ep->window_handle, WM_CLOSE, 0, 0); + return OK; +} + +Error DisplayServerWindows::remove_embedded_process(OS::ProcessID p_pid) { + _THREAD_SAFE_METHOD_ + + if (!embedded_processes.has(p_pid)) { + return ERR_DOES_NOT_EXIST; + } + + EmbeddedProcessData *ep = embedded_processes.get(p_pid); + + request_close_embedded_process(p_pid); + // This is a workaround to ensure the parent window correctly regains focus after the // embedded window is closed. When the embedded window is closed while it has focus, // the parent window (the editor) does not become active. It appears focused but is not truly activated. diff --git a/platform/windows/display_server_windows.h b/platform/windows/display_server_windows.h index 71de7a73769..30f71c8c7e1 100644 --- a/platform/windows/display_server_windows.h +++ b/platform/windows/display_server_windows.h @@ -837,6 +837,7 @@ public: virtual void enable_for_stealing_focus(OS::ProcessID pid) override; virtual Error embed_process(WindowID p_window, OS::ProcessID p_pid, const Rect2i &p_rect, bool p_visible, bool p_grab_focus) override; + virtual Error request_close_embedded_process(OS::ProcessID p_pid) override; virtual Error remove_embedded_process(OS::ProcessID p_pid) override; virtual OS::ProcessID get_focused_process_id() override; diff --git a/servers/display_server.cpp b/servers/display_server.cpp index bf3d428420a..6dd9044617e 100644 --- a/servers/display_server.cpp +++ b/servers/display_server.cpp @@ -679,6 +679,11 @@ Error DisplayServer::embed_process(WindowID p_window, OS::ProcessID p_pid, const return ERR_UNAVAILABLE; } +Error DisplayServer::request_close_embedded_process(OS::ProcessID p_pid) { + WARN_PRINT("Embedded process not supported by this display server."); + return ERR_UNAVAILABLE; +} + Error DisplayServer::remove_embedded_process(OS::ProcessID p_pid) { WARN_PRINT("Embedded process not supported by this display server."); return ERR_UNAVAILABLE; diff --git a/servers/display_server.h b/servers/display_server.h index 30bb533a5d3..79cf9ffc44b 100644 --- a/servers/display_server.h +++ b/servers/display_server.h @@ -577,6 +577,7 @@ public: virtual void enable_for_stealing_focus(OS::ProcessID pid); virtual Error embed_process(WindowID p_window, OS::ProcessID p_pid, const Rect2i &p_rect, bool p_visible, bool p_grab_focus); + virtual Error request_close_embedded_process(OS::ProcessID p_pid); virtual Error remove_embedded_process(OS::ProcessID p_pid); virtual OS::ProcessID get_focused_process_id();