1
0
mirror of https://github.com/godotengine/godot.git synced 2025-11-10 13:00:37 +00:00

MacOS: Embedded window support.

This commit is contained in:
Stuart Carnie
2025-04-29 07:01:27 +10:00
parent 1cf573f44d
commit 00e1fdec2c
37 changed files with 3670 additions and 384 deletions

View File

@@ -243,11 +243,17 @@ void GameView::_sessions_changed() {
_update_debugger_buttons();
#ifdef MACOS_ENABLED
if (!embedded_script_debugger || !embedded_script_debugger->is_session_active() || embedded_script_debugger->get_remote_pid() != embedded_process->get_embedded_pid()) {
_attach_script_debugger();
}
#else
if (embedded_process->is_embedding_completed()) {
if (!embedded_script_debugger || !embedded_script_debugger->is_session_active() || embedded_script_debugger->get_remote_pid() != embedded_process->get_embedded_pid()) {
_attach_script_debugger();
}
}
#endif
}
void GameView::_instance_starting_static(int p_idx, List<String> &r_arguments) {
@@ -370,7 +376,9 @@ void GameView::_stop_pressed() {
}
void GameView::_embedding_completed() {
#ifndef MACOS_ENABLED
_attach_script_debugger();
#endif
_update_ui();
if (make_floating_on_play) {
get_window()->set_flag(Window::FLAG_ALWAYS_ON_TOP, bool(GLOBAL_GET("display/window/size/always_on_top")));
@@ -507,9 +515,11 @@ GameView::EmbedAvailability GameView::_get_embed_available() {
if (!DisplayServer::get_singleton()->has_feature(DisplayServer::FEATURE_WINDOW_EMBEDDING)) {
return EMBED_NOT_AVAILABLE_FEATURE_NOT_SUPPORTED;
}
#ifndef MACOS_ENABLED
if (get_tree()->get_root()->is_embedding_subwindows()) {
return EMBED_NOT_AVAILABLE_SINGLE_WINDOW_MODE;
}
#endif
String display_driver = GLOBAL_GET("display/display_server/driver");
if (display_driver == "headless" || display_driver == "wayland") {
return EMBED_NOT_AVAILABLE_PROJECT_DISPLAY_DRIVER;
@@ -786,14 +796,19 @@ void GameView::_attach_script_debugger() {
}
embedded_script_debugger = nullptr;
for (int i = 0; EditorDebuggerNode::get_singleton()->get_debugger(i); i++) {
ScriptEditorDebugger *script_debugger = EditorDebuggerNode::get_singleton()->get_debugger(i);
int i = 0;
while (ScriptEditorDebugger *script_debugger = EditorDebuggerNode::get_singleton()->get_debugger(i)) {
if (script_debugger->is_session_active() && script_debugger->get_remote_pid() == embedded_process->get_embedded_pid()) {
embedded_script_debugger = script_debugger;
break;
}
i++;
}
#ifdef MACOS_ENABLED
embedded_process->set_script_debugger(embedded_script_debugger);
#endif
if (embedded_script_debugger) {
embedded_script_debugger->connect("remote_window_title_changed", callable_mp(this, &GameView::_remote_window_title_changed));
embedded_script_debugger->connect("embed_shortcut_requested", callable_mp(this, &GameView::_handle_shortcut_requested));
@@ -845,6 +860,12 @@ void GameView::_update_arguments_for_instance(int p_idx, List<String> &r_argumen
List<String>::Element *N = r_arguments.insert_before(user_args_element, "--wid");
N = r_arguments.insert_after(N, itos(DisplayServer::get_singleton()->window_get_native_handle(DisplayServer::WINDOW_HANDLE, get_window()->get_window_id())));
#if MACOS_ENABLED
r_arguments.push_back("--display-driver");
r_arguments.push_back("embedded");
r_arguments.push_back("--embedded");
#endif
// Be sure to have the correct window size in the embedded_process control.
_update_embed_window_size();
Rect2i rect = embedded_process->get_screen_embedded_window_rect();
@@ -931,11 +952,12 @@ void GameView::_feature_profile_changed() {
node_type_button[RuntimeNodeSelect::NODE_TYPE_3D]->set_visible(is_3d_enabled);
}
GameView::GameView(Ref<GameViewDebugger> p_debugger, WindowWrapper *p_wrapper) {
GameView::GameView(Ref<GameViewDebugger> p_debugger, EmbeddedProcessBase *p_embedded_process, WindowWrapper *p_wrapper) {
singleton = this;
debugger = p_debugger;
window_wrapper = p_wrapper;
embedded_process = p_embedded_process;
// Add some margin to the sides for better aesthetics.
// This prevents the first button's hover/pressed effect from "touching" the panel's border,
@@ -1051,7 +1073,6 @@ GameView::GameView(Ref<GameViewDebugger> p_debugger, WindowWrapper *p_wrapper) {
camera_override_menu->set_h_size_flags(SIZE_SHRINK_END);
camera_override_menu->set_tooltip_text(TTR("Camera Override Options"));
camera_override_menu->set_accessibility_name(TTRC("Camera Override Options"));
_camera_override_menu_id_pressed(EditorSettings::get_singleton()->get_project_metadata("game_view", "camera_override_mode", 0));
PopupMenu *menu = camera_override_menu->get_popup();
menu->connect(SceneStringName(id_pressed), callable_mp(this, &GameView::_camera_override_menu_id_pressed));
@@ -1061,6 +1082,7 @@ GameView::GameView(Ref<GameViewDebugger> p_debugger, WindowWrapper *p_wrapper) {
menu->add_radio_check_item(TTR("Manipulate In-Game"), CAMERA_MODE_INGAME);
menu->set_item_checked(menu->get_item_index(CAMERA_MODE_INGAME), true);
menu->add_radio_check_item(TTR("Manipulate From Editors"), CAMERA_MODE_EDITORS);
_camera_override_menu_id_pressed(EditorSettings::get_singleton()->get_project_metadata("game_view", "camera_override_mode", 0));
embedding_separator = memnew(VSeparator);
main_menu_hbox->add_child(embedding_separator);
@@ -1118,7 +1140,6 @@ GameView::GameView(Ref<GameViewDebugger> p_debugger, WindowWrapper *p_wrapper) {
panel->set_theme_type_variation("GamePanel");
panel->set_v_size_flags(SIZE_EXPAND_FILL);
embedded_process = memnew(EmbeddedProcess);
panel->add_child(embedded_process);
embedded_process->set_anchors_and_offsets_preset(PRESET_FULL_RECT);
embedded_process->connect("embedding_failed", callable_mp(this, &GameView::_embedding_failed));
@@ -1131,6 +1152,9 @@ GameView::GameView(Ref<GameViewDebugger> p_debugger, WindowWrapper *p_wrapper) {
state_container->add_theme_constant_override("margin_left", 8 * EDSCALE);
state_container->add_theme_constant_override("margin_right", 8 * EDSCALE);
state_container->set_anchors_and_offsets_preset(PRESET_FULL_RECT);
#ifdef MACOS_ENABLED
state_container->set_mouse_filter(Control::MOUSE_FILTER_IGNORE);
#endif
panel->add_child(state_container);
state_label = memnew(Label());
@@ -1156,7 +1180,7 @@ GameView::GameView(Ref<GameViewDebugger> p_debugger, WindowWrapper *p_wrapper) {
///////
void GameViewPlugin::selected_notify() {
void GameViewPluginBase::selected_notify() {
if (_is_window_wrapper_enabled()) {
#ifdef ANDROID_ENABLED
notify_main_screen_changed(get_plugin_name());
@@ -1168,7 +1192,7 @@ void GameViewPlugin::selected_notify() {
}
#ifndef ANDROID_ENABLED
void GameViewPlugin::make_visible(bool p_visible) {
void GameViewPluginBase::make_visible(bool p_visible) {
if (p_visible) {
window_wrapper->show();
} else {
@@ -1176,35 +1200,54 @@ void GameViewPlugin::make_visible(bool p_visible) {
}
}
void GameViewPlugin::set_window_layout(Ref<ConfigFile> p_layout) {
void GameViewPluginBase::set_window_layout(Ref<ConfigFile> p_layout) {
game_view->set_window_layout(p_layout);
}
void GameViewPlugin::get_window_layout(Ref<ConfigFile> p_layout) {
void GameViewPluginBase::get_window_layout(Ref<ConfigFile> p_layout) {
game_view->get_window_layout(p_layout);
}
void GameViewPluginBase::setup(Ref<GameViewDebugger> p_debugger, EmbeddedProcessBase *p_embedded_process) {
debugger = p_debugger;
window_wrapper = memnew(WindowWrapper);
window_wrapper->set_window_title(vformat(TTR("%s - Godot Engine"), TTR("Game Workspace")));
window_wrapper->set_margins_enabled(true);
game_view = memnew(GameView(debugger, p_embedded_process, window_wrapper));
game_view->set_v_size_flags(Control::SIZE_EXPAND_FILL);
window_wrapper->set_wrapped_control(game_view, nullptr);
EditorNode::get_singleton()->get_editor_main_screen()->get_control()->add_child(window_wrapper);
window_wrapper->set_v_size_flags(Control::SIZE_EXPAND_FILL);
window_wrapper->hide();
window_wrapper->connect("window_visibility_changed", callable_mp(this, &GameViewPlugin::_focus_another_editor).unbind(1));
}
#endif // ANDROID_ENABLED
void GameViewPlugin::_notification(int p_what) {
void GameViewPluginBase::_notification(int p_what) {
switch (p_what) {
case NOTIFICATION_ENTER_TREE: {
add_debugger_plugin(debugger);
connect("main_screen_changed", callable_mp(this, &GameViewPlugin::_save_last_editor));
connect("main_screen_changed", callable_mp(this, &GameViewPluginBase::_save_last_editor));
} break;
case NOTIFICATION_EXIT_TREE: {
remove_debugger_plugin(debugger);
disconnect("main_screen_changed", callable_mp(this, &GameViewPlugin::_save_last_editor));
disconnect("main_screen_changed", callable_mp(this, &GameViewPluginBase::_save_last_editor));
} break;
}
}
void GameViewPlugin::_save_last_editor(const String &p_editor) {
void GameViewPluginBase::_save_last_editor(const String &p_editor) {
if (p_editor != get_plugin_name()) {
last_editor = p_editor;
}
}
void GameViewPlugin::_focus_another_editor() {
void GameViewPluginBase::_focus_another_editor() {
if (_is_window_wrapper_enabled()) {
if (last_editor.is_empty()) {
EditorNode::get_singleton()->get_editor_main_screen()->select(EditorMainScreen::EDITOR_2D);
@@ -1214,7 +1257,7 @@ void GameViewPlugin::_focus_another_editor() {
}
}
bool GameViewPlugin::_is_window_wrapper_enabled() const {
bool GameViewPluginBase::_is_window_wrapper_enabled() const {
#ifdef ANDROID_ENABLED
return true;
#else
@@ -1222,22 +1265,15 @@ bool GameViewPlugin::_is_window_wrapper_enabled() const {
#endif // ANDROID_ENABLED
}
GameViewPlugin::GameViewPlugin() {
debugger.instantiate();
#ifndef ANDROID_ENABLED
window_wrapper = memnew(WindowWrapper);
window_wrapper->set_window_title(vformat(TTR("%s - Godot Engine"), TTR("Game Workspace")));
window_wrapper->set_margins_enabled(true);
game_view = memnew(GameView(debugger, window_wrapper));
game_view->set_v_size_flags(Control::SIZE_EXPAND_FILL);
window_wrapper->set_wrapped_control(game_view, nullptr);
EditorNode::get_singleton()->get_editor_main_screen()->get_control()->add_child(window_wrapper);
window_wrapper->set_v_size_flags(Control::SIZE_EXPAND_FILL);
window_wrapper->hide();
window_wrapper->connect("window_visibility_changed", callable_mp(this, &GameViewPlugin::_focus_another_editor).unbind(1));
#endif // ANDROID_ENABLED
GameViewPluginBase::GameViewPluginBase() {
}
GameViewPlugin::GameViewPlugin() :
GameViewPluginBase() {
#ifndef ANDROID_ENABLED
Ref<GameViewDebugger> game_view_debugger;
game_view_debugger.instantiate();
EmbeddedProcess *embedded_process = memnew(EmbeddedProcess);
setup(game_view_debugger, embedded_process);
#endif
}