summaryrefslogtreecommitdiffstats
path: root/platform
diff options
context:
space:
mode:
Diffstat (limited to 'platform')
-rw-r--r--platform/android/display_server_android.h2
-rw-r--r--platform/android/doc_classes/EditorExportPlatformAndroid.xml8
-rw-r--r--platform/android/export/export_plugin.cpp54
-rw-r--r--platform/android/export/export_plugin.h9
-rw-r--r--platform/android/java/lib/src/org/godotengine/godot/Godot.java5
-rw-r--r--platform/android/java/lib/src/org/godotengine/godot/input/GodotGestureHandler.kt3
-rw-r--r--platform/android/java/lib/src/org/godotengine/godot/utils/GodotNetUtils.java38
-rw-r--r--platform/android/java_godot_lib_jni.cpp33
-rw-r--r--platform/android/java_godot_wrapper.cpp12
-rw-r--r--platform/android/java_godot_wrapper.h2
-rw-r--r--platform/android/os_android.cpp20
-rw-r--r--platform/android/os_android.h4
-rw-r--r--platform/android/plugin/godot_plugin_jni.cpp3
-rw-r--r--platform/ios/display_server_ios.h2
-rw-r--r--platform/ios/doc_classes/EditorExportPlatformIOS.xml22
-rw-r--r--platform/ios/export/export_plugin.cpp18
-rw-r--r--platform/ios/export/export_plugin.h5
-rw-r--r--platform/ios/ios.mm18
-rw-r--r--platform/ios/os_ios.mm10
-rw-r--r--platform/linuxbsd/freedesktop_portal_desktop.cpp5
-rw-r--r--platform/linuxbsd/freedesktop_screensaver.cpp5
-rw-r--r--platform/linuxbsd/joypad_linux.cpp48
-rw-r--r--platform/linuxbsd/os_linuxbsd.cpp44
-rw-r--r--platform/linuxbsd/os_linuxbsd.h3
-rw-r--r--platform/linuxbsd/x11/detect_prime_x11.cpp3
-rw-r--r--platform/linuxbsd/x11/display_server_x11.cpp27
-rw-r--r--platform/linuxbsd/x11/display_server_x11.h5
-rw-r--r--platform/linuxbsd/x11/gl_manager_x11.cpp3
-rw-r--r--platform/macos/detect.py2
-rw-r--r--platform/macos/display_server_macos.h2
-rw-r--r--platform/macos/display_server_macos.mm10
-rw-r--r--platform/macos/doc_classes/EditorExportPlatformMacOS.xml8
-rw-r--r--platform/macos/export/export_plugin.cpp100
-rw-r--r--platform/macos/export/export_plugin.h11
-rw-r--r--platform/macos/os_macos.h2
-rw-r--r--platform/macos/os_macos.mm29
-rw-r--r--platform/uwp/export/export_plugin.cpp8
-rw-r--r--platform/uwp/export/export_plugin.h5
-rw-r--r--platform/web/display_server_web.h2
-rw-r--r--platform/web/export/export_plugin.cpp4
-rw-r--r--platform/windows/detect.py2
-rw-r--r--platform/windows/display_server_windows.h3
-rw-r--r--platform/windows/doc_classes/EditorExportPlatformWindows.xml3
-rw-r--r--platform/windows/export/export_plugin.cpp24
-rw-r--r--platform/windows/export/export_plugin.h6
-rw-r--r--platform/windows/os_windows.cpp43
-rw-r--r--platform/windows/os_windows.h2
47 files changed, 485 insertions, 192 deletions
diff --git a/platform/android/display_server_android.h b/platform/android/display_server_android.h
index b2400d81dc..ad1cbddb08 100644
--- a/platform/android/display_server_android.h
+++ b/platform/android/display_server_android.h
@@ -39,6 +39,8 @@ class RenderingDeviceVulkan;
#endif
class DisplayServerAndroid : public DisplayServer {
+ // No need to register with GDCLASS, it's platform-specific and nothing is added.
+
String rendering_driver;
// https://developer.android.com/reference/android/view/PointerIcon
diff --git a/platform/android/doc_classes/EditorExportPlatformAndroid.xml b/platform/android/doc_classes/EditorExportPlatformAndroid.xml
index 570e8f01f1..11129ca149 100644
--- a/platform/android/doc_classes/EditorExportPlatformAndroid.xml
+++ b/platform/android/doc_classes/EditorExportPlatformAndroid.xml
@@ -58,21 +58,27 @@
</member>
<member name="keystore/debug" type="String" setter="" getter="">
Path of the debug keystore file.
+ Can be overridden with the environment variable [code]GODOT_ANDROID_KEYSTORE_DEBUG_PATH[/code].
</member>
<member name="keystore/debug_password" type="String" setter="" getter="">
Password for the debug keystore file.
+ Can be overridden with the environment variable [code]GODOT_ANDROID_KEYSTORE_DEBUG_PASSWORD[/code].
</member>
<member name="keystore/debug_user" type="String" setter="" getter="">
User name for the debug keystore file.
+ Can be overridden with the environment variable [code]GODOT_ANDROID_KEYSTORE_DEBUG_USER[/code].
</member>
<member name="keystore/release" type="String" setter="" getter="">
Path of the release keystore file.
+ Can be overridden with the environment variable [code]GODOT_ANDROID_KEYSTORE_RELEASE_PATH[/code].
</member>
<member name="keystore/release_password" type="String" setter="" getter="">
Password for the release keystore file.
+ Can be overridden with the environment variable [code]GODOT_ANDROID_KEYSTORE_RELEASE_PASSWORD[/code].
</member>
<member name="keystore/release_user" type="String" setter="" getter="">
User name for the release keystore file.
+ Can be overridden with the environment variable [code]GODOT_ANDROID_KEYSTORE_RELEASE_USER[/code].
</member>
<member name="launcher_icons/adaptive_background_432x432" type="String" setter="" getter="">
Background layer of the application adaptive icon file.
@@ -153,7 +159,7 @@
Must be required by a HostApduService or OffHostApduService to ensure that only the system can bind to it. See [url=https://developer.android.com/reference/android/Manifest.permission#BIND_NFC_SERVICE]BIND_NFC_SERVICE[/url].
</member>
<member name="permissions/bind_notification_listener_service" type="bool" setter="" getter="">
- Must be required by an NotificationListenerService, to ensure that only the system can bind to it. See [url=https://developer.android.com/reference/android/Manifest.permission#BIND_NOTIFICATION_LISTENER_SERVICE]BIND_NOTIFICATION_LISTENER_SERVICE[/url].
+ Must be required by a NotificationListenerService, to ensure that only the system can bind to it. See [url=https://developer.android.com/reference/android/Manifest.permission#BIND_NOTIFICATION_LISTENER_SERVICE]BIND_NOTIFICATION_LISTENER_SERVICE[/url].
</member>
<member name="permissions/bind_print_service" type="bool" setter="" getter="">
Must be required by a PrintService, to ensure that only the system can bind to it. See [url=https://developer.android.com/reference/android/Manifest.permission#BIND_PRINT_SERVICE]BIND_PRINT_SERVICE[/url].
diff --git a/platform/android/export/export_plugin.cpp b/platform/android/export/export_plugin.cpp
index f52edf2b61..d8dd453faf 100644
--- a/platform/android/export/export_plugin.cpp
+++ b/platform/android/export/export_plugin.cpp
@@ -1825,12 +1825,12 @@ void EditorExportPlatformAndroid::get_export_options(List<ExportOption> *r_optio
r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, vformat("%s/%s", PNAME("architectures"), abi)), is_default));
}
- r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "keystore/debug", PROPERTY_HINT_GLOBAL_FILE, "*.keystore,*.jks"), ""));
- r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "keystore/debug_user"), ""));
- r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "keystore/debug_password"), ""));
- r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "keystore/release", PROPERTY_HINT_GLOBAL_FILE, "*.keystore,*.jks"), ""));
- r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "keystore/release_user"), ""));
- r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "keystore/release_password"), ""));
+ r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "keystore/debug", PROPERTY_HINT_GLOBAL_FILE, "*.keystore,*.jks", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_SECRET), ""));
+ r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "keystore/debug_user", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_SECRET), ""));
+ r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "keystore/debug_password", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_SECRET), ""));
+ r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "keystore/release", PROPERTY_HINT_GLOBAL_FILE, "*.keystore,*.jks", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_SECRET), ""));
+ r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "keystore/release_user", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_SECRET), ""));
+ r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "keystore/release_password", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_SECRET), ""));
r_options->push_back(ExportOption(PropertyInfo(Variant::INT, "version/code", PROPERTY_HINT_RANGE, "1,4096,1,or_greater"), 1));
r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "version/name"), "1.0"));
@@ -2277,9 +2277,9 @@ bool EditorExportPlatformAndroid::has_valid_export_configuration(const Ref<Edito
// Validate the rest of the export configuration.
- String dk = p_preset->get("keystore/debug");
- String dk_user = p_preset->get("keystore/debug_user");
- String dk_password = p_preset->get("keystore/debug_password");
+ String dk = p_preset->get_or_env("keystore/debug", ENV_ANDROID_KEYSTORE_DEBUG_PATH);
+ String dk_user = p_preset->get_or_env("keystore/debug_user", ENV_ANDROID_KEYSTORE_DEBUG_USER);
+ String dk_password = p_preset->get_or_env("keystore/debug_password", ENV_ANDROID_KEYSTORE_DEBUG_PASS);
if ((dk.is_empty() || dk_user.is_empty() || dk_password.is_empty()) && (!dk.is_empty() || !dk_user.is_empty() || !dk_password.is_empty())) {
valid = false;
@@ -2294,9 +2294,9 @@ bool EditorExportPlatformAndroid::has_valid_export_configuration(const Ref<Edito
}
}
- String rk = p_preset->get("keystore/release");
- String rk_user = p_preset->get("keystore/release_user");
- String rk_password = p_preset->get("keystore/release_password");
+ String rk = p_preset->get_or_env("keystore/release", ENV_ANDROID_KEYSTORE_RELEASE_PATH);
+ String rk_user = p_preset->get_or_env("keystore/release_user", ENV_ANDROID_KEYSTORE_RELEASE_USER);
+ String rk_password = p_preset->get_or_env("keystore/release_password", ENV_ANDROID_KEYSTORE_RELEASE_PASS);
if ((rk.is_empty() || rk_user.is_empty() || rk_password.is_empty()) && (!rk.is_empty() || !rk_user.is_empty() || !rk_password.is_empty())) {
valid = false;
@@ -2507,9 +2507,9 @@ void EditorExportPlatformAndroid::get_command_line_flags(const Ref<EditorExportP
Error EditorExportPlatformAndroid::sign_apk(const Ref<EditorExportPreset> &p_preset, bool p_debug, const String &export_path, EditorProgress &ep) {
int export_format = int(p_preset->get("gradle_build/export_format"));
String export_label = export_format == EXPORT_FORMAT_AAB ? "AAB" : "APK";
- String release_keystore = p_preset->get("keystore/release");
- String release_username = p_preset->get("keystore/release_user");
- String release_password = p_preset->get("keystore/release_password");
+ String release_keystore = p_preset->get_or_env("keystore/release", ENV_ANDROID_KEYSTORE_RELEASE_PATH);
+ String release_username = p_preset->get_or_env("keystore/release_user", ENV_ANDROID_KEYSTORE_RELEASE_USER);
+ String release_password = p_preset->get_or_env("keystore/release_password", ENV_ANDROID_KEYSTORE_RELEASE_PASS);
String target_sdk_version = p_preset->get("gradle_build/target_sdk");
if (!target_sdk_version.is_valid_int()) {
target_sdk_version = itos(DEFAULT_TARGET_SDK_VERSION);
@@ -2529,9 +2529,9 @@ Error EditorExportPlatformAndroid::sign_apk(const Ref<EditorExportPreset> &p_pre
String password;
String user;
if (p_debug) {
- keystore = p_preset->get("keystore/debug");
- password = p_preset->get("keystore/debug_password");
- user = p_preset->get("keystore/debug_user");
+ keystore = p_preset->get_or_env("keystore/debug", ENV_ANDROID_KEYSTORE_DEBUG_PATH);
+ password = p_preset->get_or_env("keystore/debug_password", ENV_ANDROID_KEYSTORE_DEBUG_PASS);
+ user = p_preset->get_or_env("keystore/debug_user", ENV_ANDROID_KEYSTORE_DEBUG_USER);
if (keystore.is_empty()) {
keystore = EDITOR_GET("export/android/debug_keystore");
@@ -2791,7 +2791,11 @@ Error EditorExportPlatformAndroid::export_project_helper(const Ref<EditorExportP
CustomExportData user_data;
user_data.assets_directory = assets_directory;
user_data.debug = p_debug;
- err = export_project_files(p_preset, p_debug, rename_and_store_file_in_gradle_project, &user_data, copy_gradle_so);
+ if (p_flags & DEBUG_FLAG_DUMB_CLIENT) {
+ err = export_project_files(p_preset, p_debug, ignore_apk_file, &user_data, copy_gradle_so);
+ } else {
+ err = export_project_files(p_preset, p_debug, rename_and_store_file_in_gradle_project, &user_data, copy_gradle_so);
+ }
if (err != OK) {
add_message(EXPORT_MESSAGE_ERROR, TTR("Export"), TTR("Could not export project files to gradle project."));
return err;
@@ -2882,9 +2886,9 @@ Error EditorExportPlatformAndroid::export_project_helper(const Ref<EditorExportP
if (should_sign) {
if (p_debug) {
- String debug_keystore = p_preset->get("keystore/debug");
- String debug_password = p_preset->get("keystore/debug_password");
- String debug_user = p_preset->get("keystore/debug_user");
+ String debug_keystore = p_preset->get_or_env("keystore/debug", ENV_ANDROID_KEYSTORE_DEBUG_PATH);
+ String debug_password = p_preset->get_or_env("keystore/debug_password", ENV_ANDROID_KEYSTORE_DEBUG_PASS);
+ String debug_user = p_preset->get_or_env("keystore/debug_user", ENV_ANDROID_KEYSTORE_DEBUG_USER);
if (debug_keystore.is_empty()) {
debug_keystore = EDITOR_GET("export/android/debug_keystore");
@@ -2904,9 +2908,9 @@ Error EditorExportPlatformAndroid::export_project_helper(const Ref<EditorExportP
cmdline.push_back("-Pdebug_keystore_password=" + debug_password); // argument to specify the debug keystore password.
} else {
// Pass the release keystore info as well
- String release_keystore = p_preset->get("keystore/release");
- String release_username = p_preset->get("keystore/release_user");
- String release_password = p_preset->get("keystore/release_password");
+ String release_keystore = p_preset->get_or_env("keystore/release", ENV_ANDROID_KEYSTORE_RELEASE_PATH);
+ String release_username = p_preset->get_or_env("keystore/release_user", ENV_ANDROID_KEYSTORE_RELEASE_USER);
+ String release_password = p_preset->get_or_env("keystore/release_password", ENV_ANDROID_KEYSTORE_RELEASE_PASS);
if (release_keystore.is_relative_path()) {
release_keystore = OS::get_singleton()->get_resource_dir().path_join(release_keystore).simplify_path();
}
diff --git a/platform/android/export/export_plugin.h b/platform/android/export/export_plugin.h
index f9dad5ce5e..390b8c6465 100644
--- a/platform/android/export/export_plugin.h
+++ b/platform/android/export/export_plugin.h
@@ -49,6 +49,15 @@ const String SPLASH_CONFIG_XML_CONTENT = R"SPLASH(<?xml version="1.0" encoding="
</layer-list>
)SPLASH";
+// Optional environment variables for defining confidential information. If any
+// of these is set, they will override the values set in the credentials file.
+const String ENV_ANDROID_KEYSTORE_DEBUG_PATH = "GODOT_ANDROID_KEYSTORE_DEBUG_PATH";
+const String ENV_ANDROID_KEYSTORE_DEBUG_USER = "GODOT_ANDROID_KEYSTORE_DEBUG_USER";
+const String ENV_ANDROID_KEYSTORE_DEBUG_PASS = "GODOT_ANDROID_KEYSTORE_DEBUG_PASSWORD";
+const String ENV_ANDROID_KEYSTORE_RELEASE_PATH = "GODOT_ANDROID_KEYSTORE_RELEASE_PATH";
+const String ENV_ANDROID_KEYSTORE_RELEASE_USER = "GODOT_ANDROID_KEYSTORE_RELEASE_USER";
+const String ENV_ANDROID_KEYSTORE_RELEASE_PASS = "GODOT_ANDROID_KEYSTORE_RELEASE_PASSWORD";
+
struct LauncherIcon {
const char *export_path;
int dimensions = 0;
diff --git a/platform/android/java/lib/src/org/godotengine/godot/Godot.java b/platform/android/java/lib/src/org/godotengine/godot/Godot.java
index e111bd18ca..99527ccf3a 100644
--- a/platform/android/java/lib/src/org/godotengine/godot/Godot.java
+++ b/platform/android/java/lib/src/org/godotengine/godot/Godot.java
@@ -1044,6 +1044,11 @@ public class Godot extends Fragment implements SensorEventListener, IDownloaderC
return PermissionsUtil.getGrantedPermissions(getActivity());
}
+ @Keep
+ private String getCACertificates() {
+ return GodotNetUtils.getCACertificates();
+ }
+
/**
* The download state should trigger changes in the UI --- it may be useful
* to show the state as being indeterminate at times. This sample can be
diff --git a/platform/android/java/lib/src/org/godotengine/godot/input/GodotGestureHandler.kt b/platform/android/java/lib/src/org/godotengine/godot/input/GodotGestureHandler.kt
index af1f38f89c..7dc5fb6f83 100644
--- a/platform/android/java/lib/src/org/godotengine/godot/input/GodotGestureHandler.kt
+++ b/platform/android/java/lib/src/org/godotengine/godot/input/GodotGestureHandler.kt
@@ -197,7 +197,10 @@ internal class GodotGestureHandler : SimpleOnGestureListener(), OnScaleGestureLi
if (event.actionMasked == MotionEvent.ACTION_UP) {
nextDownIsDoubleTap = false
GodotInputHandler.handleMotionEvent(event)
+ } else if (event.actionMasked == MotionEvent.ACTION_MOVE && panningAndScalingEnabled == false) {
+ GodotInputHandler.handleMotionEvent(event)
}
+
return true
}
diff --git a/platform/android/java/lib/src/org/godotengine/godot/utils/GodotNetUtils.java b/platform/android/java/lib/src/org/godotengine/godot/utils/GodotNetUtils.java
index 401c105cd7..c31d56a3e1 100644
--- a/platform/android/java/lib/src/org/godotengine/godot/utils/GodotNetUtils.java
+++ b/platform/android/java/lib/src/org/godotengine/godot/utils/GodotNetUtils.java
@@ -33,11 +33,17 @@ package org.godotengine.godot.utils;
import android.app.Activity;
import android.content.Context;
import android.net.wifi.WifiManager;
+import android.util.Base64;
import android.util.Log;
+import java.io.StringWriter;
+import java.security.KeyStore;
+import java.security.cert.X509Certificate;
+import java.util.Enumeration;
+
/**
* This class handles Android-specific networking functions.
- * For now, it only provides access to WifiManager.MulticastLock, which is needed on some devices
+ * It provides access to the CA certificates KeyStore, and the WifiManager.MulticastLock, which is needed on some devices
* to receive broadcast and multicast packets.
*/
public class GodotNetUtils {
@@ -79,4 +85,34 @@ public class GodotNetUtils {
Log.e("Godot", "Exception during multicast lock release: " + e);
}
}
+
+ /**
+ * Retrieves the list of trusted CA certificates from the "AndroidCAStore" and returns them in PRM format.
+ * @see https://developer.android.com/reference/java/security/KeyStore .
+ * @return A string of concatenated X509 certificates in PEM format.
+ */
+ public static String getCACertificates() {
+ try {
+ KeyStore ks = KeyStore.getInstance("AndroidCAStore");
+ StringBuilder writer = new StringBuilder();
+
+ if (ks != null) {
+ ks.load(null, null);
+ Enumeration<String> aliases = ks.aliases();
+
+ while (aliases.hasMoreElements()) {
+ String alias = (String)aliases.nextElement();
+
+ X509Certificate cert = (X509Certificate)ks.getCertificate(alias);
+ writer.append("-----BEGIN CERTIFICATE-----\n");
+ writer.append(Base64.encodeToString(cert.getEncoded(), Base64.DEFAULT));
+ writer.append("-----END CERTIFICATE-----\n");
+ }
+ }
+ return writer.toString();
+ } catch (Exception e) {
+ Log.e("Godot", "Exception while reading CA certificates: " + e);
+ return "";
+ }
+ }
}
diff --git a/platform/android/java_godot_lib_jni.cpp b/platform/android/java_godot_lib_jni.cpp
index 71339c9443..18091649e3 100644
--- a/platform/android/java_godot_lib_jni.cpp
+++ b/platform/android/java_godot_lib_jni.cpp
@@ -446,39 +446,29 @@ JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_callobject(JNIEnv *en
Object *obj = ObjectDB::get_instance(ObjectID(ID));
ERR_FAIL_NULL(obj);
- int res = env->PushLocalFrame(16);
- ERR_FAIL_COND(res != 0);
-
String str_method = jstring_to_string(method, env);
int count = env->GetArrayLength(params);
+
Variant *vlist = (Variant *)alloca(sizeof(Variant) * count);
- Variant **vptr = (Variant **)alloca(sizeof(Variant *) * count);
+ const Variant **vptr = (const Variant **)alloca(sizeof(Variant *) * count);
+
for (int i = 0; i < count; i++) {
jobject jobj = env->GetObjectArrayElement(params, i);
- Variant v;
- if (jobj) {
- v = _jobject_to_variant(env, jobj);
- }
- memnew_placement(&vlist[i], Variant);
- vlist[i] = v;
+ ERR_FAIL_NULL(jobj);
+ memnew_placement(&vlist[i], Variant(_jobject_to_variant(env, jobj)));
vptr[i] = &vlist[i];
env->DeleteLocalRef(jobj);
}
Callable::CallError err;
- obj->callp(str_method, (const Variant **)vptr, count, err);
-
- env->PopLocalFrame(nullptr);
+ obj->callp(str_method, vptr, count, err);
}
JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_calldeferred(JNIEnv *env, jclass clazz, jlong ID, jstring method, jobjectArray params) {
Object *obj = ObjectDB::get_instance(ObjectID(ID));
ERR_FAIL_NULL(obj);
- int res = env->PushLocalFrame(16);
- ERR_FAIL_COND(res != 0);
-
String str_method = jstring_to_string(method, env);
int count = env->GetArrayLength(params);
@@ -488,16 +478,13 @@ JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_calldeferred(JNIEnv *
for (int i = 0; i < count; i++) {
jobject jobj = env->GetObjectArrayElement(params, i);
- if (jobj) {
- args[i] = _jobject_to_variant(env, jobj);
- }
- env->DeleteLocalRef(jobj);
+ ERR_FAIL_NULL(jobj);
+ memnew_placement(&args[i], Variant(_jobject_to_variant(env, jobj)));
argptrs[i] = &args[i];
+ env->DeleteLocalRef(jobj);
}
- MessageQueue::get_singleton()->push_callp(obj, str_method, (const Variant **)argptrs, count);
-
- env->PopLocalFrame(nullptr);
+ MessageQueue::get_singleton()->push_callp(obj, str_method, argptrs, count);
}
JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_requestPermissionResult(JNIEnv *env, jclass clazz, jstring p_permission, jboolean p_result) {
diff --git a/platform/android/java_godot_wrapper.cpp b/platform/android/java_godot_wrapper.cpp
index 9d9d087896..2b504ad69b 100644
--- a/platform/android/java_godot_wrapper.cpp
+++ b/platform/android/java_godot_wrapper.cpp
@@ -70,6 +70,7 @@ GodotJavaWrapper::GodotJavaWrapper(JNIEnv *p_env, jobject p_activity, jobject p_
_request_permission = p_env->GetMethodID(godot_class, "requestPermission", "(Ljava/lang/String;)Z");
_request_permissions = p_env->GetMethodID(godot_class, "requestPermissions", "()Z");
_get_granted_permissions = p_env->GetMethodID(godot_class, "getGrantedPermissions", "()[Ljava/lang/String;");
+ _get_ca_certificates = p_env->GetMethodID(godot_class, "getCACertificates", "()Ljava/lang/String;");
_init_input_devices = p_env->GetMethodID(godot_class, "initInputDevices", "()V");
_get_surface = p_env->GetMethodID(godot_class, "getSurface", "()Landroid/view/Surface;");
_is_activity_resumed = p_env->GetMethodID(godot_class, "isActivityResumed", "()Z");
@@ -310,6 +311,17 @@ Vector<String> GodotJavaWrapper::get_granted_permissions() const {
return permissions_list;
}
+String GodotJavaWrapper::get_ca_certificates() const {
+ if (_get_ca_certificates) {
+ JNIEnv *env = get_jni_env();
+ ERR_FAIL_NULL_V(env, String());
+ jstring s = (jstring)env->CallObjectMethod(godot_instance, _get_ca_certificates);
+ return jstring_to_string(s, env);
+ } else {
+ return String();
+ }
+}
+
void GodotJavaWrapper::init_input_devices() {
if (_init_input_devices) {
JNIEnv *env = get_jni_env();
diff --git a/platform/android/java_godot_wrapper.h b/platform/android/java_godot_wrapper.h
index 1bd79584d8..05144380e6 100644
--- a/platform/android/java_godot_wrapper.h
+++ b/platform/android/java_godot_wrapper.h
@@ -60,6 +60,7 @@ private:
jmethodID _request_permission = nullptr;
jmethodID _request_permissions = nullptr;
jmethodID _get_granted_permissions = nullptr;
+ jmethodID _get_ca_certificates = nullptr;
jmethodID _init_input_devices = nullptr;
jmethodID _get_surface = nullptr;
jmethodID _is_activity_resumed = nullptr;
@@ -98,6 +99,7 @@ public:
bool request_permission(const String &p_name);
bool request_permissions();
Vector<String> get_granted_permissions() const;
+ String get_ca_certificates() const;
void init_input_devices();
jobject get_surface();
bool is_activity_resumed();
diff --git a/platform/android/os_android.cpp b/platform/android/os_android.cpp
index 725fea8d54..73081e35e7 100644
--- a/platform/android/os_android.cpp
+++ b/platform/android/os_android.cpp
@@ -311,7 +311,11 @@ String OS_Android::get_resource_dir() const {
#ifdef TOOLS_ENABLED
return OS_Unix::get_resource_dir();
#else
- return "/"; //android has its own filesystem for resources inside the APK
+ if (remote_fs_dir.is_empty()) {
+ return "/"; // Android has its own filesystem for resources inside the APK
+ } else {
+ return remote_fs_dir;
+ }
#endif
}
@@ -753,5 +757,19 @@ Error OS_Android::kill(const ProcessID &p_pid) {
return OS_Unix::kill(p_pid);
}
+String OS_Android::get_system_ca_certificates() {
+ return godot_java->get_ca_certificates();
+}
+
+Error OS_Android::setup_remote_filesystem(const String &p_server_host, int p_port, const String &p_password, String &r_project_path) {
+ r_project_path = get_user_data_dir();
+ Error err = OS_Unix::setup_remote_filesystem(p_server_host, p_port, p_password, r_project_path);
+ if (err == OK) {
+ remote_fs_dir = r_project_path;
+ FileAccess::make_default<FileAccessFilesystemJAndroid>(FileAccess::ACCESS_RESOURCES);
+ }
+ return err;
+}
+
OS_Android::~OS_Android() {
}
diff --git a/platform/android/os_android.h b/platform/android/os_android.h
index 53910b1498..f1d08b7cfe 100644
--- a/platform/android/os_android.h
+++ b/platform/android/os_android.h
@@ -57,6 +57,7 @@ private:
mutable String data_dir_cache;
mutable String cache_dir_cache;
+ mutable String remote_fs_dir;
AudioDriverOpenSL audio_driver_android;
@@ -159,6 +160,9 @@ 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 create_instance(const List<String> &p_arguments, ProcessID *r_child_id = nullptr) override;
virtual Error kill(const ProcessID &p_pid) override;
+ virtual String get_system_ca_certificates() override;
+
+ virtual Error setup_remote_filesystem(const String &p_server_host, int p_port, const String &p_password, String &r_project_path) override;
virtual bool _check_internal_feature_support(const String &p_feature) override;
OS_Android(GodotJavaWrapper *p_godot_java, GodotIOJavaWrapper *p_godot_io_java, bool p_use_apk_expansion);
diff --git a/platform/android/plugin/godot_plugin_jni.cpp b/platform/android/plugin/godot_plugin_jni.cpp
index 4bb90cb971..843c015d49 100644
--- a/platform/android/plugin/godot_plugin_jni.cpp
+++ b/platform/android/plugin/godot_plugin_jni.cpp
@@ -120,7 +120,8 @@ JNIEXPORT void JNICALL Java_org_godotengine_godot_plugin_GodotPlugin_nativeEmitS
for (int i = 0; i < count; i++) {
jobject j_param = env->GetObjectArrayElement(j_signal_params, i);
- variant_params[i] = _jobject_to_variant(env, j_param);
+ ERR_FAIL_NULL(j_param);
+ memnew_placement(&variant_params[i], Variant(_jobject_to_variant(env, j_param)));
args[i] = &variant_params[i];
env->DeleteLocalRef(j_param);
}
diff --git a/platform/ios/display_server_ios.h b/platform/ios/display_server_ios.h
index 6eaa7c8edc..57f601a858 100644
--- a/platform/ios/display_server_ios.h
+++ b/platform/ios/display_server_ios.h
@@ -55,7 +55,7 @@
#import <QuartzCore/CAMetalLayer.h>
class DisplayServerIOS : public DisplayServer {
- GDCLASS(DisplayServerIOS, DisplayServer)
+ // No need to register with GDCLASS, it's platform-specific and nothing is added.
_THREAD_SAFE_CLASS_
diff --git a/platform/ios/doc_classes/EditorExportPlatformIOS.xml b/platform/ios/doc_classes/EditorExportPlatformIOS.xml
index ef2b0a256d..381884067b 100644
--- a/platform/ios/doc_classes/EditorExportPlatformIOS.xml
+++ b/platform/ios/doc_classes/EditorExportPlatformIOS.xml
@@ -35,9 +35,11 @@
</member>
<member name="application/provisioning_profile_uuid_debug" type="String" setter="" getter="">
UUID of the provisioning profile. If left empty, Xcode will download or create a provisioning profile automatically. See [url=https://developer.apple.com/help/account/manage-profiles/edit-download-or-delete-profiles]Edit, download, or delete provisioning profiles[/url].
+ Can be overridden with the environment variable [code]GODOT_IOS_PROVISIONING_PROFILE_UUID_DEBUG[/code].
</member>
<member name="application/provisioning_profile_uuid_release" type="String" setter="" getter="">
UUID of the provisioning profile. If left empty, Xcode will download or create a provisioning profile automatically. See [url=https://developer.apple.com/help/account/manage-profiles/edit-download-or-delete-profiles]Edit, download, or delete provisioning profiles[/url].
+ Can be overridden with the environment variable [code]GODOT_IOS_PROVISIONING_PROFILE_UUID_RELEASE[/code].
</member>
<member name="application/short_version" type="String" setter="" getter="">
Application version visible to the user, can only contain numeric characters ([code]0-9[/code]) and periods ([code].[/code]).
@@ -69,15 +71,15 @@
<member name="icons/app_store_1024x1024" type="String" setter="" getter="">
App Store application icon file. If left empty, project icon is used instead. See [url=https://developer.apple.com/design/human-interface-guidelines/foundations/app-icons]App icons[/url].
</member>
+ <member name="icons/ipad_76x76" type="String" setter="" getter="">
+ Home screen application icon file on iPad (1x DPI). If left empty, project icon is used instead. See [url=https://developer.apple.com/design/human-interface-guidelines/foundations/app-icons]App icons[/url].
+ </member>
<member name="icons/ipad_152x152" type="String" setter="" getter="">
Home screen application icon file on iPad (2x DPI). If left empty, project icon is used instead. See [url=https://developer.apple.com/design/human-interface-guidelines/foundations/app-icons]App icons[/url].
</member>
<member name="icons/ipad_167x167" type="String" setter="" getter="">
Home screen application icon file on iPad (3x DPI). If left empty, project icon is used instead. See [url=https://developer.apple.com/design/human-interface-guidelines/foundations/app-icons]App icons[/url].
</member>
- <member name="icons/ipad_76x76" type="String" setter="" getter="">
- Home screen application icon file on iPad (1x DPI). If left empty, project icon is used instead. See [url=https://developer.apple.com/design/human-interface-guidelines/foundations/app-icons]App icons[/url].
- </member>
<member name="icons/iphone_120x120" type="String" setter="" getter="">
Home screen application icon file on iPhone (2x DPI). If left empty, project icon is used instead. See [url=https://developer.apple.com/design/human-interface-guidelines/foundations/app-icons]App icons[/url].
</member>
@@ -114,25 +116,25 @@
<member name="landscape_launch_screens/iphone_2436x1125" type="String" setter="" getter="">
Application launch screen image file, if left empty project splash screen is used instead.
</member>
- <member name="portrait_launch_screens/ipad_1536x2048" type="String" setter="" getter="">
- Application launch screen image file, if left empty project splash screen is used instead.
- </member>
<member name="portrait_launch_screens/ipad_768x1024" type="String" setter="" getter="">
Application launch screen image file, if left empty project splash screen is used instead.
</member>
- <member name="portrait_launch_screens/iphone_1125x2436" type="String" setter="" getter="">
+ <member name="portrait_launch_screens/ipad_1536x2048" type="String" setter="" getter="">
Application launch screen image file, if left empty project splash screen is used instead.
</member>
- <member name="portrait_launch_screens/iphone_1242x2208" type="String" setter="" getter="">
+ <member name="portrait_launch_screens/iphone_640x960" type="String" setter="" getter="">
Application launch screen image file, if left empty project splash screen is used instead.
</member>
<member name="portrait_launch_screens/iphone_640x1136" type="String" setter="" getter="">
Application launch screen image file, if left empty project splash screen is used instead.
</member>
- <member name="portrait_launch_screens/iphone_640x960" type="String" setter="" getter="">
+ <member name="portrait_launch_screens/iphone_750x1334" type="String" setter="" getter="">
Application launch screen image file, if left empty project splash screen is used instead.
</member>
- <member name="portrait_launch_screens/iphone_750x1334" type="String" setter="" getter="">
+ <member name="portrait_launch_screens/iphone_1125x2436" type="String" setter="" getter="">
+ Application launch screen image file, if left empty project splash screen is used instead.
+ </member>
+ <member name="portrait_launch_screens/iphone_1242x2208" type="String" setter="" getter="">
Application launch screen image file, if left empty project splash screen is used instead.
</member>
<member name="privacy/camera_usage_description" type="String" setter="" getter="">
diff --git a/platform/ios/export/export_plugin.cpp b/platform/ios/export/export_plugin.cpp
index 1b925ff3e3..06741a12e4 100644
--- a/platform/ios/export/export_plugin.cpp
+++ b/platform/ios/export/export_plugin.cpp
@@ -160,10 +160,10 @@ void EditorExportPlatformIOS::get_export_options(List<ExportOption> *r_options)
r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "application/app_store_team_id"), "", false, true));
- r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "application/provisioning_profile_uuid_debug"), ""));
+ r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "application/provisioning_profile_uuid_debug", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_SECRET), ""));
r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "application/code_sign_identity_debug", PROPERTY_HINT_PLACEHOLDER_TEXT, "iPhone Developer"), ""));
r_options->push_back(ExportOption(PropertyInfo(Variant::INT, "application/export_method_debug", PROPERTY_HINT_ENUM, "App Store,Development,Ad-Hoc,Enterprise"), 1));
- r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "application/provisioning_profile_uuid_release"), ""));
+ r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "application/provisioning_profile_uuid_release", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_SECRET), ""));
r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "application/code_sign_identity_release", PROPERTY_HINT_PLACEHOLDER_TEXT, "iPhone Distribution"), ""));
r_options->push_back(ExportOption(PropertyInfo(Variant::INT, "application/export_method_release", PROPERTY_HINT_ENUM, "App Store,Development,Ad-Hoc,Enterprise"), 0));
@@ -253,8 +253,8 @@ void EditorExportPlatformIOS::_fix_config_file(const Ref<EditorExportPreset> &p_
};
String dbg_sign_id = p_preset->get("application/code_sign_identity_debug").operator String().is_empty() ? "iPhone Developer" : p_preset->get("application/code_sign_identity_debug");
String rel_sign_id = p_preset->get("application/code_sign_identity_release").operator String().is_empty() ? "iPhone Distribution" : p_preset->get("application/code_sign_identity_release");
- bool dbg_manual = !p_preset->get("application/provisioning_profile_uuid_debug").operator String().is_empty() || (dbg_sign_id != "iPhone Developer");
- bool rel_manual = !p_preset->get("application/provisioning_profile_uuid_release").operator String().is_empty() || (rel_sign_id != "iPhone Distribution");
+ bool dbg_manual = !p_preset->get_or_env("application/provisioning_profile_uuid_debug", ENV_IOS_PROFILE_UUID_DEBUG).operator String().is_empty() || (dbg_sign_id != "iPhone Developer");
+ bool rel_manual = !p_preset->get_or_env("application/provisioning_profile_uuid_release", ENV_IOS_PROFILE_UUID_RELEASE).operator String().is_empty() || (rel_sign_id != "iPhone Distribution");
String str;
String strnew;
str.parse_utf8((const char *)pfile.ptr(), pfile.size());
@@ -288,9 +288,9 @@ void EditorExportPlatformIOS::_fix_config_file(const Ref<EditorExportPreset> &p_
int export_method = p_preset->get(p_debug ? "application/export_method_debug" : "application/export_method_release");
strnew += lines[i].replace("$export_method", export_method_string[export_method]) + "\n";
} else if (lines[i].find("$provisioning_profile_uuid_release") != -1) {
- strnew += lines[i].replace("$provisioning_profile_uuid_release", p_preset->get("application/provisioning_profile_uuid_release")) + "\n";
+ strnew += lines[i].replace("$provisioning_profile_uuid_release", p_preset->get_or_env("application/provisioning_profile_uuid_release", ENV_IOS_PROFILE_UUID_RELEASE)) + "\n";
} else if (lines[i].find("$provisioning_profile_uuid_debug") != -1) {
- strnew += lines[i].replace("$provisioning_profile_uuid_debug", p_preset->get("application/provisioning_profile_uuid_debug")) + "\n";
+ strnew += lines[i].replace("$provisioning_profile_uuid_debug", p_preset->get_or_env("application/provisioning_profile_uuid_debug", ENV_IOS_PROFILE_UUID_DEBUG)) + "\n";
} else if (lines[i].find("$code_sign_style_debug") != -1) {
if (dbg_manual) {
strnew += lines[i].replace("$code_sign_style_debug", "Manual") + "\n";
@@ -304,7 +304,7 @@ void EditorExportPlatformIOS::_fix_config_file(const Ref<EditorExportPreset> &p_
strnew += lines[i].replace("$code_sign_style_release", "Automatic") + "\n";
}
} else if (lines[i].find("$provisioning_profile_uuid") != -1) {
- String uuid = p_debug ? p_preset->get("application/provisioning_profile_uuid_debug") : p_preset->get("application/provisioning_profile_uuid_release");
+ String uuid = p_debug ? p_preset->get_or_env("application/provisioning_profile_uuid_debug", ENV_IOS_PROFILE_UUID_DEBUG) : p_preset->get_or_env("application/provisioning_profile_uuid_release", ENV_IOS_PROFILE_UUID_RELEASE);
strnew += lines[i].replace("$provisioning_profile_uuid", uuid) + "\n";
} else if (lines[i].find("$code_sign_identity_debug") != -1) {
strnew += lines[i].replace("$code_sign_identity_debug", dbg_sign_id) + "\n";
@@ -1984,6 +1984,8 @@ EditorExportPlatformIOS::EditorExportPlatformIOS() {
EditorExportPlatformIOS::~EditorExportPlatformIOS() {
#ifndef ANDROID_ENABLED
quit_request.set();
- check_for_changes_thread.wait_to_finish();
+ if (check_for_changes_thread.is_started()) {
+ check_for_changes_thread.wait_to_finish();
+ }
#endif
}
diff --git a/platform/ios/export/export_plugin.h b/platform/ios/export/export_plugin.h
index 0fde3b7c0b..9afefef121 100644
--- a/platform/ios/export/export_plugin.h
+++ b/platform/ios/export/export_plugin.h
@@ -49,6 +49,11 @@
#include <sys/stat.h>
+// Optional environment variables for defining confidential information. If any
+// of these is set, they will override the values set in the credentials file.
+const String ENV_IOS_PROFILE_UUID_DEBUG = "GODOT_IOS_PROVISIONING_PROFILE_UUID_DEBUG";
+const String ENV_IOS_PROFILE_UUID_RELEASE = "GODOT_IOS_PROVISIONING_PROFILE_UUID_RELEASE";
+
class EditorExportPlatformIOS : public EditorExportPlatform {
GDCLASS(EditorExportPlatformIOS, EditorExportPlatform);
diff --git a/platform/ios/ios.mm b/platform/ios/ios.mm
index 1065f5fd2a..c911a512a5 100644
--- a/platform/ios/ios.mm
+++ b/platform/ios/ios.mm
@@ -72,8 +72,8 @@ CHHapticEngine *iOS::get_haptic_engine_instance() API_AVAILABLE(ios(13)) {
void iOS::vibrate_haptic_engine(float p_duration_seconds) API_AVAILABLE(ios(13)) {
if (@available(iOS 13, *)) { // We need the @available check every time to make the compiler happy...
if (supports_haptic_engine()) {
- CHHapticEngine *haptic_engine = get_haptic_engine_instance();
- if (haptic_engine) {
+ CHHapticEngine *cur_haptic_engine = get_haptic_engine_instance();
+ if (cur_haptic_engine) {
NSDictionary *hapticDict = @{
CHHapticPatternKeyPattern : @[
@{CHHapticPatternKeyEvent : @{
@@ -88,7 +88,7 @@ void iOS::vibrate_haptic_engine(float p_duration_seconds) API_AVAILABLE(ios(13))
NSError *error;
CHHapticPattern *pattern = [[CHHapticPattern alloc] initWithDictionary:hapticDict error:&error];
- [[haptic_engine createPlayerWithPattern:pattern error:&error] startAtTime:0 error:&error];
+ [[cur_haptic_engine createPlayerWithPattern:pattern error:&error] startAtTime:0 error:&error];
NSLog(@"Could not vibrate using haptic engine: %@", error);
}
@@ -103,9 +103,9 @@ void iOS::vibrate_haptic_engine(float p_duration_seconds) API_AVAILABLE(ios(13))
void iOS::start_haptic_engine() {
if (@available(iOS 13, *)) {
if (supports_haptic_engine()) {
- CHHapticEngine *haptic_engine = get_haptic_engine_instance();
- if (haptic_engine) {
- [haptic_engine startWithCompletionHandler:^(NSError *returnedError) {
+ CHHapticEngine *cur_haptic_engine = get_haptic_engine_instance();
+ if (cur_haptic_engine) {
+ [cur_haptic_engine startWithCompletionHandler:^(NSError *returnedError) {
if (returnedError) {
NSLog(@"Could not start haptic engine: %@", returnedError);
}
@@ -122,9 +122,9 @@ void iOS::start_haptic_engine() {
void iOS::stop_haptic_engine() {
if (@available(iOS 13, *)) {
if (supports_haptic_engine()) {
- CHHapticEngine *haptic_engine = get_haptic_engine_instance();
- if (haptic_engine) {
- [haptic_engine stopWithCompletionHandler:^(NSError *returnedError) {
+ CHHapticEngine *cur_haptic_engine = get_haptic_engine_instance();
+ if (cur_haptic_engine) {
+ [cur_haptic_engine stopWithCompletionHandler:^(NSError *returnedError) {
if (returnedError) {
NSLog(@"Could not stop haptic engine: %@", returnedError);
}
diff --git a/platform/ios/os_ios.mm b/platform/ios/os_ios.mm
index b2f72c310f..739db419a3 100644
--- a/platform/ios/os_ios.mm
+++ b/platform/ios/os_ios.mm
@@ -240,10 +240,20 @@ Error OS_IOS::open_dynamic_library(const String p_path, void *&p_library_handle,
}
if (!FileAccess::exists(path)) {
+ // Load .dylib converted to framework from within the executable path.
+ path = get_framework_executable(get_executable_path().get_base_dir().path_join(p_path.get_file().get_basename() + ".framework"));
+ }
+
+ if (!FileAccess::exists(path)) {
// Load .dylib or framework from a standard iOS location.
path = get_framework_executable(get_executable_path().get_base_dir().path_join("Frameworks").path_join(p_path.get_file()));
}
+ if (!FileAccess::exists(path)) {
+ // Load .dylib converted to framework from a standard iOS location.
+ path = get_framework_executable(get_executable_path().get_base_dir().path_join("Frameworks").path_join(p_path.get_file().get_basename() + ".framework"));
+ }
+
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() + ".");
diff --git a/platform/linuxbsd/freedesktop_portal_desktop.cpp b/platform/linuxbsd/freedesktop_portal_desktop.cpp
index b45b7e676d..6dfa8ed93c 100644
--- a/platform/linuxbsd/freedesktop_portal_desktop.cpp
+++ b/platform/linuxbsd/freedesktop_portal_desktop.cpp
@@ -138,6 +138,11 @@ FreeDesktopPortalDesktop::FreeDesktopPortalDesktop() {
#else
unsupported = false;
#endif
+
+ if (unsupported) {
+ return;
+ }
+
bool ver_ok = false;
int version_major = 0;
int version_minor = 0;
diff --git a/platform/linuxbsd/freedesktop_screensaver.cpp b/platform/linuxbsd/freedesktop_screensaver.cpp
index 78f2337599..cf179b5735 100644
--- a/platform/linuxbsd/freedesktop_screensaver.cpp
+++ b/platform/linuxbsd/freedesktop_screensaver.cpp
@@ -141,6 +141,11 @@ FreeDesktopScreenSaver::FreeDesktopScreenSaver() {
#else
unsupported = false;
#endif
+
+ if (unsupported) {
+ return;
+ }
+
bool ver_ok = false;
int version_major = 0;
int version_minor = 0;
diff --git a/platform/linuxbsd/joypad_linux.cpp b/platform/linuxbsd/joypad_linux.cpp
index 5c623b8ba2..a9725fff2e 100644
--- a/platform/linuxbsd/joypad_linux.cpp
+++ b/platform/linuxbsd/joypad_linux.cpp
@@ -32,6 +32,8 @@
#include "joypad_linux.h"
+#include "core/os/os.h"
+
#include <dirent.h>
#include <errno.h>
#include <fcntl.h>
@@ -72,6 +74,26 @@ void JoypadLinux::Joypad::reset() {
events.clear();
}
+// This function is derived from SDL:
+// https://github.com/libsdl-org/SDL/blob/main/src/core/linux/SDL_sandbox.c#L28-L45
+static bool detect_sandbox() {
+ if (access("/.flatpak-info", F_OK) == 0) {
+ return true;
+ }
+
+ // For Snap, we check multiple variables because they might be set for
+ // unrelated reasons. This is the same thing WebKitGTK does.
+ if (OS::get_singleton()->has_environment("SNAP") && OS::get_singleton()->has_environment("SNAP_NAME") && OS::get_singleton()->has_environment("SNAP_REVISION")) {
+ return true;
+ }
+
+ if (access("/run/host/container-manager", F_OK) == 0) {
+ return true;
+ }
+
+ return false;
+}
+
JoypadLinux::JoypadLinux(Input *in) {
#ifdef UDEV_ENABLED
#ifdef SOWRAP_ENABLED
@@ -80,17 +102,25 @@ JoypadLinux::JoypadLinux(Input *in) {
#else
int dylibloader_verbose = 0;
#endif
- use_udev = initialize_libudev(dylibloader_verbose) == 0;
- if (use_udev) {
- if (!udev_new || !udev_unref || !udev_enumerate_new || !udev_enumerate_add_match_subsystem || !udev_enumerate_scan_devices || !udev_enumerate_get_list_entry || !udev_list_entry_get_next || !udev_list_entry_get_name || !udev_device_new_from_syspath || !udev_device_get_devnode || !udev_device_get_action || !udev_device_unref || !udev_enumerate_unref || !udev_monitor_new_from_netlink || !udev_monitor_filter_add_match_subsystem_devtype || !udev_monitor_enable_receiving || !udev_monitor_get_fd || !udev_monitor_receive_device || !udev_monitor_unref) {
- // There's no API to check version, check if functions are available instead.
- use_udev = false;
- print_verbose("JoypadLinux: Unsupported udev library version!");
+ if (detect_sandbox()) {
+ // Linux binaries in sandboxes / containers need special handling because
+ // libudev doesn't work there. So we need to fallback to manual parsing
+ // of /dev/input in such case.
+ use_udev = false;
+ print_verbose("JoypadLinux: udev enabled, but detected incompatible sandboxed mode. Falling back to /dev/input to detect joypads.");
+ } else {
+ use_udev = initialize_libudev(dylibloader_verbose) == 0;
+ if (use_udev) {
+ if (!udev_new || !udev_unref || !udev_enumerate_new || !udev_enumerate_add_match_subsystem || !udev_enumerate_scan_devices || !udev_enumerate_get_list_entry || !udev_list_entry_get_next || !udev_list_entry_get_name || !udev_device_new_from_syspath || !udev_device_get_devnode || !udev_device_get_action || !udev_device_unref || !udev_enumerate_unref || !udev_monitor_new_from_netlink || !udev_monitor_filter_add_match_subsystem_devtype || !udev_monitor_enable_receiving || !udev_monitor_get_fd || !udev_monitor_receive_device || !udev_monitor_unref) {
+ // There's no API to check version, check if functions are available instead.
+ use_udev = false;
+ print_verbose("JoypadLinux: Unsupported udev library version!");
+ } else {
+ print_verbose("JoypadLinux: udev enabled and loaded successfully.");
+ }
} else {
- print_verbose("JoypadLinux: udev enabled and loaded successfully.");
+ print_verbose("JoypadLinux: udev enabled, but couldn't be loaded. Falling back to /dev/input to detect joypads.");
}
- } else {
- print_verbose("JoypadLinux: udev enabled, but couldn't be loaded. Falling back to /dev/input to detect joypads.");
}
#endif
#else
diff --git a/platform/linuxbsd/os_linuxbsd.cpp b/platform/linuxbsd/os_linuxbsd.cpp
index 11c81be4a9..8d8c8ce27b 100644
--- a/platform/linuxbsd/os_linuxbsd.cpp
+++ b/platform/linuxbsd/os_linuxbsd.cpp
@@ -30,6 +30,7 @@
#include "os_linuxbsd.h"
+#include "core/io/certs_compressed.gen.h"
#include "core/io/dir_access.h"
#include "main/main.h"
#include "servers/display_server.h"
@@ -195,6 +196,10 @@ void OS_LinuxBSD::set_main_loop(MainLoop *p_main_loop) {
main_loop = p_main_loop;
}
+String OS_LinuxBSD::get_identifier() const {
+ return "linuxbsd";
+}
+
String OS_LinuxBSD::get_name() const {
#ifdef __linux__
return "Linux";
@@ -490,6 +495,11 @@ bool OS_LinuxBSD::_check_internal_feature_support(const String &p_feature) {
return true;
}
+ // Match against the specific OS (linux, freebsd, etc).
+ if (p_feature == get_name().to_lower()) {
+ return true;
+ }
+
return false;
}
@@ -1076,6 +1086,40 @@ Error OS_LinuxBSD::move_to_trash(const String &p_path) {
return OK;
}
+String OS_LinuxBSD::get_system_ca_certificates() {
+ String certfile;
+ Ref<DirAccess> da = DirAccess::create(DirAccess::ACCESS_FILESYSTEM);
+
+ // Compile time preferred certificates path.
+ if (!String(_SYSTEM_CERTS_PATH).is_empty() && da->file_exists(_SYSTEM_CERTS_PATH)) {
+ certfile = _SYSTEM_CERTS_PATH;
+ } else if (da->file_exists("/etc/ssl/certs/ca-certificates.crt")) {
+ // Debian/Ubuntu
+ certfile = "/etc/ssl/certs/ca-certificates.crt";
+ } else if (da->file_exists("/etc/pki/ca-trust/extracted/pem/tls-ca-bundle.pem")) {
+ // Fedora
+ certfile = "/etc/pki/ca-trust/extracted/pem/tls-ca-bundle.pem";
+ } else if (da->file_exists("/etc/ca-certificates/extracted/tls-ca-bundle.pem")) {
+ // Arch Linux
+ certfile = "/etc/ca-certificates/extracted/tls-ca-bundle.pem";
+ } else if (da->file_exists("/var/lib/ca-certificates/ca-bundle.pem")) {
+ // openSUSE
+ certfile = "/var/lib/ca-certificates/ca-bundle.pem";
+ } else if (da->file_exists("/etc/ssl/cert.pem")) {
+ // FreeBSD/OpenBSD
+ certfile = "/etc/ssl/cert.pem";
+ }
+
+ if (certfile.is_empty()) {
+ return "";
+ }
+
+ Ref<FileAccess> f = FileAccess::open(certfile, FileAccess::READ);
+ ERR_FAIL_COND_V_MSG(f.is_null(), "", vformat("Failed to open system CA certificates file: '%s'", certfile));
+
+ return f->get_as_text();
+}
+
OS_LinuxBSD::OS_LinuxBSD() {
main_loop = nullptr;
diff --git a/platform/linuxbsd/os_linuxbsd.h b/platform/linuxbsd/os_linuxbsd.h
index 9423514944..c1e735b0d4 100644
--- a/platform/linuxbsd/os_linuxbsd.h
+++ b/platform/linuxbsd/os_linuxbsd.h
@@ -96,6 +96,7 @@ protected:
virtual void set_main_loop(MainLoop *p_main_loop) override;
public:
+ virtual String get_identifier() const override;
virtual String get_name() const override;
virtual String get_distribution_name() const override;
virtual String get_version() const override;
@@ -132,6 +133,8 @@ public:
virtual Error move_to_trash(const String &p_path) override;
+ virtual String get_system_ca_certificates() override;
+
OS_LinuxBSD();
~OS_LinuxBSD();
};
diff --git a/platform/linuxbsd/x11/detect_prime_x11.cpp b/platform/linuxbsd/x11/detect_prime_x11.cpp
index 3d07be1c76..78778a8b56 100644
--- a/platform/linuxbsd/x11/detect_prime_x11.cpp
+++ b/platform/linuxbsd/x11/detect_prime_x11.cpp
@@ -60,6 +60,9 @@
typedef GLXContext (*GLXCREATECONTEXTATTRIBSARBPROC)(Display *, GLXFBConfig, GLXContext, Bool, const int *);
+// To prevent shadowing warnings
+#undef glGetString
+
struct vendor {
const char *glxvendor = nullptr;
int priority = 0;
diff --git a/platform/linuxbsd/x11/display_server_x11.cpp b/platform/linuxbsd/x11/display_server_x11.cpp
index ac4fbe2068..13f261aa43 100644
--- a/platform/linuxbsd/x11/display_server_x11.cpp
+++ b/platform/linuxbsd/x11/display_server_x11.cpp
@@ -186,6 +186,7 @@ bool DisplayServerX11::_refresh_device_info() {
xi.absolute_devices.clear();
xi.touch_devices.clear();
xi.pen_inverted_devices.clear();
+ xi.last_relative_time = 0;
int dev_count;
XIDeviceInfo *info = XIQueryDevice(x11_display, XIAllDevices, &dev_count);
@@ -2724,8 +2725,8 @@ void DisplayServerX11::cursor_set_custom_image(const Ref<Resource> &p_cursor, Cu
XcursorImageDestroy(cursor_image);
} else {
// Reset to default system cursor
- if (img[p_shape]) {
- cursors[p_shape] = XcursorImageLoadCursor(x11_display, img[p_shape]);
+ if (cursor_img[p_shape]) {
+ cursors[p_shape] = XcursorImageLoadCursor(x11_display, cursor_img[p_shape]);
}
CursorShape c = current_cursor;
@@ -3497,8 +3498,8 @@ void DisplayServerX11::_window_changed(XEvent *event) {
// Query display server about a possible new window state.
wd.fullscreen = _window_fullscreen_check(window_id);
- wd.minimized = _window_minimize_check(window_id);
- wd.maximized = _window_maximize_check(window_id, "_NET_WM_STATE");
+ wd.maximized = _window_maximize_check(window_id, "_NET_WM_STATE") && !wd.fullscreen;
+ wd.minimized = _window_minimize_check(window_id) && !wd.fullscreen && !wd.maximized;
// Readjusting the window position if the window is being reparented by the window manager for decoration
Window root, parent, *children;
@@ -5359,7 +5360,7 @@ DisplayServerX11::DisplayServerX11(const String &p_rendering_driver, WindowMode
for (int i = 0; i < CURSOR_MAX; i++) {
cursors[i] = None;
- img[i] = nullptr;
+ cursor_img[i] = nullptr;
}
XInitThreads(); //always use threads
@@ -5716,8 +5717,8 @@ DisplayServerX11::DisplayServerX11(const String &p_rendering_driver, WindowMode
"question_arrow"
};
- img[i] = XcursorLibraryLoadImage(cursor_file[i], cursor_theme, cursor_size);
- if (!img[i]) {
+ cursor_img[i] = XcursorLibraryLoadImage(cursor_file[i], cursor_theme, cursor_size);
+ if (!cursor_img[i]) {
const char *fallback = nullptr;
switch (i) {
@@ -5755,7 +5756,7 @@ DisplayServerX11::DisplayServerX11(const String &p_rendering_driver, WindowMode
fallback = "bd_double_arrow";
break;
case CURSOR_MOVE:
- img[i] = img[CURSOR_DRAG];
+ cursor_img[i] = cursor_img[CURSOR_DRAG];
break;
case CURSOR_VSPLIT:
fallback = "sb_v_double_arrow";
@@ -5768,11 +5769,11 @@ DisplayServerX11::DisplayServerX11(const String &p_rendering_driver, WindowMode
break;
}
if (fallback != nullptr) {
- img[i] = XcursorLibraryLoadImage(fallback, cursor_theme, cursor_size);
+ cursor_img[i] = XcursorLibraryLoadImage(fallback, cursor_theme, cursor_size);
}
}
- if (img[i]) {
- cursors[i] = XcursorImageLoadCursor(x11_display, img[i]);
+ if (cursor_img[i]) {
+ cursors[i] = XcursorImageLoadCursor(x11_display, cursor_img[i]);
} else {
print_verbose("Failed loading custom cursor: " + String(cursor_file[i]));
}
@@ -5911,8 +5912,8 @@ DisplayServerX11::~DisplayServerX11() {
if (cursors[i] != None) {
XFreeCursor(x11_display, cursors[i]);
}
- if (img[i] != nullptr) {
- XcursorImageDestroy(img[i]);
+ if (cursor_img[i] != nullptr) {
+ XcursorImageDestroy(cursor_img[i]);
}
}
diff --git a/platform/linuxbsd/x11/display_server_x11.h b/platform/linuxbsd/x11/display_server_x11.h
index e8e0680c14..6d343be3ab 100644
--- a/platform/linuxbsd/x11/display_server_x11.h
+++ b/platform/linuxbsd/x11/display_server_x11.h
@@ -119,8 +119,7 @@ typedef struct _xrr_monitor_info {
#undef CursorShape
class DisplayServerX11 : public DisplayServer {
- //No need to register, it's platform-specific and nothing is added
- //GDCLASS(DisplayServerX11, DisplayServer)
+ // No need to register with GDCLASS, it's platform-specific and nothing is added.
_THREAD_SAFE_CLASS_
@@ -307,7 +306,7 @@ class DisplayServerX11 : public DisplayServer {
const char *cursor_theme = nullptr;
int cursor_size = 0;
- XcursorImage *img[CURSOR_MAX];
+ XcursorImage *cursor_img[CURSOR_MAX];
Cursor cursors[CURSOR_MAX];
Cursor null_cursor;
CursorShape current_cursor = CURSOR_ARROW;
diff --git a/platform/linuxbsd/x11/gl_manager_x11.cpp b/platform/linuxbsd/x11/gl_manager_x11.cpp
index ee767dfa80..1e579c9f01 100644
--- a/platform/linuxbsd/x11/gl_manager_x11.cpp
+++ b/platform/linuxbsd/x11/gl_manager_x11.cpp
@@ -44,6 +44,9 @@
typedef GLXContext (*GLXCREATECONTEXTATTRIBSARBPROC)(Display *, GLXFBConfig, GLXContext, Bool, const int *);
+// To prevent shadowing warnings
+#undef glXCreateContextAttribsARB
+
struct GLManager_X11_Private {
::GLXContext glx_context;
};
diff --git a/platform/macos/detect.py b/platform/macos/detect.py
index 1fefdb3c68..7b8d3fd853 100644
--- a/platform/macos/detect.py
+++ b/platform/macos/detect.py
@@ -235,6 +235,8 @@ def configure(env: "Environment"):
"CoreMedia",
"-framework",
"QuartzCore",
+ "-framework",
+ "Security",
]
)
env.Append(LIBS=["pthread", "z"])
diff --git a/platform/macos/display_server_macos.h b/platform/macos/display_server_macos.h
index a71ac3a310..a1cd83280d 100644
--- a/platform/macos/display_server_macos.h
+++ b/platform/macos/display_server_macos.h
@@ -56,7 +56,7 @@
#undef CursorShape
class DisplayServerMacOS : public DisplayServer {
- GDCLASS(DisplayServerMacOS, DisplayServer)
+ // No need to register with GDCLASS, it's platform-specific and nothing is added.
_THREAD_SAFE_CLASS_
diff --git a/platform/macos/display_server_macos.mm b/platform/macos/display_server_macos.mm
index 5a7c309448..32f9441484 100644
--- a/platform/macos/display_server_macos.mm
+++ b/platform/macos/display_server_macos.mm
@@ -1840,9 +1840,9 @@ Error DisplayServerMacOS::dialog_show(String p_title, String p_description, Vect
if (!p_callback.is_null()) {
Variant button = button_pressed;
Variant *buttonp = &button;
- Variant ret;
+ Variant fun_ret;
Callable::CallError ce;
- p_callback.callp((const Variant **)&buttonp, 1, ret, ce);
+ p_callback.callp((const Variant **)&buttonp, 1, fun_ret, ce);
}
return OK;
@@ -1872,9 +1872,9 @@ Error DisplayServerMacOS::dialog_input_text(String p_title, String p_description
if (!p_callback.is_null()) {
Variant text = ret;
Variant *textp = &text;
- Variant ret;
+ Variant fun_ret;
Callable::CallError ce;
- p_callback.callp((const Variant **)&textp, 1, ret, ce);
+ p_callback.callp((const Variant **)&textp, 1, fun_ret, ce);
}
return OK;
@@ -1897,7 +1897,7 @@ void DisplayServerMacOS::mouse_set_mode(MouseMode p_mode) {
bool previously_shown = (mouse_mode == MOUSE_MODE_VISIBLE || mouse_mode == MOUSE_MODE_CONFINED);
if (show_cursor && !previously_shown) {
- WindowID window_id = get_window_at_screen_position(mouse_get_position());
+ window_id = get_window_at_screen_position(mouse_get_position());
if (window_id != INVALID_WINDOW_ID) {
send_window_event(windows[window_id], WINDOW_EVENT_MOUSE_ENTER);
}
diff --git a/platform/macos/doc_classes/EditorExportPlatformMacOS.xml b/platform/macos/doc_classes/EditorExportPlatformMacOS.xml
index f57af3bbd7..64e1efde26 100644
--- a/platform/macos/doc_classes/EditorExportPlatformMacOS.xml
+++ b/platform/macos/doc_classes/EditorExportPlatformMacOS.xml
@@ -50,9 +50,11 @@
</member>
<member name="codesign/certificate_file" type="String" setter="" getter="">
PKCS #12 certificate file used to sign [code].app[/code] bundle.
+ Can be overridden with the environment variable [code]GODOT_MACOS_CODESIGN_CERTIFICATE_FILE[/code].
</member>
<member name="codesign/certificate_password" type="String" setter="" getter="">
Password for the certificate file used to sign [code].app[/code] bundle.
+ Can be overridden with the environment variable [code]GODOT_MACOS_CODESIGN_CERTIFICATE_PASSWORD[/code].
</member>
<member name="codesign/codesign" type="int" setter="" getter="">
Tool to use for code signing.
@@ -138,6 +140,7 @@
</member>
<member name="codesign/provisioning_profile" type="String" setter="" getter="">
Provisioning profile file downloaded from Apple developer account dashboard. See [url=https://developer.apple.com/help/account/manage-profiles/edit-download-or-delete-profiles]Edit, download, or delete provisioning profiles[/url].
+ Can be overridden with the environment variable [code]GODOT_MACOS_CODESIGN_PROVISIONING_PROFILE[/code].
</member>
<member name="custom_template/debug" type="String" setter="" getter="">
Path to the custom export template. If left empty, default template is used.
@@ -156,18 +159,23 @@
</member>
<member name="notarization/api_key" type="String" setter="" getter="">
Apple App Store Connect API issuer key file.
+ Can be overridden with the environment variable [code]GODOT_MACOS_NOTARIZATION_API_KEY[/code].
</member>
<member name="notarization/api_key_id" type="String" setter="" getter="">
Apple App Store Connect API issuer key ID.
+ Can be overridden with the environment variable [code]GODOT_MACOS_NOTARIZATION_API_KEY_ID[/code].
</member>
<member name="notarization/api_uuid" type="String" setter="" getter="">
Apple App Store Connect API issuer UUID.
+ Can be overridden with the environment variable [code]GODOT_MACOS_NOTARIZATION_API_UUID[/code].
</member>
<member name="notarization/apple_id_name" type="String" setter="" getter="">
Apple ID account name (email address).
+ Can be overridden with the environment variable [code]GODOT_MACOS_NOTARIZATION_APPLE_ID_NAME[/code].
</member>
<member name="notarization/apple_id_password" type="String" setter="" getter="">
Apple ID app-specific password.
+ Can be overridden with the environment variable [code]GODOT_MACOS_NOTARIZATION_APPLE_ID_PASSWORD[/code].
</member>
<member name="notarization/notarization" type="int" setter="" getter="">
Tool to use for notarization.
diff --git a/platform/macos/export/export_plugin.cpp b/platform/macos/export/export_plugin.cpp
index cd9d17dd4f..be677f4da2 100644
--- a/platform/macos/export/export_plugin.cpp
+++ b/platform/macos/export/export_plugin.cpp
@@ -73,7 +73,7 @@ String EditorExportPlatformMacOS::get_export_option_warning(const EditorExportPr
ad_hoc = true;
} break;
case 2: { // "rcodesign"
- ad_hoc = p_preset->get("codesign/certificate_file").operator String().is_empty() || p_preset->get("codesign/certificate_password").operator String().is_empty();
+ ad_hoc = p_preset->get_or_env("codesign/certificate_file", ENV_MAC_CODESIGN_CERT_FILE).operator String().is_empty() || p_preset->get_or_env("codesign/certificate_password", ENV_MAC_CODESIGN_CERT_FILE).operator String().is_empty();
} break;
#ifdef MACOS_ENABLED
case 3: { // "codesign"
@@ -114,7 +114,7 @@ String EditorExportPlatformMacOS::get_export_option_warning(const EditorExportPr
}
if (p_name == "codesign/provisioning_profile" && dist_type == 2) {
- String pprof = p_preset->get("codesign/provisioning_profile");
+ String pprof = p_preset->get_or_env("codesign/provisioning_profile", ENV_MAC_CODESIGN_PROFILE);
if (pprof.is_empty()) {
return TTR("Provisioning profile is required for App Store distribution.");
}
@@ -154,8 +154,8 @@ String EditorExportPlatformMacOS::get_export_option_warning(const EditorExportPr
if (notary_tool == 2 || notary_tool == 3) {
if (p_name == "notarization/apple_id_name" || p_name == "notarization/api_uuid") {
- String apple_id = p_preset->get("notarization/apple_id_name");
- String api_uuid = p_preset->get("notarization/api_uuid");
+ String apple_id = p_preset->get_or_env("notarization/apple_id_name", ENV_MAC_NOTARIZATION_APPLE_ID);
+ String api_uuid = p_preset->get_or_env("notarization/api_uuid", ENV_MAC_NOTARIZATION_UUID);
if (apple_id.is_empty() && api_uuid.is_empty()) {
return TTR("Neither Apple ID name nor App Store Connect issuer ID name not specified.");
}
@@ -164,28 +164,28 @@ String EditorExportPlatformMacOS::get_export_option_warning(const EditorExportPr
}
}
if (p_name == "notarization/apple_id_password") {
- String apple_id = p_preset->get("notarization/apple_id_name");
- String apple_pass = p_preset->get("notarization/apple_id_password");
+ String apple_id = p_preset->get_or_env("notarization/apple_id_name", ENV_MAC_NOTARIZATION_APPLE_ID);
+ String apple_pass = p_preset->get_or_env("notarization/apple_id_password", ENV_MAC_NOTARIZATION_APPLE_PASS);
if (!apple_id.is_empty() && apple_pass.is_empty()) {
return TTR("Apple ID password not specified.");
}
}
if (p_name == "notarization/api_key_id") {
- String api_uuid = p_preset->get("notarization/api_uuid");
- String api_key = p_preset->get("notarization/api_key_id");
+ String api_uuid = p_preset->get_or_env("notarization/api_uuid", ENV_MAC_NOTARIZATION_UUID);
+ String api_key = p_preset->get_or_env("notarization/api_key_id", ENV_MAC_NOTARIZATION_KEY_ID);
if (!api_uuid.is_empty() && api_key.is_empty()) {
return TTR("App Store Connect API key ID not specified.");
}
}
} else if (notary_tool == 1) {
if (p_name == "notarization/api_uuid") {
- String api_uuid = p_preset->get("notarization/api_uuid");
+ String api_uuid = p_preset->get_or_env("notarization/api_uuid", ENV_MAC_NOTARIZATION_UUID);
if (api_uuid.is_empty()) {
return TTR("App Store Connect issuer ID name not specified.");
}
}
if (p_name == "notarization/api_key_id") {
- String api_key = p_preset->get("notarization/api_key_id");
+ String api_key = p_preset->get_or_env("notarization/api_key_id", ENV_MAC_NOTARIZATION_KEY_ID);
if (api_key.is_empty()) {
return TTR("App Store Connect API key ID not specified.");
}
@@ -398,10 +398,10 @@ void EditorExportPlatformMacOS::get_export_options(List<ExportOption> *r_options
// "codesign" only options:
r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "codesign/identity", PROPERTY_HINT_PLACEHOLDER_TEXT, "Type: Name (ID)"), ""));
// "rcodesign" only options:
- r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "codesign/certificate_file", PROPERTY_HINT_GLOBAL_FILE, "*.pfx,*.p12"), ""));
- r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "codesign/certificate_password", PROPERTY_HINT_PASSWORD), ""));
+ r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "codesign/certificate_file", PROPERTY_HINT_GLOBAL_FILE, "*.pfx,*.p12", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_SECRET), ""));
+ r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "codesign/certificate_password", PROPERTY_HINT_PASSWORD, "", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_SECRET), ""));
// "codesign" and "rcodesign" only options:
- r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "codesign/provisioning_profile", PROPERTY_HINT_GLOBAL_FILE, "*.provisionprofile"), "", false, true));
+ r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "codesign/provisioning_profile", PROPERTY_HINT_GLOBAL_FILE, "*.provisionprofile", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_SECRET), "", false, true));
r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "codesign/entitlements/custom_file", PROPERTY_HINT_GLOBAL_FILE, "*.plist"), "", true));
r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "codesign/entitlements/allow_jit_code_execution"), false));
@@ -434,12 +434,12 @@ void EditorExportPlatformMacOS::get_export_options(List<ExportOption> *r_options
r_options->push_back(ExportOption(PropertyInfo(Variant::INT, "notarization/notarization", PROPERTY_HINT_ENUM, "Disabled,rcodesign"), 0, true));
#endif
// "altool" and "notarytool" only options:
- r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "notarization/apple_id_name", PROPERTY_HINT_PLACEHOLDER_TEXT, "Apple ID email"), "", false, true));
- r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "notarization/apple_id_password", PROPERTY_HINT_PASSWORD, "Enable two-factor authentication and provide app-specific password"), "", false, true));
+ r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "notarization/apple_id_name", PROPERTY_HINT_PLACEHOLDER_TEXT, "Apple ID email", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_SECRET), "", false, true));
+ r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "notarization/apple_id_password", PROPERTY_HINT_PASSWORD, "Enable two-factor authentication and provide app-specific password", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_SECRET), "", false, true));
// "altool", "notarytool" and "rcodesign" only options:
- r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "notarization/api_uuid", PROPERTY_HINT_PLACEHOLDER_TEXT, "App Store Connect issuer ID UUID"), "", false, true));
- r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "notarization/api_key", PROPERTY_HINT_GLOBAL_FILE, "*.p8"), "", false, true));
- r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "notarization/api_key_id", PROPERTY_HINT_PLACEHOLDER_TEXT, "App Store Connect API key ID"), "", false, true));
+ r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "notarization/api_uuid", PROPERTY_HINT_PLACEHOLDER_TEXT, "App Store Connect issuer ID UUID", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_SECRET), "", false, true));
+ r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "notarization/api_key", PROPERTY_HINT_GLOBAL_FILE, "*.p8", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_SECRET), "", false, true));
+ r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "notarization/api_key_id", PROPERTY_HINT_PLACEHOLDER_TEXT, "App Store Connect API key ID", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_SECRET), "", false, true));
r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "privacy/microphone_usage_description", PROPERTY_HINT_PLACEHOLDER_TEXT, "Provide a message if you need to use the microphone"), "", false, true));
r_options->push_back(ExportOption(PropertyInfo(Variant::DICTIONARY, "privacy/microphone_usage_description_localized", PROPERTY_HINT_LOCALIZABLE_STRING), Dictionary()));
@@ -776,24 +776,24 @@ Error EditorExportPlatformMacOS::_notarize(const Ref<EditorExportPreset> &p_pres
args.push_back("notary-submit");
- if (p_preset->get("notarization/api_uuid") == "") {
+ if (p_preset->get_or_env("notarization/api_uuid", ENV_MAC_NOTARIZATION_UUID) == "") {
add_message(EXPORT_MESSAGE_ERROR, TTR("Notarization"), TTR("App Store Connect issuer ID name not specified."));
return Error::FAILED;
}
- if (p_preset->get("notarization/api_key") == "") {
+ if (p_preset->get_or_env("notarization/api_key", ENV_MAC_NOTARIZATION_KEY) == "") {
add_message(EXPORT_MESSAGE_ERROR, TTR("Notarization"), TTR("App Store Connect API key ID not specified."));
return Error::FAILED;
}
args.push_back("--api-issuer");
- args.push_back(p_preset->get("notarization/api_uuid"));
+ args.push_back(p_preset->get_or_env("notarization/api_uuid", ENV_MAC_NOTARIZATION_UUID));
args.push_back("--api-key");
- args.push_back(p_preset->get("notarization/api_key_id"));
+ args.push_back(p_preset->get_or_env("notarization/api_key_id", ENV_MAC_NOTARIZATION_KEY_ID));
- if (!p_preset->get("notarization/api_key").operator String().is_empty()) {
+ if (!p_preset->get_or_env("notarization/api_key", ENV_MAC_NOTARIZATION_KEY).operator String().is_empty()) {
args.push_back("--api-key-path");
- args.push_back(p_preset->get("notarization/api_key"));
+ args.push_back(p_preset->get_or_env("notarization/api_key", ENV_MAC_NOTARIZATION_KEY));
}
args.push_back(p_path);
@@ -840,40 +840,40 @@ Error EditorExportPlatformMacOS::_notarize(const Ref<EditorExportPreset> &p_pres
args.push_back(p_path);
- if (p_preset->get("notarization/apple_id_name") == "" && p_preset->get("notarization/api_uuid") == "") {
+ if (p_preset->get_or_env("notarization/apple_id_name", ENV_MAC_NOTARIZATION_APPLE_ID) == "" && p_preset->get_or_env("notarization/api_uuid", ENV_MAC_NOTARIZATION_UUID) == "") {
add_message(EXPORT_MESSAGE_ERROR, TTR("Notarization"), TTR("Neither Apple ID name nor App Store Connect issuer ID name not specified."));
return Error::FAILED;
}
- if (p_preset->get("notarization/apple_id_name") != "" && p_preset->get("notarization/api_uuid") != "") {
+ if (p_preset->get_or_env("notarization/apple_id_name", ENV_MAC_NOTARIZATION_APPLE_ID) != "" && p_preset->get_or_env("notarization/api_uuid", ENV_MAC_NOTARIZATION_UUID) != "") {
add_message(EXPORT_MESSAGE_ERROR, TTR("Notarization"), TTR("Both Apple ID name and App Store Connect issuer ID name are specified, only one should be set at the same time."));
return Error::FAILED;
}
- if (p_preset->get("notarization/apple_id_name") != "") {
- if (p_preset->get("notarization/apple_id_password") == "") {
+ if (p_preset->get_or_env("notarization/apple_id_name", ENV_MAC_NOTARIZATION_APPLE_ID) != "") {
+ if (p_preset->get_or_env("notarization/apple_id_password", ENV_MAC_NOTARIZATION_APPLE_PASS) == "") {
add_message(EXPORT_MESSAGE_ERROR, TTR("Notarization"), TTR("Apple ID password not specified."));
return Error::FAILED;
}
args.push_back("--apple-id");
- args.push_back(p_preset->get("notarization/apple_id_name"));
+ args.push_back(p_preset->get_or_env("notarization/apple_id_name", ENV_MAC_NOTARIZATION_APPLE_ID));
args.push_back("--password");
- args.push_back(p_preset->get("notarization/apple_id_password"));
+ args.push_back(p_preset->get_or_env("notarization/apple_id_password", ENV_MAC_NOTARIZATION_APPLE_PASS));
} else {
- if (p_preset->get("notarization/api_key_id") == "") {
+ if (p_preset->get_or_env("notarization/api_key_id", ENV_MAC_NOTARIZATION_KEY_ID) == "") {
add_message(EXPORT_MESSAGE_ERROR, TTR("Notarization"), TTR("App Store Connect API key ID not specified."));
return Error::FAILED;
}
args.push_back("--issuer");
- args.push_back(p_preset->get("notarization/api_uuid"));
+ args.push_back(p_preset->get_or_env("notarization/api_uuid", ENV_MAC_NOTARIZATION_UUID));
- if (!p_preset->get("notarization/api_key").operator String().is_empty()) {
+ if (!p_preset->get_or_env("notarization/api_key", ENV_MAC_NOTARIZATION_KEY).operator String().is_empty()) {
args.push_back("--key");
- args.push_back(p_preset->get("notarization/api_key"));
+ args.push_back(p_preset->get_or_env("notarization/api_key", ENV_MAC_NOTARIZATION_KEY));
}
args.push_back("--key-id");
- args.push_back(p_preset->get("notarization/api_key_id"));
+ args.push_back(p_preset->get_or_env("notarization/api_key_id", ENV_MAC_NOTARIZATION_KEY_ID));
}
args.push_back("--no-progress");
@@ -925,35 +925,35 @@ Error EditorExportPlatformMacOS::_notarize(const Ref<EditorExportPreset> &p_pres
args.push_back("--primary-bundle-id");
args.push_back(p_preset->get("application/bundle_identifier"));
- if (p_preset->get("notarization/apple_id_name") == "" && p_preset->get("notarization/api_uuid") == "") {
+ if (p_preset->get_or_env("notarization/apple_id_name", ENV_MAC_NOTARIZATION_APPLE_ID) == "" && p_preset->get_or_env("notarization/api_uuid", ENV_MAC_NOTARIZATION_UUID) == "") {
add_message(EXPORT_MESSAGE_ERROR, TTR("Notarization"), TTR("Neither Apple ID name nor App Store Connect issuer ID name not specified."));
return Error::FAILED;
}
- if (p_preset->get("notarization/apple_id_name") != "" && p_preset->get("notarization/api_uuid") != "") {
+ if (p_preset->get_or_env("notarization/apple_id_name", ENV_MAC_NOTARIZATION_APPLE_ID) != "" && p_preset->get_or_env("notarization/api_uuid", ENV_MAC_NOTARIZATION_UUID) != "") {
add_message(EXPORT_MESSAGE_ERROR, TTR("Notarization"), TTR("Both Apple ID name and App Store Connect issuer ID name are specified, only one should be set at the same time."));
return Error::FAILED;
}
- if (p_preset->get("notarization/apple_id_name") != "") {
- if (p_preset->get("notarization/apple_id_password") == "") {
+ if (p_preset->get_or_env("notarization/apple_id_name", ENV_MAC_NOTARIZATION_APPLE_ID) != "") {
+ if (p_preset->get_or_env("notarization/apple_id_password", ENV_MAC_NOTARIZATION_APPLE_PASS) == "") {
add_message(EXPORT_MESSAGE_ERROR, TTR("Notarization"), TTR("Apple ID password not specified."));
return Error::FAILED;
}
args.push_back("--username");
- args.push_back(p_preset->get("notarization/apple_id_name"));
+ args.push_back(p_preset->get_or_env("notarization/apple_id_name", ENV_MAC_NOTARIZATION_APPLE_ID));
args.push_back("--password");
- args.push_back(p_preset->get("notarization/apple_id_password"));
+ args.push_back(p_preset->get_or_env("notarization/apple_id_password", ENV_MAC_NOTARIZATION_APPLE_PASS));
} else {
- if (p_preset->get("notarization/api_key") == "") {
+ if (p_preset->get_or_env("notarization/api_key", ENV_MAC_NOTARIZATION_KEY) == "") {
add_message(EXPORT_MESSAGE_ERROR, TTR("Notarization"), TTR("App Store Connect API key ID not specified."));
return Error::FAILED;
}
args.push_back("--apiIssuer");
- args.push_back(p_preset->get("notarization/api_uuid"));
+ args.push_back(p_preset->get_or_env("notarization/api_uuid", ENV_MAC_NOTARIZATION_UUID));
args.push_back("--apiKey");
- args.push_back(p_preset->get("notarization/api_key_id"));
+ args.push_back(p_preset->get_or_env("notarization/api_key_id", ENV_MAC_NOTARIZATION_KEY_ID));
}
args.push_back("--type");
@@ -1032,8 +1032,8 @@ Error EditorExportPlatformMacOS::_code_sign(const Ref<EditorExportPreset> &p_pre
args.push_back(p_ent_path);
}
- String certificate_file = p_preset->get("codesign/certificate_file");
- String certificate_pass = p_preset->get("codesign/certificate_password");
+ String certificate_file = p_preset->get_or_env("codesign/certificate_file", ENV_MAC_CODESIGN_CERT_FILE);
+ String certificate_pass = p_preset->get_or_env("codesign/certificate_password", ENV_MAC_CODESIGN_CERT_PASS);
if (!certificate_file.is_empty() && !certificate_pass.is_empty()) {
args.push_back("--p12-file");
args.push_back(certificate_file);
@@ -1763,7 +1763,7 @@ Error EditorExportPlatformMacOS::export_project(const Ref<EditorExportPreset> &p
ad_hoc = true;
} break;
case 2: { // "rcodesign"
- ad_hoc = p_preset->get("codesign/certificate_file").operator String().is_empty() || p_preset->get("codesign/certificate_password").operator String().is_empty();
+ ad_hoc = p_preset->get_or_env("codesign/certificate_file", ENV_MAC_CODESIGN_CERT_FILE).operator String().is_empty() || p_preset->get_or_env("codesign/certificate_password", ENV_MAC_CODESIGN_CERT_PASS).operator String().is_empty();
} break;
#ifdef MACOS_ENABLED
case 3: { // "codesign"
@@ -1857,7 +1857,7 @@ Error EditorExportPlatformMacOS::export_project(const Ref<EditorExportPreset> &p
int dist_type = p_preset->get("export/distribution_type");
if (dist_type == 2) {
- String pprof = p_preset->get("codesign/provisioning_profile");
+ String pprof = p_preset->get_or_env("codesign/provisioning_profile", ENV_MAC_CODESIGN_PROFILE);
String teamid = p_preset->get("codesign/apple_team_id");
String bid = p_preset->get("application/bundle_identifier");
if (!pprof.is_empty() && !teamid.is_empty()) {
@@ -1990,7 +1990,7 @@ Error EditorExportPlatformMacOS::export_project(const Ref<EditorExportPreset> &p
if (err == OK && sign_enabled) {
int dist_type = p_preset->get("export/distribution_type");
if (dist_type == 2) {
- String pprof = p_preset->get("codesign/provisioning_profile").operator String();
+ String pprof = p_preset->get_or_env("codesign/provisioning_profile", ENV_MAC_CODESIGN_PROFILE).operator String();
if (!pprof.is_empty()) {
Ref<DirAccess> da = DirAccess::create(DirAccess::ACCESS_FILESYSTEM);
err = da->copy(pprof, tmp_app_path_name + "/Contents/embedded.provisionprofile");
@@ -2147,7 +2147,7 @@ bool EditorExportPlatformMacOS::has_valid_project_configuration(const Ref<Editor
ad_hoc = true;
} break;
case 2: { // "rcodesign"
- ad_hoc = p_preset->get("codesign/certificate_file").operator String().is_empty() || p_preset->get("codesign/certificate_password").operator String().is_empty();
+ ad_hoc = p_preset->get_or_env("codesign/certificate_file", ENV_MAC_CODESIGN_CERT_FILE).operator String().is_empty() || p_preset->get_or_env("codesign/certificate_password", ENV_MAC_CODESIGN_CERT_PASS).operator String().is_empty();
} break;
#ifdef MACOS_ENABLED
case 3: { // "codesign"
diff --git a/platform/macos/export/export_plugin.h b/platform/macos/export/export_plugin.h
index a8caf535c4..0477a8c0cc 100644
--- a/platform/macos/export/export_plugin.h
+++ b/platform/macos/export/export_plugin.h
@@ -43,6 +43,17 @@
#include <sys/stat.h>
+// Optional environment variables for defining confidential information. If any
+// of these is set, they will override the values set in the credentials file.
+const String ENV_MAC_CODESIGN_CERT_FILE = "GODOT_MACOS_CODESIGN_CERTIFICATE_FILE";
+const String ENV_MAC_CODESIGN_CERT_PASS = "GODOT_MACOS_CODESIGN_CERTIFICATE_PASSWORD";
+const String ENV_MAC_CODESIGN_PROFILE = "GODOT_MACOS_CODESIGN_PROVISIONING_PROFILE";
+const String ENV_MAC_NOTARIZATION_UUID = "GODOT_MACOS_NOTARIZATION_API_UUID";
+const String ENV_MAC_NOTARIZATION_KEY = "GODOT_MACOS_NOTARIZATION_API_KEY";
+const String ENV_MAC_NOTARIZATION_KEY_ID = "GODOT_MACOS_NOTARIZATION_API_KEY_ID";
+const String ENV_MAC_NOTARIZATION_APPLE_ID = "GODOT_MACOS_NOTARIZATION_APPLE_ID_NAME";
+const String ENV_MAC_NOTARIZATION_APPLE_PASS = "GODOT_MACOS_NOTARIZATION_APPLE_ID_PASSWORD";
+
class EditorExportPlatformMacOS : public EditorExportPlatform {
GDCLASS(EditorExportPlatformMacOS, EditorExportPlatform);
diff --git a/platform/macos/os_macos.h b/platform/macos/os_macos.h
index eb7a30203a..07bae479be 100644
--- a/platform/macos/os_macos.h
+++ b/platform/macos/os_macos.h
@@ -119,6 +119,8 @@ public:
virtual Error move_to_trash(const String &p_path) override;
+ virtual String get_system_ca_certificates() override;
+
void run();
OS_MacOS();
diff --git a/platform/macos/os_macos.mm b/platform/macos/os_macos.mm
index 74cdef6f25..838ae742fd 100644
--- a/platform/macos/os_macos.mm
+++ b/platform/macos/os_macos.mm
@@ -30,6 +30,7 @@
#include "os_macos.h"
+#include "core/crypto/crypto_core.h"
#include "core/version_generated.gen.h"
#include "main/main.h"
@@ -671,6 +672,34 @@ Error OS_MacOS::move_to_trash(const String &p_path) {
return OK;
}
+String OS_MacOS::get_system_ca_certificates() {
+ CFArrayRef result;
+ SecCertificateRef item;
+ CFDataRef der;
+
+ OSStatus ret = SecTrustCopyAnchorCertificates(&result);
+ ERR_FAIL_COND_V(ret != noErr, "");
+
+ CFIndex l = CFArrayGetCount(result);
+ String certs;
+ PackedByteArray pba;
+ for (CFIndex i = 0; i < l; i++) {
+ item = (SecCertificateRef)CFArrayGetValueAtIndex(result, i);
+ der = SecCertificateCopyData(item);
+ int derlen = CFDataGetLength(der);
+ if (pba.size() < derlen * 3) {
+ pba.resize(derlen * 3);
+ }
+ size_t b64len = 0;
+ Error err = CryptoCore::b64_encode(pba.ptrw(), pba.size(), &b64len, (unsigned char *)CFDataGetBytePtr(der), derlen);
+ CFRelease(der);
+ ERR_CONTINUE(err != OK);
+ certs += "-----BEGIN CERTIFICATE-----\n" + String((char *)pba.ptr(), b64len) + "\n-----END CERTIFICATE-----\n";
+ }
+ CFRelease(result);
+ return certs;
+}
+
void OS_MacOS::run() {
if (!main_loop) {
return;
diff --git a/platform/uwp/export/export_plugin.cpp b/platform/uwp/export/export_plugin.cpp
index 163236e506..aac61184b1 100644
--- a/platform/uwp/export/export_plugin.cpp
+++ b/platform/uwp/export/export_plugin.cpp
@@ -80,8 +80,8 @@ void EditorExportPlatformUWP::get_export_options(List<ExportOption> *r_options)
r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "identity/product_guid", PROPERTY_HINT_PLACEHOLDER_TEXT, "00000000-0000-0000-0000-000000000000"), ""));
r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "identity/publisher_guid", PROPERTY_HINT_PLACEHOLDER_TEXT, "00000000-0000-0000-0000-000000000000"), ""));
- r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "signing/certificate", PROPERTY_HINT_GLOBAL_FILE, "*.pfx"), ""));
- r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "signing/password"), ""));
+ r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "signing/certificate", PROPERTY_HINT_GLOBAL_FILE, "*.pfx", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_SECRET), ""));
+ r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "signing/password", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_SECRET), ""));
r_options->push_back(ExportOption(PropertyInfo(Variant::INT, "signing/algorithm", PROPERTY_HINT_ENUM, "MD5,SHA1,SHA256"), 2));
r_options->push_back(ExportOption(PropertyInfo(Variant::INT, "version/major"), 1));
@@ -465,8 +465,8 @@ Error EditorExportPlatformUWP::export_project(const Ref<EditorExportPreset> &p_p
int cert_alg = EDITOR_GET("export/uwp/debug_algorithm");
if (!p_debug) {
- cert_path = p_preset->get("signing/certificate");
- cert_pass = p_preset->get("signing/password");
+ cert_path = p_preset->get_or_env("signing/certificate", ENV_UWP_SIGNING_CERT);
+ cert_pass = p_preset->get_or_env("signing/password", ENV_UWP_SIGNING_PASS);
cert_alg = p_preset->get("signing/algorithm");
}
diff --git a/platform/uwp/export/export_plugin.h b/platform/uwp/export/export_plugin.h
index 37a32b1f7f..b42a2ae6d9 100644
--- a/platform/uwp/export/export_plugin.h
+++ b/platform/uwp/export/export_plugin.h
@@ -85,6 +85,11 @@ static const char *uwp_device_capabilities[] = {
nullptr
};
+// Optional environment variables for defining confidential information. If any
+// of these is set, they will override the values set in the credentials file.
+const String ENV_UWP_SIGNING_CERT = "GODOT_UWP_SIGNING_CERTIFICATE";
+const String ENV_UWP_SIGNING_PASS = "GODOT_UWP_SIGNING_PASSWORD";
+
class EditorExportPlatformUWP : public EditorExportPlatform {
GDCLASS(EditorExportPlatformUWP, EditorExportPlatform);
diff --git a/platform/web/display_server_web.h b/platform/web/display_server_web.h
index 2e50a6bbc8..a72977e3c3 100644
--- a/platform/web/display_server_web.h
+++ b/platform/web/display_server_web.h
@@ -37,6 +37,8 @@
#include <emscripten/html5.h>
class DisplayServerWeb : public DisplayServer {
+ // No need to register with GDCLASS, it's platform-specific and nothing is added.
+
private:
struct JSTouchEvent {
uint32_t identifier[32] = { 0 };
diff --git a/platform/web/export/export_plugin.cpp b/platform/web/export/export_plugin.cpp
index 876efdf864..2fff628c85 100644
--- a/platform/web/export/export_plugin.cpp
+++ b/platform/web/export/export_plugin.cpp
@@ -687,5 +687,7 @@ EditorExportPlatformWeb::~EditorExportPlatformWeb() {
server->stop();
}
server_quit = true;
- server_thread.wait_to_finish();
+ if (server_thread.is_started()) {
+ server_thread.wait_to_finish();
+ }
}
diff --git a/platform/windows/detect.py b/platform/windows/detect.py
index cd6d461a93..963f533d67 100644
--- a/platform/windows/detect.py
+++ b/platform/windows/detect.py
@@ -413,6 +413,7 @@ def configure_msvc(env, vcvars_msvc_config):
"dxguid",
"imm32",
"bcrypt",
+ "Crypt32",
"Avrt",
"dwmapi",
"dwrite",
@@ -592,6 +593,7 @@ def configure_mingw(env):
"ksuser",
"imm32",
"bcrypt",
+ "crypt32",
"avrt",
"uuid",
"dwmapi",
diff --git a/platform/windows/display_server_windows.h b/platform/windows/display_server_windows.h
index 80c75c63b5..a8dcc6bad0 100644
--- a/platform/windows/display_server_windows.h
+++ b/platform/windows/display_server_windows.h
@@ -280,8 +280,7 @@ typedef struct {
} ICONDIR, *LPICONDIR;
class DisplayServerWindows : public DisplayServer {
- //No need to register, it's platform-specific and nothing is added
- //GDCLASS(DisplayServerWindows, DisplayServer)
+ // No need to register with GDCLASS, it's platform-specific and nothing is added.
_THREAD_SAFE_CLASS_
diff --git a/platform/windows/doc_classes/EditorExportPlatformWindows.xml b/platform/windows/doc_classes/EditorExportPlatformWindows.xml
index fee8a118bc..ec2b105f58 100644
--- a/platform/windows/doc_classes/EditorExportPlatformWindows.xml
+++ b/platform/windows/doc_classes/EditorExportPlatformWindows.xml
@@ -64,12 +64,15 @@
</member>
<member name="codesign/identity" type="String" setter="" getter="">
PKCS #12 certificate file used to sign executable or certificate SHA-1 hash (if [member codesign/identity_type] is set to "Use certificate store"). See [url=https://learn.microsoft.com/en-us/dotnet/framework/tools/signtool-exe]Sign Tool[/url].
+ Can be overridden with the environment variable [code]GODOT_WINDOWS_CODESIGN_IDENTITY[/code].
</member>
<member name="codesign/identity_type" type="int" setter="" getter="">
Type of identity to use. See [url=https://learn.microsoft.com/en-us/dotnet/framework/tools/signtool-exe]Sign Tool[/url].
+ Can be overridden with the environment variable [code]GODOT_WINDOWS_CODESIGN_IDENTITY_TYPE[/code].
</member>
<member name="codesign/password" type="String" setter="" getter="">
Password for the certificate file used to sign executable. See [url=https://learn.microsoft.com/en-us/dotnet/framework/tools/signtool-exe]Sign Tool[/url].
+ Can be overridden with the environment variable [code]GODOT_WINDOWS_CODESIGN_PASSWORD[/code].
</member>
<member name="codesign/timestamp" type="bool" setter="" getter="">
If [code]true[/code], time-stamp is added to the signature. See [url=https://learn.microsoft.com/en-us/dotnet/framework/tools/signtool-exe]Sign Tool[/url].
diff --git a/platform/windows/export/export_plugin.cpp b/platform/windows/export/export_plugin.cpp
index 1863a3083b..ca390236fb 100644
--- a/platform/windows/export/export_plugin.cpp
+++ b/platform/windows/export/export_plugin.cpp
@@ -328,9 +328,9 @@ void EditorExportPlatformWindows::get_export_options(List<ExportOption> *r_optio
r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "binary_format/architecture", PROPERTY_HINT_ENUM, "x86_64,x86_32,arm64"), "x86_64"));
r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "codesign/enable"), false, true));
- r_options->push_back(ExportOption(PropertyInfo(Variant::INT, "codesign/identity_type", PROPERTY_HINT_ENUM, "Select automatically,Use PKCS12 file (specify *.PFX/*.P12 file),Use certificate store (specify SHA-1 hash)"), 0));
- r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "codesign/identity", PROPERTY_HINT_GLOBAL_FILE, "*.pfx,*.p12"), ""));
- r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "codesign/password", PROPERTY_HINT_PASSWORD), ""));
+ r_options->push_back(ExportOption(PropertyInfo(Variant::INT, "codesign/identity_type", PROPERTY_HINT_ENUM, "Select automatically,Use PKCS12 file (specify *.PFX/*.P12 file),Use certificate store (specify SHA-1 hash)", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_SECRET), 0));
+ r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "codesign/identity", PROPERTY_HINT_GLOBAL_FILE, "*.pfx,*.p12", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_SECRET), ""));
+ r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "codesign/password", PROPERTY_HINT_PASSWORD, "", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_SECRET), ""));
r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "codesign/timestamp"), true));
r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "codesign/timestamp_server_url"), ""));
r_options->push_back(ExportOption(PropertyInfo(Variant::INT, "codesign/digest_algorithm", PROPERTY_HINT_ENUM, "SHA1,SHA256"), 1));
@@ -518,21 +518,21 @@ Error EditorExportPlatformWindows::_code_sign(const Ref<EditorExportPreset> &p_p
//identity
#ifdef WINDOWS_ENABLED
- int id_type = p_preset->get("codesign/identity_type");
+ int id_type = p_preset->get_or_env("codesign/identity_type", ENV_WIN_CODESIGN_ID_TYPE);
if (id_type == 0) { //auto select
args.push_back("/a");
} else if (id_type == 1) { //pkcs12
- if (p_preset->get("codesign/identity") != "") {
+ if (p_preset->get_or_env("codesign/identity", ENV_WIN_CODESIGN_ID) != "") {
args.push_back("/f");
- args.push_back(p_preset->get("codesign/identity"));
+ args.push_back(p_preset->get_or_env("codesign/identity", ENV_WIN_CODESIGN_ID));
} else {
add_message(EXPORT_MESSAGE_WARNING, TTR("Code Signing"), TTR("No identity found."));
return FAILED;
}
} else if (id_type == 2) { //Windows certificate store
- if (p_preset->get("codesign/identity") != "") {
+ if (p_preset->get_or_env("codesign/identity", ENV_WIN_CODESIGN_ID) != "") {
args.push_back("/sha1");
- args.push_back(p_preset->get("codesign/identity"));
+ args.push_back(p_preset->get_or_env("codesign/identity", ENV_WIN_CODESIGN_ID));
} else {
add_message(EXPORT_MESSAGE_WARNING, TTR("Code Signing"), TTR("No identity found."));
return FAILED;
@@ -543,9 +543,9 @@ Error EditorExportPlatformWindows::_code_sign(const Ref<EditorExportPreset> &p_p
}
#else
int id_type = 1;
- if (p_preset->get("codesign/identity") != "") {
+ if (p_preset->get_or_env("codesign/identity", ENV_WIN_CODESIGN_ID) != "") {
args.push_back("-pkcs12");
- args.push_back(p_preset->get("codesign/identity"));
+ args.push_back(p_preset->get_or_env("codesign/identity", ENV_WIN_CODESIGN_ID));
} else {
add_message(EXPORT_MESSAGE_WARNING, TTR("Code Signing"), TTR("No identity found."));
return FAILED;
@@ -553,13 +553,13 @@ Error EditorExportPlatformWindows::_code_sign(const Ref<EditorExportPreset> &p_p
#endif
//password
- if ((id_type == 1) && (p_preset->get("codesign/password") != "")) {
+ if ((id_type == 1) && (p_preset->get_or_env("codesign/password", ENV_WIN_CODESIGN_PASS) != "")) {
#ifdef WINDOWS_ENABLED
args.push_back("/p");
#else
args.push_back("-pass");
#endif
- args.push_back(p_preset->get("codesign/password"));
+ args.push_back(p_preset->get_or_env("codesign/password", ENV_WIN_CODESIGN_PASS));
}
//timestamp
diff --git a/platform/windows/export/export_plugin.h b/platform/windows/export/export_plugin.h
index c466971202..184b2f96f8 100644
--- a/platform/windows/export/export_plugin.h
+++ b/platform/windows/export/export_plugin.h
@@ -36,6 +36,12 @@
#include "editor/editor_settings.h"
#include "editor/export/editor_export_platform_pc.h"
+// Optional environment variables for defining confidential information. If any
+// of these is set, they will override the values set in the credentials file.
+const String ENV_WIN_CODESIGN_ID_TYPE = "GODOT_WINDOWS_CODESIGN_IDENTITY_TYPE";
+const String ENV_WIN_CODESIGN_ID = "GODOT_WINDOWS_CODESIGN_IDENTITY";
+const String ENV_WIN_CODESIGN_PASS = "GODOT_WINDOWS_CODESIGN_PASSWORD";
+
class EditorExportPlatformWindows : public EditorExportPlatformPC {
GDCLASS(EditorExportPlatformWindows, EditorExportPlatformPC);
diff --git a/platform/windows/os_windows.cpp b/platform/windows/os_windows.cpp
index 5a749a9d6f..bd7d9f178a 100644
--- a/platform/windows/os_windows.cpp
+++ b/platform/windows/os_windows.cpp
@@ -55,6 +55,7 @@
#include <regstr.h>
#include <shlobj.h>
#include <wbemcli.h>
+#include <wincrypt.h>
#ifdef DEBUG_ENABLED
#pragma pack(push, before_imagehlp, 8)
@@ -435,8 +436,6 @@ String OS_Windows::get_distribution_name() const {
}
String OS_Windows::get_version() const {
- typedef LONG NTSTATUS;
- typedef NTSTATUS(WINAPI * RtlGetVersionPtr)(PRTL_OSVERSIONINFOW);
RtlGetVersionPtr version_ptr = (RtlGetVersionPtr)GetProcAddress(GetModuleHandle("ntdll.dll"), "RtlGetVersion");
if (version_ptr != nullptr) {
RTL_OSVERSIONINFOW fow;
@@ -554,9 +553,9 @@ OS::DateTime OS_Windows::get_datetime(bool p_utc) const {
//Get DST information from Windows, but only if p_utc is false.
TIME_ZONE_INFORMATION info;
- bool daylight = false;
+ bool is_daylight = false;
if (!p_utc && GetTimeZoneInformation(&info) == TIME_ZONE_ID_DAYLIGHT) {
- daylight = true;
+ is_daylight = true;
}
DateTime dt;
@@ -567,20 +566,20 @@ OS::DateTime OS_Windows::get_datetime(bool p_utc) const {
dt.hour = systemtime.wHour;
dt.minute = systemtime.wMinute;
dt.second = systemtime.wSecond;
- dt.dst = daylight;
+ dt.dst = is_daylight;
return dt;
}
OS::TimeZoneInfo OS_Windows::get_time_zone_info() const {
TIME_ZONE_INFORMATION info;
- bool daylight = false;
+ bool is_daylight = false;
if (GetTimeZoneInformation(&info) == TIME_ZONE_ID_DAYLIGHT) {
- daylight = true;
+ is_daylight = true;
}
// Daylight Bias needs to be added to the bias if DST is in effect, or else it will not properly update.
TimeZoneInfo ret;
- if (daylight) {
+ if (is_daylight) {
ret.name = info.DaylightName;
ret.bias = info.Bias + info.DaylightBias;
} else {
@@ -706,16 +705,16 @@ Dictionary OS_Windows::get_memory_info() const {
}
if (pref_info.PhysicalTotal * pref_info.PageSize != 0) {
- meminfo["physical"] = pref_info.PhysicalTotal * pref_info.PageSize;
+ meminfo["physical"] = static_cast<int64_t>(pref_info.PhysicalTotal * pref_info.PageSize);
}
if (pref_info.PhysicalAvailable * pref_info.PageSize != 0) {
- meminfo["free"] = pref_info.PhysicalAvailable * pref_info.PageSize;
+ meminfo["free"] = static_cast<int64_t>(pref_info.PhysicalAvailable * pref_info.PageSize);
}
if (pref_info.CommitLimit * pref_info.PageSize != 0) {
- meminfo["available"] = pref_info.CommitLimit * pref_info.PageSize;
+ meminfo["available"] = static_cast<int64_t>(pref_info.CommitLimit * pref_info.PageSize);
}
if (HighLimit - LowLimit != 0) {
- meminfo["stack"] = HighLimit - LowLimit;
+ meminfo["stack"] = static_cast<int64_t>(HighLimit - LowLimit);
}
return meminfo;
@@ -1677,6 +1676,26 @@ Error OS_Windows::move_to_trash(const String &p_path) {
return OK;
}
+String OS_Windows::get_system_ca_certificates() {
+ HCERTSTORE cert_store = CertOpenSystemStoreA(0, "ROOT");
+ ERR_FAIL_COND_V_MSG(!cert_store, "", "Failed to read the root certificate store.");
+
+ String certs;
+ PCCERT_CONTEXT curr = CertEnumCertificatesInStore(cert_store, nullptr);
+ while (curr) {
+ DWORD size = 0;
+ bool success = CryptBinaryToStringA(curr->pbCertEncoded, curr->cbCertEncoded, CRYPT_STRING_BASE64HEADER | CRYPT_STRING_NOCR, nullptr, &size);
+ ERR_CONTINUE(!success);
+ PackedByteArray pba;
+ pba.resize(size);
+ CryptBinaryToStringA(curr->pbCertEncoded, curr->cbCertEncoded, CRYPT_STRING_BASE64HEADER | CRYPT_STRING_NOCR, (char *)pba.ptrw(), &size);
+ certs += String((char *)pba.ptr(), size);
+ curr = CertEnumCertificatesInStore(cert_store, curr);
+ }
+ CertCloseStore(cert_store, 0);
+ return certs;
+}
+
OS_Windows::OS_Windows(HINSTANCE _hInstance) {
hInstance = _hInstance;
diff --git a/platform/windows/os_windows.h b/platform/windows/os_windows.h
index 960c3f30a9..c5f95870b3 100644
--- a/platform/windows/os_windows.h
+++ b/platform/windows/os_windows.h
@@ -226,6 +226,8 @@ public:
virtual Error move_to_trash(const String &p_path) override;
+ virtual String get_system_ca_certificates() override;
+
void set_main_window(HWND p_main_window) { main_window = p_main_window; }
HINSTANCE get_hinstance() { return hInstance; }