1
0
mirror of https://github.com/godotengine/godot.git synced 2025-11-04 12:00:25 +00:00

macOS: Embedded window can be dismissed by clicking close

- Installed a SIGINT handler to terminate the application gracefully.
- Handle varying display scaling
This commit is contained in:
Stuart Carnie
2025-05-08 18:51:28 +10:00
parent 19bb18716e
commit f658161619
12 changed files with 144 additions and 70 deletions

View File

@@ -131,6 +131,8 @@ static void _setup_clock() {
} }
#endif #endif
struct sigaction old_action;
static void handle_interrupt(int sig) { static void handle_interrupt(int sig) {
if (!EngineDebugger::is_active()) { if (!EngineDebugger::is_active()) {
return; return;
@@ -138,6 +140,11 @@ static void handle_interrupt(int sig) {
EngineDebugger::get_script_debugger()->set_depth(-1); EngineDebugger::get_script_debugger()->set_depth(-1);
EngineDebugger::get_script_debugger()->set_lines_left(1); EngineDebugger::get_script_debugger()->set_lines_left(1);
// Ensure we call the old action if it was configured.
if (old_action.sa_handler && old_action.sa_handler != SIG_IGN && old_action.sa_handler != SIG_DFL) {
old_action.sa_handler(sig);
}
} }
void OS_Unix::initialize_debugging() { void OS_Unix::initialize_debugging() {
@@ -145,7 +152,7 @@ void OS_Unix::initialize_debugging() {
struct sigaction action; struct sigaction action;
memset(&action, 0, sizeof(action)); memset(&action, 0, sizeof(action));
action.sa_handler = handle_interrupt; action.sa_handler = handle_interrupt;
sigaction(SIGINT, &action, nullptr); sigaction(SIGINT, &action, &old_action);
} }
} }

View File

@@ -864,7 +864,7 @@ 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("--embedded"); N = r_arguments.insert_after(N, "--embedded");
#endif #endif
// Be sure to have the correct window size in the embedded_process control. // Be sure to have the correct window size in the embedded_process control.

View File

@@ -1399,9 +1399,12 @@ Error Main::setup(const char *execpath, int argc, char *argv[], bool p_second_ph
display_driver = NULL_DISPLAY_DRIVER; display_driver = NULL_DISPLAY_DRIVER;
} else if (arg == "--embedded") { // Enable embedded mode. } else if (arg == "--embedded") { // Enable embedded mode.
#ifdef MACOS_ENABLED
display_driver = EMBEDDED_DISPLAY_DRIVER; display_driver = EMBEDDED_DISPLAY_DRIVER;
#else
OS::get_singleton()->print("--embedded is only supported on macOS, aborting.\n");
goto error;
#endif
} 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,33 +33,27 @@
#include "core/input/input.h" #include "core/input/input.h"
#include "servers/display_server.h" #include "servers/display_server.h"
#if defined(GLES3_ENABLED)
#include "embedded_gl_manager.h"
#include "platform_gl.h"
#endif // GLES3_ENABLED
#if defined(RD_ENABLED)
#include "servers/rendering/rendering_device.h"
#if defined(VULKAN_ENABLED)
#import "rendering_context_driver_vulkan_macos.h"
#endif // VULKAN_ENABLED
#if defined(METAL_ENABLED)
#import "drivers/metal/rendering_context_driver_metal.h"
#endif
#endif // RD_ENABLED
@class CAContext; @class CAContext;
@class CALayer;
class GLManagerEmbedded;
class RenderingContextDriver;
class RenderingDevice;
struct DisplayServerEmbeddedState {
/// Default to a scale of 2.0, which is the most common.
float screen_max_scale = 2.0f;
float screen_dpi = 96.0f;
void serialize(PackedByteArray &r_data);
Error deserialize(const PackedByteArray &p_data);
};
class DisplayServerEmbedded : public DisplayServer { class DisplayServerEmbedded : public DisplayServer {
GDCLASS(DisplayServerEmbedded, DisplayServer) GDCLASS(DisplayServerEmbedded, DisplayServer)
_THREAD_SAFE_CLASS_ _THREAD_SAFE_CLASS_
struct { DisplayServerEmbeddedState state;
float screen_max_scale = 1.0f;
float screen_dpi = 96.0f;
} state;
NativeMenu *native_menu = nullptr; NativeMenu *native_menu = nullptr;
@@ -70,13 +64,11 @@ class DisplayServerEmbedded : public DisplayServer {
HashMap<WindowID, Callable> input_event_callbacks; HashMap<WindowID, Callable> input_event_callbacks;
HashMap<WindowID, Callable> input_text_callbacks; HashMap<WindowID, Callable> input_text_callbacks;
float content_scale = 1.0f;
WindowID window_id_counter = MAIN_WINDOW_ID; WindowID window_id_counter = MAIN_WINDOW_ID;
CAContext *ca_context = nil; CAContext *ca_context = nullptr;
// Either be a CAMetalLayer or a CALayer depending on the rendering driver. // Either be a CAMetalLayer or a CALayer depending on the rendering driver.
CALayer *layer = nil; CALayer *layer = nullptr;
#ifdef GLES3_ENABLED #ifdef GLES3_ENABLED
GLManagerEmbedded *gl_manager = nullptr; GLManagerEmbedded *gl_manager = nullptr;
#endif #endif
@@ -222,8 +214,7 @@ public:
virtual CursorShape cursor_get_shape() const override; virtual CursorShape cursor_get_shape() const override;
virtual void cursor_set_custom_image(const Ref<Resource> &p_cursor, CursorShape p_shape = CURSOR_ARROW, const Vector2 &p_hotspot = Vector2()) override; virtual void cursor_set_custom_image(const Ref<Resource> &p_cursor, CursorShape p_shape = CURSOR_ARROW, const Vector2 &p_hotspot = Vector2()) override;
void update_state(const Dictionary &p_state); void set_state(const DisplayServerEmbeddedState &p_state);
void set_content_scale(float p_scale);
virtual void swap_buffers() override; virtual void swap_buffers() override;
DisplayServerEmbedded(const String &p_rendering_driver, DisplayServer::WindowMode p_mode, DisplayServer::VSyncMode p_vsync_mode, uint32_t p_flags, const Vector2i *p_position, const Vector2i &p_resolution, int p_screen, Context p_context, Error &r_error); DisplayServerEmbedded(const String &p_rendering_driver, DisplayServer::WindowMode p_mode, DisplayServer::VSyncMode p_vsync_mode, uint32_t p_flags, const Vector2i *p_position, const Vector2i &p_resolution, int p_screen, Context p_context, Error &r_error);

View File

@@ -30,19 +30,31 @@
#import "display_server_embedded.h" #import "display_server_embedded.h"
#if defined(GLES3_ENABLED)
#import "embedded_gl_manager.h"
#import "platform_gl.h"
#import "drivers/gles3/rasterizer_gles3.h"
#endif
#if defined(RD_ENABLED)
#import "servers/rendering/renderer_rd/renderer_compositor_rd.h"
#import "servers/rendering/rendering_device.h"
#if defined(VULKAN_ENABLED)
#import "rendering_context_driver_vulkan_macos.h"
#endif // VULKAN_ENABLED
#if defined(METAL_ENABLED)
#import "drivers/metal/rendering_context_driver_metal.h"
#endif
#endif // RD_ENABLED
#import "embedded_debugger.h" #import "embedded_debugger.h"
#import "macos_quartz_core_spi.h" #import "macos_quartz_core_spi.h"
#import "core/config/project_settings.h" #import "core/config/project_settings.h"
#import "core/debugger/engine_debugger.h" #import "core/debugger/engine_debugger.h"
#import "core/io/marshalls.h"
#if defined(GLES3_ENABLED)
#include "drivers/gles3/rasterizer_gles3.h"
#endif
#if defined(RD_ENABLED)
#import "servers/rendering/renderer_rd/renderer_compositor_rd.h"
#endif
DisplayServerEmbedded::DisplayServerEmbedded(const String &p_rendering_driver, WindowMode p_mode, DisplayServer::VSyncMode p_vsync_mode, uint32_t p_flags, const Vector2i *p_position, const Vector2i &p_resolution, int p_screen, Context p_context, Error &r_error) { DisplayServerEmbedded::DisplayServerEmbedded(const String &p_rendering_driver, WindowMode p_mode, DisplayServer::VSyncMode p_vsync_mode, uint32_t p_flags, const Vector2i *p_position, const Vector2i &p_resolution, int p_screen, Context p_context, Error &r_error) {
EmbeddedDebugger::initialize(this); EmbeddedDebugger::initialize(this);
@@ -176,15 +188,15 @@ DisplayServerEmbedded::DisplayServerEmbedded(const String &p_rendering_driver, W
} }
#endif #endif
constexpr CGFloat CONTENT_SCALE = 2.0; CGFloat scale = screen_get_max_scale();
layer.contentsScale = CONTENT_SCALE; layer.contentsScale = scale;
layer.magnificationFilter = kCAFilterNearest; layer.magnificationFilter = kCAFilterNearest;
layer.minificationFilter = kCAFilterNearest; layer.minificationFilter = kCAFilterNearest;
layer.opaque = NO; // Never opaque when embedded. layer.opaque = YES; // Always opaque when embedded.
layer.actions = @{ @"contents" : [NSNull null] }; // Disable implicit animations for contents. layer.actions = @{ @"contents" : [NSNull null] }; // Disable implicit animations for contents.
// AppKit frames, bounds and positions are always in points. // AppKit frames, bounds and positions are always in points.
CGRect bounds = CGRectMake(0, 0, p_resolution.width, p_resolution.height); CGRect bounds = CGRectMake(0, 0, p_resolution.width, p_resolution.height);
bounds = CGRectApplyAffineTransform(bounds, CGAffineTransformMakeScale(1.0 / CONTENT_SCALE, 1.0 / CONTENT_SCALE)); bounds = CGRectApplyAffineTransform(bounds, CGAffineTransformInvert(CGAffineTransformMakeScale(scale, scale)));
layer.bounds = bounds; layer.bounds = bounds;
CGSConnectionID connection_id = CGSMainConnectionID(); CGSConnectionID connection_id = CGSMainConnectionID();
@@ -582,11 +594,11 @@ void DisplayServerEmbedded::window_set_size(const Size2i p_size, WindowID p_wind
[CATransaction begin]; [CATransaction begin];
[CATransaction setDisableActions:YES]; [CATransaction setDisableActions:YES];
// TODO(sgc): Pass scale as argument from parent process. CGFloat scale = screen_get_max_scale();
constexpr CGFloat CONTENT_SCALE = 2.0;
CGRect bounds = CGRectMake(0, 0, p_size.width, p_size.height); CGRect bounds = CGRectMake(0, 0, p_size.width, p_size.height);
bounds = CGRectApplyAffineTransform(bounds, CGAffineTransformMakeScale(1.0 / CONTENT_SCALE, 1.0 / CONTENT_SCALE)); bounds = CGRectApplyAffineTransform(bounds, CGAffineTransformInvert(CGAffineTransformMakeScale(scale, scale)));
layer.bounds = bounds; layer.bounds = bounds;
layer.contentsScale = scale;
#if defined(RD_ENABLED) #if defined(RD_ENABLED)
if (rendering_context) { if (rendering_context) {
@@ -685,12 +697,8 @@ void DisplayServerEmbedded::window_set_ime_position(const Point2i &p_pos, Window
ime_last_position = p_pos; ime_last_position = p_pos;
} }
void DisplayServerEmbedded::update_state(const Dictionary &p_state) { void DisplayServerEmbedded::set_state(const DisplayServerEmbeddedState &p_state) {
state.screen_max_scale = p_state["screen_get_max_scale"]; state = p_state;
}
void DisplayServerEmbedded::set_content_scale(float p_scale) {
content_scale = p_scale;
} }
void DisplayServerEmbedded::window_set_vsync_mode(DisplayServer::VSyncMode p_vsync_mode, WindowID p_window) { void DisplayServerEmbedded::window_set_vsync_mode(DisplayServer::VSyncMode p_vsync_mode, WindowID p_window) {
@@ -742,3 +750,24 @@ void DisplayServerEmbedded::swap_buffers() {
} }
#endif #endif
} }
void DisplayServerEmbeddedState::serialize(PackedByteArray &r_data) {
r_data.resize(8);
uint8_t *data = r_data.ptrw();
data += encode_float(screen_max_scale, data);
data += encode_float(screen_dpi, data);
// Assert we had enough space.
DEV_ASSERT(data - r_data.ptrw() >= r_data.size());
}
Error DisplayServerEmbeddedState::deserialize(const PackedByteArray &p_data) {
const uint8_t *data = p_data.ptr();
screen_max_scale = decode_float(data);
data += sizeof(float);
screen_dpi = decode_float(data);
return OK;
}

View File

@@ -3297,6 +3297,7 @@ Error DisplayServerMacOS::embed_process_update(WindowID p_window, const Embedded
[CATransaction setDisableActions:YES]; [CATransaction setDisableActions:YES];
EmbeddedProcessData *ed = embedded_processes.getptr(p_pid); EmbeddedProcessData *ed = embedded_processes.getptr(p_pid);
CGFloat scale = screen_get_max_scale();
if (ed == nil) { if (ed == nil) {
ed = &embedded_processes.insert(p_pid, EmbeddedProcessData())->value; ed = &embedded_processes.insert(p_pid, EmbeddedProcessData())->value;
@@ -3305,7 +3306,7 @@ Error DisplayServerMacOS::embed_process_update(WindowID p_window, const Embedded
CALayerHost *host = [CALayerHost new]; CALayerHost *host = [CALayerHost new];
uint32_t p_context_id = p_process->get_context_id(); uint32_t p_context_id = p_process->get_context_id();
host.contextId = static_cast<CAContextID>(p_context_id); host.contextId = static_cast<CAContextID>(p_context_id);
host.contentsScale = wd->window_object.backingScaleFactor; host.contentsScale = scale;
host.contentsGravity = kCAGravityCenter; host.contentsGravity = kCAGravityCenter;
ed->layer_host = host; ed->layer_host = host;
[wd->window_view.layer addSublayer:host]; [wd->window_view.layer addSublayer:host];
@@ -3313,7 +3314,7 @@ Error DisplayServerMacOS::embed_process_update(WindowID p_window, const Embedded
Rect2i p_rect = p_process->get_screen_embedded_window_rect(); Rect2i p_rect = p_process->get_screen_embedded_window_rect();
CGRect rect = CGRectMake(p_rect.position.x, p_rect.position.y, p_rect.size.x, p_rect.size.y); CGRect rect = CGRectMake(p_rect.position.x, p_rect.position.y, p_rect.size.x, p_rect.size.y);
rect = CGRectApplyAffineTransform(rect, CGAffineTransformMakeScale(0.5, 0.5)); rect = CGRectApplyAffineTransform(rect, CGAffineTransformInvert(CGAffineTransformMakeScale(scale, scale)));
CGFloat height = wd->window_view.frame.size.height; CGFloat height = wd->window_view.frame.size.height;
CGFloat x = rect.origin.x; CGFloat x = rect.origin.x;

View File

@@ -102,12 +102,12 @@ public:
return embedding_state == EmbeddingState::COMPLETED; return embedding_state == EmbeddingState::COMPLETED;
} }
virtual bool is_process_focused() const override { return layer_host->has_focus(); } bool is_process_focused() const override { return layer_host->has_focus(); }
virtual void embed_process(OS::ProcessID p_pid) override; void embed_process(OS::ProcessID p_pid) override;
virtual int get_embedded_pid() const override { return current_process_id; } int get_embedded_pid() const override { return current_process_id; }
virtual void reset() override; void reset() override;
virtual void request_close() override; void request_close() override;
virtual void queue_update_embedded_process() override { update_embedded_process(); } void queue_update_embedded_process() override { update_embedded_process(); }
Rect2i get_adjusted_embedded_window_rect(const Rect2i &p_rect) const override; Rect2i get_adjusted_embedded_window_rect(const Rect2i &p_rect) const override;
@@ -117,4 +117,5 @@ public:
_FORCE_INLINE_ DisplayServer::MouseMode get_mouse_mode() const { return mouse_mode; } _FORCE_INLINE_ DisplayServer::MouseMode get_mouse_mode() const { return mouse_mode; }
EmbeddedProcessMacOS(); EmbeddedProcessMacOS();
~EmbeddedProcessMacOS() override;
}; };

View File

@@ -30,6 +30,7 @@
#include "embedded_process_macos.h" #include "embedded_process_macos.h"
#include "platform/macos/display_server_embedded.h"
#include "platform/macos/display_server_macos.h" #include "platform/macos/display_server_macos.h"
#include "core/input/input_event_codec.h" #include "core/input/input_event_codec.h"
@@ -122,7 +123,7 @@ void EmbeddedProcessMacOS::reset() {
void EmbeddedProcessMacOS::request_close() { void EmbeddedProcessMacOS::request_close() {
if (current_process_id != 0 && is_embedding_completed()) { if (current_process_id != 0 && is_embedding_completed()) {
ds->request_close_embedded_process(current_process_id); script_debugger->send_message("embed:win_event", { DisplayServer::WINDOW_EVENT_CLOSE_REQUEST });
} }
} }
@@ -133,19 +134,22 @@ void EmbeddedProcessMacOS::_try_embed_process() {
Error err = ds->embed_process_update(window->get_window_id(), this); Error err = ds->embed_process_update(window->get_window_id(), this);
if (err == OK) { if (err == OK) {
// Replicate some of the DisplayServer state.
{
DisplayServerEmbeddedState state;
state.screen_max_scale = ds->screen_get_max_scale();
state.screen_dpi = ds->screen_get_dpi();
PackedByteArray data;
state.serialize(data);
script_debugger->send_message("embed:ds_state", { data });
}
Rect2i rect = get_screen_embedded_window_rect(); Rect2i rect = get_screen_embedded_window_rect();
script_debugger->send_message("embed:window_size", { rect.size }); script_debugger->send_message("embed:window_size", { rect.size });
embedding_state = EmbeddingState::COMPLETED; embedding_state = EmbeddingState::COMPLETED;
queue_redraw(); queue_redraw();
emit_signal(SNAME("embedding_completed")); emit_signal(SNAME("embedding_completed"));
// Replicate some of the DisplayServer state.
{
Dictionary state;
state["screen_get_max_scale"] = ds->screen_get_max_scale();
// script_debugger->send_message("embed:ds_state", { state });
}
// Send initial joystick state. // Send initial joystick state.
{ {
Input *input = Input::get_singleton(); Input *input = Input::get_singleton();
@@ -209,13 +213,21 @@ EmbeddedProcessMacOS::EmbeddedProcessMacOS() :
ED_SHORTCUT("game_view/release_mouse", TTRC("Release Mouse"), KeyModifierMask::ALT | Key::ESCAPE); ED_SHORTCUT("game_view/release_mouse", TTRC("Release Mouse"), KeyModifierMask::ALT | Key::ESCAPE);
} }
EmbeddedProcessMacOS::~EmbeddedProcessMacOS() {
if (current_process_id != 0) {
// Stop embedding the last process.
OS::get_singleton()->kill(current_process_id);
reset();
}
}
void LayerHost::_notification(int p_what) { void LayerHost::_notification(int p_what) {
switch (p_what) { switch (p_what) {
case NOTIFICATION_FOCUS_ENTER: { case NOTIFICATION_FOCUS_ENTER: {
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. // Restore mouse capture, if necessary.
DisplayServer *ds = DisplayServer::get_singleton(); DisplayServer *ds = DisplayServer::get_singleton();
if (process->get_mouse_mode() != ds->mouse_get_mode()) { if (process->get_mouse_mode() != ds->mouse_get_mode()) {
// Restore embedded process mouse mode. // Restore embedded process mouse mode.

View File

@@ -63,6 +63,7 @@ private:
Error _msg_ime_update(const Array &p_args); Error _msg_ime_update(const Array &p_args);
Error _msg_joy_add(const Array &p_args); Error _msg_joy_add(const Array &p_args);
Error _msg_joy_del(const Array &p_args); Error _msg_joy_del(const Array &p_args);
Error _msg_ds_state(const Array &p_args);
public: public:
static Error parse_message(void *p_user, const String &p_msg, const Array &p_args, bool &r_captured); static Error parse_message(void *p_user, const String &p_msg, const Array &p_args, bool &r_captured);

View File

@@ -76,21 +76,25 @@ void EmbeddedDebugger::_init_parse_message_handlers() {
parse_message_handlers["ime_update"] = &EmbeddedDebugger::_msg_ime_update; parse_message_handlers["ime_update"] = &EmbeddedDebugger::_msg_ime_update;
parse_message_handlers["joy_add"] = &EmbeddedDebugger::_msg_joy_add; parse_message_handlers["joy_add"] = &EmbeddedDebugger::_msg_joy_add;
parse_message_handlers["joy_del"] = &EmbeddedDebugger::_msg_joy_del; parse_message_handlers["joy_del"] = &EmbeddedDebugger::_msg_joy_del;
parse_message_handlers["ds_state"] = &EmbeddedDebugger::_msg_ds_state;
} }
Error EmbeddedDebugger::_msg_window_size(const Array &p_args) { Error EmbeddedDebugger::_msg_window_size(const Array &p_args) {
ERR_FAIL_COND_V_MSG(p_args.size() != 1, ERR_INVALID_PARAMETER, "Invalid number of arguments for 'window_size' message.");
Size2i size = p_args[0]; Size2i size = p_args[0];
ds->window_set_size(size); ds->window_set_size(size);
return OK; return OK;
} }
Error EmbeddedDebugger::_msg_mouse_set_mode(const Array &p_args) { Error EmbeddedDebugger::_msg_mouse_set_mode(const Array &p_args) {
ERR_FAIL_COND_V_MSG(p_args.size() != 1, ERR_INVALID_PARAMETER, "Invalid number of arguments for 'mouse_set_mode' message.");
DisplayServer::MouseMode mode = p_args[0]; DisplayServer::MouseMode mode = p_args[0];
ds->mouse_set_mode(mode); ds->mouse_set_mode(mode);
return OK; return OK;
} }
Error EmbeddedDebugger::_msg_event(const Array &p_args) { Error EmbeddedDebugger::_msg_event(const Array &p_args) {
ERR_FAIL_COND_V_MSG(p_args.size() != 1, ERR_INVALID_PARAMETER, "Invalid number of arguments for 'event' message.");
Input *input = Input::get_singleton(); Input *input = Input::get_singleton();
if (!input) { if (!input) {
// Ignore if we've received an event before the process has initialized. // Ignore if we've received an event before the process has initialized.
@@ -130,6 +134,7 @@ Error EmbeddedDebugger::_msg_event(const Array &p_args) {
} }
Error EmbeddedDebugger::_msg_win_event(const Array &p_args) { Error EmbeddedDebugger::_msg_win_event(const Array &p_args) {
ERR_FAIL_COND_V_MSG(p_args.size() != 1, ERR_INVALID_PARAMETER, "Invalid number of arguments for 'win_event' message.");
DisplayServer::WindowEvent win_event = p_args[0]; DisplayServer::WindowEvent win_event = p_args[0];
ds->send_window_event(win_event, DisplayServer::MAIN_WINDOW_ID); ds->send_window_event(win_event, DisplayServer::MAIN_WINDOW_ID);
if (win_event == DisplayServer::WindowEvent::WINDOW_EVENT_MOUSE_EXIT) { if (win_event == DisplayServer::WindowEvent::WINDOW_EVENT_MOUSE_EXIT) {
@@ -161,6 +166,15 @@ Error EmbeddedDebugger::_msg_joy_del(const Array &p_args) {
return OK; return OK;
} }
Error EmbeddedDebugger::_msg_ds_state(const Array &p_args) {
ERR_FAIL_COND_V_MSG(p_args.size() != 1, ERR_INVALID_PARAMETER, "Invalid number of arguments for 'ds_state' message.");
PackedByteArray data = p_args[0];
DisplayServerEmbeddedState state;
state.deserialize(data);
ds->set_state(state);
return OK;
}
Error EmbeddedDebugger::parse_message(void *p_user, const String &p_msg, const Array &p_args, bool &r_captured) { Error EmbeddedDebugger::parse_message(void *p_user, const String &p_msg, const Array &p_args, bool &r_captured) {
EmbeddedDebugger *self = static_cast<EmbeddedDebugger *>(p_user); EmbeddedDebugger *self = static_cast<EmbeddedDebugger *>(p_user);
r_captured = true; r_captured = true;

View File

@@ -116,7 +116,9 @@ int main(int argc, char **argv) {
os->run(); os->run();
int exit_code = os->get_exit_code();
memdelete(os); memdelete(os);
return os->get_exit_code(); return exit_code;
} }

View File

@@ -923,6 +923,14 @@ void OS_MacOS_NSApp::run() {
[NSApp run]; [NSApp run];
} }
static bool sig_received = false;
static void handle_interrupt(int sig) {
if (sig == SIGINT) {
sig_received = true;
}
}
void OS_MacOS_NSApp::start_main() { void OS_MacOS_NSApp::start_main() {
Error err; Error err;
@autoreleasepool { @autoreleasepool {
@@ -954,7 +962,7 @@ void OS_MacOS_NSApp::start_main() {
} }
joypad_apple->process_joypads(); joypad_apple->process_joypads();
if (Main::iteration()) { if (Main::iteration() || sig_received) {
terminate(); terminate();
} }
} @catch (NSException *exception) { } @catch (NSException *exception) {
@@ -1020,6 +1028,11 @@ OS_MacOS_NSApp::OS_MacOS_NSApp(const char *p_execpath, int p_argc, char **p_argv
ERR_FAIL_NULL(delegate); ERR_FAIL_NULL(delegate);
[NSApp setDelegate:delegate]; [NSApp setDelegate:delegate];
[NSApp registerUserInterfaceItemSearchHandler:delegate]; [NSApp registerUserInterfaceItemSearchHandler:delegate];
struct sigaction action;
memset(&action, 0, sizeof(action));
action.sa_handler = handle_interrupt;
sigaction(SIGINT, &action, nullptr);
} }
// MARK: - OS_MacOS_Embedded // MARK: - OS_MacOS_Embedded