mirror of
				https://github.com/godotengine/godot.git
				synced 2025-10-30 21:21:10 +00:00 
			
		
		
		
	Merge pull request #102247 from Hilderin/fix-embedded-game-modal-dialog
Fix Modal Dialog with Embedded Game
This commit is contained in:
		
						commit
						bd87c3a76b
					
				
					 3 changed files with 68 additions and 29 deletions
				
			
		|  | @ -73,20 +73,10 @@ void EmbeddedProcess::_notification(int p_what) { | |||
| 		} break; | ||||
| 		case NOTIFICATION_APPLICATION_FOCUS_IN: { | ||||
| 			application_has_focus = true; | ||||
| 			if (embedded_process_was_focused) { | ||||
| 				embedded_process_was_focused = false; | ||||
| 				// Refocus the embedded process if it was focused when the application lost focus,
 | ||||
| 				// but do not refocus if the embedded process is currently focused (indicating it just lost focus)
 | ||||
| 				// or if the current window is a different popup or secondary window.
 | ||||
| 				if (embedding_completed && current_process_id != focused_process_id && window && window->has_focus()) { | ||||
| 					grab_focus(); | ||||
| 					queue_update_embedded_process(); | ||||
| 				} | ||||
| 			} | ||||
| 			last_application_focus_time = OS::get_singleton()->get_ticks_msec(); | ||||
| 		} break; | ||||
| 		case NOTIFICATION_APPLICATION_FOCUS_OUT: { | ||||
| 			application_has_focus = false; | ||||
| 			embedded_process_was_focused = embedding_completed && current_process_id == focused_process_id; | ||||
| 		} break; | ||||
| 	} | ||||
| } | ||||
|  | @ -295,14 +285,27 @@ void EmbeddedProcess::_check_mouse_over() { | |||
| 	// This method checks if the mouse is over the embedded process while the current application is focused.
 | ||||
| 	// The goal is to give focus to the embedded process as soon as the mouse hovers over it,
 | ||||
| 	// allowing the user to interact with it immediately without needing to click first.
 | ||||
| 	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)) { | ||||
| 	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)) { | ||||
| 		return; | ||||
| 	} | ||||
| 
 | ||||
| 	bool focused = has_focus(); | ||||
| 	// Before checking whether the mouse is truly inside the embedded process, ensure
 | ||||
| 	// the editor has enough time to re-render. When a breakpoint is hit in the script editor,
 | ||||
| 	// `_check_mouse_over` may be triggered before the editor hides the game workspace.
 | ||||
| 	// This prevents the embedded process from regaining focus immediately after the editor has taken it.
 | ||||
| 	if (OS::get_singleton()->get_ticks_msec() - last_application_focus_time < 500) { | ||||
| 		return; | ||||
| 	} | ||||
| 
 | ||||
| 	// Input::is_mouse_button_pressed is not sufficient to detect the mouse button state
 | ||||
| 	// while the floating game window is being resized.
 | ||||
| 	BitField<MouseButtonMask> mouse_button_mask = DisplayServer::get_singleton()->mouse_get_button_state(); | ||||
| 	if (!mouse_button_mask.is_empty()) { | ||||
| 		return; | ||||
| 	} | ||||
| 
 | ||||
| 	// Not stealing focus from a textfield.
 | ||||
| 	if (!focused && get_viewport()->gui_get_focus_owner() && get_viewport()->gui_get_focus_owner()->is_text_field()) { | ||||
| 	if (get_viewport()->gui_get_focus_owner() && get_viewport()->gui_get_focus_owner()->is_text_field()) { | ||||
| 		return; | ||||
| 	} | ||||
| 
 | ||||
|  | @ -318,14 +321,17 @@ void EmbeddedProcess::_check_mouse_over() { | |||
| 		return; | ||||
| 	} | ||||
| 
 | ||||
| 	// When we already have the focus and the user moves the mouse over the embedded process,
 | ||||
| 	// we just need to refocus the process.
 | ||||
| 	if (focused) { | ||||
| 		queue_update_embedded_process(); | ||||
| 	} else { | ||||
| 		grab_focus(); | ||||
| 		queue_redraw(); | ||||
| 	// When there's a modal window, we don't want to grab the focus to prevent
 | ||||
| 	// the game window to go in front of the modal window.
 | ||||
| 	if (_get_current_modal_window()) { | ||||
| 		return; | ||||
| 	} | ||||
| 
 | ||||
| 	// Force "regrabbing" the game window focus.
 | ||||
| 	last_updated_embedded_process_focused = false; | ||||
| 
 | ||||
| 	grab_focus(); | ||||
| 	queue_redraw(); | ||||
| } | ||||
| 
 | ||||
| void EmbeddedProcess::_check_focused_process_id() { | ||||
|  | @ -334,17 +340,48 @@ void EmbeddedProcess::_check_focused_process_id() { | |||
| 		focused_process_id = process_id; | ||||
| 		if (focused_process_id == current_process_id) { | ||||
| 			// The embedded process got the focus.
 | ||||
| 			emit_signal(SNAME("embedded_process_focused")); | ||||
| 			if (has_focus()) { | ||||
| 				// Redraw to updated the focus style.
 | ||||
| 				queue_redraw(); | ||||
| 			} else { | ||||
| 				grab_focus(); | ||||
| 
 | ||||
| 			// Refocus the current model when focusing the embedded process.
 | ||||
| 			Window *modal_window = _get_current_modal_window(); | ||||
| 			if (!modal_window) { | ||||
| 				emit_signal(SNAME("embedded_process_focused")); | ||||
| 				if (has_focus()) { | ||||
| 					// Redraw to updated the focus style.
 | ||||
| 					queue_redraw(); | ||||
| 				} else { | ||||
| 					grab_focus(); | ||||
| 				} | ||||
| 			} | ||||
| 		} else if (has_focus()) { | ||||
| 			release_focus(); | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	// Ensure that the opened modal dialog is refocused when the focused process is the embedded process.
 | ||||
| 	if (!application_has_focus && focused_process_id == current_process_id) { | ||||
| 		Window *modal_window = _get_current_modal_window(); | ||||
| 		if (modal_window) { | ||||
| 			if (modal_window->get_mode() == Window::MODE_MINIMIZED) { | ||||
| 				modal_window->set_mode(Window::MODE_WINDOWED); | ||||
| 			} | ||||
| 			callable_mp(modal_window, &Window::grab_focus).call_deferred(); | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| Window *EmbeddedProcess::_get_current_modal_window() { | ||||
| 	Vector<DisplayServer::WindowID> wl = DisplayServer::get_singleton()->get_window_list(); | ||||
| 	for (const DisplayServer::WindowID &window_id : wl) { | ||||
| 		Window *w = Window::get_from_id(window_id); | ||||
| 		if (!w) { | ||||
| 			continue; | ||||
| 		} | ||||
| 
 | ||||
| 		if (w->is_exclusive()) { | ||||
| 			return w; | ||||
| 		} | ||||
| 	} | ||||
| 	return nullptr; | ||||
| } | ||||
| 
 | ||||
| void EmbeddedProcess::_bind_methods() { | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 Rémi Verschelde
						Rémi Verschelde