MacOS: Additional improvements and fixes for embedded window support

This commit is contained in:
Stuart Carnie 2025-05-07 06:11:05 +10:00
parent 6a6a1168a5
commit 9290adee38
5 changed files with 50 additions and 13 deletions

View file

@ -515,11 +515,9 @@ GameView::EmbedAvailability GameView::_get_embed_available() {
if (!DisplayServer::get_singleton()->has_feature(DisplayServer::FEATURE_WINDOW_EMBEDDING)) { if (!DisplayServer::get_singleton()->has_feature(DisplayServer::FEATURE_WINDOW_EMBEDDING)) {
return EMBED_NOT_AVAILABLE_FEATURE_NOT_SUPPORTED; return EMBED_NOT_AVAILABLE_FEATURE_NOT_SUPPORTED;
} }
#ifndef MACOS_ENABLED
if (get_tree()->get_root()->is_embedding_subwindows()) { if (get_tree()->get_root()->is_embedding_subwindows()) {
return EMBED_NOT_AVAILABLE_SINGLE_WINDOW_MODE; return EMBED_NOT_AVAILABLE_SINGLE_WINDOW_MODE;
} }
#endif
String display_driver = GLOBAL_GET("display/display_server/driver"); String display_driver = GLOBAL_GET("display/display_server/driver");
if (display_driver == "headless" || display_driver == "wayland") { if (display_driver == "headless" || display_driver == "wayland") {
return EMBED_NOT_AVAILABLE_PROJECT_DISPLAY_DRIVER; return EMBED_NOT_AVAILABLE_PROJECT_DISPLAY_DRIVER;
@ -835,11 +833,16 @@ void GameView::_update_arguments_for_instance(int p_idx, List<String> &r_argumen
// Remove duplicates/unwanted parameters. // Remove duplicates/unwanted parameters.
List<String>::Element *E = r_arguments.front(); List<String>::Element *E = r_arguments.front();
List<String>::Element *user_args_element = nullptr; List<String>::Element *user_args_element = nullptr;
HashSet<String> remove_args({ "--position", "--resolution", "--screen" });
#ifdef MACOS_ENABLED
// macOS requires the embedded display driver.
remove_args.insert("--display-driver");
#endif
while (E) { while (E) {
List<String>::Element *N = E->next(); List<String>::Element *N = E->next();
//For these parameters, we need to also renove the value. // For these parameters, we need to also remove the value.
if (E->get() == "--position" || E->get() == "--resolution" || E->get() == "--screen") { if (remove_args.has(E->get())) {
r_arguments.erase(E); r_arguments.erase(E);
if (N) { if (N) {
List<String>::Element *V = N->next(); List<String>::Element *V = N->next();
@ -861,8 +864,6 @@ void GameView::_update_arguments_for_instance(int p_idx, List<String> &r_argumen
N = r_arguments.insert_after(N, itos(DisplayServer::get_singleton()->window_get_native_handle(DisplayServer::WINDOW_HANDLE, get_window()->get_window_id()))); 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 #if MACOS_ENABLED
r_arguments.push_back("--display-driver");
r_arguments.push_back("embedded");
r_arguments.push_back("--embedded"); r_arguments.push_back("--embedded");
#endif #endif

View file

@ -287,6 +287,7 @@ bool profile_gpu = false;
// Constants. // Constants.
static const String NULL_DISPLAY_DRIVER("headless"); static const String NULL_DISPLAY_DRIVER("headless");
static const String EMBEDDED_DISPLAY_DRIVER("embedded");
static const String NULL_AUDIO_DRIVER("Dummy"); static const String NULL_AUDIO_DRIVER("Dummy");
// The length of the longest column in the command-line help we should align to // The length of the longest column in the command-line help we should align to
@ -1397,6 +1398,10 @@ Error Main::setup(const char *execpath, int argc, char *argv[], bool p_second_ph
audio_driver = NULL_AUDIO_DRIVER; audio_driver = NULL_AUDIO_DRIVER;
display_driver = NULL_DISPLAY_DRIVER; display_driver = NULL_DISPLAY_DRIVER;
} else if (arg == "--embedded") { // Enable embedded mode.
display_driver = EMBEDDED_DISPLAY_DRIVER;
} else if (arg == "--log-file") { // write to log file } else if (arg == "--log-file") { // write to log file
if (N) { if (N) {

View file

@ -33,11 +33,13 @@
#include "editor/plugins/embedded_process.h" #include "editor/plugins/embedded_process.h"
class DisplayServerMacOS; class DisplayServerMacOS;
class EmbeddedProcessMacOS;
class LayerHost : public Control { class LayerHost final : public Control {
GDCLASS(LayerHost, Control); GDCLASS(LayerHost, Control);
ScriptEditorDebugger *script_debugger = nullptr; ScriptEditorDebugger *script_debugger = nullptr;
EmbeddedProcessMacOS *process = nullptr;
virtual void gui_input(const Ref<InputEvent> &p_event) override; virtual void gui_input(const Ref<InputEvent> &p_event) override;
@ -48,6 +50,8 @@ public:
void set_script_debugger(ScriptEditorDebugger *p_debugger) { void set_script_debugger(ScriptEditorDebugger *p_debugger) {
script_debugger = p_debugger; script_debugger = p_debugger;
} }
LayerHost(EmbeddedProcessMacOS *p_process);
}; };
class EmbeddedProcessMacOS final : public EmbeddedProcessBase { class EmbeddedProcessMacOS final : public EmbeddedProcessBase {
@ -69,9 +73,11 @@ class EmbeddedProcessMacOS final : public EmbeddedProcessBase {
// Embedded process state. // Embedded process state.
/// @brief The current mouse mode of the embedded process. // The last mouse mode sent by the embedded process.
DisplayServer::MouseMode mouse_mode = DisplayServer::MOUSE_MODE_VISIBLE; DisplayServer::MouseMode mouse_mode = DisplayServer::MOUSE_MODE_VISIBLE;
// Helper functions.
void _try_embed_process(); void _try_embed_process();
void update_embedded_process() const; void update_embedded_process() const;
void _joy_connection_changed(int p_index, bool p_connected) const; void _joy_connection_changed(int p_index, bool p_connected) const;
@ -81,7 +87,9 @@ protected:
public: public:
// MARK: - Message Handlers // MARK: - Message Handlers
void set_context_id(uint32_t p_context_id); void set_context_id(uint32_t p_context_id);
void mouse_set_mode(DisplayServer::MouseMode p_mode);
uint32_t get_context_id() const { return context_id; } uint32_t get_context_id() const { return context_id; }
void set_script_debugger(ScriptEditorDebugger *p_debugger) override; void set_script_debugger(ScriptEditorDebugger *p_debugger) override;
@ -90,7 +98,7 @@ public:
return embedding_state == EmbeddingState::IN_PROGRESS; return embedding_state == EmbeddingState::IN_PROGRESS;
} }
bool is_embedding_completed() const override { _FORCE_INLINE_ bool is_embedding_completed() const override {
return embedding_state == EmbeddingState::COMPLETED; return embedding_state == EmbeddingState::COMPLETED;
} }
@ -103,8 +111,10 @@ public:
Rect2i get_adjusted_embedded_window_rect(const Rect2i &p_rect) const override; Rect2i get_adjusted_embedded_window_rect(const Rect2i &p_rect) const override;
void mouse_set_mode(DisplayServer::MouseMode p_mode);
_FORCE_INLINE_ LayerHost *get_layer_host() const { return layer_host; } _FORCE_INLINE_ LayerHost *get_layer_host() const { return layer_host; }
// MARK: - Embedded process state
_FORCE_INLINE_ DisplayServer::MouseMode get_mouse_mode() const { return mouse_mode; }
EmbeddedProcessMacOS(); EmbeddedProcessMacOS();
}; };

View file

@ -34,6 +34,8 @@
#include "core/input/input_event_codec.h" #include "core/input/input_event_codec.h"
#include "editor/debugger/script_editor_debugger.h" #include "editor/debugger/script_editor_debugger.h"
#include "editor/editor_main_screen.h"
#include "editor/editor_node.h"
#include "editor/editor_settings.h" #include "editor/editor_settings.h"
#include "scene/gui/control.h" #include "scene/gui/control.h"
#include "scene/main/window.h" #include "scene/main/window.h"
@ -182,12 +184,18 @@ Rect2i EmbeddedProcessMacOS::get_adjusted_embedded_window_rect(const Rect2i &p_r
} }
void EmbeddedProcessMacOS::mouse_set_mode(DisplayServer::MouseMode p_mode) { void EmbeddedProcessMacOS::mouse_set_mode(DisplayServer::MouseMode p_mode) {
mouse_mode = p_mode;
// If the mouse is anything other than visible, we must ensure the Game view is active and the layer focused.
if (mouse_mode != DisplayServer::MOUSE_MODE_VISIBLE) {
EditorNode::get_singleton()->get_editor_main_screen()->select(EditorMainScreen::EDITOR_GAME);
layer_host->grab_focus();
}
DisplayServer::get_singleton()->mouse_set_mode(p_mode); DisplayServer::get_singleton()->mouse_set_mode(p_mode);
} }
EmbeddedProcessMacOS::EmbeddedProcessMacOS() : EmbeddedProcessMacOS::EmbeddedProcessMacOS() :
EmbeddedProcessBase() { EmbeddedProcessBase() {
layer_host = memnew(LayerHost); layer_host = memnew(LayerHost(this));
add_child(layer_host); add_child(layer_host);
layer_host->set_focus_mode(FOCUS_ALL); layer_host->set_focus_mode(FOCUS_ALL);
layer_host->set_anchors_and_offsets_preset(PRESET_FULL_RECT); layer_host->set_anchors_and_offsets_preset(PRESET_FULL_RECT);
@ -207,11 +215,22 @@ void LayerHost::_notification(int p_what) {
if (script_debugger) { if (script_debugger) {
script_debugger->send_message("embed:win_event", { DisplayServer::WINDOW_EVENT_MOUSE_ENTER }); script_debugger->send_message("embed:win_event", { DisplayServer::WINDOW_EVENT_MOUSE_ENTER });
} }
// Temporarily release mouse capture, so we can interact with the editor.
DisplayServer *ds = DisplayServer::get_singleton();
if (process->get_mouse_mode() != ds->mouse_get_mode()) {
// Restore embedded process mouse mode.
ds->mouse_set_mode(process->get_mouse_mode());
}
} break; } break;
case NOTIFICATION_FOCUS_EXIT: { case NOTIFICATION_FOCUS_EXIT: {
if (script_debugger) { if (script_debugger) {
script_debugger->send_message("embed:win_event", { DisplayServer::WINDOW_EVENT_MOUSE_EXIT }); script_debugger->send_message("embed:win_event", { DisplayServer::WINDOW_EVENT_MOUSE_EXIT });
} }
// Temporarily set mouse state back to visible, so the user can interact with the editor.
DisplayServer *ds = DisplayServer::get_singleton();
if (ds->mouse_get_mode() != DisplayServer::MOUSE_MODE_VISIBLE) {
ds->mouse_set_mode(DisplayServer::MOUSE_MODE_VISIBLE);
}
} break; } break;
case MainLoop::NOTIFICATION_OS_IME_UPDATE: { case MainLoop::NOTIFICATION_OS_IME_UPDATE: {
if (script_debugger && has_focus()) { if (script_debugger && has_focus()) {
@ -224,7 +243,7 @@ void LayerHost::_notification(int p_what) {
} }
void LayerHost::gui_input(const Ref<InputEvent> &p_event) { void LayerHost::gui_input(const Ref<InputEvent> &p_event) {
if (!script_debugger) { if (!process->is_embedding_completed()) {
return; return;
} }
@ -246,3 +265,6 @@ void LayerHost::gui_input(const Ref<InputEvent> &p_event) {
accept_event(); accept_event();
} }
} }
LayerHost::LayerHost(EmbeddedProcessMacOS *p_process) :
process(p_process) {}

View file

@ -74,7 +74,6 @@ int main(int argc, char **argv) {
if (strcmp("--embedded", argv[i]) == 0) { if (strcmp("--embedded", argv[i]) == 0) {
is_embedded = true; is_embedded = true;
continue;
} }
args.ptr()[argsc] = argv[i]; args.ptr()[argsc] = argv[i];