diff options
Diffstat (limited to 'platform')
24 files changed, 406 insertions, 367 deletions
diff --git a/platform/android/export/export.cpp b/platform/android/export/export.cpp index e3615e2298..9fe1f291d6 100644 --- a/platform/android/export/export.cpp +++ b/platform/android/export/export.cpp @@ -871,7 +871,7 @@ class EditorExportAndroid : public EditorExportPlatform { String lang = str.substr(str.find_last("-") + 1, str.length()).replace("-", "_"); String prop = "application/config/name_" + lang; - if (ProjectSettings::get_singleton()->has(prop)) { + if (ProjectSettings::get_singleton()->has_setting(prop)) { str = ProjectSettings::get_singleton()->get(prop); } else { str = get_project_name(package_name); diff --git a/platform/android/java/src/org/godotengine/godot/Godot.java b/platform/android/java/src/org/godotengine/godot/Godot.java index 53a90e4cfe..053dfa631a 100644 --- a/platform/android/java/src/org/godotengine/godot/Godot.java +++ b/platform/android/java/src/org/godotengine/godot/Godot.java @@ -277,6 +277,21 @@ public class Godot extends Activity implements SensorEventListener, IDownloaderC edittext.setView(mView); io.setEdit(edittext); + final Godot godot = this; + mView.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() { + @Override + public void onGlobalLayout() { + Point fullSize = new Point(); + godot.getWindowManager().getDefaultDisplay().getSize(fullSize); + Rect gameSize = new Rect(); + godot.mView.getWindowVisibleDisplayFrame(gameSize); + + final int keyboardHeight = fullSize.y - gameSize.bottom; + Log.d("GODOT", "setVirtualKeyboardHeight: " + keyboardHeight); + GodotLib.setVirtualKeyboardHeight(keyboardHeight); + } + }); + // Ad layout adLayout = new RelativeLayout(this); adLayout.setLayoutParams(new LayoutParams(LayoutParams.FILL_PARENT,LayoutParams.FILL_PARENT)); diff --git a/platform/android/java/src/org/godotengine/godot/GodotLib.java b/platform/android/java/src/org/godotengine/godot/GodotLib.java index 47a690140f..e0ed4cd38c 100644 --- a/platform/android/java/src/org/godotengine/godot/GodotLib.java +++ b/platform/android/java/src/org/godotengine/godot/GodotLib.java @@ -69,4 +69,6 @@ public class GodotLib { public static native void callobject(int p_ID, String p_method, Object[] p_params); public static native void calldeferred(int p_ID, String p_method, Object[] p_params); + public static native void setVirtualKeyboardHeight(int p_height); + } diff --git a/platform/android/java_glue.cpp b/platform/android/java_glue.cpp index 509d1bf123..6819a7e20f 100644 --- a/platform/android/java_glue.cpp +++ b/platform/android/java_glue.cpp @@ -754,6 +754,18 @@ static void _alert(const String &p_message, const String &p_title) { env->CallVoidMethod(_godot_instance, _alertDialog, jStrMessage, jStrTitle); } +// volatile because it can be changed from non-main thread and we need to +// ensure the change is immediately visible to other threads. +static volatile int virtual_keyboard_height; + +static int _get_vk_height() { + return virtual_keyboard_height; +} + +JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_setVirtualKeyboardHeight(JNIEnv *env, jobject obj, jint p_height) { + virtual_keyboard_height = p_height; +} + JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_initialize(JNIEnv *env, jobject obj, jobject activity, jboolean p_need_reload_hook, jobject p_asset_manager, jboolean p_use_apk_expansion) { __android_log_print(ANDROID_LOG_INFO, "godot", "**INIT EVENT! - %p\n", env); @@ -824,7 +836,7 @@ JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_initialize(JNIEnv *en AudioDriverAndroid::setup(gob); } - os_android = new OS_Android(_gfx_init_func, env, _open_uri, _get_data_dir, _get_locale, _get_model, _get_screen_dpi, _show_vk, _hide_vk, _set_screen_orient, _get_unique_id, _get_system_dir, _play_video, _is_video_playing, _pause_video, _stop_video, _set_keep_screen_on, _alert, p_use_apk_expansion); + os_android = new OS_Android(_gfx_init_func, env, _open_uri, _get_data_dir, _get_locale, _get_model, _get_screen_dpi, _show_vk, _hide_vk, _get_vk_height, _set_screen_orient, _get_unique_id, _get_system_dir, _play_video, _is_video_playing, _pause_video, _stop_video, _set_keep_screen_on, _alert, p_use_apk_expansion); os_android->set_need_reload_hooks(p_need_reload_hook); char wd[500]; @@ -841,7 +853,7 @@ JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_initialize(JNIEnv *en static void _initialize_java_modules() { - if (!ProjectSettings::get_singleton()->has("android/modules")) { + if (!ProjectSettings::get_singleton()->has_setting("android/modules")) { print_line("ANDROID MODULES: Nothing to load, aborting"); return; } diff --git a/platform/android/java_glue.h b/platform/android/java_glue.h index ec8ae9a0a6..0aa2489813 100644 --- a/platform/android/java_glue.h +++ b/platform/android/java_glue.h @@ -59,6 +59,7 @@ JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_method(JNIEnv *env, j JNIEXPORT jstring JNICALL Java_org_godotengine_godot_GodotLib_getGlobal(JNIEnv *env, jobject obj, jstring path); JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_callobject(JNIEnv *env, jobject p_obj, jint ID, jstring method, jobjectArray params); JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_calldeferred(JNIEnv *env, jobject p_obj, jint ID, jstring method, jobjectArray params); +JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_setVirtualKeyboardHeight(JNIEnv *env, jobject obj, jint p_height); } #endif diff --git a/platform/android/os_android.cpp b/platform/android/os_android.cpp index 0eb14f6af3..473a093077 100644 --- a/platform/android/os_android.cpp +++ b/platform/android/os_android.cpp @@ -519,6 +519,15 @@ bool OS_Android::has_virtual_keyboard() const { return true; } +int OS_Android::get_virtual_keyboard_height() const { + if (get_virtual_keyboard_height_func) { + return get_virtual_keyboard_height_func(); + } + + ERR_PRINT("Cannot obtain virtual keyboard height."); + return 0; +} + void OS_Android::show_virtual_keyboard(const String &p_existing_text, const Rect2 &p_screen_rect) { if (show_virtual_keyboard_func) { @@ -704,7 +713,7 @@ bool OS_Android::_check_internal_feature_support(const String &p_feature) { return p_feature == "mobile" || p_feature == "etc" || p_feature == "etc2"; //TODO support etc2 only if GLES3 driver is selected } -OS_Android::OS_Android(GFXInitFunc p_gfx_init_func, void *p_gfx_init_ud, OpenURIFunc p_open_uri_func, GetDataDirFunc p_get_data_dir_func, GetLocaleFunc p_get_locale_func, GetModelFunc p_get_model_func, GetScreenDPIFunc p_get_screen_dpi_func, ShowVirtualKeyboardFunc p_show_vk, HideVirtualKeyboardFunc p_hide_vk, SetScreenOrientationFunc p_screen_orient, GetUniqueIDFunc p_get_unique_id, GetSystemDirFunc p_get_sdir_func, VideoPlayFunc p_video_play_func, VideoIsPlayingFunc p_video_is_playing_func, VideoPauseFunc p_video_pause_func, VideoStopFunc p_video_stop_func, SetKeepScreenOnFunc p_set_keep_screen_on_func, AlertFunc p_alert_func, bool p_use_apk_expansion) { +OS_Android::OS_Android(GFXInitFunc p_gfx_init_func, void *p_gfx_init_ud, OpenURIFunc p_open_uri_func, GetDataDirFunc p_get_data_dir_func, GetLocaleFunc p_get_locale_func, GetModelFunc p_get_model_func, GetScreenDPIFunc p_get_screen_dpi_func, ShowVirtualKeyboardFunc p_show_vk, HideVirtualKeyboardFunc p_hide_vk, VirtualKeyboardHeightFunc p_vk_height_func, SetScreenOrientationFunc p_screen_orient, GetUniqueIDFunc p_get_unique_id, GetSystemDirFunc p_get_sdir_func, VideoPlayFunc p_video_play_func, VideoIsPlayingFunc p_video_is_playing_func, VideoPauseFunc p_video_pause_func, VideoStopFunc p_video_stop_func, SetKeepScreenOnFunc p_set_keep_screen_on_func, AlertFunc p_alert_func, bool p_use_apk_expansion) { use_apk_expansion = p_use_apk_expansion; default_videomode.width = 800; @@ -734,6 +743,7 @@ OS_Android::OS_Android(GFXInitFunc p_gfx_init_func, void *p_gfx_init_ud, OpenURI show_virtual_keyboard_func = p_show_vk; hide_virtual_keyboard_func = p_hide_vk; + get_virtual_keyboard_height_func = p_vk_height_func; set_screen_orientation_func = p_screen_orient; set_keep_screen_on_func = p_set_keep_screen_on_func; diff --git a/platform/android/os_android.h b/platform/android/os_android.h index a614bb8067..0c78c198a8 100644 --- a/platform/android/os_android.h +++ b/platform/android/os_android.h @@ -67,6 +67,7 @@ typedef void (*VideoPauseFunc)(); typedef void (*VideoStopFunc)(); typedef void (*SetKeepScreenOnFunc)(bool p_enabled); typedef void (*AlertFunc)(const String &, const String &); +typedef int (*VirtualKeyboardHeightFunc)(); class OS_Android : public OS_Unix { public: @@ -126,6 +127,7 @@ private: GetScreenDPIFunc get_screen_dpi_func; ShowVirtualKeyboardFunc show_virtual_keyboard_func; HideVirtualKeyboardFunc hide_virtual_keyboard_func; + VirtualKeyboardHeightFunc get_virtual_keyboard_height_func; SetScreenOrientationFunc set_screen_orientation_func; GetUniqueIDFunc get_unique_id_func; GetSystemDirFunc get_system_dir_func; @@ -201,6 +203,7 @@ public: virtual bool has_virtual_keyboard() const; virtual void show_virtual_keyboard(const String &p_existing_text, const Rect2 &p_screen_rect = Rect2()); virtual void hide_virtual_keyboard(); + virtual int get_virtual_keyboard_height() const; void set_opengl_extensions(const char *p_gl_extensions); void set_display_size(Size2 p_size); @@ -240,7 +243,7 @@ public: void joy_connection_changed(int p_device, bool p_connected, String p_name); virtual bool _check_internal_feature_support(const String &p_feature); - OS_Android(GFXInitFunc p_gfx_init_func, void *p_gfx_init_ud, OpenURIFunc p_open_uri_func, GetDataDirFunc p_get_data_dir_func, GetLocaleFunc p_get_locale_func, GetModelFunc p_get_model_func, GetScreenDPIFunc p_get_screen_dpi_func, ShowVirtualKeyboardFunc p_show_vk, HideVirtualKeyboardFunc p_hide_vk, SetScreenOrientationFunc p_screen_orient, GetUniqueIDFunc p_get_unique_id, GetSystemDirFunc p_get_sdir_func, VideoPlayFunc p_video_play_func, VideoIsPlayingFunc p_video_is_playing_func, VideoPauseFunc p_video_pause_func, VideoStopFunc p_video_stop_func, SetKeepScreenOnFunc p_set_keep_screen_on_func, AlertFunc p_alert_func, bool p_use_apk_expansion); + OS_Android(GFXInitFunc p_gfx_init_func, void *p_gfx_init_ud, OpenURIFunc p_open_uri_func, GetDataDirFunc p_get_data_dir_func, GetLocaleFunc p_get_locale_func, GetModelFunc p_get_model_func, GetScreenDPIFunc p_get_screen_dpi_func, ShowVirtualKeyboardFunc p_show_vk, HideVirtualKeyboardFunc p_hide_vk, VirtualKeyboardHeightFunc p_vk_height_func, SetScreenOrientationFunc p_screen_orient, GetUniqueIDFunc p_get_unique_id, GetSystemDirFunc p_get_sdir_func, VideoPlayFunc p_video_play_func, VideoIsPlayingFunc p_video_is_playing_func, VideoPauseFunc p_video_pause_func, VideoStopFunc p_video_stop_func, SetKeepScreenOnFunc p_set_keep_screen_on_func, AlertFunc p_alert_func, bool p_use_apk_expansion); ~OS_Android(); }; diff --git a/platform/iphone/app_delegate.mm b/platform/iphone/app_delegate.mm index da6ceacdac..65cafbd6d4 100644 --- a/platform/iphone/app_delegate.mm +++ b/platform/iphone/app_delegate.mm @@ -81,7 +81,7 @@ void _set_keep_screen_on(bool p_enabled) { extern int gargc; extern char **gargv; -extern int iphone_main(int, int, int, char **); +extern int iphone_main(int, int, int, char **, String); extern void iphone_finish(); CMMotionManager *motionManager; @@ -393,15 +393,6 @@ static int frame_count = 0; }; ++frame_count; - NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, - NSUserDomainMask, YES); - NSString *documentsDirectory = [paths objectAtIndex:0]; - // NSString *documentsDirectory = [[[NSFileManager defaultManager] - // URLsForDirectory:NSDocumentDirectory inDomains:NSUserDomainMask] - // lastObject]; - OSIPhone::get_singleton()->set_data_dir( - String::utf8([documentsDirectory UTF8String])); - NSString *locale_code = [[NSLocale currentLocale] localeIdentifier]; OSIPhone::get_singleton()->set_locale( String::utf8([locale_code UTF8String])); @@ -604,7 +595,11 @@ static int frame_count = 0; glGetRenderbufferParameterivOES(GL_RENDERBUFFER_OES, GL_RENDERBUFFER_HEIGHT_OES, &backingHeight); - int err = iphone_main(backingWidth, backingHeight, gargc, gargv); + NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, + NSUserDomainMask, YES); + NSString *documentsDirectory = [paths objectAtIndex:0]; + + int err = iphone_main(backingWidth, backingHeight, gargc, gargv, String::utf8([documentsDirectory UTF8String])); if (err != 0) { // bail, things did not go very well for us, should probably output a message on screen with our error code... exit(0); diff --git a/platform/iphone/gl_view.h b/platform/iphone/gl_view.h index a9fd8d5711..f7309396c6 100644 --- a/platform/iphone/gl_view.h +++ b/platform/iphone/gl_view.h @@ -100,6 +100,8 @@ - (void)destroyFramebuffer; - (void)audioRouteChangeListenerCallback:(NSNotification *)notification; +- (void)keyboardOnScreen:(NSNotification *)notification; +- (void)keyboardHidden:(NSNotification *)notification; @property NSTimeInterval animationInterval; @property(nonatomic, assign) BOOL useCADisplayLink; diff --git a/platform/iphone/gl_view.mm b/platform/iphone/gl_view.mm index 3e206c3a2c..02da706cc5 100644 --- a/platform/iphone/gl_view.mm +++ b/platform/iphone/gl_view.mm @@ -63,6 +63,7 @@ void _pause_video(); void _focus_out_video(); void _unpause_video(); void _stop_video(); +CGFloat _points_to_pixels(CGFloat); void _show_keyboard(String p_existing) { keyboard_text = p_existing; @@ -174,6 +175,19 @@ void _stop_video() { video_playing = false; } +CGFloat _points_to_pixels(CGFloat points) { + float pixelPerInch; + if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad) { + pixelPerInch = 132; + } else if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPhone) { + pixelPerInch = 163; + } else { + pixelPerInch = 160; + } + CGFloat pointsPerInch = 72.0; + return (points / pointsPerInch * pixelPerInch); +} + @implementation GLView @synthesize animationInterval; @@ -537,6 +551,20 @@ static void clear_touches() { [self resignFirstResponder]; }; +- (void)keyboardOnScreen:(NSNotification *)notification { + NSDictionary *info = notification.userInfo; + NSValue *value = info[UIKeyboardFrameEndUserInfoKey]; + + CGRect rawFrame = [value CGRectValue]; + CGRect keyboardFrame = [self convertRect:rawFrame fromView:nil]; + + OSIPhone::get_singleton()->set_virtual_keyboard_height(_points_to_pixels(keyboardFrame.size.height)); +} + +- (void)keyboardHidden:(NSNotification *)notification { + OSIPhone::get_singleton()->set_virtual_keyboard_height(0); +} + - (void)deleteBackward { if (keyboard_text.length()) keyboard_text.erase(keyboard_text.length() - 1, 1); @@ -606,6 +634,18 @@ static void clear_touches() { name:AVAudioSessionRouteChangeNotification object:nil]; + printf("******** adding observer for keyboard show/hide\n"); + [[NSNotificationCenter defaultCenter] + addObserver:self + selector:@selector(keyboardOnScreen:) + name:UIKeyboardDidShowNotification + object:nil]; + [[NSNotificationCenter defaultCenter] + addObserver:self + selector:@selector(keyboardHidden:) + name:UIKeyboardDidHideNotification + object:nil]; + //self.autoresizesSubviews = YES; //[self setAutoresizingMask:UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleWidth]; diff --git a/platform/iphone/godot_iphone.cpp b/platform/iphone/godot_iphone.cpp index 8c6d6d8da4..7d21d35e18 100644 --- a/platform/iphone/godot_iphone.cpp +++ b/platform/iphone/godot_iphone.cpp @@ -29,6 +29,7 @@ /*************************************************************************/ #include "main/main.h" #include "os_iphone.h" +#include "ustring.h" #include <stdio.h> #include <string.h> @@ -41,9 +42,9 @@ int add_path(int p_argc, char **p_args); int add_cmdline(int p_argc, char **p_args); }; -int iphone_main(int, int, int, char **); +int iphone_main(int, int, int, char **, String); -int iphone_main(int width, int height, int argc, char **argv) { +int iphone_main(int width, int height, int argc, char **argv, String data_dir) { int len = strlen(argv[0]); @@ -63,7 +64,7 @@ int iphone_main(int width, int height, int argc, char **argv) { char cwd[512]; getcwd(cwd, sizeof(cwd)); printf("cwd %s\n", cwd); - os = new OSIPhone(width, height); + os = new OSIPhone(width, height, data_dir); char *fargv[64]; for (int i = 0; i < argc; i++) { diff --git a/platform/iphone/os_iphone.cpp b/platform/iphone/os_iphone.cpp index 5009f7d8ae..08792b8631 100644 --- a/platform/iphone/os_iphone.cpp +++ b/platform/iphone/os_iphone.cpp @@ -97,6 +97,8 @@ void OSIPhone::initialize_core() { OS_Unix::initialize_core(); SemaphoreIphone::make_default(); + + set_data_dir(data_dir); }; void OSIPhone::initialize_logger() { @@ -463,6 +465,14 @@ void OSIPhone::hide_virtual_keyboard() { _hide_keyboard(); }; +void OSIPhone::set_virtual_keyboard_height(int p_height) { + virtual_keyboard_height = p_height; +} + +int OSIPhone::get_virtual_keyboard_height() const { + return virtual_keyboard_height; +} + Error OSIPhone::shell_open(String p_uri) { return _shell_open(p_uri); }; @@ -564,7 +574,7 @@ bool OSIPhone::_check_internal_feature_support(const String &p_feature) { return p_feature == "mobile" || p_feature == "etc" || p_feature == "pvrtc" || p_feature == "etc2"; } -OSIPhone::OSIPhone(int width, int height) { +OSIPhone::OSIPhone(int width, int height, String p_data_dir) { main_loop = NULL; visual_server = NULL; @@ -576,6 +586,11 @@ OSIPhone::OSIPhone(int width, int height) { vm.resizable = false; set_video_mode(vm); event_count = 0; + virtual_keyboard_height = 0; + + // can't call set_data_dir from here, since it requires DirAccess + // which is initialized in initialize_core + data_dir = p_data_dir; _set_logger(memnew(SyslogLogger)); }; diff --git a/platform/iphone/os_iphone.h b/platform/iphone/os_iphone.h index 11f4eed5e7..e70ac9ba98 100644 --- a/platform/iphone/os_iphone.h +++ b/platform/iphone/os_iphone.h @@ -124,6 +124,8 @@ private: InputDefault *input; + int virtual_keyboard_height; + public: bool iterate(); @@ -133,6 +135,7 @@ public: void mouse_move(int p_idx, int p_prev_x, int p_prev_y, int p_x, int p_y, bool p_use_as_mouse); void touches_cancelled(); void key(uint32_t p_key, bool p_pressed); + void set_virtual_keyboard_height(int p_height); int set_base_framebuffer(int p_fb); @@ -168,6 +171,7 @@ public: virtual bool has_virtual_keyboard() const; virtual void show_virtual_keyboard(const String &p_existing_text, const Rect2 &p_screen_rect = Rect2()); virtual void hide_virtual_keyboard(); + virtual int get_virtual_keyboard_height() const; virtual void set_cursor_shape(CursorShape p_shape); @@ -197,7 +201,7 @@ public: virtual void native_video_stop(); virtual bool _check_internal_feature_support(const String &p_feature); - OSIPhone(int width, int height); + OSIPhone(int width, int height, String p_data_dir); ~OSIPhone(); }; diff --git a/platform/javascript/javascript_main.cpp b/platform/javascript/javascript_main.cpp index 4c948bf181..ed4f416cfd 100644 --- a/platform/javascript/javascript_main.cpp +++ b/platform/javascript/javascript_main.cpp @@ -39,8 +39,13 @@ static void main_loop() { os->main_loop_iterate(); } -extern "C" void main_after_fs_sync() { +extern "C" void main_after_fs_sync(char *p_idbfs_err) { + String idbfs_err = String::utf8(p_idbfs_err); + if (!idbfs_err.empty()) { + print_line("IndexedDB not available: " + idbfs_err); + } + os->set_idbfs_available(idbfs_err.empty()); // Ease up compatibility ResourceLoader::set_abort_on_missing_resources(false); Main::start(); @@ -60,14 +65,7 @@ int main(int argc, char *argv[]) { FS.mkdir('/userfs'); FS.mount(IDBFS, {}, '/userfs'); FS.syncfs(true, function(err) { - if (err) { - Module.setStatus('Failed to load persistent data\nPlease allow (third-party) cookies'); - Module.printErr('Failed to populate IDB file system: ' + err.message); - Module.noExitRuntime = false; - } else { - Module.print('Successfully populated IDB file system'); - ccall('main_after_fs_sync', null); - } + Module['ccall']('main_after_fs_sync', null, ['string'], [err ? err.message : ""]) }); ); /* clang-format on */ diff --git a/platform/javascript/os_javascript.cpp b/platform/javascript/os_javascript.cpp index 82a8409615..f6446e77da 100644 --- a/platform/javascript/os_javascript.cpp +++ b/platform/javascript/os_javascript.cpp @@ -825,7 +825,7 @@ bool OS_JavaScript::main_loop_iterate() { if (!main_loop) return false; - if (time_to_save_sync >= 0) { + if (idbfs_available && time_to_save_sync >= 0) { int64_t newtime = get_ticks_msec(); int64_t elapsed = newtime - last_sync_time; last_sync_time = newtime; @@ -915,10 +915,10 @@ String OS_JavaScript::get_executable_path() const { void OS_JavaScript::_close_notification_funcs(const String &p_file, int p_flags) { - print_line("close " + p_file + " flags " + itos(p_flags)); - if (p_file.begins_with("/userfs") && p_flags & FileAccess::WRITE) { - static_cast<OS_JavaScript *>(get_singleton())->last_sync_time = OS::get_singleton()->get_ticks_msec(); - static_cast<OS_JavaScript *>(get_singleton())->time_to_save_sync = 5000; //five seconds since last save + OS_JavaScript *os = static_cast<OS_JavaScript *>(get_singleton()); + if (os->idbfs_available && p_file.begins_with("/userfs") && p_flags & FileAccess::WRITE) { + os->last_sync_time = OS::get_singleton()->get_ticks_msec(); + os->time_to_save_sync = 5000; //five seconds since last save } } @@ -993,6 +993,16 @@ bool OS_JavaScript::_check_internal_feature_support(const String &p_feature) { return p_feature == "web" || p_feature == "s3tc"; // TODO check for these features really being available } +void OS_JavaScript::set_idbfs_available(bool p_idbfs_available) { + + idbfs_available = p_idbfs_available; +} + +bool OS_JavaScript::is_userfs_persistent() const { + + return idbfs_available; +} + OS_JavaScript::OS_JavaScript(const char *p_execpath, GetDataDirFunc p_get_data_dir_func) { set_cmdline(p_execpath, get_cmdline_args()); main_loop = NULL; @@ -1004,6 +1014,7 @@ OS_JavaScript::OS_JavaScript(const char *p_execpath, GetDataDirFunc p_get_data_d get_data_dir_func = p_get_data_dir_func; FileAccessUnix::close_notification_func = _close_notification_funcs; + idbfs_available = false; time_to_save_sync = -1; } diff --git a/platform/javascript/os_javascript.h b/platform/javascript/os_javascript.h index 1c7bcfef45..1c939d3fd5 100644 --- a/platform/javascript/os_javascript.h +++ b/platform/javascript/os_javascript.h @@ -49,6 +49,7 @@ typedef String (*GetDataDirFunc)(); class OS_JavaScript : public OS_Unix { + bool idbfs_available; int64_t time_to_save_sync; int64_t last_sync_time; @@ -136,6 +137,8 @@ public: virtual bool can_draw() const; + virtual bool is_userfs_persistent() const; + virtual void set_cursor_shape(CursorShape p_shape); void main_loop_begin(); @@ -167,6 +170,8 @@ public: virtual bool _check_internal_feature_support(const String &p_feature); + void set_idbfs_available(bool p_idbfs_available); + OS_JavaScript(const char *p_execpath, GetDataDirFunc p_get_data_dir_func); ~OS_JavaScript(); }; diff --git a/platform/osx/detect.py b/platform/osx/detect.py index f66c3f00da..31032659b6 100644 --- a/platform/osx/detect.py +++ b/platform/osx/detect.py @@ -62,7 +62,7 @@ def configure(env): ## Compiler configuration - if (not os.environ.has_key("OSXCROSS_ROOT")): # regular native build + if "OSXCROSS_ROOT" not in os.environ: # regular native build if (env["bits"] == "fat"): env.Append(CCFLAGS=['-arch', 'i386', '-arch', 'x86_64']) env.Append(LINKFLAGS=['-arch', 'i386', '-arch', 'x86_64']) diff --git a/platform/osx/export/export.cpp b/platform/osx/export/export.cpp index 2ec76fe0dd..0ba0ddec7d 100644 --- a/platform/osx/export/export.cpp +++ b/platform/osx/export/export.cpp @@ -53,9 +53,16 @@ class EditorExportPlatformOSX : public EditorExportPlatform { void _fix_plist(const Ref<EditorExportPreset> &p_preset, Vector<uint8_t> &plist, const String &p_binary); void _make_icon(const Ref<Image> &p_icon, Vector<uint8_t> &p_data); -#ifdef OSX_ENABLED + Error _code_sign(const Ref<EditorExportPreset> &p_preset, const String &p_path); Error _create_dmg(const String &p_dmg_path, const String &p_pkg_name, const String &p_app_path_name); + +#ifdef OSX_ENABLED + bool use_codesign() const { return true; } + bool use_dmg() const { return true; } +#else + bool use_codesign() const { return false; } + bool use_dmg() const { return false; } #endif protected: @@ -67,11 +74,7 @@ public: virtual String get_os_name() const { return "OSX"; } virtual Ref<Texture> get_logo() const { return logo; } -#ifdef OSX_ENABLED - virtual String get_binary_extension() const { return "dmg"; } -#else - virtual String get_binary_extension() const { return "zip"; } -#endif + virtual String get_binary_extension() const { return use_dmg() ? "dmg" : "zip"; } virtual Error export_project(const Ref<EditorExportPreset> &p_preset, bool p_debug, const String &p_path, int p_flags = 0); virtual bool can_export(const Ref<EditorExportPreset> &p_preset, String &r_error, bool &r_missing_templates) const; @@ -97,6 +100,16 @@ void EditorExportPlatformOSX::get_preset_features(const Ref<EditorExportPreset> if (p_preset->get("texture_format/etc2")) { r_features->push_back("etc2"); } + + int bits = p_preset->get("application/bits_mode"); + + if (bits == 0 || bits == 1) { + r_features->push_back("64"); + } + + if (bits == 0 || bits == 2) { + r_features->push_back("32"); + } } void EditorExportPlatformOSX::get_export_options(List<ExportOption> *r_options) { @@ -210,7 +223,6 @@ void EditorExportPlatformOSX::_fix_plist(const Ref<EditorExportPreset> &p_preset } } -#ifdef OSX_ENABLED /** If we're running the OSX version of the Godot editor we'll: - export our application bundle to a temporary folder @@ -220,6 +232,7 @@ void EditorExportPlatformOSX::_fix_plist(const Ref<EditorExportPreset> &p_preset Error EditorExportPlatformOSX::_code_sign(const Ref<EditorExportPreset> &p_preset, const String &p_path) { List<String> args; + if (p_preset->get("codesign/entitlements") != "") { /* this should point to our entitlements.plist file that sandboxes our application, I don't know if this should also be placed in our app bundle */ args.push_back("-entitlements"); @@ -229,14 +242,25 @@ Error EditorExportPlatformOSX::_code_sign(const Ref<EditorExportPreset> &p_prese args.push_back(p_preset->get("codesign/identity")); args.push_back("-v"); /* provide some more feedback */ args.push_back(p_path); - Error err = OS::get_singleton()->execute("/usr/bin/codesign", args, true); - ERR_FAIL_COND_V(err, err); + + String str; + Error err = OS::get_singleton()->execute("/usr/bin/codesign", args, true, NULL, &str, NULL, true); + ERR_FAIL_COND_V(err != OK, err); + + print_line("codesign: " + str); + if (str.find("no identity found") != -1) { + EditorNode::add_io_error("codesign: no identity found"); + return FAILED; + } return OK; } Error EditorExportPlatformOSX::_create_dmg(const String &p_dmg_path, const String &p_pkg_name, const String &p_app_path_name) { List<String> args; + + OS::get_singleton()->move_to_trash(p_dmg_path); + args.push_back("create"); args.push_back(p_dmg_path); args.push_back("-volname"); @@ -245,8 +269,20 @@ Error EditorExportPlatformOSX::_create_dmg(const String &p_dmg_path, const Strin args.push_back("HFS+"); args.push_back("-srcfolder"); args.push_back(p_app_path_name); - Error err = OS::get_singleton()->execute("/usr/bin/hdiutil", args, true); - ERR_FAIL_COND_V(err, err); + + String str; + Error err = OS::get_singleton()->execute("/usr/bin/hdiutil", args, true, NULL, &str, NULL, true); + ERR_FAIL_COND_V(err != OK, err); + + print_line("hdiutil returned: " + str); + if (str.find("create failed") != -1) { + if (str.find("File exists") != -1) { + EditorNode::add_io_error("hdiutil: create failed - file exists"); + } else { + EditorNode::add_io_error("hdiutil: create failed"); + } + return FAILED; + } return OK; } @@ -299,28 +335,45 @@ Error EditorExportPlatformOSX::export_project(const Ref<EditorExportPreset> &p_p else pkg_name = "Unnamed"; - // We're on OSX so we can export to DMG, but first we create our application bundle - String tmp_app_path_name = p_path.get_base_dir() + "/" + pkg_name + ".app"; - print_line("Exporting to " + tmp_app_path_name); - DirAccess *tmp_app_path = DirAccess::create_for_path(tmp_app_path_name); - ERR_FAIL_COND_V(!tmp_app_path, ERR_CANT_CREATE) + Error err = OK; + String tmp_app_path_name = ""; + zlib_filefunc_def io2 = io; + FileAccess *dst_f = NULL; + io2.opaque = &dst_f; + zipFile dst_pkg_zip = NULL; + + if (use_dmg()) { + // We're on OSX so we can export to DMG, but first we create our application bundle + tmp_app_path_name = EditorSettings::get_singleton()->get_settings_path() + "/tmp/" + pkg_name + ".app"; + print_line("Exporting to " + tmp_app_path_name); + DirAccess *tmp_app_path = DirAccess::create_for_path(tmp_app_path_name); + if (!tmp_app_path) { + err = ERR_CANT_CREATE; + } - ///@TODO We should delete the existing application bundle especially if we attempt to code sign it, but what is a safe way to do this? Maybe call system function so it moves to trash? - // tmp_app_path->erase_contents_recursive(); + // Create our folder structure or rely on unzip? + if (err == OK) { + print_line("Creating " + tmp_app_path_name + "/Contents/MacOS"); + err = tmp_app_path->make_dir_recursive(tmp_app_path_name + "/Contents/MacOS"); + } - // Create our folder structure or rely on unzip? - print_line("Creating " + tmp_app_path_name + "/Contents/MacOS"); - Error dir_err = tmp_app_path->make_dir_recursive(tmp_app_path_name + "/Contents/MacOS"); - ERR_FAIL_COND_V(dir_err, ERR_CANT_CREATE) - print_line("Creating " + tmp_app_path_name + "/Contents/Resources"); - dir_err = tmp_app_path->make_dir_recursive(tmp_app_path_name + "/Contents/Resources"); - ERR_FAIL_COND_V(dir_err, ERR_CANT_CREATE) + if (err == OK) { + print_line("Creating " + tmp_app_path_name + "/Contents/Resources"); + err = tmp_app_path->make_dir_recursive(tmp_app_path_name + "/Contents/Resources"); + } + } else { + // Open our destination zip file + dst_pkg_zip = zipOpen2(p_path.utf8().get_data(), APPEND_STATUS_CREATE, NULL, &io2); + if (!dst_pkg_zip) { + err = ERR_CANT_CREATE; + } + } - /* Now process our template */ + // Now process our template bool found_binary = false; int total_size = 0; - while (ret == UNZ_OK) { + while (ret == UNZ_OK && err == OK) { bool is_execute = false; //get filename @@ -382,287 +435,152 @@ Error EditorExportPlatformOSX::export_project(const Ref<EditorExportPreset> &p_p print_line("ADDING: " + file + " size: " + itos(data.size())); total_size += data.size(); - /* write it into our application bundle */ - file = tmp_app_path_name + "/" + file; - - /* write the file, need to add chmod */ - FileAccess *f = FileAccess::open(file, FileAccess::WRITE); - ERR_FAIL_COND_V(!f, ERR_CANT_CREATE) - f->store_buffer(data.ptr(), data.size()); - f->close(); - memdelete(f); - - if (is_execute) { - // we need execute rights on this file - chmod(file.utf8().get_data(), 0755); + if (use_dmg()) { + // write it into our application bundle + file = tmp_app_path_name + "/" + file; + + // write the file, need to add chmod + FileAccess *f = FileAccess::open(file, FileAccess::WRITE); + if (f) { + f->store_buffer(data.ptr(), data.size()); + f->close(); + if (is_execute) { + // Chmod with 0755 if the file is executable + f->_chmod(file, 0755); + } + memdelete(f); + } else { + err = ERR_CANT_CREATE; + } } else { - // seems to already be set correctly - // chmod(file.utf8().get_data(), 0644); + // add it to our zip file + file = pkg_name + ".app/" + file; + + zip_fileinfo fi; + fi.tmz_date.tm_hour = info.tmu_date.tm_hour; + fi.tmz_date.tm_min = info.tmu_date.tm_min; + fi.tmz_date.tm_sec = info.tmu_date.tm_sec; + fi.tmz_date.tm_mon = info.tmu_date.tm_mon; + fi.tmz_date.tm_mday = info.tmu_date.tm_mday; + fi.tmz_date.tm_year = info.tmu_date.tm_year; + fi.dosDate = info.dosDate; + fi.internal_fa = info.internal_fa; + fi.external_fa = info.external_fa; + + int zerr = zipOpenNewFileInZip(dst_pkg_zip, + file.utf8().get_data(), + &fi, + NULL, + 0, + NULL, + 0, + NULL, + Z_DEFLATED, + Z_DEFAULT_COMPRESSION); + + print_line("OPEN ERR: " + itos(zerr)); + zerr = zipWriteInFileInZip(dst_pkg_zip, data.ptr(), data.size()); + print_line("WRITE ERR: " + itos(zerr)); + zipCloseFileInZip(dst_pkg_zip); } } ret = unzGoToNextFile(src_pkg_zip); } - /* we're done with our source zip */ + // we're done with our source zip unzClose(src_pkg_zip); if (!found_binary) { ERR_PRINTS("Requested template binary '" + binary_to_use + "' not found. It might be missing from your template archive."); - unzClose(src_pkg_zip); - return ERR_FILE_NOT_FOUND; - } - - ep.step("Making PKG", 1); - - String pack_path = tmp_app_path_name + "/Contents/Resources/" + pkg_name + ".pck"; - Error err = save_pack(p_preset, pack_path); - // chmod(pack_path.utf8().get_data(), 0644); - - if (err) { - return err; - } - - /* see if we can code sign our new package */ - if (p_preset->get("codesign/identity") != "") { - ep.step("Code signing bundle", 2); - - /* the order in which we code sign is important, this is a bit of a shame or we could do this in our loop that extracts the files from our ZIP */ - - // start with our application - err = _code_sign(p_preset, tmp_app_path_name + "/Contents/MacOS/" + pkg_name); - ERR_FAIL_COND_V(err, err); - - ///@TODO we should check the contents of /Contents/Frameworks for frameworks to sign - - // we should probably loop through all resources and sign them? - err = _code_sign(p_preset, tmp_app_path_name + "/Contents/Resources/icon.icns"); - ERR_FAIL_COND_V(err, err); - err = _code_sign(p_preset, pack_path); - ERR_FAIL_COND_V(err, err); - err = _code_sign(p_preset, tmp_app_path_name + "/Contents/Info.plist"); - ERR_FAIL_COND_V(err, err); - } - - /* and finally create a DMG */ - ep.step("Making DMG", 3); - err = _create_dmg(p_path, pkg_name, tmp_app_path_name); - ERR_FAIL_COND_V(err, err); - - return OK; -} - -#else - -/** - When exporting for OSX from any other platform we don't have access to code signing or creating DMGs so we'll wrap the bundle into a zip file. - - Should probably find a nicer way to have just one export method instead of duplicating the method like this but I would the code got very - messy with switches inside of it. -**/ -Error EditorExportPlatformOSX::export_project(const Ref<EditorExportPreset> &p_preset, bool p_debug, const String &p_path, int p_flags) { - - String src_pkg_name; - - EditorProgress ep("export", "Exporting for OSX", 104); - - if (p_debug) - src_pkg_name = p_preset->get("custom_package/debug"); - else - src_pkg_name = p_preset->get("custom_package/release"); - - if (src_pkg_name == "") { - String err; - src_pkg_name = find_export_template("osx.zip", &err); - if (src_pkg_name == "") { - EditorNode::add_io_error(err); - return ERR_FILE_NOT_FOUND; - } - } - - FileAccess *src_f = NULL; - zlib_filefunc_def io = zipio_create_io_from_file(&src_f); - - ep.step("Creating app", 0); - - unzFile src_pkg_zip = unzOpen2(src_pkg_name.utf8().get_data(), &io); - if (!src_pkg_zip) { - - EditorNode::add_io_error("Could not find template app to export:\n" + src_pkg_name); - return ERR_FILE_NOT_FOUND; + err = ERR_FILE_NOT_FOUND; } - ERR_FAIL_COND_V(!src_pkg_zip, ERR_CANT_OPEN); - int ret = unzGoToFirstFile(src_pkg_zip); + if (err == OK) { + ep.step("Making PKG", 1); - String binary_to_use = "godot_osx_" + String(p_debug ? "debug" : "release") + "."; - int bits_mode = p_preset->get("application/bits_mode"); - binary_to_use += String(bits_mode == 0 ? "fat" : bits_mode == 1 ? "64" : "32"); + if (use_dmg()) { + String pack_path = tmp_app_path_name + "/Contents/Resources/" + pkg_name + ".pck"; + err = save_pack(p_preset, pack_path); - print_line("binary: " + binary_to_use); - String pkg_name; - if (p_preset->get("application/name") != "") - pkg_name = p_preset->get("application/name"); // app_name - else if (String(ProjectSettings::get_singleton()->get("application/config/name")) != "") - pkg_name = String(ProjectSettings::get_singleton()->get("application/config/name")); - else - pkg_name = "Unnamed"; - - /* Open our destination zip file */ - zlib_filefunc_def io2 = io; - FileAccess *dst_f = NULL; - io2.opaque = &dst_f; - zipFile dst_pkg_zip = zipOpen2(p_path.utf8().get_data(), APPEND_STATUS_CREATE, NULL, &io2); + // see if we can code sign our new package + String identity = p_preset->get("codesign/identity"); + if (err == OK && identity != "") { + ep.step("Code signing bundle", 2); - bool found_binary = false; + // the order in which we code sign is important, this is a bit of a shame or we could do this in our loop that extracts the files from our ZIP - while (ret == UNZ_OK) { - - //get filename - unz_file_info info; - char fname[16384]; - ret = unzGetCurrentFileInfo(src_pkg_zip, &info, fname, 16384, NULL, 0, NULL, 0); + // start with our application + err = _code_sign(p_preset, tmp_app_path_name + "/Contents/MacOS/" + pkg_name); - String file = fname; - - print_line("READ: " + file); - Vector<uint8_t> data; - data.resize(info.uncompressed_size); - - //read - unzOpenCurrentFile(src_pkg_zip); - unzReadCurrentFile(src_pkg_zip, data.ptr(), data.size()); - unzCloseCurrentFile(src_pkg_zip); - - //write + ///@TODO we should check the contents of /Contents/Frameworks for frameworks to sign + } - file = file.replace_first("osx_template.app/", ""); + if (err == OK && identity != "") { + // we should probably loop through all resources and sign them? + err = _code_sign(p_preset, tmp_app_path_name + "/Contents/Resources/icon.icns"); + } - if (file == "Contents/Info.plist") { - print_line("parse plist"); - _fix_plist(p_preset, data, pkg_name); - } + if (err == OK && identity != "") { + err = _code_sign(p_preset, pack_path); + } - if (file.begins_with("Contents/MacOS/godot_")) { - if (file != "Contents/MacOS/" + binary_to_use) { - ret = unzGoToNextFile(src_pkg_zip); - continue; //ignore! + if (err == OK && identity != "") { + err = _code_sign(p_preset, tmp_app_path_name + "/Contents/Info.plist"); } - found_binary = true; - file = "Contents/MacOS/" + pkg_name; - } - if (file == "Contents/Resources/icon.icns") { - //see if there is an icon - String iconpath; - if (p_preset->get("application/icon") != "") - iconpath = p_preset->get("application/icon"); - else - iconpath = ProjectSettings::get_singleton()->get("application/config/icon"); - print_line("icon? " + iconpath); - if (iconpath != "") { - Ref<Image> icon; - icon.instance(); - icon->load(iconpath); - if (!icon->empty()) { - print_line("loaded?"); - _make_icon(icon, data); - } + // and finally create a DMG + if (err == OK) { + ep.step("Making DMG", 3); + err = _create_dmg(p_path, pkg_name, tmp_app_path_name); } - //bleh? - } - if (data.size() > 0) { - print_line("ADDING: " + file + " size: " + itos(data.size())); + // Clean up temporary .app dir + OS::get_singleton()->move_to_trash(tmp_app_path_name); + } else { - /* add it to our zip file */ - file = pkg_name + ".app/" + file; - - zip_fileinfo fi; - fi.tmz_date.tm_hour = info.tmu_date.tm_hour; - fi.tmz_date.tm_min = info.tmu_date.tm_min; - fi.tmz_date.tm_sec = info.tmu_date.tm_sec; - fi.tmz_date.tm_mon = info.tmu_date.tm_mon; - fi.tmz_date.tm_mday = info.tmu_date.tm_mday; - fi.tmz_date.tm_year = info.tmu_date.tm_year; - fi.dosDate = info.dosDate; - fi.internal_fa = info.internal_fa; - fi.external_fa = info.external_fa; - - int err = zipOpenNewFileInZip(dst_pkg_zip, - file.utf8().get_data(), - &fi, - NULL, - 0, - NULL, - 0, - NULL, - Z_DEFLATED, - Z_DEFAULT_COMPRESSION); - - print_line("OPEN ERR: " + itos(err)); - err = zipWriteInFileInZip(dst_pkg_zip, data.ptr(), data.size()); - print_line("WRITE ERR: " + itos(err)); - zipCloseFileInZip(dst_pkg_zip); + String pack_path = EditorSettings::get_singleton()->get_settings_path() + "/tmp/" + pkg_name + ".pck"; + Error err = save_pack(p_preset, pack_path); + + if (err == OK) { + zipOpenNewFileInZip(dst_pkg_zip, + (pkg_name + ".app/Contents/Resources/" + pkg_name + ".pck").utf8().get_data(), + NULL, + NULL, + 0, + NULL, + 0, + NULL, + Z_DEFLATED, + Z_DEFAULT_COMPRESSION); + + FileAccess *pf = FileAccess::open(pack_path, FileAccess::READ); + if (pf) { + const int BSIZE = 16384; + uint8_t buf[BSIZE]; + + while (true) { + + int r = pf->get_buffer(buf, BSIZE); + if (r <= 0) + break; + zipWriteInFileInZip(dst_pkg_zip, buf, r); + } + zipCloseFileInZip(dst_pkg_zip); + memdelete(pf); + } else { + err = ERR_CANT_OPEN; + } + } } - - ret = unzGoToNextFile(src_pkg_zip); - } - - if (!found_binary) { - ERR_PRINTS("Requested template binary '" + binary_to_use + "' not found. It might be missing from your template archive."); - zipClose(dst_pkg_zip, NULL); - unzClose(src_pkg_zip); - return ERR_FILE_NOT_FOUND; } - ep.step("Making PKG", 1); - - String pack_path = EditorSettings::get_singleton()->get_settings_path() + "/tmp/" + pkg_name + ".pck"; - Error err = save_pack(p_preset, pack_path); - - if (err) { + if (dst_pkg_zip) { zipClose(dst_pkg_zip, NULL); - unzClose(src_pkg_zip); - return err; } - { - //write datapack - - zipOpenNewFileInZip(dst_pkg_zip, - (pkg_name + ".app/Contents/Resources/" + pkg_name + ".pck").utf8().get_data(), - NULL, - NULL, - 0, - NULL, - 0, - NULL, - Z_DEFLATED, - Z_DEFAULT_COMPRESSION); - - FileAccess *pf = FileAccess::open(pack_path, FileAccess::READ); - ERR_FAIL_COND_V(!pf, ERR_CANT_OPEN); - const int BSIZE = 16384; - uint8_t buf[BSIZE]; - - while (true) { - - int r = pf->get_buffer(buf, BSIZE); - if (r <= 0) - break; - zipWriteInFileInZip(dst_pkg_zip, buf, r); - } - zipCloseFileInZip(dst_pkg_zip); - memdelete(pf); - } - - zipClose(dst_pkg_zip, NULL); - unzClose(src_pkg_zip); - return OK; } -#endif bool EditorExportPlatformOSX::can_export(const Ref<EditorExportPreset> &p_preset, String &r_error, bool &r_missing_templates) const { diff --git a/platform/osx/os_osx.h b/platform/osx/os_osx.h index eb8c0566b4..05adfeb0f5 100644 --- a/platform/osx/os_osx.h +++ b/platform/osx/os_osx.h @@ -112,15 +112,16 @@ public: CrashHandler crash_handler; float _mouse_scale(float p_scale) { - if (display_scale > 1.0) + if (_display_scale() > 1.0) return p_scale; else return 1.0; } - void _update_window(); + float _display_scale() const; + float _display_scale(id screen) const; - float display_scale; + void _update_window(); protected: virtual int get_video_driver_count() const; diff --git a/platform/osx/os_osx.mm b/platform/osx/os_osx.mm index 8323aa84a8..2c81a02014 100644 --- a/platform/osx/os_osx.mm +++ b/platform/osx/os_osx.mm @@ -180,13 +180,13 @@ static bool mouse_down_control = false; if (newBackingScaleFactor != oldBackingScaleFactor) { //Set new display scale and window size - OS_OSX::singleton->display_scale = newBackingScaleFactor; + float newDisplayScale = OS_OSX::singleton->is_hidpi_allowed() ? newBackingScaleFactor : 1.0; const NSRect contentRect = [OS_OSX::singleton->window_view frame]; const NSRect fbRect = contentRect; //convertRectToBacking(contentRect); - OS_OSX::singleton->window_size.width = fbRect.size.width * OS_OSX::singleton->display_scale; - OS_OSX::singleton->window_size.height = fbRect.size.height * OS_OSX::singleton->display_scale; + OS_OSX::singleton->window_size.width = fbRect.size.width * newDisplayScale; + OS_OSX::singleton->window_size.height = fbRect.size.height * newDisplayScale; //Update context if (OS_OSX::singleton->main_loop) { @@ -206,8 +206,9 @@ static bool mouse_down_control = false; const NSRect contentRect = [OS_OSX::singleton->window_view frame]; const NSRect fbRect = contentRect; //convertRectToBacking(contentRect); - OS_OSX::singleton->window_size.width = fbRect.size.width * OS_OSX::singleton->display_scale; - OS_OSX::singleton->window_size.height = fbRect.size.height * OS_OSX::singleton->display_scale; + float displayScale = OS_OSX::singleton->_display_scale(); + OS_OSX::singleton->window_size.width = fbRect.size.width * displayScale; + OS_OSX::singleton->window_size.height = fbRect.size.height * displayScale; if (OS_OSX::singleton->main_loop) { Main::force_redraw(); @@ -352,7 +353,8 @@ static const NSRange kEmptyRange = { NSNotFound, 0 }; - (NSRect)firstRectForCharacterRange:(NSRange)aRange actualRange:(NSRangePointer)actualRange { const NSRect contentRect = [OS_OSX::singleton->window_view frame]; - NSRect pointInWindowRect = NSMakeRect(OS_OSX::singleton->im_position.x / OS_OSX::singleton->display_scale, contentRect.size.height - (OS_OSX::singleton->im_position.y / OS_OSX::singleton->display_scale) - 1, 0, 0); + float displayScale = OS_OSX::singleton->_display_scale(); + NSRect pointInWindowRect = NSMakeRect(OS_OSX::singleton->im_position.x / displayScale, contentRect.size.height - (OS_OSX::singleton->im_position.y / displayScale) - 1, 0, 0); NSPoint pointOnScreen = [[OS_OSX::singleton->window_view window] convertRectToScreen:pointInWindowRect].origin; return NSMakeRect(pointOnScreen.x, pointOnScreen.y, 0, 0); @@ -940,15 +942,6 @@ void OS_OSX::initialize(const VideoMode &p_desired, int p_video_driver, int p_au kTISNotifySelectedKeyboardInputSourceChanged, NULL, CFNotificationSuspensionBehaviorDeliverImmediately); - if (is_hidpi_allowed() && [[NSScreen mainScreen] respondsToSelector:@selector(backingScaleFactor)]) { - for (NSScreen *screen in [NSScreen screens]) { - float s = [screen backingScaleFactor]; - if (s > display_scale) { - display_scale = s; - } - } - } - window_delegate = [[GodotWindowDelegate alloc] init]; // Don't use accumulation buffer support; it's not accelerated @@ -972,10 +965,19 @@ void OS_OSX::initialize(const VideoMode &p_desired, int p_video_driver, int p_au window_view = [[GodotContentView alloc] init]; - window_size.width = p_desired.width * display_scale; - window_size.height = p_desired.height * display_scale; + float displayScale = 1.0; + if (is_hidpi_allowed()) { + // note that mainScreen is not screen #0 but the one with the keyboard focus. + NSScreen *screen = [NSScreen mainScreen]; + if ([screen respondsToSelector:@selector(backingScaleFactor)]) { + displayScale = fmax(displayScale, [screen backingScaleFactor]); + } + } + + window_size.width = p_desired.width * displayScale; + window_size.height = p_desired.height * displayScale; - if (floor(NSAppKitVersionNumber) > NSAppKitVersionNumber10_6 && display_scale > 1) { + if (floor(NSAppKitVersionNumber) > NSAppKitVersionNumber10_6 && displayScale > 1.0) { [window_view setWantsBestResolutionOpenGLSurface:YES]; //if (current_videomode.resizable) [window_object setCollectionBehavior:NSWindowCollectionBehaviorFullScreenPrimary]; @@ -1274,7 +1276,8 @@ void OS_OSX::warp_mouse_position(const Point2 &p_to) { //local point in window coords const NSRect contentRect = [window_view frame]; - NSRect pointInWindowRect = NSMakeRect(p_to.x / display_scale, contentRect.size.height - (p_to.y / display_scale) - 1, 0, 0); + float displayScale = _display_scale(); + NSRect pointInWindowRect = NSMakeRect(p_to.x / displayScale, contentRect.size.height - (p_to.y / displayScale) - 1, 0, 0); NSPoint pointOnScreen = [[window_view window] convertRectToScreen:pointInWindowRect].origin; //point in scren coords @@ -1475,17 +1478,17 @@ int OS_OSX::get_screen_count() const { return [screenArray count]; }; +static int get_screen_index(NSScreen *screen) { + const NSUInteger index = [[NSScreen screens] indexOfObject:screen]; + return index == NSNotFound ? 0 : index; +} + int OS_OSX::get_current_screen() const { - Vector2 wpos = get_window_position(); - - int count = get_screen_count(); - for (int i = 0; i < count; i++) { - Point2 pos = get_screen_position(i); - Size2 size = get_screen_size(i); - if ((wpos.x >= pos.x && wpos.x < pos.x + size.width) && (wpos.y >= pos.y && wpos.y < pos.y + size.height)) - return i; + if (window_object) { + return get_screen_index([window_object screen]); + } else { + return get_screen_index([NSScreen mainScreen]); } - return 0; }; void OS_OSX::set_current_screen(int p_screen) { @@ -1500,12 +1503,7 @@ Point2 OS_OSX::get_screen_position(int p_screen) const { NSArray *screenArray = [NSScreen screens]; if (p_screen < [screenArray count]) { - float displayScale = 1.0; - - if (display_scale > 1.0 && [[screenArray objectAtIndex:p_screen] respondsToSelector:@selector(backingScaleFactor)]) { - displayScale = [[screenArray objectAtIndex:p_screen] backingScaleFactor]; - } - + float displayScale = _display_scale([screenArray objectAtIndex:p_screen]); NSRect nsrect = [[screenArray objectAtIndex:p_screen] frame]; return Point2(nsrect.origin.x, nsrect.origin.y) * displayScale; } @@ -1520,12 +1518,7 @@ int OS_OSX::get_screen_dpi(int p_screen) const { NSArray *screenArray = [NSScreen screens]; if (p_screen < [screenArray count]) { - float displayScale = 1.0; - - if (display_scale > 1.0 && [[screenArray objectAtIndex:p_screen] respondsToSelector:@selector(backingScaleFactor)]) { - displayScale = [[screenArray objectAtIndex:p_screen] backingScaleFactor]; - } - + float displayScale = _display_scale([screenArray objectAtIndex:p_screen]); NSDictionary *description = [[screenArray objectAtIndex:p_screen] deviceDescription]; NSSize displayPixelSize = [[description objectForKey:NSDeviceSize] sizeValue]; CGSize displayPhysicalSize = CGDisplayScreenSize( @@ -1544,12 +1537,7 @@ Size2 OS_OSX::get_screen_size(int p_screen) const { NSArray *screenArray = [NSScreen screens]; if (p_screen < [screenArray count]) { - float displayScale = 1.0; - - if (display_scale > 1.0 && [[screenArray objectAtIndex:p_screen] respondsToSelector:@selector(backingScaleFactor)]) { - displayScale = [[screenArray objectAtIndex:p_screen] backingScaleFactor]; - } - + float displayScale = _display_scale([screenArray objectAtIndex:p_screen]); // Note: Use frame to get the whole screen size NSRect nsrect = [[screenArray objectAtIndex:p_screen] frame]; return Size2(nsrect.size.width, nsrect.size.height) * displayScale; @@ -1583,10 +1571,28 @@ void OS_OSX::_update_window() { } } +float OS_OSX::_display_scale() const { + if (window_object) { + return _display_scale([window_object screen]); + } else { + return _display_scale([NSScreen mainScreen]); + } +} + +float OS_OSX::_display_scale(id screen) const { + if (is_hidpi_allowed()) { + if ([screen respondsToSelector:@selector(backingScaleFactor)]) { + return fmax(1.0, [screen backingScaleFactor]); + } + } else { + return 1.0; + } +} + Point2 OS_OSX::get_window_position() const { Size2 wp([window_object frame].origin.x, [window_object frame].origin.y); - wp *= display_scale; + wp *= _display_scale(); return wp; }; @@ -1594,10 +1600,11 @@ void OS_OSX::set_window_position(const Point2 &p_position) { Size2 scr = get_screen_size(); NSPoint pos; + float displayScale = _display_scale(); - pos.x = p_position.x / display_scale; + pos.x = p_position.x / displayScale; // For OS X the y starts at the bottom - pos.y = (scr.height - p_position.y) / display_scale; + pos.y = (scr.height - p_position.y) / displayScale; [window_object setFrameTopLeftPoint:pos]; @@ -2039,7 +2046,6 @@ OS_OSX::OS_OSX() { minimized = false; window_size = Vector2(1024, 600); zoomed = false; - display_scale = 1.0; _set_logger(memnew(OSXTerminalLogger)); } diff --git a/platform/uwp/os_uwp.cpp b/platform/uwp/os_uwp.cpp index 031c714514..ff5a935229 100644 --- a/platform/uwp/os_uwp.cpp +++ b/platform/uwp/os_uwp.cpp @@ -674,7 +674,7 @@ void OSUWP::set_cursor_shape(CursorShape p_shape) { cursor_shape = p_shape; } -Error OSUWP::execute(const String &p_path, const List<String> &p_arguments, bool p_blocking, ProcessID *r_child_id, String *r_pipe, int *r_exitcode) { +Error OSUWP::execute(const String &p_path, const List<String> &p_arguments, bool p_blocking, ProcessID *r_child_id, String *r_pipe, int *r_exitcode, bool read_stderr) { return FAILED; }; diff --git a/platform/uwp/os_uwp.h b/platform/uwp/os_uwp.h index df38faa8e1..22f8938049 100644 --- a/platform/uwp/os_uwp.h +++ b/platform/uwp/os_uwp.h @@ -215,7 +215,7 @@ public: virtual void delay_usec(uint32_t p_usec) const; virtual uint64_t get_ticks_usec() const; - virtual Error execute(const String &p_path, const List<String> &p_arguments, bool p_blocking, ProcessID *r_child_id = NULL, String *r_pipe = NULL, int *r_exitcode = NULL); + virtual Error execute(const String &p_path, const List<String> &p_arguments, bool p_blocking, ProcessID *r_child_id = NULL, String *r_pipe = NULL, int *r_exitcode = NULL, bool read_stderr = false); virtual Error kill(const ProcessID &p_pid); virtual bool has_environment(const String &p_var) const; diff --git a/platform/windows/os_windows.cpp b/platform/windows/os_windows.cpp index bee8c90ad3..c27e7c0d2b 100644 --- a/platform/windows/os_windows.cpp +++ b/platform/windows/os_windows.cpp @@ -1812,7 +1812,7 @@ void OS_Windows::set_cursor_shape(CursorShape p_shape) { cursor_shape = p_shape; } -Error OS_Windows::execute(const String &p_path, const List<String> &p_arguments, bool p_blocking, ProcessID *r_child_id, String *r_pipe, int *r_exitcode) { +Error OS_Windows::execute(const String &p_path, const List<String> &p_arguments, bool p_blocking, ProcessID *r_child_id, String *r_pipe, int *r_exitcode, bool read_stderr) { if (p_blocking && r_pipe) { diff --git a/platform/windows/os_windows.h b/platform/windows/os_windows.h index 9560bc61ca..c0b8dfc691 100644 --- a/platform/windows/os_windows.h +++ b/platform/windows/os_windows.h @@ -240,7 +240,7 @@ public: virtual void delay_usec(uint32_t p_usec) const; virtual uint64_t get_ticks_usec() const; - virtual Error execute(const String &p_path, const List<String> &p_arguments, bool p_blocking, ProcessID *r_child_id = NULL, String *r_pipe = NULL, int *r_exitcode = NULL); + virtual Error execute(const String &p_path, const List<String> &p_arguments, bool p_blocking, ProcessID *r_child_id = NULL, String *r_pipe = NULL, int *r_exitcode = NULL, bool read_stderr = false); virtual Error kill(const ProcessID &p_pid); virtual int get_process_id() const; |