Selaa lähdekoodia

Move `alert` function from `DisplayServer` to `OS`.

bruvzg 4 vuotta sitten
vanhempi
commit
618eb27e8b

+ 6 - 0
core/core_bind.cpp

@@ -196,6 +196,10 @@ int _OS::get_low_processor_usage_mode_sleep_usec() const {
 	return OS::get_singleton()->get_low_processor_usage_mode_sleep_usec();
 }
 
+void _OS::alert(const String &p_alert, const String &p_title) {
+	OS::get_singleton()->alert(p_alert, p_title);
+}
+
 String _OS::get_executable_path() const {
 	return OS::get_singleton()->get_executable_path();
 }
@@ -487,6 +491,8 @@ void _OS::_bind_methods() {
 	ClassDB::bind_method(D_METHOD("open_midi_inputs"), &_OS::open_midi_inputs);
 	ClassDB::bind_method(D_METHOD("close_midi_inputs"), &_OS::close_midi_inputs);
 
+	ClassDB::bind_method(D_METHOD("alert", "text", "title"), &_OS::alert, DEFVAL("Alert!"));
+
 	ClassDB::bind_method(D_METHOD("set_low_processor_usage_mode", "enable"), &_OS::set_low_processor_usage_mode);
 	ClassDB::bind_method(D_METHOD("is_in_low_processor_usage_mode"), &_OS::is_in_low_processor_usage_mode);
 

+ 2 - 0
core/core_bind.h

@@ -162,6 +162,8 @@ public:
 	void set_low_processor_usage_mode_sleep_usec(int p_usec);
 	int get_low_processor_usage_mode_sleep_usec() const;
 
+	void alert(const String &p_alert, const String &p_title = "ALERT!");
+
 	String get_executable_path() const;
 	int execute(const String &p_path, const Vector<String> &p_arguments, Array r_output = Array(), bool p_read_stderr = false);
 	int create_process(const String &p_path, const Vector<String> &p_arguments);

+ 4 - 0
core/os/os.cpp

@@ -110,6 +110,10 @@ void OS::printerr(const char *p_format, ...) {
 	va_end(argp);
 }
 
+void OS::alert(const String &p_alert, const String &p_title) {
+	fprintf(stderr, "%s: %s\n", p_title.utf8().get_data(), p_alert.utf8().get_data());
+}
+
 void OS::set_low_processor_usage_mode(bool p_enabled) {
 	low_processor_usage_mode = p_enabled;
 }

+ 2 - 0
core/os/os.h

@@ -120,6 +120,8 @@ public:
 	virtual void open_midi_inputs();
 	virtual void close_midi_inputs();
 
+	virtual void alert(const String &p_alert, const String &p_title = "ALERT!");
+
 	virtual Error open_dynamic_library(const String p_path, void *&p_library_handle, bool p_also_set_library_path = false) { return ERR_UNAVAILABLE; }
 	virtual Error close_dynamic_library(void *p_library_handle) { return ERR_UNAVAILABLE; }
 	virtual Error get_dynamic_library_symbol_handle(void *p_library_handle, const String p_name, void *&p_symbol_handle, bool p_optional = false) { return ERR_UNAVAILABLE; }

+ 0 - 10
doc/classes/DisplayServer.xml

@@ -7,16 +7,6 @@
 	<tutorials>
 	</tutorials>
 	<methods>
-		<method name="alert">
-			<return type="void">
-			</return>
-			<argument index="0" name="text" type="String">
-			</argument>
-			<argument index="1" name="title" type="String" default="&quot;Alert!&quot;">
-			</argument>
-			<description>
-			</description>
-		</method>
 		<method name="clipboard_get" qualifiers="const">
 			<return type="String">
 			</return>

+ 11 - 0
doc/classes/OS.xml

@@ -10,6 +10,17 @@
 		<link title="OS Test Demo">https://godotengine.org/asset-library/asset/677</link>
 	</tutorials>
 	<methods>
+		<method name="alert">
+			<return type="void">
+			</return>
+			<argument index="0" name="text" type="String">
+			</argument>
+			<argument index="1" name="title" type="String" default="&quot;Alert!&quot;">
+			</argument>
+			<description>
+				Displays a modal dialog box using the host OS' facilities. Execution is blocked until the dialog is closed.
+			</description>
+		</method>
 		<method name="can_use_threads" qualifiers="const">
 			<return type="bool">
 			</return>

+ 0 - 4
drivers/unix/os_unix.cpp

@@ -139,10 +139,6 @@ void OS_Unix::finalize_core() {
 	NetSocketPosix::cleanup();
 }
 
-void OS_Unix::alert(const String &p_alert, const String &p_title) {
-	fprintf(stderr, "ERROR: %s\n", p_alert.utf8().get_data());
-}
-
 String OS_Unix::get_stdin_string(bool p_block) {
 	if (p_block) {
 		char buff[1024];

+ 0 - 1
drivers/unix/os_unix.h

@@ -52,7 +52,6 @@ protected:
 public:
 	OS_Unix();
 
-	virtual void alert(const String &p_alert, const String &p_title = "ALERT!");
 	virtual String get_stdin_string(bool p_block) override;
 
 	//virtual void set_mouse_show(bool p_show);

+ 6 - 6
main/main.cpp

@@ -1080,7 +1080,7 @@ Error Main::setup(const char *execpath, int argc, char *argv[], bool p_second_ph
 #else
 		const String error_msg = "Error: Couldn't load project data at path \"" + project_path + "\". Is the .pck file missing?\nIf you've renamed the executable, the associated .pck file should also be renamed to match the executable's name (without the extension).\n";
 		OS::get_singleton()->print("%s", error_msg.ascii().get_data());
-		DisplayServer::get_singleton()->alert(error_msg);
+		OS::get_singleton()->alert(error_msg);
 
 		goto error;
 #endif
@@ -2015,6 +2015,7 @@ bool Main::start() {
 		// Let's throw an error gently. The code leading to this is pretty brittle so
 		// this might end up triggered by valid usage, in which case we'll have to
 		// fine-tune further.
+		OS::get_singleton()->alert("Couldn't detect whether to run the editor, the project manager or a specific project. Aborting.");
 		ERR_FAIL_V_MSG(false, "Couldn't detect whether to run the editor, the project manager or a specific project. Aborting.");
 	}
 #endif
@@ -2044,9 +2045,8 @@ bool Main::start() {
 				if (obj) {
 					memdelete(obj);
 				}
-				ERR_FAIL_V_MSG(false,
-						vformat("Can't load the script \"%s\" as it doesn't inherit from SceneTree or MainLoop.",
-								script));
+				OS::get_singleton()->alert(vformat("Can't load the script \"%s\" as it doesn't inherit from SceneTree or MainLoop.", script));
+				ERR_FAIL_V_MSG(false, vformat("Can't load the script \"%s\" as it doesn't inherit from SceneTree or MainLoop.", script));
 			}
 
 			script_loop->set_initialize_script(script_res);
@@ -2065,7 +2065,7 @@ bool Main::start() {
 				if (obj) {
 					memdelete(obj);
 				}
-				DisplayServer::get_singleton()->alert("Error: Invalid MainLoop script base type: " + script_base);
+				OS::get_singleton()->alert("Error: Invalid MainLoop script base type: " + script_base);
 				ERR_FAIL_V_MSG(false, vformat("The global class %s does not inherit from SceneTree or MainLoop.", main_loop_type));
 			}
 			script_loop->set_initialize_script(script_res);
@@ -2079,7 +2079,7 @@ bool Main::start() {
 
 	if (!main_loop) {
 		if (!ClassDB::class_exists(main_loop_type)) {
-			DisplayServer::get_singleton()->alert("Error: MainLoop type doesn't exist: " + main_loop_type);
+			OS::get_singleton()->alert("Error: MainLoop type doesn't exist: " + main_loop_type);
 			return false;
 		} else {
 			Object *ml = ClassDB::instantiate(main_loop_type);

+ 1 - 8
platform/android/display_server_android.cpp

@@ -334,13 +334,6 @@ bool DisplayServerAndroid::can_any_window_draw() const {
 	return true;
 }
 
-void DisplayServerAndroid::alert(const String &p_alert, const String &p_title) {
-	GodotJavaWrapper *godot_java = OS_Android::get_singleton()->get_godot_java();
-	ERR_FAIL_COND(!godot_java);
-
-	godot_java->alert(p_alert, p_title);
-}
-
 void DisplayServerAndroid::process_events() {
 	Input::get_singleton()->flush_accumulated_events();
 }
@@ -361,7 +354,7 @@ Vector<String> DisplayServerAndroid::get_rendering_drivers_func() {
 DisplayServer *DisplayServerAndroid::create_func(const String &p_rendering_driver, DisplayServer::WindowMode p_mode, DisplayServer::VSyncMode p_vsync_mode, uint32_t p_flags, const Vector2i &p_resolution, Error &r_error) {
 	DisplayServer *ds = memnew(DisplayServerAndroid(p_rendering_driver, p_mode, p_vsync_mode, p_flags, p_resolution, r_error));
 	if (r_error != OK) {
-		ds->alert("Your video card driver does not support any of the supported Vulkan versions.", "Unable to initialize Video driver");
+		OS::get_singleton()->alert("Your video card driver does not support any of the supported Vulkan versions.", "Unable to initialize Video driver");
 	}
 	return ds;
 }

+ 0 - 2
platform/android/display_server_android.h

@@ -204,8 +204,6 @@ public:
 	virtual void window_set_vsync_mode(DisplayServer::VSyncMode p_vsync_mode, WindowID p_window = MAIN_WINDOW_ID) override;
 	virtual DisplayServer::VSyncMode window_get_vsync_mode(WindowID p_vsync_mode) const override;
 
-	virtual void alert(const String &p_alert, const String &p_title) override;
-
 	virtual void process_events() override;
 
 	void process_accelerometer(const Vector3 &p_accelerometer);

+ 7 - 0
platform/android/os_android.cpp

@@ -71,6 +71,13 @@ public:
 	virtual ~AndroidLogger() {}
 };
 
+void OS_Android::alert(const String &p_alert, const String &p_title) {
+	GodotJavaWrapper *godot_java = OS_Android::get_singleton()->get_godot_java();
+	ERR_FAIL_COND(!godot_java);
+
+	godot_java->alert(p_alert, p_title);
+}
+
 void OS_Android::initialize_core() {
 	OS_Unix::initialize_core();
 

+ 2 - 0
platform/android/os_android.h

@@ -86,6 +86,8 @@ public:
 	virtual bool request_permissions() override;
 	virtual Vector<String> get_granted_permissions() const override;
 
+	virtual void alert(const String &p_alert, const String &p_title) override;
+
 	virtual Error open_dynamic_library(const String p_path, void *&p_library_handle, bool p_also_set_library_path = false) override;
 
 	virtual String get_name() const override;

+ 0 - 2
platform/iphone/display_server_iphone.h

@@ -119,8 +119,6 @@ public:
 	virtual bool has_feature(Feature p_feature) const override;
 	virtual String get_name() const override;
 
-	virtual void alert(const String &p_alert, const String &p_title = "ALERT!") override;
-
 	virtual int get_screen_count() const override;
 	virtual Point2i screen_get_position(int p_screen = SCREEN_OF_MAIN_WINDOW) const override;
 	virtual Size2i screen_get_size(int p_screen = SCREEN_OF_MAIN_WINDOW) const override;

+ 0 - 6
platform/iphone/display_server_iphone.mm

@@ -320,12 +320,6 @@ String DisplayServerIPhone::get_name() const {
 	return "iPhone";
 }
 
-void DisplayServerIPhone::alert(const String &p_alert, const String &p_title) {
-	const CharString utf8_alert = p_alert.utf8();
-	const CharString utf8_title = p_title.utf8();
-	iOS::alert(utf8_alert.get_data(), utf8_title.get_data());
-}
-
 int DisplayServerIPhone::get_screen_count() const {
 	return 1;
 }

+ 2 - 3
platform/iphone/os_iphone.h

@@ -92,13 +92,12 @@ public:
 
 	void start();
 
+	virtual void alert(const String &p_alert, const String &p_title = "ALERT!") override;
+
 	virtual Error open_dynamic_library(const String p_path, void *&p_library_handle, bool p_also_set_library_path = false) override;
 	virtual Error close_dynamic_library(void *p_library_handle) override;
 	virtual Error get_dynamic_library_symbol_handle(void *p_library_handle, const String p_name, void *&p_symbol_handle, bool p_optional = false) override;
 
-	virtual void alert(const String &p_alert,
-			const String &p_title = "ALERT!") override;
-
 	virtual String get_name() const override;
 	virtual String get_model_name() const override;
 

+ 6 - 6
platform/iphone/os_iphone.mm

@@ -114,6 +114,12 @@ OSIPhone::OSIPhone(String p_data_dir) {
 
 OSIPhone::~OSIPhone() {}
 
+void OSIPhone::alert(const String &p_alert, const String &p_title) {
+	const CharString utf8_alert = p_alert.utf8();
+	const CharString utf8_title = p_title.utf8();
+	iOS::alert(utf8_alert.get_data(), utf8_title.get_data());
+}
+
 void OSIPhone::initialize_core() {
 	OS_Unix::initialize_core();
 
@@ -221,12 +227,6 @@ Error OSIPhone::get_dynamic_library_symbol_handle(void *p_library_handle, const
 	return OS_Unix::get_dynamic_library_symbol_handle(p_library_handle, p_name, p_symbol_handle, p_optional);
 }
 
-void OSIPhone::alert(const String &p_alert, const String &p_title) {
-	const CharString utf8_alert = p_alert.utf8();
-	const CharString utf8_title = p_title.utf8();
-	iOS::alert(utf8_alert.get_data(), utf8_title.get_data());
-}
-
 String OSIPhone::get_name() const {
 	return "iOS";
 };

+ 0 - 4
platform/javascript/display_server_javascript.cpp

@@ -659,10 +659,6 @@ void DisplayServerJavaScript::send_window_event_callback(int p_notification) {
 	}
 }
 
-void DisplayServerJavaScript::alert(const String &p_alert, const String &p_title) {
-	godot_js_display_alert(p_alert.utf8().get_data());
-}
-
 void DisplayServerJavaScript::set_icon(const Ref<Image> &p_icon) {
 	ERR_FAIL_COND(p_icon.is_null());
 	Ref<Image> icon = p_icon;

+ 0 - 1
platform/javascript/display_server_javascript.h

@@ -109,7 +109,6 @@ public:
 	bool check_size_force_redraw();
 
 	// from DisplayServer
-	virtual void alert(const String &p_alert, const String &p_title = "ALERT!") override;
 	virtual bool has_feature(Feature p_feature) const override;
 	virtual String get_name() const override;
 

+ 4 - 0
platform/javascript/os_javascript.cpp

@@ -47,6 +47,10 @@
 
 #include "godot_js.h"
 
+void OS_JavaScript::alert(const String &p_alert, const String &p_title) {
+	godot_js_display_alert(p_alert.utf8().get_data());
+}
+
 // Lifecycle
 void OS_JavaScript::initialize() {
 	OS_Unix::initialize_core();

+ 3 - 0
platform/javascript/os_javascript.h

@@ -89,6 +89,9 @@ public:
 	String get_user_data_dir() const override;
 
 	bool is_userfs_persistent() const override;
+
+	void alert(const String &p_alert, const String &p_title = "ALERT!") override;
+
 	Error open_dynamic_library(const String p_path, void *&p_library_handle, bool p_also_set_library_path) override;
 
 	void resume_audio();

+ 4 - 68
platform/linuxbsd/display_server_x11.cpp

@@ -136,70 +136,6 @@ String DisplayServerX11::get_name() const {
 	return "X11";
 }
 
-void DisplayServerX11::alert(const String &p_alert, const String &p_title) {
-	const char *message_programs[] = { "zenity", "kdialog", "Xdialog", "xmessage" };
-
-	String path = OS::get_singleton()->get_environment("PATH");
-	Vector<String> path_elems = path.split(":", false);
-	String program;
-
-	for (int i = 0; i < path_elems.size(); i++) {
-		for (uint64_t k = 0; k < sizeof(message_programs) / sizeof(char *); k++) {
-			String tested_path = path_elems[i].plus_file(message_programs[k]);
-
-			if (FileAccess::exists(tested_path)) {
-				program = tested_path;
-				break;
-			}
-		}
-
-		if (program.length()) {
-			break;
-		}
-	}
-
-	List<String> args;
-
-	if (program.ends_with("zenity")) {
-		args.push_back("--error");
-		args.push_back("--width");
-		args.push_back("500");
-		args.push_back("--title");
-		args.push_back(p_title);
-		args.push_back("--text");
-		args.push_back(p_alert);
-	}
-
-	if (program.ends_with("kdialog")) {
-		args.push_back("--error");
-		args.push_back(p_alert);
-		args.push_back("--title");
-		args.push_back(p_title);
-	}
-
-	if (program.ends_with("Xdialog")) {
-		args.push_back("--title");
-		args.push_back(p_title);
-		args.push_back("--msgbox");
-		args.push_back(p_alert);
-		args.push_back("0");
-		args.push_back("0");
-	}
-
-	if (program.ends_with("xmessage")) {
-		args.push_back("-center");
-		args.push_back("-title");
-		args.push_back(p_title);
-		args.push_back(p_alert);
-	}
-
-	if (program.length()) {
-		OS::get_singleton()->execute(program, args);
-	} else {
-		print_line(p_alert);
-	}
-}
-
 void DisplayServerX11::_update_real_mouse_position(const WindowData &wd) {
 	Window root_return, child_return;
 	int root_x, root_y, win_x, win_y;
@@ -3677,8 +3613,8 @@ Vector<String> DisplayServerX11::get_rendering_drivers_func() {
 DisplayServer *DisplayServerX11::create_func(const String &p_rendering_driver, WindowMode p_mode, VSyncMode p_vsync_mode, uint32_t p_flags, const Vector2i &p_resolution, Error &r_error) {
 	DisplayServer *ds = memnew(DisplayServerX11(p_rendering_driver, p_mode, p_vsync_mode, p_flags, p_resolution, r_error));
 	if (r_error != OK) {
-		ds->alert("Your video card driver does not support any of the supported Vulkan versions.\n"
-				  "Please update your drivers or if you have a very old or integrated GPU upgrade it.",
+		OS::get_singleton()->alert("Your video card driver does not support any of the supported Vulkan versions.\n"
+								   "Please update your drivers or if you have a very old or integrated GPU upgrade it.",
 				"Unable to initialize Video driver");
 	}
 	return ds;
@@ -3976,8 +3912,8 @@ DisplayServerX11::DisplayServerX11(const String &p_rendering_driver, WindowMode
 	}
 
 	if (!_refresh_device_info()) {
-		alert("Your system does not support XInput 2.\n"
-			  "Please upgrade your distribution.",
+		OS::get_singleton()->alert("Your system does not support XInput 2.\n"
+								   "Please upgrade your distribution.",
 				"Unable to initialize XInput");
 		r_error = ERR_UNAVAILABLE;
 		return;

+ 0 - 2
platform/linuxbsd/display_server_x11.h

@@ -280,8 +280,6 @@ public:
 	virtual bool has_feature(Feature p_feature) const override;
 	virtual String get_name() const override;
 
-	virtual void alert(const String &p_alert, const String &p_title = "ALERT!") override;
-
 	virtual void mouse_set_mode(MouseMode p_mode) override;
 	virtual MouseMode mouse_get_mode() const override;
 

+ 64 - 0
platform/linuxbsd/os_linuxbsd.cpp

@@ -51,6 +51,70 @@
 #include <sys/types.h>
 #include <unistd.h>
 
+void OS_LinuxBSD::alert(const String &p_alert, const String &p_title) {
+	const char *message_programs[] = { "zenity", "kdialog", "Xdialog", "xmessage" };
+
+	String path = get_environment("PATH");
+	Vector<String> path_elems = path.split(":", false);
+	String program;
+
+	for (int i = 0; i < path_elems.size(); i++) {
+		for (uint64_t k = 0; k < sizeof(message_programs) / sizeof(char *); k++) {
+			String tested_path = path_elems[i].plus_file(message_programs[k]);
+
+			if (FileAccess::exists(tested_path)) {
+				program = tested_path;
+				break;
+			}
+		}
+
+		if (program.length()) {
+			break;
+		}
+	}
+
+	List<String> args;
+
+	if (program.ends_with("zenity")) {
+		args.push_back("--error");
+		args.push_back("--width");
+		args.push_back("500");
+		args.push_back("--title");
+		args.push_back(p_title);
+		args.push_back("--text");
+		args.push_back(p_alert);
+	}
+
+	if (program.ends_with("kdialog")) {
+		args.push_back("--error");
+		args.push_back(p_alert);
+		args.push_back("--title");
+		args.push_back(p_title);
+	}
+
+	if (program.ends_with("Xdialog")) {
+		args.push_back("--title");
+		args.push_back(p_title);
+		args.push_back("--msgbox");
+		args.push_back(p_alert);
+		args.push_back("0");
+		args.push_back("0");
+	}
+
+	if (program.ends_with("xmessage")) {
+		args.push_back("-center");
+		args.push_back("-title");
+		args.push_back(p_title);
+		args.push_back(p_alert);
+	}
+
+	if (program.length()) {
+		execute(program, args);
+	} else {
+		print_line(p_alert);
+	}
+}
+
 void OS_LinuxBSD::initialize() {
 	crash_handler.initialize();
 

+ 2 - 0
platform/linuxbsd/os_linuxbsd.h

@@ -90,6 +90,8 @@ public:
 
 	virtual String get_unique_id() const override;
 
+	virtual void alert(const String &p_alert, const String &p_title = "ALERT!") override;
+
 	virtual bool _check_internal_feature_support(const String &p_feature) override;
 
 	void run();

+ 4 - 2
platform/osx/display_server_osx.h

@@ -60,6 +60,10 @@ class DisplayServerOSX : public DisplayServer {
 	_THREAD_SAFE_CLASS_
 
 public:
+	void _send_event(NSEvent *p_event);
+	NSMenu *_get_dock_menu() const;
+	void _menu_callback(id p_sender);
+
 #if defined(OPENGL_ENABLED)
 	ContextGL_OSX *context_gles2;
 #endif
@@ -163,7 +167,6 @@ public:
 
 	String rendering_driver;
 
-	id delegate;
 	id autoreleasePool;
 	CGEventSourceRef eventSource;
 
@@ -207,7 +210,6 @@ public:
 	virtual void global_menu_remove_item(const String &p_menu_root, int p_idx) override;
 	virtual void global_menu_clear(const String &p_menu_root) override;
 
-	virtual void alert(const String &p_alert, const String &p_title = "ALERT!") override;
 	virtual Error dialog_show(String p_title, String p_description, Vector<String> p_buttons, const Callable &p_callback) override;
 	virtual Error dialog_input_text(String p_title, String p_description, String p_partial, const Callable &p_callback) override;
 

+ 53 - 211
platform/osx/display_server_osx.mm

@@ -104,46 +104,6 @@ static NSCursor *_cursorFromSelector(SEL selector, SEL fallback = nil) {
 	return [NSCursor arrowCursor];
 }
 
-/*************************************************************************/
-/* GodotApplication                                                      */
-/*************************************************************************/
-
-@interface GodotApplication : NSApplication
-@end
-
-@implementation GodotApplication
-
-- (void)sendEvent:(NSEvent *)event {
-	// special case handling of command-period, which is traditionally a special
-	// shortcut in macOS and doesn't arrive at our regular keyDown handler.
-	if ([event type] == NSEventTypeKeyDown) {
-		if (([event modifierFlags] & NSEventModifierFlagCommand) && [event keyCode] == 0x2f) {
-			Ref<InputEventKey> k;
-			k.instantiate();
-
-			_get_key_modifier_state([event modifierFlags], k);
-			k->set_window_id(DisplayServerOSX::INVALID_WINDOW_ID);
-			k->set_pressed(true);
-			k->set_keycode(KEY_PERIOD);
-			k->set_physical_keycode(KEY_PERIOD);
-			k->set_echo([event isARepeat]);
-
-			Input::get_singleton()->accumulate_input_event(k);
-		}
-	}
-
-	// From http://cocoadev.com/index.pl?GameKeyboardHandlingAlmost
-	// This works around an AppKit bug, where key up events while holding
-	// down the command key don't get sent to the key window.
-	if ([event type] == NSEventTypeKeyUp && ([event modifierFlags] & NSEventModifierFlagCommand)) {
-		[[self keyWindow] sendEvent:event];
-	} else {
-		[super sendEvent:event];
-	}
-}
-
-@end
-
 /*************************************************************************/
 /* GlobalMenuItem                                                       */
 /*************************************************************************/
@@ -160,121 +120,6 @@ static NSCursor *_cursorFromSelector(SEL selector, SEL fallback = nil) {
 @implementation GlobalMenuItem
 @end
 
-/*************************************************************************/
-/* GodotApplicationDelegate                                              */
-/*************************************************************************/
-
-@interface GodotApplicationDelegate : NSObject
-- (void)forceUnbundledWindowActivationHackStep1;
-- (void)forceUnbundledWindowActivationHackStep2;
-- (void)forceUnbundledWindowActivationHackStep3;
-@end
-
-@implementation GodotApplicationDelegate
-
-- (void)forceUnbundledWindowActivationHackStep1 {
-	// Step1: Switch focus to macOS Dock.
-	// Required to perform step 2, TransformProcessType will fail if app is already the in focus.
-	for (NSRunningApplication *app in [NSRunningApplication runningApplicationsWithBundleIdentifier:@"com.apple.dock"]) {
-		[app activateWithOptions:NSApplicationActivateIgnoringOtherApps];
-		break;
-	}
-	[self performSelector:@selector(forceUnbundledWindowActivationHackStep2) withObject:nil afterDelay:0.02];
-}
-
-- (void)forceUnbundledWindowActivationHackStep2 {
-	// Step 2: Register app as foreground process.
-	ProcessSerialNumber psn = { 0, kCurrentProcess };
-	(void)TransformProcessType(&psn, kProcessTransformToForegroundApplication);
-	[self performSelector:@selector(forceUnbundledWindowActivationHackStep3) withObject:nil afterDelay:0.02];
-}
-
-- (void)forceUnbundledWindowActivationHackStep3 {
-	// Step 3: Switch focus back to app window.
-	[[NSRunningApplication currentApplication] activateWithOptions:NSApplicationActivateIgnoringOtherApps];
-}
-
-- (void)applicationDidFinishLaunching:(NSNotification *)notice {
-	NSString *nsappname = [[[NSBundle mainBundle] infoDictionary] objectForKey:@"CFBundleName"];
-	if (nsappname == nil) {
-		// If executable is not a bundled, macOS WindowServer won't register and activate app window correctly (menu and title bar are grayed out and input ignored).
-		[self performSelector:@selector(forceUnbundledWindowActivationHackStep1) withObject:nil afterDelay:0.02];
-	}
-}
-
-- (void)applicationDidResignActive:(NSNotification *)notification {
-	if (OS_OSX::get_singleton()->get_main_loop()) {
-		OS_OSX::get_singleton()->get_main_loop()->notification(MainLoop::NOTIFICATION_APPLICATION_FOCUS_OUT);
-	}
-}
-
-- (void)applicationDidBecomeActive:(NSNotification *)notification {
-	if (OS_OSX::get_singleton()->get_main_loop()) {
-		OS_OSX::get_singleton()->get_main_loop()->notification(MainLoop::NOTIFICATION_APPLICATION_FOCUS_IN);
-	}
-}
-
-- (void)globalMenuCallback:(id)sender {
-	if (![sender representedObject]) {
-		return;
-	}
-
-	GlobalMenuItem *value = [sender representedObject];
-
-	if (value) {
-		if (value->checkable) {
-			if ([sender state] == NSControlStateValueOff) {
-				[sender setState:NSControlStateValueOn];
-			} else {
-				[sender setState:NSControlStateValueOff];
-			}
-		}
-
-		if (value->callback != Callable()) {
-			Variant tag = value->meta;
-			Variant *tagp = &tag;
-			Variant ret;
-			Callable::CallError ce;
-			value->callback.call((const Variant **)&tagp, 1, ret, ce);
-		}
-	}
-}
-
-- (NSMenu *)applicationDockMenu:(NSApplication *)sender {
-	return DS_OSX->dock_menu;
-}
-
-- (BOOL)application:(NSApplication *)sender openFile:(NSString *)filename {
-	// Note: may be called called before main loop init!
-	char *utfs = strdup([filename UTF8String]);
-	((OS_OSX *)(OS_OSX::get_singleton()))->open_with_filename.parse_utf8(utfs);
-	free(utfs);
-
-#ifdef TOOLS_ENABLED
-	// Open new instance
-	if (OS_OSX::get_singleton()->get_main_loop()) {
-		List<String> args;
-		args.push_back(((OS_OSX *)(OS_OSX::get_singleton()))->open_with_filename);
-		String exec = OS::get_singleton()->get_executable_path();
-		OS::get_singleton()->create_process(exec, args);
-	}
-#endif
-	return YES;
-}
-
-- (NSApplicationTerminateReply)applicationShouldTerminate:(NSApplication *)sender {
-	DS_OSX->_send_window_event(DS_OSX->windows[DisplayServerOSX::MAIN_WINDOW_ID], DisplayServerOSX::WINDOW_EVENT_CLOSE_REQUEST);
-	return NSTerminateCancel;
-}
-
-- (void)showAbout:(id)sender {
-	if (OS_OSX::get_singleton()->get_main_loop()) {
-		OS_OSX::get_singleton()->get_main_loop()->notification(MainLoop::NOTIFICATION_WM_ABOUT);
-	}
-}
-
-@end
-
 /*************************************************************************/
 /* GodotWindowDelegate                                                   */
 /*************************************************************************/
@@ -1983,26 +1828,6 @@ void DisplayServerOSX::global_menu_clear(const String &p_menu_root) {
 	}
 }
 
-void DisplayServerOSX::alert(const String &p_alert, const String &p_title) {
-	_THREAD_SAFE_METHOD_
-
-	NSAlert *window = [[NSAlert alloc] init];
-	NSString *ns_title = [NSString stringWithUTF8String:p_title.utf8().get_data()];
-	NSString *ns_alert = [NSString stringWithUTF8String:p_alert.utf8().get_data()];
-
-	[window addButtonWithTitle:@"OK"];
-	[window setMessageText:ns_title];
-	[window setInformativeText:ns_alert];
-	[window setAlertStyle:NSAlertStyleWarning];
-
-	id key_window = [[NSApplication sharedApplication] keyWindow];
-	[window runModal];
-	[window release];
-	if (key_window) {
-		[key_window makeKeyAndOrderFront:nil];
-	}
-}
-
 Error DisplayServerOSX::dialog_show(String p_title, String p_description, Vector<String> p_buttons, const Callable &p_callback) {
 	_THREAD_SAFE_METHOD_
 
@@ -3375,6 +3200,56 @@ void DisplayServerOSX::_release_pressed_events() {
 	}
 }
 
+NSMenu *DisplayServerOSX::_get_dock_menu() const {
+	return dock_menu;
+}
+
+void DisplayServerOSX::_menu_callback(id p_sender) {
+	if (![p_sender representedObject]) {
+		return;
+	}
+
+	GlobalMenuItem *value = [p_sender representedObject];
+
+	if (value) {
+		if (value->checkable) {
+			if ([p_sender state] == NSControlStateValueOff) {
+				[p_sender setState:NSControlStateValueOn];
+			} else {
+				[p_sender setState:NSControlStateValueOff];
+			}
+		}
+
+		if (value->callback != Callable()) {
+			Variant tag = value->meta;
+			Variant *tagp = &tag;
+			Variant ret;
+			Callable::CallError ce;
+			value->callback.call((const Variant **)&tagp, 1, ret, ce);
+		}
+	}
+}
+
+void DisplayServerOSX::_send_event(NSEvent *p_event) {
+	// special case handling of command-period, which is traditionally a special
+	// shortcut in macOS and doesn't arrive at our regular keyDown handler.
+	if ([p_event type] == NSEventTypeKeyDown) {
+		if (([p_event modifierFlags] & NSEventModifierFlagCommand) && [p_event keyCode] == 0x2f) {
+			Ref<InputEventKey> k;
+			k.instantiate();
+
+			_get_key_modifier_state([p_event modifierFlags], k);
+			k->set_window_id(DisplayServerOSX::INVALID_WINDOW_ID);
+			k->set_pressed(true);
+			k->set_keycode(KEY_PERIOD);
+			k->set_physical_keycode(KEY_PERIOD);
+			k->set_echo([p_event isARepeat]);
+
+			Input::get_singleton()->accumulate_input_event(k);
+		}
+	}
+}
+
 void DisplayServerOSX::_process_key_events() {
 	Ref<InputEventKey> k;
 	for (int i = 0; i < key_event_pos; i++) {
@@ -3615,7 +3490,7 @@ ObjectID DisplayServerOSX::window_get_attached_instance_id(WindowID p_window) co
 DisplayServer *DisplayServerOSX::create_func(const String &p_rendering_driver, WindowMode p_mode, VSyncMode p_vsync_mode, uint32_t p_flags, const Vector2i &p_resolution, Error &r_error) {
 	DisplayServer *ds = memnew(DisplayServerOSX(p_rendering_driver, p_mode, p_vsync_mode, p_flags, p_resolution, r_error));
 	if (r_error != OK) {
-		ds->alert("Your video card driver does not support any of the supported Metal versions.", "Unable to initialize Video driver");
+		OS::get_singleton()->alert("Your video card driver does not support any of the supported Metal versions.", "Unable to initialize Video driver");
 	}
 	return ds;
 }
@@ -3785,12 +3660,6 @@ DisplayServerOSX::DisplayServerOSX(const String &p_rendering_driver, WindowMode
 
 	CGEventSourceSetLocalEventsSuppressionInterval(eventSource, 0.0);
 
-	// Implicitly create shared NSApplication instance
-	[GodotApplication sharedApplication];
-
-	// In case we are unbundled, make us a proper UI application
-	[NSApp setActivationPolicy:NSApplicationActivationPolicyRegular];
-
 	keyboard_layout_dirty = true;
 	displays_arrangement_dirty = true;
 	displays_scale_dirty = true;
@@ -3804,9 +3673,6 @@ DisplayServerOSX::DisplayServerOSX(const String &p_rendering_driver, WindowMode
 	// Register to be notified on displays arrangement changes
 	CGDisplayRegisterReconfigurationCallback(displays_arrangement_changed, nullptr);
 
-	// Menu bar setup must go between sharedApplication above and
-	// finishLaunching below, in order to properly emulate the behavior
-	// of NSApplicationMain
 	NSMenuItem *menu_item;
 	NSString *title;
 
@@ -3846,32 +3712,10 @@ DisplayServerOSX::DisplayServerOSX(const String &p_rendering_driver, WindowMode
 	title = [NSString stringWithFormat:NSLocalizedString(@"Quit %@", nil), nsappname];
 	[apple_menu addItemWithTitle:title action:@selector(terminate:) keyEquivalent:@"q"];
 
-	// Setup menu bar
-	NSMenu *main_menu = [[[NSMenu alloc] initWithTitle:@""] autorelease];
+	// Add items to the menu bar
+	NSMenu *main_menu = [NSApp mainMenu];
 	menu_item = [main_menu addItemWithTitle:@"" action:nil keyEquivalent:@""];
 	[main_menu setSubmenu:apple_menu forItem:menu_item];
-	[NSApp setMainMenu:main_menu];
-
-	[NSApp finishLaunching];
-
-	delegate = [[GodotApplicationDelegate alloc] init];
-	ERR_FAIL_COND(!delegate);
-	[NSApp setDelegate:delegate];
-
-	//process application:openFile: event
-	while (true) {
-		NSEvent *event = [NSApp
-				nextEventMatchingMask:NSEventMaskAny
-							untilDate:[NSDate distantPast]
-							   inMode:NSDefaultRunLoopMode
-							  dequeue:YES];
-
-		if (event == nil) {
-			break;
-		}
-
-		[NSApp sendEvent:event];
-	}
 
 	//!!!!!!!!!!!!!!!!!!!!!!!!!!
 	//TODO - do Vulkan and GLES2 support checks, driver selection and fallback
@@ -3924,8 +3768,6 @@ DisplayServerOSX::DisplayServerOSX(const String &p_rendering_driver, WindowMode
 		RendererCompositorRD::make_current();
 	}
 #endif
-
-	[NSApp activateIgnoringOtherApps:YES];
 }
 
 DisplayServerOSX::~DisplayServerOSX() {

+ 2 - 0
platform/osx/os_osx.h

@@ -72,6 +72,8 @@ protected:
 public:
 	virtual String get_name() const override;
 
+	virtual void alert(const String &p_alert, const String &p_title = "ALERT!") override;
+
 	virtual Error open_dynamic_library(const String p_path, void *&p_library_handle, bool p_also_set_library_path = false) override;
 
 	virtual MainLoop *get_main_loop() const override;

+ 184 - 0
platform/osx/os_osx.mm

@@ -41,6 +41,137 @@
 #include <mach-o/dyld.h>
 #include <os/log.h>
 
+#define DS_OSX ((DisplayServerOSX *)(DisplayServerOSX::get_singleton()))
+
+/*************************************************************************/
+/* GodotApplication                                                      */
+/*************************************************************************/
+
+@interface GodotApplication : NSApplication
+@end
+
+@implementation GodotApplication
+
+- (void)sendEvent:(NSEvent *)event {
+	if (DS_OSX) {
+		DS_OSX->_send_event(event);
+	}
+
+	// From http://cocoadev.com/index.pl?GameKeyboardHandlingAlmost
+	// This works around an AppKit bug, where key up events while holding
+	// down the command key don't get sent to the key window.
+	if ([event type] == NSEventTypeKeyUp && ([event modifierFlags] & NSEventModifierFlagCommand)) {
+		[[self keyWindow] sendEvent:event];
+	} else {
+		[super sendEvent:event];
+	}
+}
+
+@end
+
+/*************************************************************************/
+/* GodotApplicationDelegate                                              */
+/*************************************************************************/
+
+@interface GodotApplicationDelegate : NSObject
+- (void)forceUnbundledWindowActivationHackStep1;
+- (void)forceUnbundledWindowActivationHackStep2;
+- (void)forceUnbundledWindowActivationHackStep3;
+@end
+
+@implementation GodotApplicationDelegate
+
+- (void)forceUnbundledWindowActivationHackStep1 {
+	// Step1: Switch focus to macOS Dock.
+	// Required to perform step 2, TransformProcessType will fail if app is already the in focus.
+	for (NSRunningApplication *app in [NSRunningApplication runningApplicationsWithBundleIdentifier:@"com.apple.dock"]) {
+		[app activateWithOptions:NSApplicationActivateIgnoringOtherApps];
+		break;
+	}
+	[self performSelector:@selector(forceUnbundledWindowActivationHackStep2)
+			   withObject:nil
+			   afterDelay:0.02];
+}
+
+- (void)forceUnbundledWindowActivationHackStep2 {
+	// Step 2: Register app as foreground process.
+	ProcessSerialNumber psn = { 0, kCurrentProcess };
+	(void)TransformProcessType(&psn, kProcessTransformToForegroundApplication);
+	[self performSelector:@selector(forceUnbundledWindowActivationHackStep3) withObject:nil afterDelay:0.02];
+}
+
+- (void)forceUnbundledWindowActivationHackStep3 {
+	// Step 3: Switch focus back to app window.
+	[[NSRunningApplication currentApplication] activateWithOptions:NSApplicationActivateIgnoringOtherApps];
+}
+
+- (void)applicationDidFinishLaunching:(NSNotification *)notice {
+	NSString *nsappname = [[[NSBundle mainBundle] infoDictionary] objectForKey:@"CFBundleName"];
+	if (nsappname == nil) {
+		// If executable is not a bundled, macOS WindowServer won't register and activate app window correctly (menu and title bar are grayed out and input ignored).
+		[self performSelector:@selector(forceUnbundledWindowActivationHackStep1) withObject:nil afterDelay:0.02];
+	}
+}
+
+- (void)applicationDidResignActive:(NSNotification *)notification {
+	if (OS::get_singleton()->get_main_loop()) {
+		OS::get_singleton()->get_main_loop()->notification(MainLoop::NOTIFICATION_APPLICATION_FOCUS_OUT);
+	}
+}
+
+- (void)applicationDidBecomeActive:(NSNotification *)notification {
+	if (OS::get_singleton()->get_main_loop()) {
+		OS::get_singleton()->get_main_loop()->notification(MainLoop::NOTIFICATION_APPLICATION_FOCUS_IN);
+	}
+}
+
+- (void)globalMenuCallback:(id)sender {
+	if (DS_OSX) {
+		return DS_OSX->_menu_callback(sender);
+	}
+}
+
+- (NSMenu *)applicationDockMenu:(NSApplication *)sender {
+	if (DS_OSX) {
+		return DS_OSX->_get_dock_menu();
+	} else {
+		return nullptr;
+	}
+}
+
+- (BOOL)application:(NSApplication *)sender openFile:(NSString *)filename {
+	// Note: may be called called before main loop init!
+	char *utfs = strdup([filename UTF8String]);
+	((OS_OSX *)OS_OSX::get_singleton())->open_with_filename.parse_utf8(utfs);
+	free(utfs);
+
+#ifdef TOOLS_ENABLED
+	// Open new instance
+	if (OS_OSX::get_singleton()->get_main_loop()) {
+		List<String> args;
+		args.push_back(((OS_OSX *)OS_OSX::get_singleton())->open_with_filename);
+		String exec = OS_OSX::get_singleton()->get_executable_path();
+		OS_OSX::get_singleton()->create_process(exec, args);
+	}
+#endif
+	return YES;
+}
+
+- (NSApplicationTerminateReply)applicationShouldTerminate:(NSApplication *)sender {
+	if (DS_OSX) {
+		DS_OSX->_send_window_event(DS_OSX->windows[DisplayServerOSX::MAIN_WINDOW_ID], DisplayServerOSX::WINDOW_EVENT_CLOSE_REQUEST);
+	}
+	return NSTerminateCancel;
+}
+
+- (void)showAbout:(id)sender {
+	if (OS_OSX::get_singleton()->get_main_loop()) {
+		OS_OSX::get_singleton()->get_main_loop()->notification(MainLoop::NOTIFICATION_WM_ABOUT);
+	}
+}
+
+@end
+
 /*************************************************************************/
 /* OSXTerminalLogger                                                     */
 /*************************************************************************/
@@ -119,6 +250,24 @@ String OS_OSX::get_unique_id() const {
 	return serial_number;
 }
 
+void OS_OSX::alert(const String &p_alert, const String &p_title) {
+	NSAlert *window = [[NSAlert alloc] init];
+	NSString *ns_title = [NSString stringWithUTF8String:p_title.utf8().get_data()];
+	NSString *ns_alert = [NSString stringWithUTF8String:p_alert.utf8().get_data()];
+
+	[window addButtonWithTitle:@"OK"];
+	[window setMessageText:ns_title];
+	[window setInformativeText:ns_alert];
+	[window setAlertStyle:NSAlertStyleWarning];
+
+	id key_window = [[NSApplication sharedApplication] keyWindow];
+	[window runModal];
+	[window release];
+	if (key_window) {
+		[key_window makeKeyAndOrderFront:nil];
+	}
+}
+
 void OS_OSX::initialize_core() {
 	OS_Unix::initialize_core();
 
@@ -372,6 +521,41 @@ OS_OSX::OS_OSX() {
 #endif
 
 	DisplayServerOSX::register_osx_driver();
+
+	// Implicitly create shared NSApplication instance
+	[GodotApplication sharedApplication];
+
+	// In case we are unbundled, make us a proper UI application
+	[NSApp setActivationPolicy:NSApplicationActivationPolicyRegular];
+
+	// Menu bar setup must go between sharedApplication above and
+	// finishLaunching below, in order to properly emulate the behavior
+	// of NSApplicationMain
+
+	NSMenu *main_menu = [[[NSMenu alloc] initWithTitle:@""] autorelease];
+	[NSApp setMainMenu:main_menu];
+	[NSApp finishLaunching];
+
+	id delegate = [[GodotApplicationDelegate alloc] init];
+	ERR_FAIL_COND(!delegate);
+	[NSApp setDelegate:delegate];
+
+	//process application:openFile: event
+	while (true) {
+		NSEvent *event = [NSApp
+				nextEventMatchingMask:NSEventMaskAny
+							untilDate:[NSDate distantPast]
+							   inMode:NSDefaultRunLoopMode
+							  dequeue:YES];
+
+		if (event == nil) {
+			break;
+		}
+
+		[NSApp sendEvent:event];
+	}
+
+	[NSApp activateIgnoringOtherApps:YES];
 }
 
 bool OS_OSX::_check_internal_feature_support(const String &p_feature) {

+ 2 - 6
platform/windows/display_server_windows.cpp

@@ -79,10 +79,6 @@ String DisplayServerWindows::get_name() const {
 	return "Windows";
 }
 
-void DisplayServerWindows::alert(const String &p_alert, const String &p_title) {
-	MessageBoxW(nullptr, (LPCWSTR)(p_alert.utf16().get_data()), (LPCWSTR)(p_title.utf16().get_data()), MB_OK | MB_ICONEXCLAMATION | MB_TASKMODAL);
-}
-
 void DisplayServerWindows::_set_mouse_mode_impl(MouseMode p_mode) {
 	if (p_mode == MOUSE_MODE_CAPTURED || p_mode == MOUSE_MODE_CONFINED || p_mode == MOUSE_MODE_CONFINED_HIDDEN) {
 		// Mouse is grabbed (captured or confined).
@@ -3358,8 +3354,8 @@ Vector<String> DisplayServerWindows::get_rendering_drivers_func() {
 DisplayServer *DisplayServerWindows::create_func(const String &p_rendering_driver, WindowMode p_mode, VSyncMode p_vsync_mode, uint32_t p_flags, const Vector2i &p_resolution, Error &r_error) {
 	DisplayServer *ds = memnew(DisplayServerWindows(p_rendering_driver, p_mode, p_vsync_mode, p_flags, p_resolution, r_error));
 	if (r_error != OK) {
-		ds->alert("Your video card driver does not support any of the supported Vulkan versions.\n"
-				  "Please update your drivers or if you have a very old or integrated GPU upgrade it.",
+		OS::get_singleton()->alert("Your video card driver does not support any of the supported Vulkan versions.\n"
+								   "Please update your drivers or if you have a very old or integrated GPU upgrade it.",
 				"Unable to initialize Video driver");
 	}
 	return ds;

+ 0 - 2
platform/windows/display_server_windows.h

@@ -442,8 +442,6 @@ public:
 	virtual bool has_feature(Feature p_feature) const override;
 	virtual String get_name() const override;
 
-	virtual void alert(const String &p_alert, const String &p_title = "ALERT!") override;
-
 	virtual void mouse_set_mode(MouseMode p_mode) override;
 	virtual MouseMode mouse_get_mode() const override;
 

+ 4 - 0
platform/windows/os_windows.cpp

@@ -165,6 +165,10 @@ BOOL WINAPI HandlerRoutine(_In_ DWORD dwCtrlType) {
 	}
 }
 
+void OS_Windows::alert(const String &p_alert, const String &p_title) {
+	MessageBoxW(nullptr, (LPCWSTR)(p_alert.utf16().get_data()), (LPCWSTR)(p_title.utf16().get_data()), MB_OK | MB_ICONEXCLAMATION | MB_TASKMODAL);
+}
+
 void OS_Windows::initialize_debugging() {
 	SetConsoleCtrlHandler(HandlerRoutine, TRUE);
 }

+ 2 - 0
platform/windows/os_windows.h

@@ -108,6 +108,8 @@ protected:
 	Map<ProcessID, ProcessInfo> *process_map;
 
 public:
+	virtual void alert(const String &p_alert, const String &p_title = "ALERT!") override;
+
 	virtual Error open_dynamic_library(const String p_path, void *&p_library_handle, bool p_also_set_library_path = false) override;
 	virtual Error close_dynamic_library(void *p_library_handle) override;
 	virtual Error get_dynamic_library_symbol_handle(void *p_library_handle, const String p_name, void *&p_symbol_handle, bool p_optional = false) override;

+ 0 - 2
servers/display_server.cpp

@@ -346,8 +346,6 @@ void DisplayServer::_bind_methods() {
 	ClassDB::bind_method(D_METHOD("global_menu_remove_item", "menu_root", "idx"), &DisplayServer::global_menu_remove_item);
 	ClassDB::bind_method(D_METHOD("global_menu_clear", "menu_root"), &DisplayServer::global_menu_clear);
 
-	ClassDB::bind_method(D_METHOD("alert", "text", "title"), &DisplayServer::alert, DEFVAL("Alert!"));
-
 	ClassDB::bind_method(D_METHOD("mouse_set_mode", "mouse_mode"), &DisplayServer::mouse_set_mode);
 	ClassDB::bind_method(D_METHOD("mouse_get_mode"), &DisplayServer::mouse_get_mode);
 

+ 0 - 2
servers/display_server.h

@@ -143,8 +143,6 @@ public:
 	virtual void global_menu_remove_item(const String &p_menu_root, int p_idx);
 	virtual void global_menu_clear(const String &p_menu_root);
 
-	virtual void alert(const String &p_alert, const String &p_title = "ALERT!") = 0;
-
 	enum MouseMode {
 		MOUSE_MODE_VISIBLE,
 		MOUSE_MODE_HIDDEN,

+ 0 - 2
servers/display_server_headless.h

@@ -55,8 +55,6 @@ public:
 	bool has_feature(Feature p_feature) const override { return false; }
 	String get_name() const override { return "headless"; }
 
-	void alert(const String &p_alert, const String &p_title = "ALERT!") override {}
-
 	int get_screen_count() const override { return 0; }
 	Point2i screen_get_position(int p_screen = SCREEN_OF_MAIN_WINDOW) const override { return Point2i(); }
 	Size2i screen_get_size(int p_screen = SCREEN_OF_MAIN_WINDOW) const override { return Size2i(); }