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

This commit is contained in:
bruvzg 2021-07-22 19:23:48 +03:00
parent 5de991d57c
commit 618eb27e8b
36 changed files with 377 additions and 350 deletions

View File

@ -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);

View File

@ -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);

View File

@ -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;
}

View File

@ -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; }

View File

@ -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>

View File

@ -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>

View File

@ -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];

View File

@ -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);

View File

@ -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);

View File

@ -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;
}

View File

@ -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);

View File

@ -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();

View File

@ -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;

View File

@ -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;

View File

@ -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;
}

View File

@ -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;

View File

@ -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";
};

View File

@ -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;

View File

@ -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;

View File

@ -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();

View File

@ -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();

View File

@ -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;

View File

@ -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;

View File

@ -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();

View File

@ -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();

View File

@ -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;

View File

@ -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() {

View File

@ -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;

View File

@ -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) {

View File

@ -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;

View File

@ -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;

View File

@ -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);
}

View File

@ -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;

View File

@ -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);

View File

@ -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,

View File

@ -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(); }