diff options
Diffstat (limited to 'platform')
35 files changed, 782 insertions, 721 deletions
diff --git a/platform/android/SCsub b/platform/android/SCsub index e9a370869f..7fa0262359 100644 --- a/platform/android/SCsub +++ b/platform/android/SCsub @@ -46,8 +46,18 @@ gradle_baseout = open_utf8(abspath + "/java/build.gradle", "w") gradle_text = gradle_basein.read() - +gradle_maven_flat_text = "" +if len(env.android_flat_dirs) > 0: + gradle_maven_flat_text += "flatDir {\n" + gradle_maven_flat_text += "\tdirs " + for x in env.android_flat_dirs: + gradle_maven_flat_text += "'" + x + "'," + + gradle_maven_flat_text = gradle_maven_flat_text[:-1] + gradle_maven_flat_text += "\n\t}\n" + gradle_maven_repos_text = "" +gradle_maven_repos_text += gradle_maven_flat_text if len(env.android_maven_repos) > 0: gradle_maven_repos_text += "" diff --git a/platform/android/build.gradle.template b/platform/android/build.gradle.template index 1df56ce621..7cb6cf860a 100644 --- a/platform/android/build.gradle.template +++ b/platform/android/build.gradle.template @@ -1,6 +1,7 @@ buildscript { repositories { jcenter() + $$GRADLE_REPOSITORY_URLS$$ } dependencies { classpath 'com.android.tools.build:gradle:2.3.3' @@ -54,11 +55,11 @@ android { ] res.srcDirs = [ 'res' - $$GRADLE_RES_DIRS$$ + $$GRADLE_RES_DIRS$$ ] aidl.srcDirs = [ 'aidl' - $$GRADLE_AIDL_DIRS$$ + $$GRADLE_AIDL_DIRS$$ ] assets.srcDirs = [ 'assets' 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/file_access_android.cpp b/platform/android/file_access_android.cpp index c7b0d9afcd..0fdf9002d7 100644 --- a/platform/android/file_access_android.cpp +++ b/platform/android/file_access_android.cpp @@ -146,6 +146,11 @@ Error FileAccessAndroid::get_error() const { return eof ? ERR_FILE_EOF : OK; //not sure what else it may happen } +void FileAccessAndroid::flush() { + + ERR_FAIL(); +} + void FileAccessAndroid::store_8(uint8_t p_dest) { ERR_FAIL(); diff --git a/platform/android/file_access_android.h b/platform/android/file_access_android.h index beccf494dd..c8fedbe684 100644 --- a/platform/android/file_access_android.h +++ b/platform/android/file_access_android.h @@ -63,6 +63,7 @@ public: virtual Error get_error() const; ///< get last error + virtual void flush(); virtual void store_8(uint8_t p_dest); ///< store a byte virtual bool file_exists(const String &p_path); ///< return true if a file exists diff --git a/platform/android/file_access_jandroid.cpp b/platform/android/file_access_jandroid.cpp index fe934c89fb..980afd8f46 100644 --- a/platform/android/file_access_jandroid.cpp +++ b/platform/android/file_access_jandroid.cpp @@ -157,6 +157,9 @@ Error FileAccessJAndroid::get_error() const { return OK; } +void FileAccessJAndroid::flush() { +} + void FileAccessJAndroid::store_8(uint8_t p_dest) { } diff --git a/platform/android/file_access_jandroid.h b/platform/android/file_access_jandroid.h index 75a6a21335..368d2c98fa 100644 --- a/platform/android/file_access_jandroid.h +++ b/platform/android/file_access_jandroid.h @@ -67,6 +67,7 @@ public: virtual Error get_error() const; ///< get last error + virtual void flush(); virtual void store_8(uint8_t p_dest); ///< store a byte virtual bool file_exists(const String &p_path); ///< return true if a file exists 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/src/org/godotengine/godot/input/GodotTextInputWrapper.java b/platform/android/java/src/org/godotengine/godot/input/GodotTextInputWrapper.java index 04669a3b0c..ac424ab9f8 100644 --- a/platform/android/java/src/org/godotengine/godot/input/GodotTextInputWrapper.java +++ b/platform/android/java/src/org/godotengine/godot/input/GodotTextInputWrapper.java @@ -88,79 +88,48 @@ public class GodotTextInputWrapper implements TextWatcher, OnEditorActionListene public void beforeTextChanged(final CharSequence pCharSequence, final int start, final int count, final int after) { //Log.d(TAG, "beforeTextChanged(" + pCharSequence + ")start: " + start + ",count: " + count + ",after: " + after); - for (int i=0;i<count;i++){ - mView.queueEvent(new Runnable() { - @Override - public void run() { + mView.queueEvent(new Runnable() { + @Override + public void run() { + for (int i = 0; i < count; ++i) { GodotLib.key(KeyEvent.KEYCODE_DEL, 0, true); GodotLib.key(KeyEvent.KEYCODE_DEL, 0, false); } - }); - } + } + }); } @Override public void onTextChanged(final CharSequence pCharSequence, final int start, final int before, final int count) { //Log.d(TAG, "onTextChanged(" + pCharSequence + ")start: " + start + ",count: " + count + ",before: " + before); - for (int i=start;i<start+count;i++){ - final int ch = pCharSequence.charAt(i); - mView.queueEvent(new Runnable() { - @Override - public void run() { + mView.queueEvent(new Runnable() { + @Override + public void run() { + for (int i = start; i < start + count; ++i) { + final int ch = pCharSequence.charAt(i); GodotLib.key(0, ch, true); GodotLib.key(0, ch, false); } - }); - } - + } + }); } @Override public boolean onEditorAction(final TextView pTextView, final int pActionID, final KeyEvent pKeyEvent) { if (this.mEdit == pTextView && this.isFullScreenEdit()) { - // user press the action button, delete all old text and insert new text - for (int i = this.mOriginText.length(); i > 0; i--) { - mView.queueEvent(new Runnable() { - @Override - public void run() { - GodotLib.key(KeyEvent.KEYCODE_DEL, 0, true); - GodotLib.key(KeyEvent.KEYCODE_DEL, 0, false); - } - }); + final String characters = pKeyEvent.getCharacters(); - /* - if (BuildConfig.DEBUG) { - Log.d(TAG, "deleteBackward"); - } - */ - } - String text = pTextView.getText().toString(); - - /* If user input nothing, translate "\n" to engine. */ - if (text.compareTo("") == 0) { - text = "\n"; - } - - if ('\n' != text.charAt(text.length() - 1)) { - text += '\n'; - } - - for(int i = 0; i < text.length(); i++) { - final int ch = text.codePointAt(i); - mView.queueEvent(new Runnable() { - @Override - public void run() { + mView.queueEvent(new Runnable() { + @Override + public void run() { + for (int i = 0; i < characters.length(); i++) { + final int ch = characters.codePointAt(i); GodotLib.key(0, ch, true); GodotLib.key(0, ch, false); } - }); - } - /* - if (BuildConfig.DEBUG) { - Log.d(TAG, "insertText(" + insertText + ")"); - } - */ + } + }); } if (pActionID == EditorInfo.IME_ACTION_DONE) { diff --git a/platform/android/java_glue.cpp b/platform/android/java_glue.cpp index 509d1bf123..0b193f5882 100644 --- a/platform/android/java_glue.cpp +++ b/platform/android/java_glue.cpp @@ -602,21 +602,10 @@ struct TST { TST tst; -struct JAndroidPointerEvent { - - Vector<OS_Android::TouchPos> points; - int pointer; - int what; -}; - -static List<JAndroidPointerEvent> pointer_events; -static List<Ref<InputEvent> > key_events; -static List<OS_Android::JoypadEvent> joy_events; static bool initialized = false; static int step = 0; static bool resized = false; static bool resized_reload = false; -static bool go_back_request = false; static Size2 new_size; static Vector3 accelerometer; static Vector3 magnetometer; @@ -624,8 +613,6 @@ static Vector3 gyroscope; static HashMap<String, JNISingleton *> jni_singletons; static jobject godot_io; -static Vector<int> joy_device_ids; - typedef void (*GFXInitFunc)(void *ud, bool gl2); static jmethodID _on_video_init = 0; @@ -754,6 +741,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 +823,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 +840,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; } @@ -986,7 +985,7 @@ JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_newcontext(JNIEnv *en } JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_back(JNIEnv *env, jobject obj) { - go_back_request = true; + os_android->main_loop_request_go_back(); } JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_step(JNIEnv *env, jobject obj) { @@ -1011,36 +1010,6 @@ JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_step(JNIEnv *env, job //__android_log_print(ANDROID_LOG_INFO,"godot","**STEP EVENT! - %p-%i\n",env,Thread::get_caller_id()); - while (pointer_events.size()) { - - JAndroidPointerEvent jpe = pointer_events.front()->get(); - os_android->process_touch(jpe.what, jpe.pointer, jpe.points); - - pointer_events.pop_front(); - } - - while (key_events.size()) { - - Ref<InputEvent> event = key_events.front()->get(); - os_android->process_event(event); - - key_events.pop_front(); - }; - - while (joy_events.size()) { - - OS_Android::JoypadEvent event = joy_events.front()->get(); - os_android->process_joy_event(event); - - joy_events.pop_front(); - } - - if (go_back_request) { - - os_android->main_loop_request_go_back(); - go_back_request = false; - } - os_android->process_accelerometer(accelerometer); os_android->process_magnetometer(magnetometer); @@ -1071,12 +1040,8 @@ JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_touch(JNIEnv *env, jo points.push_back(tp); } - JAndroidPointerEvent jpe; - jpe.pointer = pointer; - jpe.points = points; - jpe.what = ev; + os_android->process_touch(ev, pointer, points); - pointer_events.push_back(jpe); /* if (os_android) os_android->process_touch(ev,pointer,points); @@ -1346,7 +1311,7 @@ JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_joybutton(JNIEnv *env jevent.index = p_button; jevent.pressed = p_pressed; - joy_events.push_back(jevent); + os_android->process_joy_event(jevent); } JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_joyaxis(JNIEnv *env, jobject obj, jint p_device, jint p_axis, jfloat p_value) { @@ -1357,7 +1322,7 @@ JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_joyaxis(JNIEnv *env, jevent.index = p_axis; jevent.value = p_value; - joy_events.push_back(jevent); + os_android->process_joy_event(jevent); } JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_joyhat(JNIEnv *env, jobject obj, jint p_device, jint p_hat_x, jint p_hat_y) { @@ -1378,7 +1343,8 @@ JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_joyhat(JNIEnv *env, j hat |= InputDefault::HAT_MASK_DOWN; } jevent.hat = hat; - joy_events.push_back(jevent); + + os_android->process_joy_event(jevent); } JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_joyconnectionchanged(JNIEnv *env, jobject obj, jint p_device, jboolean p_connected, jstring p_name) { @@ -1391,6 +1357,7 @@ JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_joyconnectionchanged( JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_key(JNIEnv *env, jobject obj, jint p_scancode, jint p_unicode_char, jboolean p_pressed) { Ref<InputEventKey> ievent; + ievent.instance(); int val = p_unicode_char; int scancode = android_get_keysym(p_scancode); ievent->set_scancode(scancode); @@ -1409,10 +1376,10 @@ JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_key(JNIEnv *env, jobj ievent->set_unicode(KEY_ENTER); } else if (p_scancode == 4) { - go_back_request = true; + os_android->main_loop_request_go_back(); } - key_events.push_back(ievent); + os_android->process_event(ievent); } JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_accelerometer(JNIEnv *env, jobject obj, jfloat x, jfloat y, jfloat z) { 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 dbea2d7531..473a093077 100644 --- a/platform/android/os_android.cpp +++ b/platform/android/os_android.cpp @@ -47,6 +47,15 @@ #include "file_access_jandroid.h" #endif +class AndroidLogger : public Logger { +public: + virtual void logv(const char *p_format, va_list p_list, bool p_err) { + __android_log_vprint(p_err ? ANDROID_LOG_ERROR : ANDROID_LOG_INFO, "godot", p_format, p_list); + } + + virtual ~AndroidLogger() {} +}; + int OS_Android::get_video_driver_count() const { return 1; @@ -111,6 +120,13 @@ void OS_Android::initialize_core() { #endif } +void OS_Android::initialize_logger() { + Vector<Logger *> loggers; + loggers.push_back(memnew(AndroidLogger)); + loggers.push_back(memnew(RotatedFileLogger("user://logs/log.txt"))); + _set_logger(memnew(CompositeLogger(loggers))); +} + void OS_Android::set_opengl_extensions(const char *p_gl_extensions) { ERR_FAIL_COND(!p_gl_extensions); @@ -162,23 +178,9 @@ void OS_Android::delete_main_loop() { } void OS_Android::finalize() { - memdelete(input); } -void OS_Android::vprint(const char *p_format, va_list p_list, bool p_stderr) { - - __android_log_vprint(p_stderr ? ANDROID_LOG_ERROR : ANDROID_LOG_INFO, "godot", p_format, p_list); -} - -void OS_Android::print(const char *p_format, ...) { - - va_list argp; - va_start(argp, p_format); - __android_log_vprint(ANDROID_LOG_INFO, "godot", p_format, argp); - va_end(argp); -} - void OS_Android::alert(const String &p_alert, const String &p_title) { //print("ALERT: %s\n", p_alert.utf8().get_data()); @@ -517,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) { @@ -702,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; @@ -732,11 +743,14 @@ 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; alert_func = p_alert_func; use_reload_hooks = false; + + _set_logger(memnew(AndroidLogger)); } OS_Android::~OS_Android() { diff --git a/platform/android/os_android.h b/platform/android/os_android.h index 119c14bff3..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; @@ -149,6 +151,7 @@ public: virtual int get_audio_driver_count() const; virtual const char *get_audio_driver_name(int p_driver) const; + virtual void initialize_logger(); virtual void initialize_core(); virtual void initialize(const VideoMode &p_desired, int p_video_driver, int p_audio_driver); @@ -161,8 +164,6 @@ public: static OS *get_singleton(); - virtual void vprint(const char *p_format, va_list p_list, bool p_stderr = false); - virtual void print(const char *p_format, ...); virtual void alert(const String &p_alert, const String &p_title = "ALERT!"); virtual void set_mouse_show(bool p_show); @@ -202,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); @@ -241,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/game_center.mm b/platform/iphone/game_center.mm index 821ef2a3ab..3955b9f0aa 100644 --- a/platform/iphone/game_center.mm +++ b/platform/iphone/game_center.mm @@ -89,7 +89,7 @@ Error GameCenter::connect() { ret["type"] = "authentication"; if (player.isAuthenticated) { ret["result"] = "ok"; - ret["player_id"] = player.playerID; + ret["player_id"] = [player.playerID UTF8String]; GameCenter::get_singleton()->connected = true; } else { ret["result"] = "error"; 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 086cbe5010..08792b8631 100644 --- a/platform/iphone/os_iphone.cpp +++ b/platform/iphone/os_iphone.cpp @@ -41,6 +41,7 @@ #include "core/os/dir_access.h" #include "core/os/file_access.h" #include "core/project_settings.h" +#include "drivers/unix/syslog_logger.h" #include "sem_iphone.h" @@ -96,8 +97,17 @@ void OSIPhone::initialize_core() { OS_Unix::initialize_core(); SemaphoreIphone::make_default(); + + set_data_dir(data_dir); }; +void OSIPhone::initialize_logger() { + Vector<Logger *> loggers; + loggers.push_back(memnew(SyslogLogger)); + loggers.push_back(memnew(RotatedFileLogger("user://logs/log.txt"))); + _set_logger(memnew(CompositeLogger(loggers))); +} + void OSIPhone::initialize(const VideoMode &p_desired, int p_video_driver, int p_audio_driver) { supported_orientations = 0; @@ -455,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); }; @@ -556,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; @@ -568,6 +586,13 @@ 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)); }; OSIPhone::~OSIPhone() { diff --git a/platform/iphone/os_iphone.h b/platform/iphone/os_iphone.h index 3ebd5a74db..e70ac9ba98 100644 --- a/platform/iphone/os_iphone.h +++ b/platform/iphone/os_iphone.h @@ -90,6 +90,7 @@ private: virtual VideoMode get_default_video_mode() const; + virtual void initialize_logger(); virtual void initialize_core(); virtual void initialize(const VideoMode &p_desired, int p_video_driver, int p_audio_driver); @@ -123,6 +124,8 @@ private: InputDefault *input; + int virtual_keyboard_height; + public: bool iterate(); @@ -132,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); @@ -167,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); @@ -196,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 f103035b27..f6446e77da 100644 --- a/platform/javascript/os_javascript.cpp +++ b/platform/javascript/os_javascript.cpp @@ -85,6 +85,10 @@ void OS_JavaScript::initialize_core() { FileAccess::make_default<FileAccessBufferedFA<FileAccessUnix> >(FileAccess::ACCESS_RESOURCES); } +void OS_JavaScript::initialize_logger() { + _set_logger(memnew(StdLogger)); +} + void OS_JavaScript::set_opengl_extensions(const char *p_gl_extensions) { ERR_FAIL_COND(!p_gl_extensions); @@ -821,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; @@ -911,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 } } @@ -989,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; @@ -1000,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 4c6469cb58..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; @@ -92,6 +93,7 @@ public: virtual int get_audio_driver_count() const; virtual const char *get_audio_driver_name(int p_driver) const; + virtual void initialize_logger(); virtual void initialize_core(); virtual void initialize(const VideoMode &p_desired, int p_video_driver, int p_audio_driver); @@ -104,11 +106,6 @@ public: //static OS* get_singleton(); - virtual void print_error(const char *p_function, const char *p_file, int p_line, const char *p_code, const char *p_rationale, ErrorType p_type) { - - OS::print_error(p_function, p_file, p_line, p_code, p_rationale, p_type); - } - virtual void alert(const String &p_alert, const String &p_title = "ALERT!"); virtual void set_mouse_mode(MouseMode p_mode); @@ -140,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(); @@ -171,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 2662e40561..05adfeb0f5 100644 --- a/platform/osx/os_osx.h +++ b/platform/osx/os_osx.h @@ -112,21 +112,23 @@ 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; virtual const char *get_video_driver_name(int p_driver) const; virtual VideoMode get_default_video_mode() const; + virtual void initialize_logger(); virtual void initialize_core(); virtual void initialize(const VideoMode &p_desired, int p_video_driver, int p_audio_driver); virtual void finalize(); @@ -141,8 +143,6 @@ public: virtual String get_name(); - virtual void print_error(const char *p_function, const char *p_file, int p_line, const char *p_code, const char *p_rationale, ErrorType p_type = ERR_ERROR); - virtual void alert(const String &p_alert, const String &p_title = "ALERT!"); virtual void set_cursor_shape(CursorShape p_shape); diff --git a/platform/osx/os_osx.mm b/platform/osx/os_osx.mm index 6502001100..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]; @@ -1145,43 +1147,67 @@ String OS_OSX::get_name() { return "OSX"; } -void OS_OSX::print_error(const char *p_function, const char *p_file, int p_line, const char *p_code, const char *p_rationale, ErrorType p_type) { - #if MAC_OS_X_VERSION_MAX_ALLOWED >= 101200 - if (!_print_error_enabled) - return; - - const char *err_details; - if (p_rationale && p_rationale[0]) - err_details = p_rationale; - else - err_details = p_code; +class OSXTerminalLogger : public StdLogger { +public: + virtual void log_error(const char *p_function, const char *p_file, int p_line, const char *p_code, const char *p_rationale, ErrorType p_type = ERR_ERROR) { + if (!should_log(true)) { + return; + } - switch (p_type) { - case ERR_ERROR: - os_log_error(OS_LOG_DEFAULT, "ERROR: %{public}s: %{public}s\nAt: %{public}s:%i.", p_function, err_details, p_file, p_line); - print("\E[1;31mERROR: %s: \E[0m\E[1m%s\n", p_function, err_details); - print("\E[0;31m At: %s:%i.\E[0m\n", p_file, p_line); - break; - case ERR_WARNING: - os_log_info(OS_LOG_DEFAULT, "WARNING: %{public}s: %{public}s\nAt: %{public}s:%i.", p_function, err_details, p_file, p_line); - print("\E[1;33mWARNING: %s: \E[0m\E[1m%s\n", p_function, err_details); - print("\E[0;33m At: %s:%i.\E[0m\n", p_file, p_line); - break; - case ERR_SCRIPT: - os_log_error(OS_LOG_DEFAULT, "SCRIPT ERROR: %{public}s: %{public}s\nAt: %{public}s:%i.", p_function, err_details, p_file, p_line); - print("\E[1;35mSCRIPT ERROR: %s: \E[0m\E[1m%s\n", p_function, err_details); - print("\E[0;35m At: %s:%i.\E[0m\n", p_file, p_line); - break; - case ERR_SHADER: - os_log_error(OS_LOG_DEFAULT, "SHADER ERROR: %{public}s: %{public}s\nAt: %{public}s:%i.", p_function, err_details, p_file, p_line); - print("\E[1;36mSHADER ERROR: %s: \E[0m\E[1m%s\n", p_function, err_details); - print("\E[0;36m At: %s:%i.\E[0m\n", p_file, p_line); - break; + const char *err_details; + if (p_rationale && p_rationale[0]) + err_details = p_rationale; + else + err_details = p_code; + + switch (p_type) { + case ERR_WARNING: + os_log_info(OS_LOG_DEFAULT, + "WARNING: %{public}s: %{public}s\nAt: %{public}s:%i.", + p_function, err_details, p_file, p_line); + logf_error("\E[1;33mWARNING: %s: \E[0m\E[1m%s\n", p_function, + err_details); + logf_error("\E[0;33m At: %s:%i.\E[0m\n", p_file, p_line); + break; + case ERR_SCRIPT: + os_log_error(OS_LOG_DEFAULT, + "SCRIPT ERROR: %{public}s: %{public}s\nAt: %{public}s:%i.", + p_function, err_details, p_file, p_line); + logf_error("\E[1;35mSCRIPT ERROR: %s: \E[0m\E[1m%s\n", p_function, + err_details); + logf_error("\E[0;35m At: %s:%i.\E[0m\n", p_file, p_line); + break; + case ERR_SHADER: + os_log_error(OS_LOG_DEFAULT, + "SHADER ERROR: %{public}s: %{public}s\nAt: %{public}s:%i.", + p_function, err_details, p_file, p_line); + logf_error("\E[1;36mSHADER ERROR: %s: \E[0m\E[1m%s\n", p_function, + err_details); + logf_error("\E[0;36m At: %s:%i.\E[0m\n", p_file, p_line); + break; + case ERR_ERROR: + default: + os_log_error(OS_LOG_DEFAULT, + "ERROR: %{public}s: %{public}s\nAt: %{public}s:%i.", + p_function, err_details, p_file, p_line); + logf_error("\E[1;31mERROR: %s: \E[0m\E[1m%s\n", p_function, err_details); + logf_error("\E[0;31m At: %s:%i.\E[0m\n", p_file, p_line); + break; + } } +}; + #else - OS_Unix::print_error(p_function, p_file, p_line, p_code, p_rationale, p_type); + +typedef UnixTerminalLogger OSXTerminalLogger; #endif + +void OS_OSX::initialize_logger() { + Vector<Logger *> loggers; + loggers.push_back(memnew(OSXTerminalLogger)); + loggers.push_back(memnew(RotatedFileLogger("user://logs/log.txt"))); + _set_logger(memnew(CompositeLogger(loggers))); } void OS_OSX::alert(const String &p_alert, const String &p_title) { @@ -1250,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 @@ -1451,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) { @@ -1476,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; } @@ -1496,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( @@ -1520,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; @@ -1559,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; }; @@ -1570,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]; @@ -2015,7 +2046,8 @@ OS_OSX::OS_OSX() { minimized = false; window_size = Vector2(1024, 600); zoomed = false; - display_scale = 1.0; + + _set_logger(memnew(OSXTerminalLogger)); } bool OS_OSX::_check_internal_feature_support(const String &p_feature) { diff --git a/platform/uwp/os_uwp.cpp b/platform/uwp/os_uwp.cpp index b909ccccd6..ff5a935229 100644 --- a/platform/uwp/os_uwp.cpp +++ b/platform/uwp/os_uwp.cpp @@ -40,6 +40,7 @@ #include "platform/windows/packet_peer_udp_winsock.h" #include "platform/windows/stream_peer_winsock.h" #include "platform/windows/tcp_server_winsock.h" +#include "platform/windows/windows_terminal_logger.h" #include "project_settings.h" #include "servers/audio_server.h" #include "servers/visual/visual_server_raster.h" @@ -182,6 +183,13 @@ void OSUWP::initialize_core() { cursor_shape = CURSOR_ARROW; } +void OSUWP::initialize_logger() { + Vector<Logger *> loggers; + loggers.push_back(memnew(WindowsTerminalLogger)); + loggers.push_back(memnew(RotatedFileLogger("user://logs/log.txt"))); + _set_logger(memnew(CompositeLogger(loggers))); +} + bool OSUWP::can_draw() const { return !minimized; @@ -371,32 +379,6 @@ void OSUWP::finalize() { void OSUWP::finalize_core() { } -void OSUWP::vprint(const char *p_format, va_list p_list, bool p_stderr) { - - char buf[16384 + 1]; - int len = vsnprintf(buf, 16384, p_format, p_list); - if (len <= 0) - return; - buf[len] = 0; - - int wlen = MultiByteToWideChar(CP_UTF8, 0, buf, len, NULL, 0); - if (wlen < 0) - return; - - wchar_t *wbuf = (wchar_t *)malloc((len + 1) * sizeof(wchar_t)); - MultiByteToWideChar(CP_UTF8, 0, buf, len, wbuf, wlen); - wbuf[wlen] = 0; - - if (p_stderr) - fwprintf(stderr, L"%s", wbuf); - else - wprintf(L"%s", wbuf); - - free(wbuf); - - fflush(stdout); -}; - void OSUWP::alert(const String &p_alert, const String &p_title) { Platform::String ^ alert = ref new Platform::String(p_alert.c_str()); @@ -520,30 +502,6 @@ OS::VideoMode OSUWP::get_video_mode(int p_screen) const { void OSUWP::get_fullscreen_mode_list(List<VideoMode> *p_list, int p_screen) const { } -void OSUWP::print_error(const char *p_function, const char *p_file, int p_line, const char *p_code, const char *p_rationale, ErrorType p_type) { - - const char *err_details; - if (p_rationale && p_rationale[0]) - err_details = p_rationale; - else - err_details = p_code; - - switch (p_type) { - case ERR_ERROR: - print("ERROR: %s: %s\n", p_function, err_details); - print(" At: %s:%i\n", p_file, p_line); - break; - case ERR_WARNING: - print("WARNING: %s: %s\n", p_function, err_details); - print(" At: %s:%i\n", p_file, p_line); - break; - case ERR_SCRIPT: - print("SCRIPT ERROR: %s: %s\n", p_function, err_details); - print(" At: %s:%i\n", p_file, p_line); - break; - } -} - String OSUWP::get_name() { return "UWP"; @@ -716,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; }; @@ -890,6 +848,8 @@ OSUWP::OSUWP() { mouse_mode_changed = CreateEvent(NULL, TRUE, FALSE, L"os_mouse_mode_changed"); AudioDriverManager::add_driver(&audio_driver); + + _set_logger(memnew(WindowsTerminalLogger)); } OSUWP::~OSUWP() { diff --git a/platform/uwp/os_uwp.h b/platform/uwp/os_uwp.h index a7a5d32cb9..22f8938049 100644 --- a/platform/uwp/os_uwp.h +++ b/platform/uwp/os_uwp.h @@ -163,6 +163,7 @@ protected: virtual int get_audio_driver_count() const; virtual const char *get_audio_driver_name(int p_driver) const; + virtual void initialize_logger(); virtual void initialize_core(); virtual void initialize(const VideoMode &p_desired, int p_video_driver, int p_audio_driver); @@ -180,9 +181,6 @@ public: // Event to send to the app wrapper HANDLE mouse_mode_changed; - void print_error(const char *p_function, const char *p_file, int p_line, const char *p_code, const char *p_rationale, ErrorType p_type); - - virtual void vprint(const char *p_format, va_list p_list, bool p_stderr = false); virtual void alert(const String &p_alert, const String &p_title = "ALERT!"); String get_stdin_string(bool p_block); @@ -217,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/SCsub b/platform/windows/SCsub index d3c160f052..aa9eb3e69b 100644 --- a/platform/windows/SCsub +++ b/platform/windows/SCsub @@ -19,6 +19,7 @@ common_win = [ "stream_peer_winsock.cpp", "joypad.cpp", "power_windows.cpp", + "windows_terminal_logger.cpp" ] restarget = "godot_res" + env["OBJSUFFIX"] diff --git a/platform/windows/os_windows.cpp b/platform/windows/os_windows.cpp index d715c51a71..c27e7c0d2b 100644 --- a/platform/windows/os_windows.cpp +++ b/platform/windows/os_windows.cpp @@ -48,6 +48,7 @@ #include "servers/visual/visual_server_wrap_mt.h" #include "stream_peer_winsock.h" #include "tcp_server_winsock.h" +#include "windows_terminal_logger.h" #include <process.h> #include <regstr.h> @@ -205,6 +206,13 @@ void OS_Windows::initialize_core() { cursor_shape = CURSOR_ARROW; } +void OS_Windows::initialize_logger() { + Vector<Logger *> loggers; + loggers.push_back(memnew(WindowsTerminalLogger)); + loggers.push_back(memnew(RotatedFileLogger("user://logs/log.txt"))); + _set_logger(memnew(CompositeLogger(loggers))); +} + bool OS_Windows::can_draw() const { return !minimized; @@ -1231,38 +1239,6 @@ void OS_Windows::finalize_core() { StreamPeerWinsock::cleanup(); } -void OS_Windows::vprint(const char *p_format, va_list p_list, bool p_stderr) { - - const unsigned int BUFFER_SIZE = 16384; - char buf[BUFFER_SIZE + 1]; // +1 for the terminating character - int len = vsnprintf(buf, BUFFER_SIZE, p_format, p_list); - if (len <= 0) - return; - if (len >= BUFFER_SIZE) - len = BUFFER_SIZE; // Output is too big, will be truncated - buf[len] = 0; - - int wlen = MultiByteToWideChar(CP_UTF8, 0, buf, len, NULL, 0); - if (wlen < 0) - return; - - wchar_t *wbuf = (wchar_t *)malloc((len + 1) * sizeof(wchar_t)); - MultiByteToWideChar(CP_UTF8, 0, buf, len, wbuf, wlen); - wbuf[wlen] = 0; - - if (p_stderr) - fwprintf(stderr, L"%ls", wbuf); - else - wprintf(L"%ls", wbuf); - -#ifdef STDOUT_FILE -//vwfprintf(stdo,p_format,p_list); -#endif - free(wbuf); - - fflush(stdout); -}; - void OS_Windows::alert(const String &p_alert, const String &p_title) { if (!is_no_window_mode_enabled()) @@ -1676,107 +1652,6 @@ void OS_Windows::request_attention() { FlashWindowEx(&info); } -void OS_Windows::print_error(const char *p_function, const char *p_file, int p_line, const char *p_code, const char *p_rationale, ErrorType p_type) { - - HANDLE hCon = GetStdHandle(STD_OUTPUT_HANDLE); - if (!hCon || hCon == INVALID_HANDLE_VALUE) { - - const char *err_details; - if (p_rationale && p_rationale[0]) - err_details = p_rationale; - else - err_details = p_code; - - switch (p_type) { - case ERR_ERROR: - print("ERROR: %s: %s\n", p_function, err_details); - print(" At: %s:%i\n", p_file, p_line); - break; - case ERR_WARNING: - print("WARNING: %s: %s\n", p_function, err_details); - print(" At: %s:%i\n", p_file, p_line); - break; - case ERR_SCRIPT: - print("SCRIPT ERROR: %s: %s\n", p_function, err_details); - print(" At: %s:%i\n", p_file, p_line); - break; - case ERR_SHADER: - print("SHADER ERROR: %s: %s\n", p_function, err_details); - print(" At: %s:%i\n", p_file, p_line); - break; - } - - } else { - - CONSOLE_SCREEN_BUFFER_INFO sbi; //original - GetConsoleScreenBufferInfo(hCon, &sbi); - - WORD current_fg = sbi.wAttributes & (FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE | FOREGROUND_INTENSITY); - WORD current_bg = sbi.wAttributes & (BACKGROUND_RED | BACKGROUND_GREEN | BACKGROUND_BLUE | BACKGROUND_INTENSITY); - - uint32_t basecol = 0; - switch (p_type) { - case ERR_ERROR: basecol = FOREGROUND_RED; break; - case ERR_WARNING: basecol = FOREGROUND_RED | FOREGROUND_GREEN; break; - case ERR_SCRIPT: basecol = FOREGROUND_RED | FOREGROUND_BLUE; break; - case ERR_SHADER: basecol = FOREGROUND_GREEN | FOREGROUND_BLUE; break; - } - - basecol |= current_bg; - - if (p_rationale && p_rationale[0]) { - - SetConsoleTextAttribute(hCon, basecol | FOREGROUND_INTENSITY); - switch (p_type) { - case ERR_ERROR: print("ERROR: "); break; - case ERR_WARNING: print("WARNING: "); break; - case ERR_SCRIPT: print("SCRIPT ERROR: "); break; - case ERR_SHADER: print("SHADER ERROR: "); break; - } - - SetConsoleTextAttribute(hCon, current_fg | current_bg | FOREGROUND_INTENSITY); - print("%s\n", p_rationale); - - SetConsoleTextAttribute(hCon, basecol); - switch (p_type) { - case ERR_ERROR: print(" At: "); break; - case ERR_WARNING: print(" At: "); break; - case ERR_SCRIPT: print(" At: "); break; - case ERR_SHADER: print(" At: "); break; - } - - SetConsoleTextAttribute(hCon, current_fg | current_bg); - print("%s:%i\n", p_file, p_line); - - } else { - - SetConsoleTextAttribute(hCon, basecol | FOREGROUND_INTENSITY); - switch (p_type) { - case ERR_ERROR: print("ERROR: %s: ", p_function); break; - case ERR_WARNING: print("WARNING: %s: ", p_function); break; - case ERR_SCRIPT: print("SCRIPT ERROR: %s: ", p_function); break; - case ERR_SHADER: print("SCRIPT ERROR: %s: ", p_function); break; - } - - SetConsoleTextAttribute(hCon, current_fg | current_bg | FOREGROUND_INTENSITY); - print("%s\n", p_code); - - SetConsoleTextAttribute(hCon, basecol); - switch (p_type) { - case ERR_ERROR: print(" At: "); break; - case ERR_WARNING: print(" At: "); break; - case ERR_SCRIPT: print(" At: "); break; - case ERR_SHADER: print(" At: "); break; - } - - SetConsoleTextAttribute(hCon, current_fg | current_bg); - print("%s:%i\n", p_file, p_line); - } - - SetConsoleTextAttribute(hCon, sbi.wAttributes); - } -} - String OS_Windows::get_name() { return "Windows"; @@ -1937,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) { @@ -2429,6 +2304,8 @@ OS_Windows::OS_Windows(HINSTANCE _hInstance) { #ifdef XAUDIO2_ENABLED AudioDriverManager::add_driver(&driver_xaudio2); #endif + + _set_logger(memnew(WindowsTerminalLogger)); } OS_Windows::~OS_Windows() { diff --git a/platform/windows/os_windows.h b/platform/windows/os_windows.h index bc1dc318cb..c0b8dfc691 100644 --- a/platform/windows/os_windows.h +++ b/platform/windows/os_windows.h @@ -152,6 +152,7 @@ protected: virtual int get_audio_driver_count() const; virtual const char *get_audio_driver_name(int p_driver) const; + virtual void initialize_logger(); virtual void initialize_core(); virtual void initialize(const VideoMode &p_desired, int p_video_driver, int p_audio_driver); @@ -180,9 +181,6 @@ protected: public: LRESULT WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam); - void print_error(const char *p_function, const char *p_file, int p_line, const char *p_code, const char *p_rationale, ErrorType p_type); - - virtual void vprint(const char *p_format, va_list p_list, bool p_stderr = false); virtual void alert(const String &p_alert, const String &p_title = "ALERT!"); String get_stdin_string(bool p_block); @@ -242,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; diff --git a/platform/windows/windows_terminal_logger.cpp b/platform/windows/windows_terminal_logger.cpp new file mode 100644 index 0000000000..ef8140ffa7 --- /dev/null +++ b/platform/windows/windows_terminal_logger.cpp @@ -0,0 +1,157 @@ +/*************************************************************************/ +/* windows_terminal_logger.cpp */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ + +#include "windows_terminal_logger.h" + +#ifdef WINDOWS_ENABLED + +#include <stdio.h> +#include <windows.h> + +void WindowsTerminalLogger::logv(const char *p_format, va_list p_list, bool p_err) { + if (!should_log(p_err)) { + return; + } + + const unsigned int BUFFER_SIZE = 16384; + char buf[BUFFER_SIZE + 1]; // +1 for the terminating character + int len = vsnprintf(buf, BUFFER_SIZE, p_format, p_list); + if (len <= 0) + return; + if (len >= BUFFER_SIZE) + len = BUFFER_SIZE; // Output is too big, will be truncated + buf[len] = 0; + + int wlen = MultiByteToWideChar(CP_UTF8, 0, buf, len, NULL, 0); + if (wlen < 0) + return; + + wchar_t *wbuf = (wchar_t *)malloc((len + 1) * sizeof(wchar_t)); + MultiByteToWideChar(CP_UTF8, 0, buf, len, wbuf, wlen); + wbuf[wlen] = 0; + + if (p_err) + fwprintf(stderr, L"%ls", wbuf); + else + wprintf(L"%ls", wbuf); + + free(wbuf); + +#ifdef DEBUG_ENABLED + fflush(stdout); +#endif +} + +void WindowsTerminalLogger::log_error(const char *p_function, const char *p_file, int p_line, const char *p_code, const char *p_rationale, ErrorType p_type) { + if (!should_log(true)) { + return; + } + +#ifndef UWP_ENABLED + HANDLE hCon = GetStdHandle(STD_OUTPUT_HANDLE); + if (!hCon || hCon == INVALID_HANDLE_VALUE) { +#endif + StdLogger::log_error(p_function, p_file, p_line, p_code, p_rationale, p_type); +#ifndef UWP_ENABLED + } else { + + CONSOLE_SCREEN_BUFFER_INFO sbi; //original + GetConsoleScreenBufferInfo(hCon, &sbi); + + WORD current_fg = sbi.wAttributes & (FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE | FOREGROUND_INTENSITY); + WORD current_bg = sbi.wAttributes & (BACKGROUND_RED | BACKGROUND_GREEN | BACKGROUND_BLUE | BACKGROUND_INTENSITY); + + uint32_t basecol = 0; + switch (p_type) { + case ERR_ERROR: basecol = FOREGROUND_RED; break; + case ERR_WARNING: basecol = FOREGROUND_RED | FOREGROUND_GREEN; break; + case ERR_SCRIPT: basecol = FOREGROUND_RED | FOREGROUND_BLUE; break; + case ERR_SHADER: basecol = FOREGROUND_GREEN | FOREGROUND_BLUE; break; + } + + basecol |= current_bg; + + if (p_rationale && p_rationale[0]) { + + SetConsoleTextAttribute(hCon, basecol | FOREGROUND_INTENSITY); + switch (p_type) { + case ERR_ERROR: logf("ERROR: "); break; + case ERR_WARNING: logf("WARNING: "); break; + case ERR_SCRIPT: logf("SCRIPT ERROR: "); break; + case ERR_SHADER: logf("SHADER ERROR: "); break; + } + + SetConsoleTextAttribute(hCon, current_fg | current_bg | FOREGROUND_INTENSITY); + logf("%s\n", p_rationale); + + SetConsoleTextAttribute(hCon, basecol); + switch (p_type) { + case ERR_ERROR: logf(" At: "); break; + case ERR_WARNING: logf(" At: "); break; + case ERR_SCRIPT: logf(" At: "); break; + case ERR_SHADER: logf(" At: "); break; + } + + SetConsoleTextAttribute(hCon, current_fg | current_bg); + logf("%s:%i\n", p_file, p_line); + + } else { + + SetConsoleTextAttribute(hCon, basecol | FOREGROUND_INTENSITY); + switch (p_type) { + case ERR_ERROR: logf("ERROR: %s: ", p_function); break; + case ERR_WARNING: logf("WARNING: %s: ", p_function); break; + case ERR_SCRIPT: logf("SCRIPT ERROR: %s: ", p_function); break; + case ERR_SHADER: logf("SCRIPT ERROR: %s: ", p_function); break; + } + + SetConsoleTextAttribute(hCon, current_fg | current_bg | FOREGROUND_INTENSITY); + logf("%s\n", p_code); + + SetConsoleTextAttribute(hCon, basecol); + switch (p_type) { + case ERR_ERROR: logf(" At: "); break; + case ERR_WARNING: logf(" At: "); break; + case ERR_SCRIPT: logf(" At: "); break; + case ERR_SHADER: logf(" At: "); break; + } + + SetConsoleTextAttribute(hCon, current_fg | current_bg); + logf("%s:%i\n", p_file, p_line); + } + + SetConsoleTextAttribute(hCon, sbi.wAttributes); + } +#endif +} + +WindowsTerminalLogger::~WindowsTerminalLogger() {} + +#endif
\ No newline at end of file diff --git a/platform/windows/windows_terminal_logger.h b/platform/windows/windows_terminal_logger.h new file mode 100644 index 0000000000..f6b1a68d18 --- /dev/null +++ b/platform/windows/windows_terminal_logger.h @@ -0,0 +1,47 @@ +/*************************************************************************/ +/* windows_terminal_logger.h */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ + +#ifndef WINDOWS_TERMINAL_LOGGER_H +#define WINDOWS_TERMINAL_LOGGER_H + +#ifdef WINDOWS_ENABLED + +#include "io/logger.h" + +class WindowsTerminalLogger : public StdLogger { +public: + virtual void logv(const char *p_format, va_list p_list, bool p_err); + virtual void log_error(const char *p_function, const char *p_file, int p_line, const char *p_code, const char *p_rationale, ErrorType p_type = ERR_ERROR); + virtual ~WindowsTerminalLogger(); +}; + +#endif + +#endif
\ No newline at end of file |