diff options
Diffstat (limited to 'platform')
55 files changed, 648 insertions, 391 deletions
diff --git a/platform/android/display_server_android.cpp b/platform/android/display_server_android.cpp index 2eb7056a36..d414ea5824 100644 --- a/platform/android/display_server_android.cpp +++ b/platform/android/display_server_android.cpp @@ -136,6 +136,18 @@ bool DisplayServerAndroid::clipboard_has() const { } } +Array DisplayServerAndroid::get_display_cutouts() const { + GodotIOJavaWrapper *godot_io_java = OS_Android::get_singleton()->get_godot_io_java(); + ERR_FAIL_NULL_V(godot_io_java, Array()); + return godot_io_java->get_display_cutouts(); +} + +Rect2i DisplayServerAndroid::get_display_safe_area() const { + GodotIOJavaWrapper *godot_io_java = OS_Android::get_singleton()->get_godot_io_java(); + ERR_FAIL_NULL_V(godot_io_java, Rect2i()); + return godot_io_java->get_display_safe_area(); +} + void DisplayServerAndroid::screen_set_keep_on(bool p_enable) { GodotJavaWrapper *godot_java = OS_Android::get_singleton()->get_godot_java(); ERR_FAIL_COND(!godot_java); @@ -177,11 +189,8 @@ Size2i DisplayServerAndroid::screen_get_size(int p_screen) const { } Rect2i DisplayServerAndroid::screen_get_usable_rect(int p_screen) const { - GodotIOJavaWrapper *godot_io_java = OS_Android::get_singleton()->get_godot_io_java(); - ERR_FAIL_COND_V(!godot_io_java, Rect2i()); - int xywh[4]; - godot_io_java->screen_get_usable_rect(xywh); - return Rect2i(xywh[0], xywh[1], xywh[2], xywh[3]); + Size2i display_size = OS_Android::get_singleton()->get_display_size(); + return Rect2i(0, 0, display_size.width, display_size.height); } int DisplayServerAndroid::screen_get_dpi(int p_screen) const { diff --git a/platform/android/display_server_android.h b/platform/android/display_server_android.h index 2604214ac0..65bf2ec1a8 100644 --- a/platform/android/display_server_android.h +++ b/platform/android/display_server_android.h @@ -104,6 +104,9 @@ public: virtual String clipboard_get() const override; virtual bool clipboard_has() const override; + virtual Array get_display_cutouts() const override; + virtual Rect2i get_display_safe_area() const override; + virtual void screen_set_keep_on(bool p_enable) override; virtual bool screen_is_kept_on() const override; diff --git a/platform/android/export/export_plugin.cpp b/platform/android/export/export_plugin.cpp index 8cfa3a67b9..d357cd586e 100644 --- a/platform/android/export/export_plugin.cpp +++ b/platform/android/export/export_plugin.cpp @@ -1000,16 +1000,23 @@ void EditorExportPlatformAndroid::_fix_manifest(const Ref<EditorExportPreset> &p } } - if (tname == "meta-data" && attrname == "name" && value == "xr_hand_tracking_metadata_name") { - if (xr_mode_index == XR_MODE_OPENXR && hand_tracking_index > XR_HAND_TRACKING_NONE) { + // Hand tracking related configurations + if (xr_mode_index == XR_MODE_OPENXR && hand_tracking_index > XR_HAND_TRACKING_NONE) { + if (tname == "meta-data" && attrname == "name" && value == "xr_hand_tracking_metadata_name") { string_table.write[attr_value] = "com.oculus.handtracking.frequency"; } - } - if (tname == "meta-data" && attrname == "value" && value == "xr_hand_tracking_metadata_value") { - if (xr_mode_index == XR_MODE_OPENXR && hand_tracking_index > XR_HAND_TRACKING_NONE) { + if (tname == "meta-data" && attrname == "value" && value == "xr_hand_tracking_metadata_value") { string_table.write[attr_value] = (hand_tracking_frequency_index == XR_HAND_TRACKING_FREQUENCY_LOW ? "LOW" : "HIGH"); } + + if (tname == "meta-data" && attrname == "name" && value == "xr_hand_tracking_version_name") { + string_table.write[attr_value] = "com.oculus.handtracking.version"; + } + + if (tname == "meta-data" && attrname == "name" && value == "xr_hand_tracking_version_value") { + string_table.write[attr_value] = "V2.0"; + } } iofs += 20; diff --git a/platform/android/export/gradle_export_util.cpp b/platform/android/export/gradle_export_util.cpp index 173bb8bcb7..d9574a1a52 100644 --- a/platform/android/export/gradle_export_util.cpp +++ b/platform/android/export/gradle_export_util.cpp @@ -279,6 +279,7 @@ String _get_application_tag(const Ref<EditorExportPreset> &p_preset, bool p_has_ " android:requestLegacyExternalStorage=\"%s\"\n" " tools:replace=\"android:allowBackup,android:isGame,android:hasFragileUserData,android:requestLegacyExternalStorage\"\n" " tools:ignore=\"GoogleAppIndexingWarning\">\n\n" + " <meta-data tools:node=\"remove\" android:name=\"xr_hand_tracking_version_name\" />\n" " <meta-data tools:node=\"remove\" android:name=\"xr_hand_tracking_metadata_name\" />\n", bool_to_string(p_preset->get("user_data_backup/allow")), bool_to_string(p_preset->get("package/classify_as_game")), @@ -293,6 +294,7 @@ String _get_application_tag(const Ref<EditorExportPreset> &p_preset, bool p_has_ manifest_application_text += vformat( " <meta-data tools:node=\"replace\" android:name=\"com.oculus.handtracking.frequency\" android:value=\"%s\" />\n", hand_tracking_frequency); + manifest_application_text += " <meta-data tools:node=\"replace\" android:name=\"com.oculus.handtracking.version\" android:value=\"V2.0\" />\n"; } } else { manifest_application_text += " <meta-data tools:node=\"remove\" android:name=\"com.oculus.supportedDevices\" />\n"; diff --git a/platform/android/java/app/AndroidManifest.xml b/platform/android/java/app/AndroidManifest.xml index 4c4501729d..c98e8f1d55 100644 --- a/platform/android/java/app/AndroidManifest.xml +++ b/platform/android/java/app/AndroidManifest.xml @@ -40,6 +40,13 @@ android:name="xr_hand_tracking_metadata_name" android:value="xr_hand_tracking_metadata_value"/> + <!-- XR hand tracking version --> + <!-- This is modified by the exporter based on the selected xr mode. DO NOT CHANGE the values here. --> + <!-- Removed at export time if the xr mode is not VR or hand tracking is disabled. --> + <meta-data + android:name="xr_hand_tracking_version_name" + android:value="xr_hand_tracking_version_value"/> + <!-- Supported Meta devices --> <!-- This is removed by the exporter if the xr mode is not VR. --> <meta-data diff --git a/platform/android/java/lib/src/org/godotengine/godot/GodotIO.java b/platform/android/java/lib/src/org/godotengine/godot/GodotIO.java index e8e292df5d..b69d25dd8b 100644 --- a/platform/android/java/lib/src/org/godotengine/godot/GodotIO.java +++ b/platform/android/java/lib/src/org/godotengine/godot/GodotIO.java @@ -38,6 +38,7 @@ import android.content.Intent; import android.content.pm.ActivityInfo; import android.content.res.AssetManager; import android.graphics.Point; +import android.graphics.Rect; import android.net.Uri; import android.os.Build; import android.os.Environment; @@ -51,6 +52,7 @@ import android.view.DisplayCutout; import android.view.WindowInsets; import java.io.IOException; +import java.util.List; import java.util.Locale; // Wrapper for native library @@ -238,7 +240,7 @@ public class GodotIO { return fallback; } - public int[] screenGetUsableRect() { + public int[] getDisplaySafeArea() { DisplayMetrics metrics = activity.getResources().getDisplayMetrics(); Display display = activity.getWindowManager().getDefaultDisplay(); Point size = new Point(); @@ -260,6 +262,25 @@ public class GodotIO { return result; } + public int[] getDisplayCutouts() { + if (Build.VERSION.SDK_INT < Build.VERSION_CODES.P) + return new int[0]; + DisplayCutout cutout = activity.getWindow().getDecorView().getRootWindowInsets().getDisplayCutout(); + if (cutout == null) + return new int[0]; + List<Rect> rects = cutout.getBoundingRects(); + int cutouts = rects.size(); + int[] result = new int[cutouts * 4]; + int index = 0; + for (Rect rect : rects) { + result[index++] = rect.left; + result[index++] = rect.top; + result[index++] = rect.width(); + result[index++] = rect.height(); + } + return result; + } + public void showKeyboard(String p_existing_text, boolean p_multiline, int p_max_input_length, int p_cursor_start, int p_cursor_end) { if (edit != null) edit.showKeyboard(p_existing_text, p_multiline, p_max_input_length, p_cursor_start, p_cursor_end); diff --git a/platform/android/java_godot_io_wrapper.cpp b/platform/android/java_godot_io_wrapper.cpp index 5b21e696c3..7ae3a65105 100644 --- a/platform/android/java_godot_io_wrapper.cpp +++ b/platform/android/java_godot_io_wrapper.cpp @@ -31,6 +31,8 @@ #include "java_godot_io_wrapper.h" #include "core/error/error_list.h" +#include "core/math/rect2.h" +#include "core/variant/variant.h" // JNIEnv is only valid within the thread it belongs to, in a multi threading environment // we can't cache it. @@ -51,12 +53,13 @@ GodotIOJavaWrapper::GodotIOJavaWrapper(JNIEnv *p_env, jobject p_godot_io_instanc _open_URI = p_env->GetMethodID(cls, "openURI", "(Ljava/lang/String;)I"); _get_cache_dir = p_env->GetMethodID(cls, "getCacheDir", "()Ljava/lang/String;"); _get_data_dir = p_env->GetMethodID(cls, "getDataDir", "()Ljava/lang/String;"); + _get_display_cutouts = p_env->GetMethodID(cls, "getDisplayCutouts", "()[I"), + _get_display_safe_area = p_env->GetMethodID(cls, "getDisplaySafeArea", "()[I"), _get_locale = p_env->GetMethodID(cls, "getLocale", "()Ljava/lang/String;"); _get_model = p_env->GetMethodID(cls, "getModel", "()Ljava/lang/String;"); _get_screen_DPI = p_env->GetMethodID(cls, "getScreenDPI", "()I"); _get_scaled_density = p_env->GetMethodID(cls, "getScaledDensity", "()F"); _get_screen_refresh_rate = p_env->GetMethodID(cls, "getScreenRefreshRate", "(D)D"); - _screen_get_usable_rect = p_env->GetMethodID(cls, "screenGetUsableRect", "()[I"), _get_unique_id = p_env->GetMethodID(cls, "getUniqueID", "()Ljava/lang/String;"); _show_keyboard = p_env->GetMethodID(cls, "showKeyboard", "(Ljava/lang/String;ZIII)V"); _hide_keyboard = p_env->GetMethodID(cls, "hideKeyboard", "()V"); @@ -162,18 +165,38 @@ float GodotIOJavaWrapper::get_screen_refresh_rate(float fallback) { return fallback; } -void GodotIOJavaWrapper::screen_get_usable_rect(int (&p_rect_xywh)[4]) { - if (_screen_get_usable_rect) { - JNIEnv *env = get_jni_env(); - ERR_FAIL_COND(env == nullptr); - jintArray returnArray = (jintArray)env->CallObjectMethod(godot_io_instance, _screen_get_usable_rect); - ERR_FAIL_COND(env->GetArrayLength(returnArray) != 4); - jint *arrayBody = env->GetIntArrayElements(returnArray, JNI_FALSE); - for (int i = 0; i < 4; i++) { - p_rect_xywh[i] = arrayBody[i]; - } - env->ReleaseIntArrayElements(returnArray, arrayBody, 0); +Array GodotIOJavaWrapper::get_display_cutouts() { + Array result; + ERR_FAIL_NULL_V(_get_display_cutouts, result); + JNIEnv *env = get_jni_env(); + ERR_FAIL_NULL_V(env, result); + jintArray returnArray = (jintArray)env->CallObjectMethod(godot_io_instance, _get_display_cutouts); + jint arrayLength = env->GetArrayLength(returnArray); + jint *arrayBody = env->GetIntArrayElements(returnArray, JNI_FALSE); + int cutouts = arrayLength / 4; + for (int i = 0; i < cutouts; i++) { + int x = arrayBody[i * 4]; + int y = arrayBody[i * 4 + 1]; + int width = arrayBody[i * 4 + 2]; + int height = arrayBody[i * 4 + 3]; + Rect2 cutout(x, y, width, height); + result.append(cutout); } + env->ReleaseIntArrayElements(returnArray, arrayBody, 0); + return result; +} + +Rect2i GodotIOJavaWrapper::get_display_safe_area() { + Rect2i result; + ERR_FAIL_NULL_V(_get_display_safe_area, result); + JNIEnv *env = get_jni_env(); + ERR_FAIL_NULL_V(env, result); + jintArray returnArray = (jintArray)env->CallObjectMethod(godot_io_instance, _get_display_safe_area); + ERR_FAIL_COND_V(env->GetArrayLength(returnArray) != 4, result); + jint *arrayBody = env->GetIntArrayElements(returnArray, JNI_FALSE); + result = Rect2i(arrayBody[0], arrayBody[1], arrayBody[2], arrayBody[3]); + env->ReleaseIntArrayElements(returnArray, arrayBody, 0); + return result; } String GodotIOJavaWrapper::get_unique_id() { diff --git a/platform/android/java_godot_io_wrapper.h b/platform/android/java_godot_io_wrapper.h index 08e3092afd..02c57130ab 100644 --- a/platform/android/java_godot_io_wrapper.h +++ b/platform/android/java_godot_io_wrapper.h @@ -37,6 +37,8 @@ #include <android/log.h> #include <jni.h> +#include "core/math/rect2i.h" +#include "core/variant/array.h" #include "string_android.h" // Class that makes functions in java/src/org/godotengine/godot/GodotIO.java callable from C++ @@ -48,12 +50,13 @@ private: jmethodID _open_URI = 0; jmethodID _get_cache_dir = 0; jmethodID _get_data_dir = 0; + jmethodID _get_display_cutouts = 0; + jmethodID _get_display_safe_area = 0; jmethodID _get_locale = 0; jmethodID _get_model = 0; jmethodID _get_screen_DPI = 0; jmethodID _get_scaled_density = 0; jmethodID _get_screen_refresh_rate = 0; - jmethodID _screen_get_usable_rect = 0; jmethodID _get_unique_id = 0; jmethodID _show_keyboard = 0; jmethodID _hide_keyboard = 0; @@ -75,7 +78,8 @@ public: int get_screen_dpi(); float get_scaled_density(); float get_screen_refresh_rate(float fallback); - void screen_get_usable_rect(int (&p_rect_xywh)[4]); + Array get_display_cutouts(); + Rect2i get_display_safe_area(); String get_unique_id(); bool has_vk(); void show_vk(const String &p_existing, bool p_multiline, int p_max_input_length, int p_cursor_start, int p_cursor_end); diff --git a/platform/android/os_android.cpp b/platform/android/os_android.cpp index fc46005b41..25daf1ca90 100644 --- a/platform/android/os_android.cpp +++ b/platform/android/os_android.cpp @@ -162,9 +162,14 @@ Vector<String> OS_Android::get_granted_permissions() const { return godot_java->get_granted_permissions(); } -Error OS_Android::open_dynamic_library(const String p_path, void *&p_library_handle, bool p_also_set_library_path) { +Error OS_Android::open_dynamic_library(const String p_path, void *&p_library_handle, bool p_also_set_library_path, String *r_resolved_path) { p_library_handle = dlopen(p_path.utf8().get_data(), RTLD_NOW); ERR_FAIL_COND_V_MSG(!p_library_handle, ERR_CANT_OPEN, "Can't open dynamic library: " + p_path + ", error: " + dlerror() + "."); + + if (r_resolved_path != nullptr) { + *r_resolved_path = p_path; + } + return OK; } diff --git a/platform/android/os_android.h b/platform/android/os_android.h index a40e17dc2c..f86c5b5212 100644 --- a/platform/android/os_android.h +++ b/platform/android/os_android.h @@ -90,7 +90,7 @@ public: virtual void alert(const String &p_alert, const String &p_title) override; - virtual Error open_dynamic_library(const String p_path, void *&p_library_handle, bool p_also_set_library_path = false) override; + virtual Error open_dynamic_library(const String p_path, void *&p_library_handle, bool p_also_set_library_path = false, String *r_resolved_path = nullptr) override; virtual String get_name() const override; virtual MainLoop *get_main_loop() const override; diff --git a/platform/iphone/display_server_iphone.h b/platform/iphone/display_server_iphone.h index 6ae190b81a..7af222e3f8 100644 --- a/platform/iphone/display_server_iphone.h +++ b/platform/iphone/display_server_iphone.h @@ -134,6 +134,8 @@ public: virtual void tts_resume() override; virtual void tts_stop() override; + virtual Rect2i get_display_safe_area() const override; + virtual int get_screen_count() const override; virtual Point2i screen_get_position(int p_screen = SCREEN_OF_MAIN_WINDOW) const override; virtual Size2i screen_get_size(int p_screen = SCREEN_OF_MAIN_WINDOW) const override; diff --git a/platform/iphone/display_server_iphone.mm b/platform/iphone/display_server_iphone.mm index ec58ab195a..573ee9b7a8 100644 --- a/platform/iphone/display_server_iphone.mm +++ b/platform/iphone/display_server_iphone.mm @@ -360,6 +360,22 @@ void DisplayServerIPhone::tts_stop() { [tts stopSpeaking]; } +Rect2i DisplayServerIPhone::get_display_safe_area() const { + if (@available(iOS 11, *)) { + UIEdgeInsets insets = UIEdgeInsetsZero; + UIView *view = AppDelegate.viewController.godotView; + if ([view respondsToSelector:@selector(safeAreaInsets)]) { + insets = [view safeAreaInsets]; + } + float scale = screen_get_scale(); + Size2i insets_position = Size2i(insets.left, insets.top) * scale; + Size2i insets_size = Size2i(insets.left + insets.right, insets.top + insets.bottom) * scale; + return Rect2i(screen_get_position() + insets_position, screen_get_size() - insets_size); + } else { + return Rect2i(screen_get_position(), screen_get_size()); + } +} + int DisplayServerIPhone::get_screen_count() const { return 1; } @@ -379,22 +395,7 @@ Size2i DisplayServerIPhone::screen_get_size(int p_screen) const { } Rect2i DisplayServerIPhone::screen_get_usable_rect(int p_screen) const { - if (@available(iOS 11, *)) { - UIEdgeInsets insets = UIEdgeInsetsZero; - UIView *view = AppDelegate.viewController.godotView; - - if ([view respondsToSelector:@selector(safeAreaInsets)]) { - insets = [view safeAreaInsets]; - } - - float scale = screen_get_scale(p_screen); - Size2i insets_position = Size2i(insets.left, insets.top) * scale; - Size2i insets_size = Size2i(insets.left + insets.right, insets.top + insets.bottom) * scale; - - return Rect2i(screen_get_position(p_screen) + insets_position, screen_get_size(p_screen) - insets_size); - } else { - return Rect2i(screen_get_position(p_screen), screen_get_size(p_screen)); - } + return Rect2i(screen_get_position(p_screen), screen_get_size(p_screen)); } int DisplayServerIPhone::screen_get_dpi(int p_screen) const { diff --git a/platform/iphone/export/export_plugin.h b/platform/iphone/export/export_plugin.h index 3831f3bff2..2c6faed691 100644 --- a/platform/iphone/export/export_plugin.h +++ b/platform/iphone/export/export_plugin.h @@ -53,8 +53,6 @@ class EditorExportPlatformIOS : public EditorExportPlatform { GDCLASS(EditorExportPlatformIOS, EditorExportPlatform); - int version_code; - Ref<ImageTexture> logo; // Plugins diff --git a/platform/iphone/godot_view_gesture_recognizer.mm b/platform/iphone/godot_view_gesture_recognizer.mm index c8137f35ff..49a92add5e 100644 --- a/platform/iphone/godot_view_gesture_recognizer.mm +++ b/platform/iphone/godot_view_gesture_recognizer.mm @@ -70,6 +70,7 @@ const CGFloat kGLGestureMovementDistance = 0.5; self.cancelsTouchesInView = YES; self.delaysTouchesBegan = YES; self.delaysTouchesEnded = YES; + self.requiresExclusiveTouchType = NO; self.delayTimeInterval = GLOBAL_GET("input_devices/pointing/ios/touch_delay"); diff --git a/platform/iphone/os_iphone.h b/platform/iphone/os_iphone.h index 6a61f3a910..d03403bbb4 100644 --- a/platform/iphone/os_iphone.h +++ b/platform/iphone/os_iphone.h @@ -92,7 +92,7 @@ public: virtual void alert(const String &p_alert, const String &p_title = "ALERT!") override; - virtual Error open_dynamic_library(const String p_path, void *&p_library_handle, bool p_also_set_library_path = false) override; + virtual Error open_dynamic_library(const String p_path, void *&p_library_handle, bool p_also_set_library_path = false, String *r_resolved_path = nullptr) override; virtual Error close_dynamic_library(void *p_library_handle) override; virtual Error get_dynamic_library_symbol_handle(void *p_library_handle, const String p_name, void *&p_symbol_handle, bool p_optional = false) override; diff --git a/platform/iphone/os_iphone.mm b/platform/iphone/os_iphone.mm index f7974c4b3d..95b06b728e 100644 --- a/platform/iphone/os_iphone.mm +++ b/platform/iphone/os_iphone.mm @@ -204,12 +204,17 @@ void OSIPhone::finalize() { // MARK: Dynamic Libraries -Error OSIPhone::open_dynamic_library(const String p_path, void *&p_library_handle, bool p_also_set_library_path) { +Error OSIPhone::open_dynamic_library(const String p_path, void *&p_library_handle, bool p_also_set_library_path, String *r_resolved_path) { if (p_path.length() == 0) { p_library_handle = RTLD_SELF; + + if (r_resolved_path != nullptr) { + *r_resolved_path = p_path; + } + return OK; } - return OS_Unix::open_dynamic_library(p_path, p_library_handle, p_also_set_library_path); + return OS_Unix::open_dynamic_library(p_path, p_library_handle, p_also_set_library_path, r_resolved_path); } Error OSIPhone::close_dynamic_library(void *p_library_handle) { diff --git a/platform/iphone/tts_ios.h b/platform/iphone/tts_ios.h index c7defeb98f..3fac762b62 100644 --- a/platform/iphone/tts_ios.h +++ b/platform/iphone/tts_ios.h @@ -31,7 +31,11 @@ #ifndef TTS_IOS_H #define TTS_IOS_H -#include <AVFAudio/AVSpeechSynthesis.h> +#if __has_include(<AVFAudio/AVSpeechSynthesis.h>) +#import <AVFAudio/AVSpeechSynthesis.h> +#else +#import <AVFoundation/AVFoundation.h> +#endif #include "core/string/ustring.h" #include "core/templates/list.h" diff --git a/platform/javascript/api/javascript_tools_editor_plugin.cpp b/platform/javascript/api/javascript_tools_editor_plugin.cpp index 31ce71127d..198af61eff 100644 --- a/platform/javascript/api/javascript_tools_editor_plugin.cpp +++ b/platform/javascript/api/javascript_tools_editor_plugin.cpp @@ -122,7 +122,7 @@ void JavaScriptToolsEditorPlugin::_zip_file(String p_path, String p_base_path, z void JavaScriptToolsEditorPlugin::_zip_recursive(String p_path, String p_base_path, zipFile p_zip) { Ref<DirAccess> dir = DirAccess::open(p_path); - if (!dir) { + if (dir.is_null()) { WARN_PRINT("Unable to open directory for zipping: " + p_path); return; } diff --git a/platform/javascript/detect.py b/platform/javascript/detect.py index b6be44fbb2..709104c5ee 100644 --- a/platform/javascript/detect.py +++ b/platform/javascript/detect.py @@ -212,6 +212,8 @@ def configure(env): sys.exit(255) env.Append(CCFLAGS=["-s", "RELOCATABLE=1"]) env.Append(LINKFLAGS=["-s", "RELOCATABLE=1"]) + # Weak symbols are broken upstream: https://github.com/emscripten-core/emscripten/issues/12819 + env.Append(CPPDEFINES=["ZSTD_HAVE_WEAK_SYMBOLS=0"]) env.extra_suffix = ".gdnative" + env.extra_suffix # Reduce code size by generating less support code (e.g. skip NodeJS support). diff --git a/platform/javascript/display_server_javascript.cpp b/platform/javascript/display_server_javascript.cpp index cc77c8fcd5..312707c3b5 100644 --- a/platform/javascript/display_server_javascript.cpp +++ b/platform/javascript/display_server_javascript.cpp @@ -371,7 +371,7 @@ DisplayServer::CursorShape DisplayServerJavaScript::cursor_get_shape() const { return cursor_shape; } -void DisplayServerJavaScript::cursor_set_custom_image(const RES &p_cursor, CursorShape p_shape, const Vector2 &p_hotspot) { +void DisplayServerJavaScript::cursor_set_custom_image(const Ref<Resource> &p_cursor, CursorShape p_shape, const Vector2 &p_hotspot) { if (p_cursor.is_valid()) { Ref<Texture2D> texture = p_cursor; Ref<AtlasTexture> atlas_texture = p_cursor; diff --git a/platform/javascript/display_server_javascript.h b/platform/javascript/display_server_javascript.h index bbd0206087..623546bbd0 100644 --- a/platform/javascript/display_server_javascript.h +++ b/platform/javascript/display_server_javascript.h @@ -134,7 +134,7 @@ public: // cursor virtual void cursor_set_shape(CursorShape p_shape) override; virtual CursorShape cursor_get_shape() const override; - virtual void cursor_set_custom_image(const RES &p_cursor, CursorShape p_shape = CURSOR_ARROW, const Vector2 &p_hotspot = Vector2()) override; + virtual void cursor_set_custom_image(const Ref<Resource> &p_cursor, CursorShape p_shape = CURSOR_ARROW, const Vector2 &p_hotspot = Vector2()) override; // mouse virtual void mouse_set_mode(MouseMode p_mode) override; diff --git a/platform/javascript/godot_webgl2.h b/platform/javascript/godot_webgl2.h new file mode 100644 index 0000000000..7c357ff66d --- /dev/null +++ b/platform/javascript/godot_webgl2.h @@ -0,0 +1,37 @@ +/*************************************************************************/ +/* godot_webgl2.h */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 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 GODOT_WEBGL2_H +#define GODOT_WEBGL2_H + +#include "GLES3/gl3.h" +#include "webgl/webgl2.h" + +#endif diff --git a/platform/javascript/http_client_javascript.cpp b/platform/javascript/http_client_javascript.cpp index c946302862..32bdfed4c7 100644 --- a/platform/javascript/http_client_javascript.cpp +++ b/platform/javascript/http_client_javascript.cpp @@ -76,7 +76,7 @@ void HTTPClientJavaScript::set_connection(const Ref<StreamPeer> &p_connection) { } Ref<StreamPeer> HTTPClientJavaScript::get_connection() const { - ERR_FAIL_V_MSG(REF(), "Accessing an HTTPClientJavaScript's StreamPeer is not supported for the HTML5 platform."); + ERR_FAIL_V_MSG(Ref<RefCounted>(), "Accessing an HTTPClientJavaScript's StreamPeer is not supported for the HTML5 platform."); } Error HTTPClientJavaScript::request(Method p_method, const String &p_url, const Vector<String> &p_headers, const uint8_t *p_body, int p_body_len) { diff --git a/platform/javascript/js/libs/library_godot_display.js b/platform/javascript/js/libs/library_godot_display.js index 54d48643db..5997631bf8 100644 --- a/platform/javascript/js/libs/library_godot_display.js +++ b/platform/javascript/js/libs/library_godot_display.js @@ -462,6 +462,7 @@ const GodotDisplay = { GodotRuntime.setHeapValue(height, window.screen.height * scale, 'i32'); }, + godot_js_display_window_size_get__sig: 'vii', godot_js_display_window_size_get: function (p_width, p_height) { GodotRuntime.setHeapValue(p_width, GodotConfig.canvas.width, 'i32'); GodotRuntime.setHeapValue(p_height, GodotConfig.canvas.height, 'i32'); diff --git a/platform/javascript/js/libs/library_godot_os.js b/platform/javascript/js/libs/library_godot_os.js index 12d06a8d51..377eec3234 100644 --- a/platform/javascript/js/libs/library_godot_os.js +++ b/platform/javascript/js/libs/library_godot_os.js @@ -305,7 +305,9 @@ const GodotOS = { godot_js_os_hw_concurrency_get__sig: 'i', godot_js_os_hw_concurrency_get: function () { - return navigator.hardwareConcurrency || 1; + // TODO Godot core needs fixing to avoid spawning too many threads (> 24). + const concurrency = navigator.hardwareConcurrency || 1; + return concurrency < 2 ? concurrency : 2; }, godot_js_os_download_buffer__sig: 'viiii', diff --git a/platform/javascript/os_javascript.cpp b/platform/javascript/os_javascript.cpp index da88ea18b0..1686353229 100644 --- a/platform/javascript/os_javascript.cpp +++ b/platform/javascript/os_javascript.cpp @@ -131,6 +131,10 @@ int OS_JavaScript::get_process_id() const { ERR_FAIL_V_MSG(0, "OS::get_process_id() is not available on the HTML5 platform."); } +bool OS_JavaScript::is_process_running(const ProcessID &p_pid) const { + return false; +} + int OS_JavaScript::get_processor_count() const { return godot_js_os_hw_concurrency_get(); } @@ -221,10 +225,15 @@ bool OS_JavaScript::is_userfs_persistent() const { return idb_available; } -Error OS_JavaScript::open_dynamic_library(const String p_path, void *&p_library_handle, bool p_also_set_library_path) { +Error OS_JavaScript::open_dynamic_library(const String p_path, void *&p_library_handle, bool p_also_set_library_path, String *r_resolved_path) { String path = p_path.get_file(); p_library_handle = dlopen(path.utf8().get_data(), RTLD_NOW); ERR_FAIL_COND_V_MSG(!p_library_handle, ERR_CANT_OPEN, "Can't open dynamic library: " + p_path + ". Error: " + dlerror()); + + if (r_resolved_path != nullptr) { + *r_resolved_path = path; + } + return OK; } diff --git a/platform/javascript/os_javascript.h b/platform/javascript/os_javascript.h index 9e272f9aa1..0c672111cc 100644 --- a/platform/javascript/os_javascript.h +++ b/platform/javascript/os_javascript.h @@ -79,6 +79,7 @@ public: Error create_process(const String &p_path, const List<String> &p_arguments, ProcessID *r_child_id = nullptr, bool p_open_console = false) override; Error kill(const ProcessID &p_pid) override; int get_process_id() const override; + bool is_process_running(const ProcessID &p_pid) const override; int get_processor_count() const override; int get_default_thread_pool_size() const override { return 1; } @@ -99,7 +100,7 @@ public: void alert(const String &p_alert, const String &p_title = "ALERT!") override; - Error open_dynamic_library(const String p_path, void *&p_library_handle, bool p_also_set_library_path) override; + Error open_dynamic_library(const String p_path, void *&p_library_handle, bool p_also_set_library_path = false, String *r_resolved_path = nullptr) override; void resume_audio(); diff --git a/platform/javascript/platform_config.h b/platform/javascript/platform_config.h index ba1b0d459e..1970fe0fa0 100644 --- a/platform/javascript/platform_config.h +++ b/platform/javascript/platform_config.h @@ -29,3 +29,5 @@ /*************************************************************************/ #include <alloca.h> + +#define OPENGL_INCLUDE_H "platform/javascript/godot_webgl2.h" diff --git a/platform/linuxbsd/crash_handler_linuxbsd.cpp b/platform/linuxbsd/crash_handler_linuxbsd.cpp index b4ec7924f6..33da094860 100644 --- a/platform/linuxbsd/crash_handler_linuxbsd.cpp +++ b/platform/linuxbsd/crash_handler_linuxbsd.cpp @@ -32,6 +32,7 @@ #include "core/config/project_settings.h" #include "core/os/os.h" +#include "core/string/print_string.h" #include "core/version.h" #include "main/main.h" @@ -61,21 +62,22 @@ static void handle_crash(int sig) { msg = proj_settings->get("debug/settings/crash_handler/message"); } - // Dump the backtrace to stderr with a message to the user - fprintf(stderr, "\n================================================================\n"); - fprintf(stderr, "%s: Program crashed with signal %d\n", __FUNCTION__, sig); - + // Tell MainLoop about the crash. This can be handled by users too in Node. if (OS::get_singleton()->get_main_loop()) { OS::get_singleton()->get_main_loop()->notification(MainLoop::NOTIFICATION_CRASH); } + // Dump the backtrace to stderr with a message to the user + print_error("\n================================================================"); + print_error(vformat("%s: Program crashed with signal %d", __FUNCTION__, sig)); + // Print the engine version just before, so that people are reminded to include the version in backtrace reports. if (String(VERSION_HASH).is_empty()) { - fprintf(stderr, "Engine version: %s\n", VERSION_FULL_NAME); + print_error(vformat("Engine version: %s", VERSION_FULL_NAME)); } else { - fprintf(stderr, "Engine version: %s (%s)\n", VERSION_FULL_NAME, VERSION_HASH); + print_error(vformat("Engine version: %s (%s)", VERSION_FULL_NAME, VERSION_HASH)); } - fprintf(stderr, "Dumping the backtrace. %s\n", msg.utf8().get_data()); + print_error(vformat("Dumping the backtrace. %s", msg)); char **strings = backtrace_symbols(bt_buffer, size); if (strings) { for (size_t i = 1; i < size; i++) { @@ -117,13 +119,13 @@ static void handle_crash(int sig) { output = output.substr(0, output.length() - 1); } - fprintf(stderr, "[%ld] %s (%s)\n", (long int)i, fname, output.utf8().get_data()); + print_error(vformat("[%d] %s (%s)", (int64_t)i, fname, output)); } free(strings); } - fprintf(stderr, "-- END OF BACKTRACE --\n"); - fprintf(stderr, "================================================================\n"); + print_error("-- END OF BACKTRACE --"); + print_error("================================================================"); // Abort to pass the error to the OS abort(); diff --git a/platform/linuxbsd/detect_prime_x11.cpp b/platform/linuxbsd/detect_prime_x11.cpp index 63531d33fa..42b7f68a5e 100644 --- a/platform/linuxbsd/detect_prime_x11.cpp +++ b/platform/linuxbsd/detect_prime_x11.cpp @@ -55,7 +55,7 @@ typedef GLXContext (*GLXCREATECONTEXTATTRIBSARBPROC)(Display *, GLXFBConfig, GLXContext, Bool, const int *); struct vendor { - const char *glxvendor; + const char *glxvendor = nullptr; int priority = 0; }; diff --git a/platform/linuxbsd/display_server_x11.cpp b/platform/linuxbsd/display_server_x11.cpp index 027f8562eb..b35f0daec6 100644 --- a/platform/linuxbsd/display_server_x11.cpp +++ b/platform/linuxbsd/display_server_x11.cpp @@ -2356,7 +2356,7 @@ DisplayServerX11::CursorShape DisplayServerX11::cursor_get_shape() const { return current_cursor; } -void DisplayServerX11::cursor_set_custom_image(const RES &p_cursor, CursorShape p_shape, const Vector2 &p_hotspot) { +void DisplayServerX11::cursor_set_custom_image(const Ref<Resource> &p_cursor, CursorShape p_shape, const Vector2 &p_hotspot) { _THREAD_SAFE_METHOD_ if (p_cursor.is_valid()) { @@ -4531,24 +4531,11 @@ DisplayServerX11::DisplayServerX11(const String &p_rendering_driver, WindowMode r_error = OK; - current_cursor = CURSOR_ARROW; - mouse_mode = MOUSE_MODE_VISIBLE; - for (int i = 0; i < CURSOR_MAX; i++) { cursors[i] = None; img[i] = nullptr; } - xmbstring = nullptr; - - last_click_ms = 0; - last_click_button_index = MouseButton::NONE; - last_click_pos = Point2i(-100, -100); - - last_timestamp = 0; - last_mouse_pos_valid = false; - last_keyrelease_time = 0; - XInitThreads(); //always use threads /** XLIB INITIALIZATION **/ @@ -4583,8 +4570,6 @@ DisplayServerX11::DisplayServerX11(const String &p_rendering_driver, WindowMode } const char *err; - xrr_get_monitors = nullptr; - xrr_free_monitors = nullptr; int xrandr_major = 0; int xrandr_minor = 0; int event_base, error_base; @@ -4660,11 +4645,10 @@ DisplayServerX11::DisplayServerX11(const String &p_rendering_driver, WindowMode XFree(imvalret); } - /* Atorm internment */ + /* Atom internment */ wm_delete = XInternAtom(x11_display, "WM_DELETE_WINDOW", true); - //Set Xdnd (drag & drop) support + // Set Xdnd (drag & drop) support. xdnd_aware = XInternAtom(x11_display, "XdndAware", False); - xdnd_version = 5; xdnd_enter = XInternAtom(x11_display, "XdndEnter", False); xdnd_position = XInternAtom(x11_display, "XdndPosition", False); xdnd_status = XInternAtom(x11_display, "XdndStatus", False); @@ -4751,11 +4735,7 @@ DisplayServerX11::DisplayServerX11(const String &p_rendering_driver, WindowMode } driver_found = true; - // gl_manager->set_use_vsync(current_videomode.use_vsync); - if (true) { - // if (RasterizerGLES3::is_viable() == OK) { - // RasterizerGLES3::register_config(); RasterizerGLES3::make_current(); } else { memdelete(gl_manager); @@ -4930,12 +4910,6 @@ DisplayServerX11::DisplayServerX11(const String &p_rendering_driver, WindowMode } cursor_set_shape(CURSOR_BUSY); - requested = None; - - /*if (p_desired.layered) { - set_window_per_pixel_transparency_enabled(true); - }*/ - XEvent xevent; while (XPending(x11_display) > 0) { XNextEvent(x11_display, &xevent); diff --git a/platform/linuxbsd/display_server_x11.h b/platform/linuxbsd/display_server_x11.h index 3d49886b94..ee47d1a12c 100644 --- a/platform/linuxbsd/display_server_x11.h +++ b/platform/linuxbsd/display_server_x11.h @@ -100,8 +100,8 @@ class DisplayServerX11 : public DisplayServer { Atom xdnd_finished; Atom xdnd_selection; Atom xdnd_aware; - Atom requested; - int xdnd_version; + Atom requested = None; + int xdnd_version = 5; #if defined(GLES3_ENABLED) GLManager_X11 *gl_manager = nullptr; @@ -174,21 +174,21 @@ class DisplayServerX11 : public DisplayServer { String internal_clipboard; String internal_clipboard_primary; - Window xdnd_source_window; + Window xdnd_source_window = 0; ::Display *x11_display; char *xmbstring = nullptr; - int xmblen; - unsigned long last_timestamp; - ::Time last_keyrelease_time; + int xmblen = 0; + unsigned long last_timestamp = 0; + ::Time last_keyrelease_time = 0; ::XIM xim; ::XIMStyle xim_style; static void _xim_destroy_callback(::XIM im, ::XPointer client_data, ::XPointer call_data); Point2i last_mouse_pos; - bool last_mouse_pos_valid; - Point2i last_click_pos; - uint64_t last_click_ms; + bool last_mouse_pos_valid = false; + Point2i last_click_pos = Point2i(-100, -100); + uint64_t last_click_ms = 0; MouseButton last_click_button_index = MouseButton::NONE; MouseButton last_button_state = MouseButton::NONE; bool app_focused = false; @@ -221,7 +221,7 @@ class DisplayServerX11 : public DisplayServer { void _get_key_modifier_state(unsigned int p_x11_state, Ref<InputEventWithModifiers> state); void _flush_mouse_motion(); - MouseMode mouse_mode; + MouseMode mouse_mode = MOUSE_MODE_VISIBLE; Point2i center; void _handle_key_event(WindowID p_window, XKeyEvent *p_event, LocalVector<XEvent> &p_events, uint32_t &p_event_index, bool p_echo = false); @@ -233,30 +233,26 @@ class DisplayServerX11 : public DisplayServer { String _clipboard_get(Atom p_source, Window x11_window) const; void _clipboard_transfer_ownership(Atom p_source, Window x11_window) const; - //bool minimized; - //bool window_has_focus; - bool do_mouse_warp; + bool do_mouse_warp = false; - const char *cursor_theme; - int cursor_size; + const char *cursor_theme = nullptr; + int cursor_size = 0; XcursorImage *img[CURSOR_MAX]; Cursor cursors[CURSOR_MAX]; Cursor null_cursor; - CursorShape current_cursor; + CursorShape current_cursor = CURSOR_ARROW; Map<CursorShape, Vector<Variant>> cursors_cache; - bool layered_window; + bool layered_window = false; String rendering_driver; - //bool window_focused; - //void set_wm_border(bool p_enabled); void set_wm_fullscreen(bool p_enabled); void set_wm_above(bool p_enabled); typedef xrr_monitor_info *(*xrr_get_monitors_t)(Display *dpy, Window window, Bool get_active, int *nmonitors); typedef void (*xrr_free_monitors_t)(xrr_monitor_info *monitors); - xrr_get_monitors_t xrr_get_monitors; - xrr_free_monitors_t xrr_free_monitors; + xrr_get_monitors_t xrr_get_monitors = nullptr; + xrr_free_monitors_t xrr_free_monitors = nullptr; void *xrandr_handle = nullptr; Bool xrandr_ext_ok; @@ -411,7 +407,7 @@ public: virtual void cursor_set_shape(CursorShape p_shape) override; virtual CursorShape cursor_get_shape() const override; - virtual void cursor_set_custom_image(const RES &p_cursor, CursorShape p_shape, const Vector2 &p_hotspot) override; + virtual void cursor_set_custom_image(const Ref<Resource> &p_cursor, CursorShape p_shape, const Vector2 &p_hotspot) override; virtual int keyboard_get_layout_count() const override; virtual int keyboard_get_current_layout() const override; diff --git a/platform/linuxbsd/joypad_linux.cpp b/platform/linuxbsd/joypad_linux.cpp index 22a9518a25..bc018e366b 100644 --- a/platform/linuxbsd/joypad_linux.cpp +++ b/platform/linuxbsd/joypad_linux.cpp @@ -65,6 +65,7 @@ void JoypadLinux::Joypad::reset() { abs_map[i] = -1; curr_axis[i] = 0; } + events.clear(); } JoypadLinux::JoypadLinux(Input *in) { @@ -84,23 +85,26 @@ JoypadLinux::JoypadLinux(Input *in) { print_verbose("JoypadLinux: udev disabled, parsing /dev/input to detect joypads."); #endif input = in; - joy_thread.start(joy_thread_func, this); + monitor_joypads_thread.start(monitor_joypads_thread_func, this); + joypad_events_thread.start(joypad_events_thread_func, this); } JoypadLinux::~JoypadLinux() { - exit_monitor.set(); - joy_thread.wait_to_finish(); - close_joypad(); + monitor_joypads_exit.set(); + joypad_events_exit.set(); + monitor_joypads_thread.wait_to_finish(); + joypad_events_thread.wait_to_finish(); + close_joypads(); } -void JoypadLinux::joy_thread_func(void *p_user) { +void JoypadLinux::monitor_joypads_thread_func(void *p_user) { if (p_user) { JoypadLinux *joy = static_cast<JoypadLinux *>(p_user); - joy->run_joypad_thread(); + joy->monitor_joypads_thread_run(); } } -void JoypadLinux::run_joypad_thread() { +void JoypadLinux::monitor_joypads_thread_run() { #ifdef UDEV_ENABLED if (use_udev) { udev *_udev = udev_new(); @@ -140,7 +144,6 @@ void JoypadLinux::enumerate_joypads(udev *p_udev) { if (devnode) { String devnode_str = devnode; if (devnode_str.find(ignore_str) == -1) { - MutexLock lock(joy_mutex); open_joypad(devnode); } } @@ -156,7 +159,7 @@ void JoypadLinux::monitor_joypads(udev *p_udev) { udev_monitor_enable_receiving(mon); int fd = udev_monitor_get_fd(mon); - while (!exit_monitor.is_set()) { + while (!monitor_joypads_exit.is_set()) { fd_set fds; struct timeval tv; int ret; @@ -175,7 +178,6 @@ void JoypadLinux::monitor_joypads(udev *p_udev) { dev = udev_monitor_receive_device(mon); if (dev && udev_device_get_devnode(dev) != nullptr) { - MutexLock lock(joy_mutex); String action = udev_device_get_action(dev); const char *devnode = udev_device_get_devnode(dev); if (devnode) { @@ -184,11 +186,10 @@ void JoypadLinux::monitor_joypads(udev *p_udev) { if (action == "add") { open_joypad(devnode); } else if (String(action) == "remove") { - close_joypad(get_joy_from_path(devnode)); + close_joypad(devnode); } } } - udev_device_unref(dev); } } @@ -199,59 +200,54 @@ void JoypadLinux::monitor_joypads(udev *p_udev) { #endif void JoypadLinux::monitor_joypads() { - while (!exit_monitor.is_set()) { - { - MutexLock lock(joy_mutex); - - DIR *input_directory; - input_directory = opendir("/dev/input"); - if (input_directory) { - struct dirent *current; - char fname[64]; - - while ((current = readdir(input_directory)) != nullptr) { - if (strncmp(current->d_name, "event", 5) != 0) { - continue; - } - sprintf(fname, "/dev/input/%.*s", 16, current->d_name); - if (attached_devices.find(fname) == -1) { - open_joypad(fname); - } + while (!monitor_joypads_exit.is_set()) { + DIR *input_directory; + input_directory = opendir("/dev/input"); + if (input_directory) { + struct dirent *current; + char fname[64]; + + while ((current = readdir(input_directory)) != nullptr) { + if (strncmp(current->d_name, "event", 5) != 0) { + continue; + } + sprintf(fname, "/dev/input/%.*s", 16, current->d_name); + if (attached_devices.find(fname) == -1) { + open_joypad(fname); } } - closedir(input_directory); } - usleep(1000000); // 1s + closedir(input_directory); } + usleep(1000000); // 1s } -int JoypadLinux::get_joy_from_path(String p_path) const { +void JoypadLinux::close_joypads() { for (int i = 0; i < JOYPADS_MAX; i++) { - if (joypads[i].devpath == p_path) { - return i; - } + MutexLock lock(joypads_mutex[i]); + Joypad &joypad = joypads[i]; + close_joypad(joypad, i); } - return -2; } -void JoypadLinux::close_joypad(int p_id) { - if (p_id == -1) { - for (int i = 0; i < JOYPADS_MAX; i++) { - close_joypad(i); +void JoypadLinux::close_joypad(const char *p_devpath) { + for (int i = 0; i < JOYPADS_MAX; i++) { + MutexLock lock(joypads_mutex[i]); + Joypad &joypad = joypads[i]; + if (joypads[i].devpath == p_devpath) { + close_joypad(joypad, i); } - return; - } else if (p_id < 0) { - return; } +} - Joypad &joy = joypads[p_id]; - - if (joy.fd != -1) { - close(joy.fd); - joy.fd = -1; - attached_devices.remove_at(attached_devices.find(joy.devpath)); +void JoypadLinux::close_joypad(Joypad &p_joypad, int p_id) { + if (p_joypad.fd != -1) { + close(p_joypad.fd); + p_joypad.fd = -1; + attached_devices.erase(p_joypad.devpath); input->joy_connection_changed(p_id, false, ""); } + p_joypad.events.clear(); } static String _hex_str(uint8_t p_byte) { @@ -265,27 +261,25 @@ static String _hex_str(uint8_t p_byte) { return ret; } -void JoypadLinux::setup_joypad_properties(int p_id) { - Joypad *joy = &joypads[p_id]; - +void JoypadLinux::setup_joypad_properties(Joypad &p_joypad) { unsigned long keybit[NBITS(KEY_MAX)] = { 0 }; unsigned long absbit[NBITS(ABS_MAX)] = { 0 }; int num_buttons = 0; int num_axes = 0; - if ((ioctl(joy->fd, EVIOCGBIT(EV_KEY, sizeof(keybit)), keybit) < 0) || - (ioctl(joy->fd, EVIOCGBIT(EV_ABS, sizeof(absbit)), absbit) < 0)) { + if ((ioctl(p_joypad.fd, EVIOCGBIT(EV_KEY, sizeof(keybit)), keybit) < 0) || + (ioctl(p_joypad.fd, EVIOCGBIT(EV_ABS, sizeof(absbit)), absbit) < 0)) { return; } for (int i = BTN_JOYSTICK; i < KEY_MAX; ++i) { if (test_bit(i, keybit)) { - joy->key_map[i] = num_buttons++; + p_joypad.key_map[i] = num_buttons++; } } for (int i = BTN_MISC; i < BTN_JOYSTICK; ++i) { if (test_bit(i, keybit)) { - joy->key_map[i] = num_buttons++; + p_joypad.key_map[i] = num_buttons++; } } for (int i = 0; i < ABS_MISC; ++i) { @@ -295,21 +289,21 @@ void JoypadLinux::setup_joypad_properties(int p_id) { continue; } if (test_bit(i, absbit)) { - joy->abs_map[i] = num_axes++; - joy->abs_info[i] = memnew(input_absinfo); - if (ioctl(joy->fd, EVIOCGABS(i), joy->abs_info[i]) < 0) { - memdelete(joy->abs_info[i]); - joy->abs_info[i] = nullptr; + p_joypad.abs_map[i] = num_axes++; + p_joypad.abs_info[i] = memnew(input_absinfo); + if (ioctl(p_joypad.fd, EVIOCGABS(i), p_joypad.abs_info[i]) < 0) { + memdelete(p_joypad.abs_info[i]); + p_joypad.abs_info[i] = nullptr; } } } - joy->force_feedback = false; - joy->ff_effect_timestamp = 0; + p_joypad.force_feedback = false; + p_joypad.ff_effect_timestamp = 0; unsigned long ffbit[NBITS(FF_CNT)]; - if (ioctl(joy->fd, EVIOCGBIT(EV_FF, sizeof(ffbit)), ffbit) != -1) { + if (ioctl(p_joypad.fd, EVIOCGBIT(EV_FF, sizeof(ffbit)), ffbit) != -1) { if (test_bit(FF_RUMBLE, ffbit)) { - joy->force_feedback = true; + p_joypad.force_feedback = true; } } } @@ -353,12 +347,12 @@ void JoypadLinux::open_joypad(const char *p_path) { return; } - joypads[joy_num].reset(); - - Joypad &joy = joypads[joy_num]; - joy.fd = fd; - joy.devpath = String(p_path); - setup_joypad_properties(joy_num); + MutexLock lock(joypads_mutex[joy_num]); + Joypad &joypad = joypads[joy_num]; + joypad.reset(); + joypad.fd = fd; + joypad.devpath = String(p_path); + setup_joypad_properties(joypad); sprintf(uid, "%04x%04x", BSWAP16(inpid.bustype), 0); if (inpid.vendor && inpid.product && inpid.version) { uint16_t vendor = BSWAP16(inpid.vendor); @@ -379,13 +373,12 @@ void JoypadLinux::open_joypad(const char *p_path) { } } -void JoypadLinux::joypad_vibration_start(int p_id, float p_weak_magnitude, float p_strong_magnitude, float p_duration, uint64_t p_timestamp) { - Joypad &joy = joypads[p_id]; - if (!joy.force_feedback || joy.fd == -1 || p_weak_magnitude < 0.f || p_weak_magnitude > 1.f || p_strong_magnitude < 0.f || p_strong_magnitude > 1.f) { +void JoypadLinux::joypad_vibration_start(Joypad &p_joypad, float p_weak_magnitude, float p_strong_magnitude, float p_duration, uint64_t p_timestamp) { + if (!p_joypad.force_feedback || p_joypad.fd == -1 || p_weak_magnitude < 0.f || p_weak_magnitude > 1.f || p_strong_magnitude < 0.f || p_strong_magnitude > 1.f) { return; } - if (joy.ff_effect_id != -1) { - joypad_vibration_stop(p_id, p_timestamp); + if (p_joypad.ff_effect_id != -1) { + joypad_vibration_stop(p_joypad, p_timestamp); } struct ff_effect effect; @@ -396,7 +389,7 @@ void JoypadLinux::joypad_vibration_start(int p_id, float p_weak_magnitude, float effect.replay.length = floor(p_duration * 1000); effect.replay.delay = 0; - if (ioctl(joy.fd, EVIOCSFF, &effect) < 0) { + if (ioctl(p_joypad.fd, EVIOCSFF, &effect) < 0) { return; } @@ -404,26 +397,25 @@ void JoypadLinux::joypad_vibration_start(int p_id, float p_weak_magnitude, float play.type = EV_FF; play.code = effect.id; play.value = 1; - if (write(joy.fd, (const void *)&play, sizeof(play)) == -1) { + if (write(p_joypad.fd, (const void *)&play, sizeof(play)) == -1) { print_verbose("Couldn't write to Joypad device."); } - joy.ff_effect_id = effect.id; - joy.ff_effect_timestamp = p_timestamp; + p_joypad.ff_effect_id = effect.id; + p_joypad.ff_effect_timestamp = p_timestamp; } -void JoypadLinux::joypad_vibration_stop(int p_id, uint64_t p_timestamp) { - Joypad &joy = joypads[p_id]; - if (!joy.force_feedback || joy.fd == -1 || joy.ff_effect_id == -1) { +void JoypadLinux::joypad_vibration_stop(Joypad &p_joypad, uint64_t p_timestamp) { + if (!p_joypad.force_feedback || p_joypad.fd == -1 || p_joypad.ff_effect_id == -1) { return; } - if (ioctl(joy.fd, EVIOCRMFF, joy.ff_effect_id) < 0) { + if (ioctl(p_joypad.fd, EVIOCRMFF, p_joypad.ff_effect_id) < 0) { return; } - joy.ff_effect_id = -1; - joy.ff_effect_timestamp = p_timestamp; + p_joypad.ff_effect_id = -1; + p_joypad.ff_effect_timestamp = p_timestamp; } float JoypadLinux::axis_correct(const input_absinfo *p_abs, int p_value) const { @@ -433,104 +425,124 @@ float JoypadLinux::axis_correct(const input_absinfo *p_abs, int p_value) const { return 2.0f * (p_value - min) / (max - min) - 1.0f; } -void JoypadLinux::process_joypads() { - if (joy_mutex.try_lock() != OK) { - return; +void JoypadLinux::joypad_events_thread_func(void *p_user) { + if (p_user) { + JoypadLinux *joy = (JoypadLinux *)p_user; + joy->joypad_events_thread_run(); } +} + +void JoypadLinux::joypad_events_thread_run() { + while (!joypad_events_exit.is_set()) { + bool no_events = true; + for (int i = 0; i < JOYPADS_MAX; i++) { + MutexLock lock(joypads_mutex[i]); + Joypad &joypad = joypads[i]; + if (joypad.fd == -1) { + continue; + } + input_event event; + while (read(joypad.fd, &event, sizeof(event)) > 0) { + no_events = false; + JoypadEvent joypad_event; + joypad_event.type = event.type; + joypad_event.code = event.code; + joypad_event.value = event.value; + joypad.events.push_back(joypad_event); + } + if (errno != EAGAIN) { + close_joypad(joypad, i); + } + } + if (no_events) { + usleep(10000); // 10ms + } + } +} + +void JoypadLinux::process_joypads() { for (int i = 0; i < JOYPADS_MAX; i++) { - if (joypads[i].fd == -1) { + MutexLock lock(joypads_mutex[i]); + Joypad &joypad = joypads[i]; + if (joypad.fd == -1) { continue; } + for (uint32_t j = 0; j < joypad.events.size(); j++) { + const JoypadEvent &joypad_event = joypad.events[j]; + // joypad_event may be tainted and out of MAX_KEY range, which will cause + // joypad.key_map[joypad_event.code] to crash + if (joypad_event.code >= MAX_KEY) { + return; + } - input_event events[32]; - Joypad *joy = &joypads[i]; - - int len; - - while ((len = read(joy->fd, events, (sizeof events))) > 0) { - len /= sizeof(events[0]); - for (int j = 0; j < len; j++) { - input_event &ev = events[j]; - - // ev may be tainted and out of MAX_KEY range, which will cause - // joy->key_map[ev.code] to crash - if (ev.code >= MAX_KEY) { - return; - } - - switch (ev.type) { - case EV_KEY: - input->joy_button(i, (JoyButton)joy->key_map[ev.code], ev.value); - break; - - case EV_ABS: - - switch (ev.code) { - case ABS_HAT0X: - if (ev.value != 0) { - if (ev.value < 0) { - joy->dpad = (HatMask)((joy->dpad | HatMask::LEFT) & ~HatMask::RIGHT); - } else { - joy->dpad = (HatMask)((joy->dpad | HatMask::RIGHT) & ~HatMask::LEFT); - } + switch (joypad_event.type) { + case EV_KEY: + input->joy_button(i, (JoyButton)joypad.key_map[joypad_event.code], joypad_event.value); + break; + + case EV_ABS: + switch (joypad_event.code) { + case ABS_HAT0X: + if (joypad_event.value != 0) { + if (joypad_event.value < 0) { + joypad.dpad = (HatMask)((joypad.dpad | HatMask::LEFT) & ~HatMask::RIGHT); } else { - joy->dpad &= ~(HatMask::LEFT | HatMask::RIGHT); + joypad.dpad = (HatMask)((joypad.dpad | HatMask::RIGHT) & ~HatMask::LEFT); } - - input->joy_hat(i, (HatMask)joy->dpad); - break; - - case ABS_HAT0Y: - if (ev.value != 0) { - if (ev.value < 0) { - joy->dpad = (HatMask)((joy->dpad | HatMask::UP) & ~HatMask::DOWN); - } else { - joy->dpad = (HatMask)((joy->dpad | HatMask::DOWN) & ~HatMask::UP); - } + } else { + joypad.dpad &= ~(HatMask::LEFT | HatMask::RIGHT); + } + input->joy_hat(i, (HatMask)joypad.dpad); + break; + + case ABS_HAT0Y: + if (joypad_event.value != 0) { + if (joypad_event.value < 0) { + joypad.dpad = (HatMask)((joypad.dpad | HatMask::UP) & ~HatMask::DOWN); } else { - joy->dpad &= ~(HatMask::UP | HatMask::DOWN); + joypad.dpad = (HatMask)((joypad.dpad | HatMask::DOWN) & ~HatMask::UP); } - - input->joy_hat(i, (HatMask)joy->dpad); - break; - - default: - if (ev.code >= MAX_ABS) { - return; - } - if (joy->abs_map[ev.code] != -1 && joy->abs_info[ev.code]) { - float value = axis_correct(joy->abs_info[ev.code], ev.value); - joy->curr_axis[joy->abs_map[ev.code]] = value; - } - break; - } - break; - } + } else { + joypad.dpad &= ~(HatMask::UP | HatMask::DOWN); + } + input->joy_hat(i, (HatMask)joypad.dpad); + break; + + default: + if (joypad_event.code >= MAX_ABS) { + return; + } + if (joypad.abs_map[joypad_event.code] != -1 && joypad.abs_info[joypad_event.code]) { + float value = axis_correct(joypad.abs_info[joypad_event.code], joypad_event.value); + joypad.curr_axis[joypad.abs_map[joypad_event.code]] = value; + } + break; + } + break; } } + joypad.events.clear(); + for (int j = 0; j < MAX_ABS; j++) { - int index = joy->abs_map[j]; + int index = joypad.abs_map[j]; if (index != -1) { - input->joy_axis(i, (JoyAxis)index, joy->curr_axis[index]); + input->joy_axis(i, (JoyAxis)index, joypad.curr_axis[index]); } } - if (len == 0 || (len < 0 && errno != EAGAIN)) { - close_joypad(i); - } - if (joy->force_feedback) { + if (joypad.force_feedback) { uint64_t timestamp = input->get_joy_vibration_timestamp(i); - if (timestamp > joy->ff_effect_timestamp) { + if (timestamp > joypad.ff_effect_timestamp) { Vector2 strength = input->get_joy_vibration_strength(i); float duration = input->get_joy_vibration_duration(i); if (strength.x == 0 && strength.y == 0) { - joypad_vibration_stop(i, timestamp); + joypad_vibration_stop(joypad, timestamp); } else { - joypad_vibration_start(i, strength.x, strength.y, duration, timestamp); + joypad_vibration_start(joypad, strength.x, strength.y, duration, timestamp); } } } } - joy_mutex.unlock(); } -#endif + +#endif // JOYDEV_ENABLED diff --git a/platform/linuxbsd/joypad_linux.h b/platform/linuxbsd/joypad_linux.h index 9177465547..4afc261ce7 100644 --- a/platform/linuxbsd/joypad_linux.h +++ b/platform/linuxbsd/joypad_linux.h @@ -35,6 +35,7 @@ #include "core/input/input.h" #include "core/os/mutex.h" #include "core/os/thread.h" +#include "core/templates/local_vector.h" struct input_absinfo; @@ -51,6 +52,12 @@ private: MAX_KEY = 767, // Hack because <linux/input.h> can't be included here }; + struct JoypadEvent { + uint16_t type; + uint16_t code; + int32_t value; + }; + struct Joypad { float curr_axis[MAX_ABS]; int key_map[MAX_KEY]; @@ -65,6 +72,8 @@ private: int ff_effect_id = 0; uint64_t ff_effect_timestamp = 0; + LocalVector<JoypadEvent> events; + ~Joypad(); void reset(); }; @@ -72,29 +81,39 @@ private: #ifdef UDEV_ENABLED bool use_udev = false; #endif - SafeFlag exit_monitor; - Mutex joy_mutex; - Thread joy_thread; Input *input = nullptr; + + SafeFlag monitor_joypads_exit; + SafeFlag joypad_events_exit; + Thread monitor_joypads_thread; + Thread joypad_events_thread; + Joypad joypads[JOYPADS_MAX]; + Mutex joypads_mutex[JOYPADS_MAX]; + Vector<String> attached_devices; - static void joy_thread_func(void *p_user); + static void monitor_joypads_thread_func(void *p_user); + void monitor_joypads_thread_run(); + + void open_joypad(const char *p_path); + void setup_joypad_properties(Joypad &p_joypad); - int get_joy_from_path(String p_path) const; + void close_joypads(); + void close_joypad(const char *p_devpath); + void close_joypad(Joypad &p_joypad, int p_id); - void setup_joypad_properties(int p_id); - void close_joypad(int p_id = -1); #ifdef UDEV_ENABLED void enumerate_joypads(struct udev *p_udev); void monitor_joypads(struct udev *p_udev); #endif void monitor_joypads(); - void run_joypad_thread(); - void open_joypad(const char *p_path); - void joypad_vibration_start(int p_id, float p_weak_magnitude, float p_strong_magnitude, float p_duration, uint64_t p_timestamp); - void joypad_vibration_stop(int p_id, uint64_t p_timestamp); + void joypad_vibration_start(Joypad &p_joypad, float p_weak_magnitude, float p_strong_magnitude, float p_duration, uint64_t p_timestamp); + void joypad_vibration_stop(Joypad &p_joypad, uint64_t p_timestamp); + + static void joypad_events_thread_func(void *p_user); + void joypad_events_thread_run(); float axis_correct(const input_absinfo *p_abs, int p_value) const; }; diff --git a/platform/osx/crash_handler_osx.mm b/platform/osx/crash_handler_osx.mm index 06ed91907c..a798ba3b46 100644 --- a/platform/osx/crash_handler_osx.mm +++ b/platform/osx/crash_handler_osx.mm @@ -32,6 +32,7 @@ #include "core/config/project_settings.h" #include "core/os/os.h" +#include "core/string/print_string.h" #include "core/version.h" #include "main/main.h" @@ -85,21 +86,22 @@ static void handle_crash(int sig) { msg = proj_settings->get("debug/settings/crash_handler/message"); } - // Dump the backtrace to stderr with a message to the user - fprintf(stderr, "\n================================================================\n"); - fprintf(stderr, "%s: Program crashed with signal %d\n", __FUNCTION__, sig); - + // Tell MainLoop about the crash. This can be handled by users too in Node. if (OS::get_singleton()->get_main_loop()) { OS::get_singleton()->get_main_loop()->notification(MainLoop::NOTIFICATION_CRASH); } + // Dump the backtrace to stderr with a message to the user + print_error("\n================================================================"); + print_error(vformat("%s: Program crashed with signal %d", __FUNCTION__, sig)); + // Print the engine version just before, so that people are reminded to include the version in backtrace reports. if (String(VERSION_HASH).is_empty()) { - fprintf(stderr, "Engine version: %s\n", VERSION_FULL_NAME); + print_error(vformat("Engine version: %s", VERSION_FULL_NAME)); } else { - fprintf(stderr, "Engine version: %s (%s)\n", VERSION_FULL_NAME, VERSION_HASH); + print_error(vformat("Engine version: %s (%s)", VERSION_FULL_NAME, VERSION_HASH)); } - fprintf(stderr, "Dumping the backtrace. %s\n", msg.utf8().get_data()); + print_error(vformat("Dumping the backtrace. %s", msg)); char **strings = backtrace_symbols(bt_buffer, size); if (strings) { void *load_addr = (void *)load_address(); @@ -157,13 +159,13 @@ static void handle_crash(int sig) { } } - fprintf(stderr, "[%zu] %s\n", i, output.utf8().get_data()); + print_error(vformat("[%d] %s", (int64_t)i, output)); } free(strings); } - fprintf(stderr, "-- END OF BACKTRACE --\n"); - fprintf(stderr, "================================================================\n"); + print_error("-- END OF BACKTRACE --"); + print_error("================================================================"); // Abort to pass the error to the OS abort(); diff --git a/platform/osx/dir_access_osx.mm b/platform/osx/dir_access_osx.mm index d26f35e847..6bafb9470d 100644 --- a/platform/osx/dir_access_osx.mm +++ b/platform/osx/dir_access_osx.mm @@ -34,8 +34,8 @@ #include <errno.h> -#include <AppKit/NSWorkspace.h> -#include <Foundation/Foundation.h> +#import <AppKit/NSWorkspace.h> +#import <Foundation/Foundation.h> String DirAccessOSX::fix_unicode_name(const char *p_name) const { String fname; diff --git a/platform/osx/display_server_osx.h b/platform/osx/display_server_osx.h index fcb3a62bec..538a9bc04c 100644 --- a/platform/osx/display_server_osx.h +++ b/platform/osx/display_server_osx.h @@ -45,10 +45,11 @@ #include "platform/osx/vulkan_context_osx.h" #endif // VULKAN_ENABLED -#include <AppKit/AppKit.h> -#include <AppKit/NSCursor.h> -#include <ApplicationServices/ApplicationServices.h> -#include <CoreVideo/CoreVideo.h> +#import <AppKit/AppKit.h> +#import <AppKit/NSCursor.h> +#import <ApplicationServices/ApplicationServices.h> +#import <CoreVideo/CoreVideo.h> +#import <Foundation/Foundation.h> #undef BitMap #undef CursorShape @@ -372,7 +373,7 @@ public: void cursor_update_shape(); virtual void cursor_set_shape(CursorShape p_shape) override; virtual CursorShape cursor_get_shape() const override; - virtual void cursor_set_custom_image(const RES &p_cursor, CursorShape p_shape = CURSOR_ARROW, const Vector2 &p_hotspot = Vector2()) override; + virtual void cursor_set_custom_image(const Ref<Resource> &p_cursor, CursorShape p_shape = CURSOR_ARROW, const Vector2 &p_hotspot = Vector2()) override; virtual bool get_swap_cancel_ok() override; diff --git a/platform/osx/display_server_osx.mm b/platform/osx/display_server_osx.mm index 17a44a3fbd..a16bd2e8de 100644 --- a/platform/osx/display_server_osx.mm +++ b/platform/osx/display_server_osx.mm @@ -45,12 +45,12 @@ #include "main/main.h" #include "scene/resources/texture.h" -#include <Carbon/Carbon.h> -#include <Cocoa/Cocoa.h> -#include <IOKit/IOCFPlugIn.h> -#include <IOKit/IOKitLib.h> -#include <IOKit/hid/IOHIDKeys.h> -#include <IOKit/hid/IOHIDLib.h> +#import <Carbon/Carbon.h> +#import <Cocoa/Cocoa.h> +#import <IOKit/IOCFPlugIn.h> +#import <IOKit/IOKitLib.h> +#import <IOKit/hid/IOHIDKeys.h> +#import <IOKit/hid/IOHIDLib.h> #if defined(GLES3_ENABLED) #include "drivers/gles3/rasterizer_gles3.h" @@ -146,7 +146,7 @@ DisplayServerOSX::WindowID DisplayServerOSX::_create_window(WindowMode p_mode, V [wd.window_object setTabbingMode:NSWindowTabbingModeDisallowed]; } - CALayer *layer = [wd.window_view layer]; + CALayer *layer = [(NSView *)wd.window_view layer]; if (layer) { layer.contentsScale = scale; } @@ -174,7 +174,7 @@ DisplayServerOSX::WindowID DisplayServerOSX::_create_window(WindowMode p_mode, V wd.size.width = contentRect.size.width * scale; wd.size.height = contentRect.size.height * scale; - CALayer *layer = [wd.window_view layer]; + CALayer *layer = [(NSView *)wd.window_view layer]; if (layer) { layer.contentsScale = scale; } @@ -209,16 +209,16 @@ void DisplayServerOSX::_update_window_style(WindowData p_wd) { if (borderless_full) { // If the window covers up the screen set the level to above the main menu and hide on deactivate. - [p_wd.window_object setLevel:NSMainMenuWindowLevel + 1]; - [p_wd.window_object setHidesOnDeactivate:YES]; + [(NSWindow *)p_wd.window_object setLevel:NSMainMenuWindowLevel + 1]; + [(NSWindow *)p_wd.window_object setHidesOnDeactivate:YES]; } else { // Reset these when our window is not a borderless window that covers up the screen. if (p_wd.on_top && !p_wd.fullscreen) { - [p_wd.window_object setLevel:NSFloatingWindowLevel]; + [(NSWindow *)p_wd.window_object setLevel:NSFloatingWindowLevel]; } else { - [p_wd.window_object setLevel:NSNormalWindowLevel]; + [(NSWindow *)p_wd.window_object setLevel:NSNormalWindowLevel]; } - [p_wd.window_object setHidesOnDeactivate:NO]; + [(NSWindow *)p_wd.window_object setHidesOnDeactivate:NO]; } } @@ -234,7 +234,7 @@ void DisplayServerOSX::_set_window_per_pixel_transparency_enabled(bool p_enabled [wd.window_object setBackgroundColor:[NSColor clearColor]]; [wd.window_object setOpaque:NO]; [wd.window_object setHasShadow:NO]; - CALayer *layer = [wd.window_view layer]; + CALayer *layer = [(NSView *)wd.window_view layer]; if (layer) { [layer setBackgroundColor:[NSColor clearColor].CGColor]; [layer setOpaque:NO]; @@ -249,7 +249,7 @@ void DisplayServerOSX::_set_window_per_pixel_transparency_enabled(bool p_enabled [wd.window_object setBackgroundColor:[NSColor colorWithCalibratedWhite:1 alpha:1]]; [wd.window_object setOpaque:YES]; [wd.window_object setHasShadow:YES]; - CALayer *layer = [wd.window_view layer]; + CALayer *layer = [(NSView *)wd.window_view layer]; if (layer) { [layer setBackgroundColor:[NSColor colorWithCalibratedWhite:1 alpha:1].CGColor]; [layer setOpaque:YES]; @@ -2256,7 +2256,7 @@ void DisplayServerOSX::window_set_mode(WindowMode p_mode, WindowID p_window) { } break; case WINDOW_MODE_EXCLUSIVE_FULLSCREEN: case WINDOW_MODE_FULLSCREEN: { - [wd.window_object setLevel:NSNormalWindowLevel]; + [(NSWindow *)wd.window_object setLevel:NSNormalWindowLevel]; _set_window_per_pixel_transparency_enabled(true, p_window); if (wd.resize_disabled) { // Restore resize disabled. [wd.window_object setStyleMask:[wd.window_object styleMask] & ~NSWindowStyleMaskResizable]; @@ -2380,9 +2380,9 @@ void DisplayServerOSX::window_set_flag(WindowFlags p_flag, bool p_enabled, Windo return; } if (p_enabled) { - [wd.window_object setLevel:NSFloatingWindowLevel]; + [(NSWindow *)wd.window_object setLevel:NSFloatingWindowLevel]; } else { - [wd.window_object setLevel:NSNormalWindowLevel]; + [(NSWindow *)wd.window_object setLevel:NSNormalWindowLevel]; } } break; case WINDOW_FLAG_TRANSPARENT: { @@ -2423,7 +2423,7 @@ bool DisplayServerOSX::window_get_flag(WindowFlags p_flag, WindowID p_window) co if (wd.fullscreen) { return wd.on_top; } else { - return [wd.window_object level] == NSFloatingWindowLevel; + return [(NSWindow *)wd.window_object level] == NSFloatingWindowLevel; } } break; case WINDOW_FLAG_TRANSPARENT: { @@ -2674,7 +2674,7 @@ DisplayServerOSX::CursorShape DisplayServerOSX::cursor_get_shape() const { return cursor_shape; } -void DisplayServerOSX::cursor_set_custom_image(const RES &p_cursor, CursorShape p_shape, const Vector2 &p_hotspot) { +void DisplayServerOSX::cursor_set_custom_image(const Ref<Resource> &p_cursor, CursorShape p_shape, const Vector2 &p_hotspot) { _THREAD_SAFE_METHOD_ if (p_cursor.is_valid()) { diff --git a/platform/osx/gl_manager_osx_legacy.h b/platform/osx/gl_manager_osx_legacy.h index b5a1b9dd98..76d58de229 100644 --- a/platform/osx/gl_manager_osx_legacy.h +++ b/platform/osx/gl_manager_osx_legacy.h @@ -38,9 +38,9 @@ #include "core/templates/local_vector.h" #include "servers/display_server.h" -#include <AppKit/AppKit.h> -#include <ApplicationServices/ApplicationServices.h> -#include <CoreVideo/CoreVideo.h> +#import <AppKit/AppKit.h> +#import <ApplicationServices/ApplicationServices.h> +#import <CoreVideo/CoreVideo.h> class GLManager_OSX { public: diff --git a/platform/osx/joypad_osx.h b/platform/osx/joypad_osx.h index b09d5ce34a..3f89048ce6 100644 --- a/platform/osx/joypad_osx.h +++ b/platform/osx/joypad_osx.h @@ -32,13 +32,13 @@ #define JOYPADOSX_H #ifdef MACOS_10_0_4 -#include <IOKit/hidsystem/IOHIDUsageTables.h> +#import <IOKit/hidsystem/IOHIDUsageTables.h> #else -#include <Kernel/IOKit/hidsystem/IOHIDUsageTables.h> +#import <Kernel/IOKit/hidsystem/IOHIDUsageTables.h> #endif -#include <ForceFeedback/ForceFeedback.h> -#include <ForceFeedback/ForceFeedbackConstants.h> -#include <IOKit/hid/IOHIDLib.h> +#import <ForceFeedback/ForceFeedback.h> +#import <ForceFeedback/ForceFeedbackConstants.h> +#import <IOKit/hid/IOHIDLib.h> #include "core/input/input.h" diff --git a/platform/osx/key_mapping_osx.mm b/platform/osx/key_mapping_osx.mm index fde9206824..bfec45de58 100644 --- a/platform/osx/key_mapping_osx.mm +++ b/platform/osx/key_mapping_osx.mm @@ -30,8 +30,8 @@ #include "key_mapping_osx.h" -#include <Carbon/Carbon.h> -#include <Cocoa/Cocoa.h> +#import <Carbon/Carbon.h> +#import <Cocoa/Cocoa.h> bool KeyMappingOSX::is_numpad_key(unsigned int key) { static const unsigned int table[] = { diff --git a/platform/osx/os_osx.h b/platform/osx/os_osx.h index 53c5c8bd90..e4ec411c96 100644 --- a/platform/osx/os_osx.h +++ b/platform/osx/os_osx.h @@ -80,7 +80,7 @@ public: virtual void alert(const String &p_alert, const String &p_title = "ALERT!") override; - virtual Error open_dynamic_library(const String p_path, void *&p_library_handle, bool p_also_set_library_path = false) override; + virtual Error open_dynamic_library(const String p_path, void *&p_library_handle, bool p_also_set_library_path = false, String *r_resolved_path = nullptr) override; virtual MainLoop *get_main_loop() const override; diff --git a/platform/osx/os_osx.mm b/platform/osx/os_osx.mm index 33fee01c08..a8fa56e34b 100644 --- a/platform/osx/os_osx.mm +++ b/platform/osx/os_osx.mm @@ -150,7 +150,7 @@ void OS_OSX::alert(const String &p_alert, const String &p_title) { } } -Error OS_OSX::open_dynamic_library(const String p_path, void *&p_library_handle, bool p_also_set_library_path) { +Error OS_OSX::open_dynamic_library(const String p_path, void *&p_library_handle, bool p_also_set_library_path, String *r_resolved_path) { String path = get_framework_executable(p_path); if (!FileAccess::exists(path)) { @@ -165,6 +165,11 @@ Error OS_OSX::open_dynamic_library(const String p_path, void *&p_library_handle, p_library_handle = dlopen(path.utf8().get_data(), RTLD_NOW); ERR_FAIL_COND_V_MSG(!p_library_handle, ERR_CANT_OPEN, "Can't open dynamic library: " + p_path + ", error: " + dlerror() + "."); + + if (r_resolved_path != nullptr) { + *r_resolved_path = path; + } + return OK; } diff --git a/platform/osx/tts_osx.h b/platform/osx/tts_osx.h index 2cf6d21c18..54d419e573 100644 --- a/platform/osx/tts_osx.h +++ b/platform/osx/tts_osx.h @@ -37,8 +37,13 @@ #include "core/variant/array.h" #include "servers/display_server.h" -#include <AVFAudio/AVSpeechSynthesis.h> -#include <AppKit/AppKit.h> +#import <AppKit/AppKit.h> + +#if __has_include(<AVFAudio/AVSpeechSynthesis.h>) +#import <AVFAudio/AVSpeechSynthesis.h> +#else +#import <AVFoundation/AVFoundation.h> +#endif @interface TTS_OSX : NSObject <AVSpeechSynthesizerDelegate> { // AVSpeechSynthesizer diff --git a/platform/osx/vulkan_context_osx.h b/platform/osx/vulkan_context_osx.h index b78b4eb141..ade0f4a4c9 100644 --- a/platform/osx/vulkan_context_osx.h +++ b/platform/osx/vulkan_context_osx.h @@ -32,7 +32,7 @@ #define VULKAN_DEVICE_OSX_H #include "drivers/vulkan/vulkan_context.h" -#include <AppKit/AppKit.h> +#import <AppKit/AppKit.h> class VulkanContextOSX : public VulkanContext { virtual const char *_get_platform_surface_extension() const; diff --git a/platform/uwp/export/app_packager.h b/platform/uwp/export/app_packager.h index a32b78bf04..ea42e9bdfe 100644 --- a/platform/uwp/export/app_packager.h +++ b/platform/uwp/export/app_packager.h @@ -93,8 +93,8 @@ class AppxPackager { Vector<FileMeta> file_metadata; - ZPOS64_T central_dir_offset; - ZPOS64_T end_of_central_dir_offset; + ZPOS64_T central_dir_offset = 0; + ZPOS64_T end_of_central_dir_offset = 0; Vector<uint8_t> central_dir_data; String hash_block(const uint8_t *p_block_data, size_t p_block_len); diff --git a/platform/uwp/os_uwp.cpp b/platform/uwp/os_uwp.cpp index 22a54911f9..1614bfdcc3 100644 --- a/platform/uwp/os_uwp.cpp +++ b/platform/uwp/os_uwp.cpp @@ -631,7 +631,7 @@ OS::CursorShape OS_UWP::get_cursor_shape() const { return cursor_shape; } -void OS_UWP::set_custom_mouse_cursor(const RES &p_cursor, CursorShape p_shape, const Vector2 &p_hotspot) { +void OS_UWP::set_custom_mouse_cursor(const Ref<Resource> &p_cursor, CursorShape p_shape, const Vector2 &p_hotspot) { // TODO } @@ -647,6 +647,10 @@ Error OS_UWP::kill(const ProcessID &p_pid) { return FAILED; } +bool OS_UWP::is_process_running(const ProcessID &p_pid) const { + return false; +} + Error OS_UWP::set_cwd(const String &p_cwd) { return FAILED; } @@ -733,10 +737,15 @@ static String format_error_message(DWORD id) { return msg; } -Error OS_UWP::open_dynamic_library(const String p_path, void *&p_library_handle, bool p_also_set_library_path) { +Error OS_UWP::open_dynamic_library(const String p_path, void *&p_library_handle, bool p_also_set_library_path, String *r_resolved_path) { String full_path = "game/" + p_path; p_library_handle = (void *)LoadPackagedLibrary((LPCWSTR)(full_path.utf16().get_data()), 0); ERR_FAIL_COND_V_MSG(!p_library_handle, ERR_CANT_OPEN, "Can't open dynamic library: " + full_path + ", error: " + format_error_message(GetLastError()) + "."); + + if (r_resolved_path != nullptr) { + *r_resolved_path = full_path; + } + return OK; } diff --git a/platform/uwp/os_uwp.h b/platform/uwp/os_uwp.h index f955be1da9..bddf63ff18 100644 --- a/platform/uwp/os_uwp.h +++ b/platform/uwp/os_uwp.h @@ -198,6 +198,7 @@ public: virtual Error execute(const String &p_path, const List<String> &p_arguments, String *r_pipe = nullptr, int *r_exitcode = nullptr, bool read_stderr = false, Mutex *p_pipe_mutex = nullptr, bool p_open_console = false); virtual Error create_process(const String &p_path, const List<String> &p_arguments, ProcessID *r_child_id = nullptr, bool p_open_console = false); virtual Error kill(const ProcessID &p_pid); + virtual bool is_process_running(const ProcessID &p_pid) const; virtual bool has_environment(const String &p_var) const; virtual String get_environment(const String &p_var) const; @@ -208,7 +209,7 @@ public: void set_cursor_shape(CursorShape p_shape); CursorShape get_cursor_shape() const; - virtual void set_custom_mouse_cursor(const RES &p_cursor, CursorShape p_shape, const Vector2 &p_hotspot); + virtual void set_custom_mouse_cursor(const Ref<Resource> &p_cursor, CursorShape p_shape, const Vector2 &p_hotspot); void set_icon(const Ref<Image> &p_icon); virtual String get_executable_path() const; @@ -233,7 +234,7 @@ public: virtual void show_virtual_keyboard(const String &p_existing_text, const Rect2 &p_screen_rect = Rect2(), bool p_multiline = false, int p_max_input_length = -1, int p_cursor_start = -1, int p_cursor_end = -1); virtual void hide_virtual_keyboard(); - virtual Error open_dynamic_library(const String p_path, void *&p_library_handle, bool p_also_set_library_path = false); + virtual Error open_dynamic_library(const String p_path, void *&p_library_handle, bool p_also_set_library_path = false, String *r_resolved_path = nullptr); virtual Error close_dynamic_library(void *p_library_handle); virtual Error get_dynamic_library_symbol_handle(void *p_library_handle, const String p_name, void *&p_symbol_handle, bool p_optional = false); diff --git a/platform/windows/crash_handler_windows.cpp b/platform/windows/crash_handler_windows.cpp index 3b2c6fe9f6..6ce10e6f0f 100644 --- a/platform/windows/crash_handler_windows.cpp +++ b/platform/windows/crash_handler_windows.cpp @@ -32,6 +32,7 @@ #include "core/config/project_settings.h" #include "core/os/os.h" +#include "core/string/print_string.h" #include "core/version.h" #include "main/main.h" @@ -129,13 +130,28 @@ DWORD CrashHandlerException(EXCEPTION_POINTERS *ep) { return EXCEPTION_CONTINUE_SEARCH; } - fprintf(stderr, "\n================================================================\n"); - fprintf(stderr, "%s: Program crashed\n", __FUNCTION__); + String msg; + const ProjectSettings *proj_settings = ProjectSettings::get_singleton(); + if (proj_settings) { + msg = proj_settings->get("debug/settings/crash_handler/message"); + } + // Tell MainLoop about the crash. This can be handled by users too in Node. if (OS::get_singleton()->get_main_loop()) { OS::get_singleton()->get_main_loop()->notification(MainLoop::NOTIFICATION_CRASH); } + print_error("\n================================================================"); + print_error(vformat("%s: Program crashed", __FUNCTION__)); + + // Print the engine version just before, so that people are reminded to include the version in backtrace reports. + if (String(VERSION_HASH).is_empty()) { + print_error(vformat("Engine version: %s", VERSION_FULL_NAME)); + } else { + print_error(vformat("Engine version: %s (%s)", VERSION_FULL_NAME, VERSION_HASH)); + } + print_error(vformat("Dumping the backtrace. %s", msg)); + // Load the symbols: if (!SymInitialize(process, nullptr, false)) { return EXCEPTION_CONTINUE_SEARCH; @@ -174,20 +190,6 @@ DWORD CrashHandlerException(EXCEPTION_POINTERS *ep) { IMAGE_NT_HEADERS *h = ImageNtHeader(base); DWORD image_type = h->FileHeader.Machine; - String msg; - const ProjectSettings *proj_settings = ProjectSettings::get_singleton(); - if (proj_settings) { - msg = proj_settings->get("debug/settings/crash_handler/message"); - } - - // Print the engine version just before, so that people are reminded to include the version in backtrace reports. - if (String(VERSION_HASH).is_empty()) { - fprintf(stderr, "Engine version: %s\n", VERSION_FULL_NAME); - } else { - fprintf(stderr, "Engine version: %s (%s)\n", VERSION_FULL_NAME, VERSION_HASH); - } - fprintf(stderr, "Dumping the backtrace. %s\n", msg.utf8().get_data()); - int n = 0; do { if (skip_first) { @@ -197,12 +199,12 @@ DWORD CrashHandlerException(EXCEPTION_POINTERS *ep) { std::string fnName = symbol(process, frame.AddrPC.Offset).undecorated_name(); if (SymGetLineFromAddr64(process, frame.AddrPC.Offset, &offset_from_symbol, &line)) { - fprintf(stderr, "[%d] %s (%s:%d)\n", n, fnName.c_str(), line.FileName, line.LineNumber); + print_error(vformat("[%d] %s (%s:%d)", n, fnName.c_str(), (char *)line.FileName, (int)line.LineNumber)); } else { - fprintf(stderr, "[%d] %s\n", n, fnName.c_str()); + print_error(vformat("[%d] %s", n, fnName.c_str())); } } else { - fprintf(stderr, "[%d] ???\n", n); + print_error(vformat("[%d] ???", n)); } n++; @@ -213,8 +215,8 @@ DWORD CrashHandlerException(EXCEPTION_POINTERS *ep) { } } while (frame.AddrReturn.Offset != 0 && n < 256); - fprintf(stderr, "-- END OF BACKTRACE --\n"); - fprintf(stderr, "================================================================\n"); + print_error("-- END OF BACKTRACE --"); + print_error("================================================================"); SymCleanup(process); diff --git a/platform/windows/display_server_windows.cpp b/platform/windows/display_server_windows.cpp index 0412eb2d9c..93cab85441 100644 --- a/platform/windows/display_server_windows.cpp +++ b/platform/windows/display_server_windows.cpp @@ -1106,6 +1106,10 @@ void DisplayServerWindows::_update_window_style(WindowID p_window, bool p_repain SetWindowLongPtr(wd.hWnd, GWL_STYLE, style); SetWindowLongPtr(wd.hWnd, GWL_EXSTYLE, style_ex); + if (icon.is_valid()) { + set_icon(icon); + } + SetWindowPos(wd.hWnd, wd.always_on_top ? HWND_TOPMOST : HWND_NOTOPMOST, 0, 0, 0, 0, SWP_FRAMECHANGED | SWP_NOMOVE | SWP_NOSIZE | ((wd.no_focus || wd.is_popup) ? SWP_NOACTIVATE : 0)); if (p_repaint) { @@ -1490,7 +1494,7 @@ void DisplayServerWindows::GetMaskBitmaps(HBITMAP hSourceBitmap, COLORREF clrTra DeleteDC(hMainDC); } -void DisplayServerWindows::cursor_set_custom_image(const RES &p_cursor, CursorShape p_shape, const Vector2 &p_hotspot) { +void DisplayServerWindows::cursor_set_custom_image(const Ref<Resource> &p_cursor, CursorShape p_shape, const Vector2 &p_hotspot) { _THREAD_SAFE_METHOD_ if (p_cursor.is_valid()) { @@ -1895,9 +1899,11 @@ void DisplayServerWindows::set_icon(const Ref<Image> &p_icon) { _THREAD_SAFE_METHOD_ ERR_FAIL_COND(!p_icon.is_valid()); - Ref<Image> icon = p_icon->duplicate(); - if (icon->get_format() != Image::FORMAT_RGBA8) { - icon->convert(Image::FORMAT_RGBA8); + if (icon != p_icon) { + icon = p_icon->duplicate(); + if (icon->get_format() != Image::FORMAT_RGBA8) { + icon->convert(Image::FORMAT_RGBA8); + } } int w = icon->get_width(); int h = icon->get_height(); diff --git a/platform/windows/display_server_windows.h b/platform/windows/display_server_windows.h index 80faf71bd4..febc8a2043 100644 --- a/platform/windows/display_server_windows.h +++ b/platform/windows/display_server_windows.h @@ -399,6 +399,7 @@ class DisplayServerWindows : public DisplayServer { HHOOK mouse_monitor = nullptr; List<WindowID> popup_list; uint64_t time_since_popup = 0; + Ref<Image> icon; WindowID _create_window(WindowMode p_mode, VSyncMode p_vsync_mode, uint32_t p_flags, const Rect2i &p_rect); WindowID window_id_counter = MAIN_WINDOW_ID; @@ -561,7 +562,7 @@ public: virtual void cursor_set_shape(CursorShape p_shape) override; virtual CursorShape cursor_get_shape() const override; - virtual void cursor_set_custom_image(const RES &p_cursor, CursorShape p_shape = CURSOR_ARROW, const Vector2 &p_hotspot = Vector2()) override; + virtual void cursor_set_custom_image(const Ref<Resource> &p_cursor, CursorShape p_shape = CURSOR_ARROW, const Vector2 &p_hotspot = Vector2()) override; virtual bool get_swap_cancel_ok() override; diff --git a/platform/windows/export/export_plugin.cpp b/platform/windows/export/export_plugin.cpp index b4d8ce64b2..7627a3cba3 100644 --- a/platform/windows/export/export_plugin.cpp +++ b/platform/windows/export/export_plugin.cpp @@ -53,21 +53,24 @@ Error EditorExportPlatformWindows::_export_debug_script(const Ref<EditorExportPr return OK; } +Error EditorExportPlatformWindows::modify_template(const Ref<EditorExportPreset> &p_preset, bool p_debug, const String &p_path, int p_flags) { + if (p_preset->get("application/modify_resources")) { + return _rcedit_add_data(p_preset, p_path); + } else { + return OK; + } +} + Error EditorExportPlatformWindows::export_project(const Ref<EditorExportPreset> &p_preset, bool p_debug, const String &p_path, int p_flags) { String pck_path = p_path; if (p_preset->get("binary_format/embed_pck")) { pck_path = p_path.get_basename() + ".tmp"; } - Error err = EditorExportPlatformPC::prepare_template(p_preset, p_debug, pck_path, p_flags); - if (p_preset->get("application/modify_resources") && err == OK) { - err = _rcedit_add_data(p_preset, pck_path); - } - if (err == OK) { - err = EditorExportPlatformPC::export_project_data(p_preset, p_debug, pck_path, p_flags); - } + Error err = EditorExportPlatformPC::export_project(p_preset, p_debug, pck_path, p_flags); if (p_preset->get("codesign/enable") && err == OK) { err = _code_sign(p_preset, pck_path); } + if (p_preset->get("binary_format/embed_pck") && err == OK) { Ref<DirAccess> tmp_dir = DirAccess::create_for_path(p_path.get_base_dir()); err = tmp_dir->rename(pck_path, p_path); diff --git a/platform/windows/export/export_plugin.h b/platform/windows/export/export_plugin.h index c33c7f1f63..b48ee7c985 100644 --- a/platform/windows/export/export_plugin.h +++ b/platform/windows/export/export_plugin.h @@ -44,6 +44,7 @@ class EditorExportPlatformWindows : public EditorExportPlatformPC { public: virtual Error export_project(const Ref<EditorExportPreset> &p_preset, bool p_debug, const String &p_path, int p_flags = 0) override; + virtual Error modify_template(const Ref<EditorExportPreset> &p_preset, bool p_debug, const String &p_path, int p_flags) override; virtual Error sign_shared_object(const Ref<EditorExportPreset> &p_preset, bool p_debug, const String &p_path) override; virtual List<String> get_binary_extensions(const Ref<EditorExportPreset> &p_preset) const override; virtual void get_export_options(List<ExportOption> *r_options) override; diff --git a/platform/windows/os_windows.cpp b/platform/windows/os_windows.cpp index 8755bc65dc..68e188bbed 100644 --- a/platform/windows/os_windows.cpp +++ b/platform/windows/os_windows.cpp @@ -202,7 +202,7 @@ Error OS_Windows::get_entropy(uint8_t *r_buffer, int p_bytes) { return OK; } -Error OS_Windows::open_dynamic_library(const String p_path, void *&p_library_handle, bool p_also_set_library_path) { +Error OS_Windows::open_dynamic_library(const String p_path, void *&p_library_handle, bool p_also_set_library_path, String *r_resolved_path) { String path = p_path.replace("/", "\\"); if (!FileAccess::exists(path)) { @@ -230,6 +230,10 @@ Error OS_Windows::open_dynamic_library(const String p_path, void *&p_library_han remove_dll_directory(cookie); } + if (r_resolved_path != nullptr) { + *r_resolved_path = path; + } + return OK; } @@ -383,6 +387,31 @@ String OS_Windows::_quote_command_line_argument(const String &p_text) const { return p_text; } +static void _append_to_pipe(char *p_bytes, int p_size, String *r_pipe, Mutex *p_pipe_mutex) { + // Try to convert from default ANSI code page to Unicode. + LocalVector<wchar_t> wchars; + int total_wchars = MultiByteToWideChar(CP_ACP, 0, p_bytes, p_size, nullptr, 0); + if (total_wchars > 0) { + wchars.resize(total_wchars); + if (MultiByteToWideChar(CP_ACP, 0, p_bytes, p_size, wchars.ptr(), total_wchars) == 0) { + wchars.clear(); + } + } + + if (p_pipe_mutex) { + p_pipe_mutex->lock(); + } + if (wchars.is_empty()) { + // Let's hope it's compatible with UTF-8. + (*r_pipe) += String::utf8(p_bytes, p_size); + } else { + (*r_pipe) += String(wchars.ptr(), total_wchars); + } + if (p_pipe_mutex) { + p_pipe_mutex->unlock(); + } +} + Error OS_Windows::execute(const String &p_path, const List<String> &p_arguments, String *r_pipe, int *r_exitcode, bool read_stderr, Mutex *p_pipe_mutex, bool p_open_console) { String path = p_path.replace("/", "\\"); String command = _quote_command_line_argument(path); @@ -431,21 +460,44 @@ Error OS_Windows::execute(const String &p_path, const List<String> &p_arguments, if (r_pipe) { CloseHandle(pipe[1]); // Close pipe write handle (only child process is writing). - char buf[4096]; + + LocalVector<char> bytes; + int bytes_in_buffer = 0; + + const int CHUNK_SIZE = 4096; DWORD read = 0; for (;;) { // Read StdOut and StdErr from pipe. - bool success = ReadFile(pipe[0], buf, 4096, &read, NULL); + bytes.resize(bytes_in_buffer + CHUNK_SIZE); + const bool success = ReadFile(pipe[0], bytes.ptr() + bytes_in_buffer, CHUNK_SIZE, &read, NULL); if (!success || read == 0) { break; } - if (p_pipe_mutex) { - p_pipe_mutex->lock(); + + // Assume that all possible encodings are ASCII-compatible. + // Break at newline to allow receiving long output in portions. + int newline_index = -1; + for (int i = read - 1; i >= 0; i--) { + if (bytes[bytes_in_buffer + i] == '\n') { + newline_index = i; + break; + } } - (*r_pipe) += String::utf8(buf, read); - if (p_pipe_mutex) { - p_pipe_mutex->unlock(); + if (newline_index == -1) { + bytes_in_buffer += read; + continue; } + + const int bytes_to_convert = bytes_in_buffer + (newline_index + 1); + _append_to_pipe(bytes.ptr(), bytes_to_convert, r_pipe, p_pipe_mutex); + + bytes_in_buffer = read - (newline_index + 1); + memmove(bytes.ptr(), bytes.ptr() + bytes_to_convert, bytes_in_buffer); + } + + if (bytes_in_buffer > 0) { + _append_to_pipe(bytes.ptr(), bytes_in_buffer, r_pipe, p_pipe_mutex); } + CloseHandle(pipe[0]); // Close pipe read handle. } else { WaitForSingleObject(pi.pi.hProcess, INFINITE); @@ -513,6 +565,25 @@ int OS_Windows::get_process_id() const { return _getpid(); } +bool OS_Windows::is_process_running(const ProcessID &p_pid) const { + if (!process_map->has(p_pid)) { + return false; + } + + const PROCESS_INFORMATION &pi = (*process_map)[p_pid].pi; + + DWORD dw_exit_code = 0; + if (!GetExitCodeProcess(pi.hProcess, &dw_exit_code)) { + return false; + } + + if (dw_exit_code != STILL_ACTIVE) { + return false; + } + + return true; +} + Error OS_Windows::set_cwd(const String &p_cwd) { if (_wchdir((LPCWSTR)(p_cwd.utf16().get_data())) != 0) { return ERR_CANT_OPEN; diff --git a/platform/windows/os_windows.h b/platform/windows/os_windows.h index 370cb77fde..378438a075 100644 --- a/platform/windows/os_windows.h +++ b/platform/windows/os_windows.h @@ -108,7 +108,7 @@ public: virtual Error get_entropy(uint8_t *r_buffer, int p_bytes) override; - virtual Error open_dynamic_library(const String p_path, void *&p_library_handle, bool p_also_set_library_path = false) override; + virtual Error open_dynamic_library(const String p_path, void *&p_library_handle, bool p_also_set_library_path = false, String *r_resolved_path = nullptr) override; virtual Error close_dynamic_library(void *p_library_handle) override; virtual Error get_dynamic_library_symbol_handle(void *p_library_handle, const String p_name, void *&p_symbol_handle, bool p_optional = false) override; @@ -132,6 +132,7 @@ public: virtual Error create_process(const String &p_path, const List<String> &p_arguments, ProcessID *r_child_id = nullptr, bool p_open_console = false) override; virtual Error kill(const ProcessID &p_pid) override; virtual int get_process_id() const override; + virtual bool is_process_running(const ProcessID &p_pid) const override; virtual bool has_environment(const String &p_var) const override; virtual String get_environment(const String &p_var) const override; |