Skip to content

Commit 76f074b

Browse files
committed
Merge pull request #101895 from Hilderin/fix-close-request-notification-embedded-game
Fix NOTIFICATION_WM_CLOSE_REQUEST in Embedded Floating Window
2 parents a6da0aa + 9eed43d commit 76f074b

File tree

6 files changed

+53
-15
lines changed

6 files changed

+53
-15
lines changed

editor/plugins/game_view_plugin.cpp

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -652,14 +652,20 @@ void GameView::_update_arguments_for_instance(int p_idx, List<String> &r_argumen
652652
r_arguments.insert_after(N, itos(rect.size.x) + "x" + itos(rect.size.y));
653653
}
654654

655-
void GameView::_window_before_closing() {
655+
void GameView::_window_close_request() {
656656
// Before the parent window closed, we close the embedded game. That prevents
657657
// the embedded game to be seen without a parent window for a fraction of second.
658658
if (EditorRunBar::get_singleton()->is_playing() && (embedded_process->is_embedding_completed() || embedded_process->is_embedding_in_progress())) {
659+
// Try to gracefully close the window. That way, the NOTIFICATION_WM_CLOSE_REQUEST
660+
// notification should be propagated in the game process.
659661
embedded_process->reset();
660-
// Call deferred to prevent the _stop_pressed callback to be executed before the wrapper window
661-
// actually closes.
662-
callable_mp(EditorRunBar::get_singleton(), &EditorRunBar::stop_playing).call_deferred();
662+
663+
// When the embedding is not complete, we need to kill the process.
664+
if (embedded_process->is_embedding_in_progress()) {
665+
// Call deferred to prevent the _stop_pressed callback to be executed before the wrapper window
666+
// actually closes.
667+
callable_mp(EditorRunBar::get_singleton(), &EditorRunBar::stop_playing).call_deferred();
668+
}
663669
}
664670
}
665671

@@ -829,7 +835,8 @@ GameView::GameView(Ref<GameViewDebugger> p_debugger, WindowWrapper *p_wrapper) {
829835
p_debugger->connect("session_started", callable_mp(this, &GameView::_sessions_changed));
830836
p_debugger->connect("session_stopped", callable_mp(this, &GameView::_sessions_changed));
831837

832-
p_wrapper->connect("window_before_closing", callable_mp(this, &GameView::_window_before_closing));
838+
p_wrapper->set_override_close_request(true);
839+
p_wrapper->connect("window_close_requested", callable_mp(this, &GameView::_window_close_request));
833840
p_wrapper->connect("window_size_changed", callable_mp(this, &GameView::_update_floating_window_settings));
834841
}
835842

editor/plugins/game_view_plugin.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -162,7 +162,7 @@ class GameView : public VBoxContainer {
162162
void _camera_override_button_toggled(bool p_pressed);
163163
void _camera_override_menu_id_pressed(int p_id);
164164

165-
void _window_before_closing();
165+
void _window_close_request();
166166
void _update_floating_window_settings();
167167
void _attach_script_debugger();
168168
void _detach_script_debugger();

editor/window_wrapper.cpp

Lines changed: 14 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -101,12 +101,6 @@ void WindowWrapper::_set_window_enabled_with_rect(bool p_visible, const Rect2 p_
101101

102102
Node *parent = _get_wrapped_control_parent();
103103

104-
// In the GameView plugin, we need to the the signal before the window is actually closed
105-
// to prevent the embedded game to be seen the parent window for a fraction of a second.
106-
if (!p_visible) {
107-
emit_signal("window_before_closing");
108-
}
109-
110104
if (wrapped_control->get_parent() != parent) {
111105
// Move the control to the window.
112106
wrapped_control->reparent(parent, false);
@@ -120,7 +114,7 @@ void WindowWrapper::_set_window_enabled_with_rect(bool p_visible, const Rect2 p_
120114
}
121115

122116
window->set_visible(p_visible);
123-
if (!p_visible) {
117+
if (!p_visible && !override_close_request) {
124118
emit_signal("window_close_requested");
125119
}
126120
emit_signal("window_visibility_changed", p_visible);
@@ -141,10 +135,17 @@ void WindowWrapper::_window_size_changed() {
141135
emit_signal(SNAME("window_size_changed"));
142136
}
143137

138+
void WindowWrapper::_window_close_request() {
139+
if (override_close_request) {
140+
emit_signal("window_close_requested");
141+
} else {
142+
set_window_enabled(false);
143+
}
144+
}
145+
144146
void WindowWrapper::_bind_methods() {
145147
ADD_SIGNAL(MethodInfo("window_visibility_changed", PropertyInfo(Variant::BOOL, "visible")));
146148
ADD_SIGNAL(MethodInfo("window_close_requested"));
147-
ADD_SIGNAL(MethodInfo("window_before_closing"));
148149
ADD_SIGNAL(MethodInfo("window_size_changed"));
149150
}
150151

@@ -330,6 +331,10 @@ void WindowWrapper::grab_window_focus() {
330331
}
331332
}
332333

334+
void WindowWrapper::set_override_close_request(bool p_enabled) {
335+
override_close_request = p_enabled;
336+
}
337+
333338
WindowWrapper::WindowWrapper() {
334339
if (!EditorNode::get_singleton()->is_multi_window_enabled()) {
335340
return;
@@ -342,7 +347,7 @@ WindowWrapper::WindowWrapper() {
342347
add_child(window);
343348
window->hide();
344349

345-
window->connect("close_requested", callable_mp(this, &WindowWrapper::set_window_enabled).bind(false));
350+
window->connect("close_requested", callable_mp(this, &WindowWrapper::_window_close_request));
346351
window->connect("size_changed", callable_mp(this, &WindowWrapper::_window_size_changed));
347352

348353
ShortcutBin *capturer = memnew(ShortcutBin);

editor/window_wrapper.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,12 +50,15 @@ class WindowWrapper : public MarginContainer {
5050

5151
Ref<Shortcut> enable_shortcut;
5252

53+
bool override_close_request = false;
54+
5355
Rect2 _get_default_window_rect() const;
5456
Node *_get_wrapped_control_parent() const;
5557

5658
void _set_window_enabled_with_rect(bool p_visible, const Rect2 p_rect);
5759
void _set_window_rect(const Rect2 p_rect);
5860
void _window_size_changed();
61+
void _window_close_request();
5962

6063
protected:
6164
static void _bind_methods();
@@ -84,6 +87,8 @@ class WindowWrapper : public MarginContainer {
8487
void set_margins_enabled(bool p_enabled);
8588
void grab_window_focus();
8689

90+
void set_override_close_request(bool p_enabled);
91+
8792
WindowWrapper();
8893
~WindowWrapper();
8994
};

platform/linuxbsd/x11/display_server_x11.cpp

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5849,6 +5849,24 @@ Error DisplayServerX11::remove_embedded_process(OS::ProcessID p_pid) {
58495849
}
58505850

58515851
EmbeddedProcessData *ep = embedded_processes.get(p_pid);
5852+
5853+
// Handle bad window errors silently because just in case the embedded window was closed.
5854+
int (*oldHandler)(Display *, XErrorEvent *) = XSetErrorHandler(&bad_window_error_handler);
5855+
5856+
// Send the message to gracefully close the window.
5857+
XEvent ev;
5858+
memset(&ev, 0, sizeof(ev));
5859+
ev.xclient.type = ClientMessage;
5860+
ev.xclient.window = ep->process_window;
5861+
ev.xclient.message_type = XInternAtom(x11_display, "WM_PROTOCOLS", True);
5862+
ev.xclient.format = 32;
5863+
ev.xclient.data.l[0] = XInternAtom(x11_display, "WM_DELETE_WINDOW", False);
5864+
ev.xclient.data.l[1] = CurrentTime;
5865+
XSendEvent(x11_display, ep->process_window, False, NoEventMask, &ev);
5866+
5867+
// Restore default error handler.
5868+
XSetErrorHandler(oldHandler);
5869+
58525870
embedded_processes.erase(p_pid);
58535871
memdelete(ep);
58545872

platform/windows/display_server_windows.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2975,6 +2975,9 @@ Error DisplayServerWindows::remove_embedded_process(OS::ProcessID p_pid) {
29752975

29762976
EmbeddedProcessData *ep = embedded_processes.get(p_pid);
29772977

2978+
// Send a close message to gracefully close the process.
2979+
PostMessage(ep->window_handle, WM_CLOSE, 0, 0);
2980+
29782981
// This is a workaround to ensure the parent window correctly regains focus after the
29792982
// embedded window is closed. When the embedded window is closed while it has focus,
29802983
// the parent window (the editor) does not become active. It appears focused but is not truly activated.

0 commit comments

Comments
 (0)