summaryrefslogtreecommitdiffstats
path: root/platform
diff options
context:
space:
mode:
Diffstat (limited to 'platform')
-rw-r--r--platform/android/SCsub3
-rw-r--r--platform/android/detect.py21
-rw-r--r--platform/android/display_server_android.cpp2
-rw-r--r--platform/ios/detect.py8
-rw-r--r--platform/ios/display_server_ios.mm2
-rw-r--r--platform/ios/doc_classes/EditorExportPlatformIOS.xml444
-rw-r--r--platform/ios/export/export_plugin.cpp289
-rw-r--r--platform/linuxbsd/detect.py56
-rw-r--r--platform/linuxbsd/wayland/wayland_thread.cpp193
-rw-r--r--platform/linuxbsd/wayland/wayland_thread.h62
-rw-r--r--platform/linuxbsd/x11/display_server_x11.cpp2
-rw-r--r--platform/macos/detect.py8
-rw-r--r--platform/macos/display_server_macos.mm12
-rw-r--r--platform/macos/export/export_plugin.cpp48
-rw-r--r--platform/macos/export/export_plugin.h8
-rw-r--r--platform/macos/export/macho.cpp20
-rw-r--r--platform/macos/export/macho.h1
-rw-r--r--platform/macos/godot_content_view.mm2
-rw-r--r--platform/macos/godot_window_delegate.mm4
-rw-r--r--platform/web/SCsub4
-rw-r--r--platform/web/api/web_tools_editor_plugin.h2
-rw-r--r--platform/web/detect.py16
-rw-r--r--platform/web/display_server_web.cpp10
-rw-r--r--platform/web/javascript_bridge_singleton.cpp2
-rw-r--r--platform/web/js/engine/features.js3
-rw-r--r--platform/windows/SCsub6
-rw-r--r--platform/windows/console_wrapper_windows.cpp4
-rw-r--r--platform/windows/crash_handler_windows.h5
-rw-r--r--platform/windows/crash_handler_windows_seh.cpp (renamed from platform/windows/crash_handler_windows.cpp)2
-rw-r--r--platform/windows/crash_handler_windows_signal.cpp205
-rw-r--r--platform/windows/detect.py74
-rw-r--r--platform/windows/display_server_windows.cpp10
-rw-r--r--platform/windows/godot_windows.cpp2
-rw-r--r--platform/windows/os_windows.cpp34
-rw-r--r--platform/windows/windows_terminal_logger.cpp22
35 files changed, 1290 insertions, 296 deletions
diff --git a/platform/android/SCsub b/platform/android/SCsub
index 31bc7c25b0..7380511d6d 100644
--- a/platform/android/SCsub
+++ b/platform/android/SCsub
@@ -1,6 +1,7 @@
#!/usr/bin/env python
import subprocess
+from methods import print_warning
Import("env")
@@ -52,7 +53,7 @@ elif env["arch"] == "x86_32":
elif env["arch"] == "x86_64":
lib_arch_dir = "x86_64"
else:
- print("WARN: Architecture not suitable for embedding into APK; keeping .so at \\bin")
+ print_warning("Architecture not suitable for embedding into APK; keeping .so at \\bin")
if lib_arch_dir != "":
if env.dev_build:
diff --git a/platform/android/detect.py b/platform/android/detect.py
index fea8ec3287..cbd6144182 100644
--- a/platform/android/detect.py
+++ b/platform/android/detect.py
@@ -2,7 +2,7 @@ import os
import sys
import platform
import subprocess
-
+from methods import print_warning, print_error
from typing import TYPE_CHECKING
if TYPE_CHECKING:
@@ -76,7 +76,6 @@ def get_flags():
# Check if Android NDK version is installed
# If not, install it.
def install_ndk_if_needed(env: "SConsEnvironment"):
- print("Checking for Android NDK...")
sdk_root = env["ANDROID_HOME"]
if not os.path.exists(get_android_ndk_root(env)):
extension = ".bat" if os.name == "nt" else ""
@@ -87,13 +86,11 @@ def install_ndk_if_needed(env: "SConsEnvironment"):
ndk_download_args = "ndk;" + get_ndk_version()
subprocess.check_call([sdkmanager, ndk_download_args])
else:
- print("Cannot find " + sdkmanager)
- print(
- "Please ensure ANDROID_HOME is correct and cmdline-tools are installed, or install NDK version "
- + get_ndk_version()
- + " manually."
+ print_error(
+ f'Cannot find "{sdkmanager}". Please ensure ANDROID_HOME is correct and cmdline-tools'
+ f'are installed, or install NDK version "{get_ndk_version()}" manually.'
)
- sys.exit()
+ sys.exit(255)
env["ANDROID_NDK_ROOT"] = get_android_ndk_root(env)
@@ -101,15 +98,15 @@ def configure(env: "SConsEnvironment"):
# Validate arch.
supported_arches = ["x86_32", "x86_64", "arm32", "arm64"]
if env["arch"] not in supported_arches:
- print(
+ print_error(
'Unsupported CPU architecture "%s" for Android. Supported architectures are: %s.'
% (env["arch"], ", ".join(supported_arches))
)
- sys.exit()
+ sys.exit(255)
if get_min_sdk_version(env["ndk_platform"]) < get_min_target_api():
- print(
- "WARNING: minimum supported Android target api is %d. Forcing target api %d."
+ print_warning(
+ "Minimum supported Android target api is %d. Forcing target api %d."
% (get_min_target_api(), get_min_target_api())
)
env["ndk_platform"] = "android-" + str(get_min_target_api())
diff --git a/platform/android/display_server_android.cpp b/platform/android/display_server_android.cpp
index c6f2f82117..9869756be1 100644
--- a/platform/android/display_server_android.cpp
+++ b/platform/android/display_server_android.cpp
@@ -326,7 +326,7 @@ void DisplayServerAndroid::window_set_drop_files_callback(const Callable &p_call
}
void DisplayServerAndroid::_window_callback(const Callable &p_callable, const Variant &p_arg, bool p_deferred) const {
- if (!p_callable.is_null()) {
+ if (p_callable.is_valid()) {
if (p_deferred) {
p_callable.call_deferred(p_arg);
} else {
diff --git a/platform/ios/detect.py b/platform/ios/detect.py
index 0c9b7b3204..e3bac4ec5c 100644
--- a/platform/ios/detect.py
+++ b/platform/ios/detect.py
@@ -1,6 +1,6 @@
import os
import sys
-from methods import detect_darwin_sdk_path
+from methods import print_error, detect_darwin_sdk_path
from typing import TYPE_CHECKING
@@ -60,11 +60,11 @@ def configure(env: "SConsEnvironment"):
# Validate arch.
supported_arches = ["x86_64", "arm64"]
if env["arch"] not in supported_arches:
- print(
+ print_error(
'Unsupported CPU architecture "%s" for iOS. Supported architectures are: %s.'
% (env["arch"], ", ".join(supported_arches))
)
- sys.exit()
+ sys.exit(255)
## LTO
@@ -118,7 +118,7 @@ def configure(env: "SConsEnvironment"):
if env["arch"] == "x86_64":
if not env["ios_simulator"]:
- print("ERROR: Building for iOS with 'arch=x86_64' requires 'ios_simulator=yes'.")
+ print_error("Building for iOS with 'arch=x86_64' requires 'ios_simulator=yes'.")
sys.exit(255)
env["ENV"]["MACOSX_DEPLOYMENT_TARGET"] = "10.9"
diff --git a/platform/ios/display_server_ios.mm b/platform/ios/display_server_ios.mm
index cd6f855d77..62bc55dce8 100644
--- a/platform/ios/display_server_ios.mm
+++ b/platform/ios/display_server_ios.mm
@@ -218,7 +218,7 @@ void DisplayServerIOS::send_window_event(DisplayServer::WindowEvent p_event) con
}
void DisplayServerIOS::_window_callback(const Callable &p_callable, const Variant &p_arg) const {
- if (!p_callable.is_null()) {
+ if (p_callable.is_valid()) {
p_callable.call(p_arg);
}
}
diff --git a/platform/ios/doc_classes/EditorExportPlatformIOS.xml b/platform/ios/doc_classes/EditorExportPlatformIOS.xml
index 0c0ded5fea..20c1647843 100644
--- a/platform/ios/doc_classes/EditorExportPlatformIOS.xml
+++ b/platform/ios/doc_classes/EditorExportPlatformIOS.xml
@@ -29,6 +29,9 @@
<member name="application/code_sign_identity_release" type="String" setter="" getter="">
The "Full Name", "Common Name" or SHA-1 hash of the signing identity used for release export.
</member>
+ <member name="application/delete_old_export_files_unconditionally" type="bool" setter="" getter="">
+ If [code]true[/code], existing "project name" and "project name.xcodeproj" in the export destination directory will be unconditionally deleted during export.
+ </member>
<member name="application/export_method_debug" type="int" setter="" getter="">
Application distribution target (debug export).
</member>
@@ -123,12 +126,441 @@
<member name="icons/spotlight_80x80" type="String" setter="" getter="">
Spotlight icon file on iPad and iPhone (2x DPI). If left empty, it will fallback to [member ProjectSettings.application/config/icon]. See [url=https://developer.apple.com/design/human-interface-guidelines/foundations/app-icons]App icons[/url].
</member>
+ <member name="privacy/active_keyboard_access_reasons" type="int" setter="" getter="">
+ The reasons your app use active keyboard API. See [url=https://developer.apple.com/documentation/bundleresources/privacy_manifest_files/describing_use_of_required_reason_api]Describing use of required reason API[/url].
+ </member>
<member name="privacy/camera_usage_description" type="String" setter="" getter="">
A message displayed when requesting access to the device's camera (in English).
</member>
<member name="privacy/camera_usage_description_localized" type="Dictionary" setter="" getter="">
A message displayed when requesting access to the device's camera (localized).
</member>
+ <member name="privacy/collected_data/advertising_data/collected" type="bool" setter="" getter="">
+ Indicates whether your app collects advertising data.
+ </member>
+ <member name="privacy/collected_data/advertising_data/collection_purposes" type="int" setter="" getter="">
+ The reasons your app collects advertising data. See [url=https://developer.apple.com/documentation/bundleresources/privacy_manifest_files/describing_data_use_in_privacy_manifests]Describing data use in privacy manifests[/url].
+ </member>
+ <member name="privacy/collected_data/advertising_data/linked_to_user" type="bool" setter="" getter="">
+ Indicates whether your app links advertising data to the user's identity.
+ </member>
+ <member name="privacy/collected_data/advertising_data/used_for_tracking" type="bool" setter="" getter="">
+ Indicates whether your app uses advertising data for tracking.
+ </member>
+ <member name="privacy/collected_data/audio_data/collected" type="bool" setter="" getter="">
+ Indicates whether your app collects audio data data.
+ </member>
+ <member name="privacy/collected_data/audio_data/collection_purposes" type="int" setter="" getter="">
+ The reasons your app collects audio data. See [url=https://developer.apple.com/documentation/bundleresources/privacy_manifest_files/describing_data_use_in_privacy_manifests]Describing data use in privacy manifests[/url].
+ </member>
+ <member name="privacy/collected_data/audio_data/linked_to_user" type="bool" setter="" getter="">
+ Indicates whether your app links audio data data to the user's identity.
+ </member>
+ <member name="privacy/collected_data/audio_data/used_for_tracking" type="bool" setter="" getter="">
+ Indicates whether your app uses audio data data for tracking.
+ </member>
+ <member name="privacy/collected_data/browsing_history/collected" type="bool" setter="" getter="">
+ Indicates whether your app collects browsing history.
+ </member>
+ <member name="privacy/collected_data/browsing_history/collection_purposes" type="int" setter="" getter="">
+ The reasons your app collects browsing history. See [url=https://developer.apple.com/documentation/bundleresources/privacy_manifest_files/describing_data_use_in_privacy_manifests]Describing data use in privacy manifests[/url].
+ </member>
+ <member name="privacy/collected_data/browsing_history/linked_to_user" type="bool" setter="" getter="">
+ Indicates whether your app links browsing history to the user's identity.
+ </member>
+ <member name="privacy/collected_data/browsing_history/used_for_tracking" type="bool" setter="" getter="">
+ Indicates whether your app uses browsing history for tracking.
+ </member>
+ <member name="privacy/collected_data/coarse_location/collected" type="bool" setter="" getter="">
+ Indicates whether your app collects coarse location data.
+ </member>
+ <member name="privacy/collected_data/coarse_location/collection_purposes" type="int" setter="" getter="">
+ The reasons your app collects coarse location data. See [url=https://developer.apple.com/documentation/bundleresources/privacy_manifest_files/describing_data_use_in_privacy_manifests]Describing data use in privacy manifests[/url].
+ </member>
+ <member name="privacy/collected_data/coarse_location/linked_to_user" type="bool" setter="" getter="">
+ Indicates whether your app links coarse location data to the user's identity.
+ </member>
+ <member name="privacy/collected_data/coarse_location/used_for_tracking" type="bool" setter="" getter="">
+ Indicates whether your app uses coarse location data for tracking.
+ </member>
+ <member name="privacy/collected_data/contacts/collected" type="bool" setter="" getter="">
+ Indicates whether your app collects contacts.
+ </member>
+ <member name="privacy/collected_data/contacts/collection_purposes" type="int" setter="" getter="">
+ The reasons your app collects contacts. See [url=https://developer.apple.com/documentation/bundleresources/privacy_manifest_files/describing_data_use_in_privacy_manifests]Describing data use in privacy manifests[/url].
+ </member>
+ <member name="privacy/collected_data/contacts/linked_to_user" type="bool" setter="" getter="">
+ Indicates whether your app links contacts to the user's identity.
+ </member>
+ <member name="privacy/collected_data/contacts/used_for_tracking" type="bool" setter="" getter="">
+ Indicates whether your app uses contacts for tracking.
+ </member>
+ <member name="privacy/collected_data/crash_data/collected" type="bool" setter="" getter="">
+ Indicates whether your app collects crash data.
+ </member>
+ <member name="privacy/collected_data/crash_data/collection_purposes" type="int" setter="" getter="">
+ The reasons your app collects crash data. See [url=https://developer.apple.com/documentation/bundleresources/privacy_manifest_files/describing_data_use_in_privacy_manifests]Describing data use in privacy manifests[/url].
+ </member>
+ <member name="privacy/collected_data/crash_data/linked_to_user" type="bool" setter="" getter="">
+ Indicates whether your app links crash data to the user's identity.
+ </member>
+ <member name="privacy/collected_data/crash_data/used_for_tracking" type="bool" setter="" getter="">
+ Indicates whether your app uses crash data for tracking.
+ </member>
+ <member name="privacy/collected_data/credit_info/collected" type="bool" setter="" getter="">
+ Indicates whether your app collects credit information.
+ </member>
+ <member name="privacy/collected_data/credit_info/collection_purposes" type="int" setter="" getter="">
+ The reasons your app collects credit information. See [url=https://developer.apple.com/documentation/bundleresources/privacy_manifest_files/describing_data_use_in_privacy_manifests]Describing data use in privacy manifests[/url].
+ </member>
+ <member name="privacy/collected_data/credit_info/linked_to_user" type="bool" setter="" getter="">
+ Indicates whether your app links credit information to the user's identity.
+ </member>
+ <member name="privacy/collected_data/credit_info/used_for_tracking" type="bool" setter="" getter="">
+ Indicates whether your app uses credit information for tracking.
+ </member>
+ <member name="privacy/collected_data/customer_support/collected" type="bool" setter="" getter="">
+ Indicates whether your app collects customer support data.
+ </member>
+ <member name="privacy/collected_data/customer_support/collection_purposes" type="int" setter="" getter="">
+ The reasons your app collects customer support data. See [url=https://developer.apple.com/documentation/bundleresources/privacy_manifest_files/describing_data_use_in_privacy_manifests]Describing data use in privacy manifests[/url].
+ </member>
+ <member name="privacy/collected_data/customer_support/linked_to_user" type="bool" setter="" getter="">
+ Indicates whether your app links customer support data to the user's identity.
+ </member>
+ <member name="privacy/collected_data/customer_support/used_for_tracking" type="bool" setter="" getter="">
+ Indicates whether your app uses customer support data for tracking.
+ </member>
+ <member name="privacy/collected_data/device_id/collected" type="bool" setter="" getter="">
+ Indicates whether your app collects device IDs.
+ </member>
+ <member name="privacy/collected_data/device_id/collection_purposes" type="int" setter="" getter="">
+ The reasons your app collects device IDs. See [url=https://developer.apple.com/documentation/bundleresources/privacy_manifest_files/describing_data_use_in_privacy_manifests]Describing data use in privacy manifests[/url].
+ </member>
+ <member name="privacy/collected_data/device_id/linked_to_user" type="bool" setter="" getter="">
+ Indicates whether your app links device IDs to the user's identity.
+ </member>
+ <member name="privacy/collected_data/device_id/used_for_tracking" type="bool" setter="" getter="">
+ Indicates whether your app uses device IDs for tracking.
+ </member>
+ <member name="privacy/collected_data/email_address/collected" type="bool" setter="" getter="">
+ Indicates whether your app collects email address.
+ </member>
+ <member name="privacy/collected_data/email_address/collection_purposes" type="int" setter="" getter="">
+ The reasons your app collects email address. See [url=https://developer.apple.com/documentation/bundleresources/privacy_manifest_files/describing_data_use_in_privacy_manifests]Describing data use in privacy manifests[/url].
+ </member>
+ <member name="privacy/collected_data/email_address/linked_to_user" type="bool" setter="" getter="">
+ Indicates whether your app links email address to the user's identity.
+ </member>
+ <member name="privacy/collected_data/email_address/used_for_tracking" type="bool" setter="" getter="">
+ Indicates whether your app uses email address for tracking.
+ </member>
+ <member name="privacy/collected_data/emails_or_text_messages/collected" type="bool" setter="" getter="">
+ Indicates whether your app collects emails or text messages.
+ </member>
+ <member name="privacy/collected_data/emails_or_text_messages/collection_purposes" type="int" setter="" getter="">
+ The reasons your app collects emails or text messages. See [url=https://developer.apple.com/documentation/bundleresources/privacy_manifest_files/describing_data_use_in_privacy_manifests]Describing data use in privacy manifests[/url].
+ </member>
+ <member name="privacy/collected_data/emails_or_text_messages/linked_to_user" type="bool" setter="" getter="">
+ Indicates whether your app links emails or text messages to the user's identity.
+ </member>
+ <member name="privacy/collected_data/emails_or_text_messages/used_for_tracking" type="bool" setter="" getter="">
+ Indicates whether your app uses emails or text messages for tracking.
+ </member>
+ <member name="privacy/collected_data/environment_scanning/collected" type="bool" setter="" getter="">
+ Indicates whether your app collects environment scanning data.
+ </member>
+ <member name="privacy/collected_data/environment_scanning/collection_purposes" type="int" setter="" getter="">
+ The reasons your app collects environment scanning data. See [url=https://developer.apple.com/documentation/bundleresources/privacy_manifest_files/describing_data_use_in_privacy_manifests]Describing data use in privacy manifests[/url].
+ </member>
+ <member name="privacy/collected_data/environment_scanning/linked_to_user" type="bool" setter="" getter="">
+ Indicates whether your app links environment scanning data to the user's identity.
+ </member>
+ <member name="privacy/collected_data/environment_scanning/used_for_tracking" type="bool" setter="" getter="">
+ Indicates whether your app uses environment scanning data for tracking.
+ </member>
+ <member name="privacy/collected_data/fitness/collected" type="bool" setter="" getter="">
+ Indicates whether your app collects fitness and exercise data.
+ </member>
+ <member name="privacy/collected_data/fitness/collection_purposes" type="int" setter="" getter="">
+ The reasons your app collects fitness and exercise data. See [url=https://developer.apple.com/documentation/bundleresources/privacy_manifest_files/describing_data_use_in_privacy_manifests]Describing data use in privacy manifests[/url].
+ </member>
+ <member name="privacy/collected_data/fitness/linked_to_user" type="bool" setter="" getter="">
+ Indicates whether your app links fitness and exercise data to the user's identity.
+ </member>
+ <member name="privacy/collected_data/fitness/used_for_tracking" type="bool" setter="" getter="">
+ Indicates whether your app uses fitness and exercise data for tracking.
+ </member>
+ <member name="privacy/collected_data/gameplay_content/collected" type="bool" setter="" getter="">
+ Indicates whether your app collects gameplay content.
+ </member>
+ <member name="privacy/collected_data/gameplay_content/collection_purposes" type="int" setter="" getter="">
+ The reasons your app collects gameplay content. See [url=https://developer.apple.com/documentation/bundleresources/privacy_manifest_files/describing_data_use_in_privacy_manifests]Describing data use in privacy manifests[/url].
+ </member>
+ <member name="privacy/collected_data/gameplay_content/linked_to_user" type="bool" setter="" getter="">
+ Indicates whether your app links gameplay content to the user's identity.
+ </member>
+ <member name="privacy/collected_data/gameplay_content/used_for_tracking" type="bool" setter="" getter="">
+ Indicates whether your app uses gameplay content for tracking.
+ </member>
+ <member name="privacy/collected_data/hands/collected" type="bool" setter="" getter="">
+ Indicates whether your app collects user's hand structure and hand movements.
+ </member>
+ <member name="privacy/collected_data/hands/collection_purposes" type="int" setter="" getter="">
+ The reasons your app collects user's hand structure and hand movements. See [url=https://developer.apple.com/documentation/bundleresources/privacy_manifest_files/describing_data_use_in_privacy_manifests]Describing data use in privacy manifests[/url].
+ </member>
+ <member name="privacy/collected_data/hands/linked_to_user" type="bool" setter="" getter="">
+ Indicates whether your app links user's hand structure and hand movements to the user's identity.
+ </member>
+ <member name="privacy/collected_data/hands/used_for_tracking" type="bool" setter="" getter="">
+ Indicates whether your app uses user's hand structure and hand movements for tracking.
+ </member>
+ <member name="privacy/collected_data/head/collected" type="bool" setter="" getter="">
+ Indicates whether your app collects user's head movement.
+ </member>
+ <member name="privacy/collected_data/head/collection_purposes" type="int" setter="" getter="">
+ The reasons your app collects user's head movement. See [url=https://developer.apple.com/documentation/bundleresources/privacy_manifest_files/describing_data_use_in_privacy_manifests]Describing data use in privacy manifests[/url].
+ </member>
+ <member name="privacy/collected_data/head/linked_to_user" type="bool" setter="" getter="">
+ Indicates whether your app links user's head movement to the user's identity.
+ </member>
+ <member name="privacy/collected_data/head/used_for_tracking" type="bool" setter="" getter="">
+ Indicates whether your app uses user's head movement for tracking.
+ </member>
+ <member name="privacy/collected_data/health/collected" type="bool" setter="" getter="">
+ Indicates whether your app collects health and medical data.
+ </member>
+ <member name="privacy/collected_data/health/collection_purposes" type="int" setter="" getter="">
+ The reasons your app collects health and medical data. See [url=https://developer.apple.com/documentation/bundleresources/privacy_manifest_files/describing_data_use_in_privacy_manifests]Describing data use in privacy manifests[/url].
+ </member>
+ <member name="privacy/collected_data/health/linked_to_user" type="bool" setter="" getter="">
+ Indicates whether your app links health and medical data to the user's identity.
+ </member>
+ <member name="privacy/collected_data/health/used_for_tracking" type="bool" setter="" getter="">
+ Indicates whether your app uses health and medical data for tracking.
+ </member>
+ <member name="privacy/collected_data/name/collected" type="bool" setter="" getter="">
+ Indicates whether your app collects user's name.
+ </member>
+ <member name="privacy/collected_data/name/collection_purposes" type="int" setter="" getter="">
+ The reasons your app collects user's name. See [url=https://developer.apple.com/documentation/bundleresources/privacy_manifest_files/describing_data_use_in_privacy_manifests]Describing data use in privacy manifests[/url].
+ </member>
+ <member name="privacy/collected_data/name/linked_to_user" type="bool" setter="" getter="">
+ Indicates whether your app links user's name to the user's identity.
+ </member>
+ <member name="privacy/collected_data/name/used_for_tracking" type="bool" setter="" getter="">
+ Indicates whether your app uses user's name for tracking.
+ </member>
+ <member name="privacy/collected_data/other_contact_info/collected" type="bool" setter="" getter="">
+ Indicates whether your app collects any other contact information.
+ </member>
+ <member name="privacy/collected_data/other_contact_info/collection_purposes" type="int" setter="" getter="">
+ The reasons your app collects any other contact information. See [url=https://developer.apple.com/documentation/bundleresources/privacy_manifest_files/describing_data_use_in_privacy_manifests]Describing data use in privacy manifests[/url].
+ </member>
+ <member name="privacy/collected_data/other_contact_info/linked_to_user" type="bool" setter="" getter="">
+ Indicates whether your app links any other contact information to the user's identity.
+ </member>
+ <member name="privacy/collected_data/other_contact_info/used_for_tracking" type="bool" setter="" getter="">
+ Indicates whether your app uses any other contact information for tracking.
+ </member>
+ <member name="privacy/collected_data/other_data_types/collected" type="bool" setter="" getter="">
+ Indicates whether your app collects any other data.
+ </member>
+ <member name="privacy/collected_data/other_data_types/collection_purposes" type="int" setter="" getter="">
+ The reasons your app collects any other data. See [url=https://developer.apple.com/documentation/bundleresources/privacy_manifest_files/describing_data_use_in_privacy_manifests]Describing data use in privacy manifests[/url].
+ </member>
+ <member name="privacy/collected_data/other_data_types/linked_to_user" type="bool" setter="" getter="">
+ Indicates whether your app links any other data to the user's identity.
+ </member>
+ <member name="privacy/collected_data/other_data_types/used_for_tracking" type="bool" setter="" getter="">
+ Indicates whether your app uses any other data for tracking.
+ </member>
+ <member name="privacy/collected_data/other_diagnostic_data/collected" type="bool" setter="" getter="">
+ Indicates whether your app collects any other diagnostic data.
+ </member>
+ <member name="privacy/collected_data/other_diagnostic_data/collection_purposes" type="int" setter="" getter="">
+ The reasons your app collects any other diagnostic data. See [url=https://developer.apple.com/documentation/bundleresources/privacy_manifest_files/describing_data_use_in_privacy_manifests]Describing data use in privacy manifests[/url].
+ </member>
+ <member name="privacy/collected_data/other_diagnostic_data/linked_to_user" type="bool" setter="" getter="">
+ Indicates whether your app links any other diagnostic data to the user's identity.
+ </member>
+ <member name="privacy/collected_data/other_diagnostic_data/used_for_tracking" type="bool" setter="" getter="">
+ Indicates whether your app uses any other diagnostic data for tracking.
+ </member>
+ <member name="privacy/collected_data/other_financial_info/collected" type="bool" setter="" getter="">
+ Indicates whether your app collects any other financial information.
+ </member>
+ <member name="privacy/collected_data/other_financial_info/collection_purposes" type="int" setter="" getter="">
+ The reasons your app collects any other financial information. See [url=https://developer.apple.com/documentation/bundleresources/privacy_manifest_files/describing_data_use_in_privacy_manifests]Describing data use in privacy manifests[/url].
+ </member>
+ <member name="privacy/collected_data/other_financial_info/linked_to_user" type="bool" setter="" getter="">
+ Indicates whether your app links any other financial information to the user's identity.
+ </member>
+ <member name="privacy/collected_data/other_financial_info/used_for_tracking" type="bool" setter="" getter="">
+ Indicates whether your app uses any other financial information for tracking.
+ </member>
+ <member name="privacy/collected_data/other_usage_data/collected" type="bool" setter="" getter="">
+ Indicates whether your app collects any other usage data.
+ </member>
+ <member name="privacy/collected_data/other_usage_data/collection_purposes" type="int" setter="" getter="">
+ The reasons your app collects any other usage data. See [url=https://developer.apple.com/documentation/bundleresources/privacy_manifest_files/describing_data_use_in_privacy_manifests]Describing data use in privacy manifests[/url].
+ </member>
+ <member name="privacy/collected_data/other_usage_data/linked_to_user" type="bool" setter="" getter="">
+ Indicates whether your app links any other usage data to the user's identity.
+ </member>
+ <member name="privacy/collected_data/other_usage_data/used_for_tracking" type="bool" setter="" getter="">
+ Indicates whether your app uses any other usage data for tracking.
+ </member>
+ <member name="privacy/collected_data/other_user_content/collected" type="bool" setter="" getter="">
+ Indicates whether your app collects any other user generated content.
+ </member>
+ <member name="privacy/collected_data/other_user_content/collection_purposes" type="int" setter="" getter="">
+ The reasons your app collects any other user generated content. See [url=https://developer.apple.com/documentation/bundleresources/privacy_manifest_files/describing_data_use_in_privacy_manifests]Describing data use in privacy manifests[/url].
+ </member>
+ <member name="privacy/collected_data/other_user_content/linked_to_user" type="bool" setter="" getter="">
+ Indicates whether your app links any other user generated content to the user's identity.
+ </member>
+ <member name="privacy/collected_data/other_user_content/used_for_tracking" type="bool" setter="" getter="">
+ Indicates whether your app uses any other user generated content for tracking.
+ </member>
+ <member name="privacy/collected_data/payment_info/collected" type="bool" setter="" getter="">
+ Indicates whether your app collects payment information.
+ </member>
+ <member name="privacy/collected_data/payment_info/collection_purposes" type="int" setter="" getter="">
+ The reasons your app collects payment information. See [url=https://developer.apple.com/documentation/bundleresources/privacy_manifest_files/describing_data_use_in_privacy_manifests]Describing data use in privacy manifests[/url].
+ </member>
+ <member name="privacy/collected_data/payment_info/linked_to_user" type="bool" setter="" getter="">
+ Indicates whether your app links payment information to the user's identity.
+ </member>
+ <member name="privacy/collected_data/payment_info/used_for_tracking" type="bool" setter="" getter="">
+ Indicates whether your app uses payment information for tracking.
+ </member>
+ <member name="privacy/collected_data/performance_data/collected" type="bool" setter="" getter="">
+ Indicates whether your app collects performance data.
+ </member>
+ <member name="privacy/collected_data/performance_data/collection_purposes" type="int" setter="" getter="">
+ The reasons your app collects performance data. See [url=https://developer.apple.com/documentation/bundleresources/privacy_manifest_files/describing_data_use_in_privacy_manifests]Describing data use in privacy manifests[/url].
+ </member>
+ <member name="privacy/collected_data/performance_data/linked_to_user" type="bool" setter="" getter="">
+ Indicates whether your app links performance data to the user's identity.
+ </member>
+ <member name="privacy/collected_data/performance_data/used_for_tracking" type="bool" setter="" getter="">
+ Indicates whether your app uses performance data for tracking.
+ </member>
+ <member name="privacy/collected_data/phone_number/collected" type="bool" setter="" getter="">
+ Indicates whether your app collects phone number.
+ </member>
+ <member name="privacy/collected_data/phone_number/collection_purposes" type="int" setter="" getter="">
+ The reasons your app collects phone number. See [url=https://developer.apple.com/documentation/bundleresources/privacy_manifest_files/describing_data_use_in_privacy_manifests]Describing data use in privacy manifests[/url].
+ </member>
+ <member name="privacy/collected_data/phone_number/linked_to_user" type="bool" setter="" getter="">
+ Indicates whether your app links phone number to the user's identity.
+ </member>
+ <member name="privacy/collected_data/phone_number/used_for_tracking" type="bool" setter="" getter="">
+ Indicates whether your app uses phone number for tracking.
+ </member>
+ <member name="privacy/collected_data/photos_or_videos/collected" type="bool" setter="" getter="">
+ Indicates whether your app collects photos or videos.
+ </member>
+ <member name="privacy/collected_data/photos_or_videos/collection_purposes" type="int" setter="" getter="">
+ The reasons your app collects photos or videos. See [url=https://developer.apple.com/documentation/bundleresources/privacy_manifest_files/describing_data_use_in_privacy_manifests]Describing data use in privacy manifests[/url].
+ </member>
+ <member name="privacy/collected_data/photos_or_videos/linked_to_user" type="bool" setter="" getter="">
+ Indicates whether your app links photos or videos to the user's identity.
+ </member>
+ <member name="privacy/collected_data/photos_or_videos/used_for_tracking" type="bool" setter="" getter="">
+ Indicates whether your app uses photos or videos for tracking.
+ </member>
+ <member name="privacy/collected_data/physical_address/collected" type="bool" setter="" getter="">
+ Indicates whether your app collects physical address.
+ </member>
+ <member name="privacy/collected_data/physical_address/collection_purposes" type="int" setter="" getter="">
+ The reasons your app collects physical address. See [url=https://developer.apple.com/documentation/bundleresources/privacy_manifest_files/describing_data_use_in_privacy_manifests]Describing data use in privacy manifests[/url].
+ </member>
+ <member name="privacy/collected_data/physical_address/linked_to_user" type="bool" setter="" getter="">
+ Indicates whether your app links physical address to the user's identity.
+ </member>
+ <member name="privacy/collected_data/physical_address/used_for_tracking" type="bool" setter="" getter="">
+ Indicates whether your app uses physical address for tracking.
+ </member>
+ <member name="privacy/collected_data/precise_location/collected" type="bool" setter="" getter="">
+ Indicates whether your app collects precise location data.
+ </member>
+ <member name="privacy/collected_data/precise_location/collection_purposes" type="int" setter="" getter="">
+ The reasons your app collects precise location data. See [url=https://developer.apple.com/documentation/bundleresources/privacy_manifest_files/describing_data_use_in_privacy_manifests]Describing data use in privacy manifests[/url].
+ </member>
+ <member name="privacy/collected_data/precise_location/linked_to_user" type="bool" setter="" getter="">
+ Indicates whether your app links precise location data to the user's identity.
+ </member>
+ <member name="privacy/collected_data/precise_location/used_for_tracking" type="bool" setter="" getter="">
+ Indicates whether your app uses precise location data for tracking.
+ </member>
+ <member name="privacy/collected_data/product_interaction/collected" type="bool" setter="" getter="">
+ Indicates whether your app collects product interaction data.
+ </member>
+ <member name="privacy/collected_data/product_interaction/collection_purposes" type="int" setter="" getter="">
+ The reasons your app collects product interaction data. See [url=https://developer.apple.com/documentation/bundleresources/privacy_manifest_files/describing_data_use_in_privacy_manifests]Describing data use in privacy manifests[/url].
+ </member>
+ <member name="privacy/collected_data/product_interaction/linked_to_user" type="bool" setter="" getter="">
+ Indicates whether your app links product interaction data to the user's identity.
+ </member>
+ <member name="privacy/collected_data/product_interaction/used_for_tracking" type="bool" setter="" getter="">
+ Indicates whether your app uses product interaction data for tracking.
+ </member>
+ <member name="privacy/collected_data/purchase_history/collected" type="bool" setter="" getter="">
+ Indicates whether your app collects purchase history.
+ </member>
+ <member name="privacy/collected_data/purchase_history/collection_purposes" type="int" setter="" getter="">
+ The reasons your app collects purchase history. See [url=https://developer.apple.com/documentation/bundleresources/privacy_manifest_files/describing_data_use_in_privacy_manifests]Describing data use in privacy manifests[/url].
+ </member>
+ <member name="privacy/collected_data/purchase_history/linked_to_user" type="bool" setter="" getter="">
+ Indicates whether your app links purchase history to the user's identity.
+ </member>
+ <member name="privacy/collected_data/purchase_history/used_for_tracking" type="bool" setter="" getter="">
+ Indicates whether your app uses purchase history for tracking.
+ </member>
+ <member name="privacy/collected_data/search_hhistory/collected" type="bool" setter="" getter="">
+ Indicates whether your app collects search history.
+ </member>
+ <member name="privacy/collected_data/search_hhistory/collection_purposes" type="int" setter="" getter="">
+ The reasons your app collects search history. See [url=https://developer.apple.com/documentation/bundleresources/privacy_manifest_files/describing_data_use_in_privacy_manifests]Describing data use in privacy manifests[/url].
+ </member>
+ <member name="privacy/collected_data/search_hhistory/linked_to_user" type="bool" setter="" getter="">
+ Indicates whether your app links search history to the user's identity.
+ </member>
+ <member name="privacy/collected_data/search_hhistory/used_for_tracking" type="bool" setter="" getter="">
+ Indicates whether your app uses search history for tracking.
+ </member>
+ <member name="privacy/collected_data/sensitive_info/collected" type="bool" setter="" getter="">
+ Indicates whether your app collects sensitive user information.
+ </member>
+ <member name="privacy/collected_data/sensitive_info/collection_purposes" type="int" setter="" getter="">
+ The reasons your app collects sensitive user information. See [url=https://developer.apple.com/documentation/bundleresources/privacy_manifest_files/describing_data_use_in_privacy_manifests]Describing data use in privacy manifests[/url].
+ </member>
+ <member name="privacy/collected_data/sensitive_info/linked_to_user" type="bool" setter="" getter="">
+ Indicates whether your app links sensitive user information to the user's identity.
+ </member>
+ <member name="privacy/collected_data/sensitive_info/used_for_tracking" type="bool" setter="" getter="">
+ Indicates whether your app uses sensitive user information for tracking.
+ </member>
+ <member name="privacy/collected_data/user_id/collected" type="bool" setter="" getter="">
+ Indicates whether your app collects user IDs.
+ </member>
+ <member name="privacy/collected_data/user_id/collection_purposes" type="int" setter="" getter="">
+ The reasons your app collects user IDs. See [url=https://developer.apple.com/documentation/bundleresources/privacy_manifest_files/describing_data_use_in_privacy_manifests]Describing data use in privacy manifests[/url].
+ </member>
+ <member name="privacy/collected_data/user_id/linked_to_user" type="bool" setter="" getter="">
+ Indicates whether your app links user IDs to the user's identity.
+ </member>
+ <member name="privacy/collected_data/user_id/used_for_tracking" type="bool" setter="" getter="">
+ Indicates whether your app uses user IDs for tracking.
+ </member>
+ <member name="privacy/disk_space_access_reasons" type="int" setter="" getter="">
+ The reasons your app use free disk space API. See [url=https://developer.apple.com/documentation/bundleresources/privacy_manifest_files/describing_use_of_required_reason_api]Describing use of required reason API[/url].
+ </member>
+ <member name="privacy/file_timestamp_access_reasons" type="int" setter="" getter="">
+ The reasons your app use file timestamp/metadata API. See [url=https://developer.apple.com/documentation/bundleresources/privacy_manifest_files/describing_use_of_required_reason_api]Describing use of required reason API[/url].
+ </member>
<member name="privacy/microphone_usage_description" type="String" setter="" getter="">
A message displayed when requesting access to the device's microphone (in English).
</member>
@@ -141,6 +573,18 @@
<member name="privacy/photolibrary_usage_description_localized" type="Dictionary" setter="" getter="">
A message displayed when requesting access to the user's photo library (localized).
</member>
+ <member name="privacy/system_boot_time_access_reasons" type="int" setter="" getter="">
+ The reasons your app use system boot time / absolute time API. See [url=https://developer.apple.com/documentation/bundleresources/privacy_manifest_files/describing_use_of_required_reason_api]Describing use of required reason API[/url].
+ </member>
+ <member name="privacy/tracking_domains" type="PackedStringArray" setter="" getter="">
+ The list of internet domains your app connects to that engage in tracking. See [url=https://developer.apple.com/documentation/bundleresources/privacy_manifest_files]Privacy manifest files[/url].
+ </member>
+ <member name="privacy/tracking_enabled" type="bool" setter="" getter="">
+ Indicates whether your app uses data for tracking. See [url=https://developer.apple.com/documentation/bundleresources/privacy_manifest_files]Privacy manifest files[/url].
+ </member>
+ <member name="privacy/user_defaults_access_reasons" type="int" setter="" getter="">
+ The reasons your app use user defaults API. See [url=https://developer.apple.com/documentation/bundleresources/privacy_manifest_files/describing_use_of_required_reason_api]Describing use of required reason API[/url].
+ </member>
<member name="storyboard/custom_bg_color" type="Color" setter="" getter="">
A custom background color of the storyboard launch screen.
</member>
diff --git a/platform/ios/export/export_plugin.cpp b/platform/ios/export/export_plugin.cpp
index 33389129b7..c35c72d093 100644
--- a/platform/ios/export/export_plugin.cpp
+++ b/platform/ios/export/export_plugin.cpp
@@ -106,6 +106,94 @@ static const IconInfo icon_infos[] = {
{ PNAME("icons/notification_60x60"), "iphone", "Icon-60.png", "60", "3x", "20x20", false }
};
+struct APIAccessInfo {
+ String prop_name;
+ String type_name;
+ Vector<String> prop_flag_value;
+ Vector<String> prop_flag_name;
+ int default_value;
+};
+
+static const APIAccessInfo api_info[] = {
+ { "file_timestamp",
+ "NSPrivacyAccessedAPICategoryFileTimestamp",
+ { "DDA9.1", "C617.1", "3B52.1" },
+ { "Display to user on-device:", "Inside app or group container", "Files provided to app by user" },
+ 3 },
+ { "system_boot_time",
+ "NSPrivacyAccessedAPICategorySystemBootTime",
+ { "35F9.1", "8FFB.1", "3D61.1" },
+ { "Measure time on-device", "Calculate absolute event timestamps", "User-initiated bug report" },
+ 1 },
+ { "disk_space",
+ "NSPrivacyAccessedAPICategoryDiskSpace",
+ { "E174.1", "85F4.1", "7D9E.1", "B728.1" },
+ { "Write or delete file on-device", "Display to user on-device", "User-initiated bug report", "Health research app" },
+ 3 },
+ { "active_keyboard",
+ "NSPrivacyAccessedAPICategoryActiveKeyboards",
+ { "3EC4.1", "54BD.1" },
+ { "Custom keyboard app on-device", "Customize UI on-device:2" },
+ 0 },
+ { "user_defaults",
+ "NSPrivacyAccessedAPICategoryUserDefaults",
+ { "1C8F.1", "AC6B.1", "CA92.1" },
+ { "Access info from same App Group", "Access managed app configuration", "Access info from same app" },
+ 0 }
+};
+
+struct DataCollectionInfo {
+ String prop_name;
+ String type_name;
+};
+
+static const DataCollectionInfo data_collect_type_info[] = {
+ { "name", "NSPrivacyCollectedDataTypeName" },
+ { "email_address", "NSPrivacyCollectedDataTypeEmailAddress" },
+ { "phone_number", "NSPrivacyCollectedDataTypePhoneNumber" },
+ { "physical_address", "NSPrivacyCollectedDataTypePhysicalAddress" },
+ { "other_contact_info", "NSPrivacyCollectedDataTypeOtherUserContactInfo" },
+ { "health", "NSPrivacyCollectedDataTypeHealth" },
+ { "fitness", "NSPrivacyCollectedDataTypeFitness" },
+ { "payment_info", "NSPrivacyCollectedDataTypePaymentInfo" },
+ { "credit_info", "NSPrivacyCollectedDataTypeCreditInfo" },
+ { "other_financial_info", "NSPrivacyCollectedDataTypeOtherFinancialInfo" },
+ { "precise_location", "NSPrivacyCollectedDataTypePreciseLocation" },
+ { "coarse_location", "NSPrivacyCollectedDataTypeCoarseLocation" },
+ { "sensitive_info", "NSPrivacyCollectedDataTypeSensitiveInfo" },
+ { "contacts", "NSPrivacyCollectedDataTypeContacts" },
+ { "emails_or_text_messages", "NSPrivacyCollectedDataTypeEmailsOrTextMessages" },
+ { "photos_or_videos", "NSPrivacyCollectedDataTypePhotosorVideos" },
+ { "audio_data", "NSPrivacyCollectedDataTypeAudioData" },
+ { "gameplay_content", "NSPrivacyCollectedDataTypeGameplayContent" },
+ { "customer_support", "NSPrivacyCollectedDataTypeCustomerSupport" },
+ { "other_user_content", "NSPrivacyCollectedDataTypeOtherUserContent" },
+ { "browsing_history", "NSPrivacyCollectedDataTypeBrowsingHistory" },
+ { "search_hhistory", "NSPrivacyCollectedDataTypeSearchHistory" },
+ { "user_id", "NSPrivacyCollectedDataTypeUserID" },
+ { "device_id", "NSPrivacyCollectedDataTypeDeviceID" },
+ { "purchase_history", "NSPrivacyCollectedDataTypePurchaseHistory" },
+ { "product_interaction", "NSPrivacyCollectedDataTypeProductInteraction" },
+ { "advertising_data", "NSPrivacyCollectedDataTypeAdvertisingData" },
+ { "other_usage_data", "NSPrivacyCollectedDataTypeOtherUsageData" },
+ { "crash_data", "NSPrivacyCollectedDataTypeCrashData" },
+ { "performance_data", "NSPrivacyCollectedDataTypePerformanceData" },
+ { "other_diagnostic_data", "NSPrivacyCollectedDataTypeOtherDiagnosticData" },
+ { "environment_scanning", "NSPrivacyCollectedDataTypeEnvironmentScanning" },
+ { "hands", "NSPrivacyCollectedDataTypeHands" },
+ { "head", "NSPrivacyCollectedDataTypeHead" },
+ { "other_data_types", "NSPrivacyCollectedDataTypeOtherDataTypes" },
+};
+
+static const DataCollectionInfo data_collect_purpose_info[] = {
+ { "Analytics", "NSPrivacyCollectedDataTypePurposeAnalytics" },
+ { "App Functionality", "NSPrivacyCollectedDataTypePurposeAppFunctionality" },
+ { "Developer Advertising", "NSPrivacyCollectedDataTypePurposeDeveloperAdvertising" },
+ { "Third-party Advertising", "NSPrivacyCollectedDataTypePurposeThirdPartyAdvertising" },
+ { "Product Personalization", "NSPrivacyCollectedDataTypePurposeProductPersonalization" },
+ { "Other", "NSPrivacyCollectedDataTypePurposeOther" },
+};
+
String EditorExportPlatformIOS::get_export_option_warning(const EditorExportPreset *p_preset, const StringName &p_name) const {
if (p_preset) {
if (p_name == "application/app_store_team_id") {
@@ -119,6 +207,21 @@ String EditorExportPlatformIOS::get_export_option_warning(const EditorExportPres
if (!is_package_name_valid(identifier, &pn_err)) {
return TTR("Invalid Identifier:") + " " + pn_err;
}
+ } else if (p_name == "privacy/file_timestamp_access_reasons") {
+ int access = p_preset->get("privacy/file_timestamp_access_reasons");
+ if (access == 0) {
+ return TTR("At least one file timestamp access reason should be selected.");
+ }
+ } else if (p_name == "privacy/disk_space_access_reasons") {
+ int access = p_preset->get("privacy/disk_space_access_reasons");
+ if (access == 0) {
+ return TTR("At least one disk space access reason should be selected.");
+ }
+ } else if (p_name == "privacy/system_boot_time_access_reasons") {
+ int access = p_preset->get("privacy/system_boot_time_access_reasons");
+ if (access == 0) {
+ return TTR("At least one system boot time access reason should be selected.");
+ }
}
}
return String();
@@ -140,6 +243,15 @@ bool EditorExportPlatformIOS::get_export_option_visibility(const EditorExportPre
return false;
}
+ if (p_preset == nullptr) {
+ return true;
+ }
+
+ bool advanced_options_enabled = p_preset->are_advanced_options_enabled();
+ if (p_option.begins_with("privacy")) {
+ return advanced_options_enabled;
+ }
+
return true;
}
@@ -175,6 +287,7 @@ void EditorExportPlatformIOS::get_export_options(List<ExportOption> *r_options)
r_options->push_back(ExportOption(PropertyInfo(Variant::INT, "application/icon_interpolation", PROPERTY_HINT_ENUM, "Nearest neighbor,Bilinear,Cubic,Trilinear,Lanczos"), 4));
r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "application/export_project_only"), false));
+ r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "application/delete_old_export_files_unconditionally"), false));
Vector<PluginConfigIOS> found_plugins = get_plugins();
for (int i = 0; i < found_plugins.size(); i++) {
@@ -220,6 +333,37 @@ void EditorExportPlatformIOS::get_export_options(List<ExportOption> *r_options)
r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "privacy/photolibrary_usage_description", PROPERTY_HINT_PLACEHOLDER_TEXT, "Provide a message if you need access to the photo library"), ""));
r_options->push_back(ExportOption(PropertyInfo(Variant::DICTIONARY, "privacy/photolibrary_usage_description_localized", PROPERTY_HINT_LOCALIZABLE_STRING), Dictionary()));
+ for (uint64_t i = 0; i < sizeof(api_info) / sizeof(api_info[0]); ++i) {
+ String prop_name = vformat("privacy/%s_access_reasons", api_info[i].prop_name);
+ String hint;
+ for (int j = 0; j < api_info[i].prop_flag_value.size(); j++) {
+ if (j != 0) {
+ hint += ",";
+ }
+ hint += vformat("%s - %s:%d", api_info[i].prop_flag_value[j], api_info[i].prop_flag_name[j], (1 << j));
+ }
+ r_options->push_back(ExportOption(PropertyInfo(Variant::INT, prop_name, PROPERTY_HINT_FLAGS, hint), api_info[i].default_value));
+ }
+
+ r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "privacy/tracking_enabled"), false));
+ r_options->push_back(ExportOption(PropertyInfo(Variant::PACKED_STRING_ARRAY, "privacy/tracking_domains"), Vector<String>()));
+
+ {
+ String hint;
+ for (uint64_t i = 0; i < sizeof(data_collect_purpose_info) / sizeof(data_collect_purpose_info[0]); ++i) {
+ if (i != 0) {
+ hint += ",";
+ }
+ hint += vformat("%s:%d", data_collect_purpose_info[i].prop_name, (1 << i));
+ }
+ for (uint64_t i = 0; i < sizeof(data_collect_type_info) / sizeof(data_collect_type_info[0]); ++i) {
+ r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, vformat("privacy/collected_data/%s/collected", data_collect_type_info[i].prop_name)), false));
+ r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, vformat("privacy/collected_data/%s/linked_to_user", data_collect_type_info[i].prop_name)), false));
+ r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, vformat("privacy/collected_data/%s/used_for_tracking", data_collect_type_info[i].prop_name)), false));
+ r_options->push_back(ExportOption(PropertyInfo(Variant::INT, vformat("privacy/collected_data/%s/collection_purposes", data_collect_type_info[i].prop_name), PROPERTY_HINT_FLAGS, hint), 0));
+ }
+ }
+
HashSet<String> used_names;
for (uint64_t i = 0; i < sizeof(icon_infos) / sizeof(icon_infos[0]); ++i) {
if (!used_names.has(icon_infos[i].preset_key)) {
@@ -522,6 +666,87 @@ void EditorExportPlatformIOS::_fix_config_file(const Ref<EditorExportPreset> &p_
} else if (lines[i].find("$swift_runtime_build_phase") != -1) {
String value = !p_config.use_swift_runtime ? "" : "90B4C2B62680C7E90039117A /* dummy.swift */,";
strnew += lines[i].replace("$swift_runtime_build_phase", value) + "\n";
+ } else if (lines[i].find("$priv_collection") != -1) {
+ bool section_opened = false;
+ for (uint64_t j = 0; j < sizeof(data_collect_type_info) / sizeof(data_collect_type_info[0]); ++j) {
+ bool data_collected = p_preset->get(vformat("privacy/collected_data/%s/collected", data_collect_type_info[j].prop_name));
+ bool linked = p_preset->get(vformat("privacy/collected_data/%s/linked_to_user", data_collect_type_info[j].prop_name));
+ bool tracking = p_preset->get(vformat("privacy/collected_data/%s/used_for_tracking", data_collect_type_info[j].prop_name));
+ int purposes = p_preset->get(vformat("privacy/collected_data/%s/collection_purposes", data_collect_type_info[j].prop_name));
+ if (data_collected) {
+ if (!section_opened) {
+ section_opened = true;
+ strnew += "\t<key>NSPrivacyCollectedDataTypes</key>\n";
+ strnew += "\t<array>\n";
+ }
+ strnew += "\t\t<dict>\n";
+ strnew += "\t\t\t<key>NSPrivacyCollectedDataType</key>\n";
+ strnew += vformat("\t\t\t<string>%s</string>\n", data_collect_type_info[j].type_name);
+ strnew += "\t\t\t\t<key>NSPrivacyCollectedDataTypeLinked</key>\n";
+ if (linked) {
+ strnew += "\t\t\t\t<true/>\n";
+ } else {
+ strnew += "\t\t\t\t<false/>\n";
+ }
+ strnew += "\t\t\t\t<key>NSPrivacyCollectedDataTypeTracking</key>\n";
+ if (tracking) {
+ strnew += "\t\t\t\t<true/>\n";
+ } else {
+ strnew += "\t\t\t\t<false/>\n";
+ }
+ if (purposes != 0) {
+ strnew += "\t\t\t\t<key>NSPrivacyCollectedDataTypePurposes</key>\n";
+ strnew += "\t\t\t\t<array>\n";
+ for (uint64_t k = 0; k < sizeof(data_collect_purpose_info) / sizeof(data_collect_purpose_info[0]); ++k) {
+ if (purposes & (1 << k)) {
+ strnew += vformat("\t\t\t\t\t<string>%s</string>\n", data_collect_purpose_info[k].type_name);
+ }
+ }
+ strnew += "\t\t\t\t</array>\n";
+ }
+ strnew += "\t\t\t</dict>\n";
+ }
+ }
+ if (section_opened) {
+ strnew += "\t</array>\n";
+ }
+ } else if (lines[i].find("$priv_tracking") != -1) {
+ bool tracking = p_preset->get("privacy/tracking_enabled");
+ strnew += "\t<key>NSPrivacyTracking</key>\n";
+ if (tracking) {
+ strnew += "\t<true/>\n";
+ } else {
+ strnew += "\t<false/>\n";
+ }
+ Vector<String> tracking_domains = p_preset->get("privacy/tracking_domains");
+ if (!tracking_domains.is_empty()) {
+ strnew += "\t<key>NSPrivacyTrackingDomains</key>\n";
+ strnew += "\t<array>\n";
+ for (const String &E : tracking_domains) {
+ strnew += "\t\t<string>" + E + "</string>\n";
+ }
+ strnew += "\t</array>\n";
+ }
+ } else if (lines[i].find("$priv_api_types") != -1) {
+ strnew += "\t<array>\n";
+ for (uint64_t j = 0; j < sizeof(api_info) / sizeof(api_info[0]); ++j) {
+ int api_access = p_preset->get(vformat("privacy/%s_access_reasons", api_info[j].prop_name));
+ if (api_access != 0) {
+ strnew += "\t\t<dict>\n";
+ strnew += "\t\t\t<key>NSPrivacyAccessedAPITypeReasons</key>\n";
+ strnew += "\t\t\t<array>\n";
+ for (int k = 0; k < api_info[j].prop_flag_value.size(); k++) {
+ if (api_access & (1 << k)) {
+ strnew += vformat("\t\t\t\t<string>%s</string>\n", api_info[j].prop_flag_value[k]);
+ }
+ }
+ strnew += "\t\t\t</array>\n";
+ strnew += "\t\t\t<key>NSPrivacyAccessedAPIType</key>\n";
+ strnew += vformat("\t\t\t<string>%s</string>\n", api_info[j].type_name);
+ strnew += "\t\t</dict>\n";
+ }
+ }
+ strnew += "\t</array>\n";
} else {
strnew += lines[i] + "\n";
}
@@ -1632,19 +1857,72 @@ Error EditorExportPlatformIOS::_export_project_helper(const Ref<EditorExportPres
}
{
+ bool delete_old = p_preset->get("application/delete_old_export_files_unconditionally");
Ref<DirAccess> da = DirAccess::create(DirAccess::ACCESS_FILESYSTEM);
if (da.is_valid()) {
String current_dir = da->get_current_dir();
- // remove leftovers from last export so they don't interfere
- // in case some files are no longer needed
+ // Remove leftovers from last export so they don't interfere in case some files are no longer needed.
if (da->change_dir(binary_dir + ".xcodeproj") == OK) {
- da->erase_contents_recursive();
+ // Check directory content before deleting.
+ int expected_files = 0;
+ int total_files = 0;
+ if (!delete_old) {
+ da->list_dir_begin();
+ for (String n = da->get_next(); !n.is_empty(); n = da->get_next()) {
+ if (!n.begins_with(".")) { // Ignore ".", ".." and hidden files.
+ if (da->current_is_dir()) {
+ if (n == "xcshareddata" || n == "project.xcworkspace") {
+ expected_files++;
+ }
+ } else {
+ if (n == "project.pbxproj") {
+ expected_files++;
+ }
+ }
+ total_files++;
+ }
+ }
+ da->list_dir_end();
+ }
+ if ((total_files == 0) || (expected_files >= Math::floor(total_files * 0.8))) {
+ da->erase_contents_recursive();
+ } else {
+ add_message(EXPORT_MESSAGE_ERROR, TTR("Export"), vformat(TTR("Unexpected files found in the export destination directory \"%s.xcodeproj\", delete it manually or select another destination."), binary_dir));
+ return ERR_CANT_CREATE;
+ }
}
+ da->change_dir(current_dir);
+
if (da->change_dir(binary_dir) == OK) {
- da->erase_contents_recursive();
+ // Check directory content before deleting.
+ int expected_files = 0;
+ int total_files = 0;
+ if (!delete_old) {
+ da->list_dir_begin();
+ for (String n = da->get_next(); !n.is_empty(); n = da->get_next()) {
+ if (!n.begins_with(".")) { // Ignore ".", ".." and hidden files.
+ if (da->current_is_dir()) {
+ if (n == "dylibs" || n == "Images.xcassets" || n.ends_with(".lproj") || n == "godot-publish-dotnet" || n.ends_with(".xcframework") || n.ends_with(".framework")) {
+ expected_files++;
+ }
+ } else {
+ if (n == binary_name + "-Info.plist" || n == binary_name + ".entitlements" || n == "Launch Screen.storyboard" || n == "export_options.plist" || n.begins_with("dummy.") || n.ends_with(".gdip")) {
+ expected_files++;
+ }
+ }
+ total_files++;
+ }
+ }
+ da->list_dir_end();
+ }
+ if ((total_files == 0) || (expected_files >= Math::floor(total_files * 0.8))) {
+ da->erase_contents_recursive();
+ } else {
+ add_message(EXPORT_MESSAGE_ERROR, TTR("Export"), vformat(TTR("Unexpected files found in the export destination directory \"%s\", delete it manually or select another destination."), binary_dir));
+ return ERR_CANT_CREATE;
+ }
}
-
da->change_dir(current_dir);
if (!da->dir_exists(binary_dir)) {
@@ -1694,6 +1972,7 @@ Error EditorExportPlatformIOS::_export_project_helper(const Ref<EditorExportPres
files_to_parse.insert("godot_ios.xcodeproj/xcshareddata/xcschemes/godot_ios.xcscheme");
files_to_parse.insert("godot_ios/godot_ios.entitlements");
files_to_parse.insert("godot_ios/Launch Screen.storyboard");
+ files_to_parse.insert("PrivacyInfo.xcprivacy");
IOSConfigData config_data = {
pkg_name,
diff --git a/platform/linuxbsd/detect.py b/platform/linuxbsd/detect.py
index 27dec73b65..afc9d25a80 100644
--- a/platform/linuxbsd/detect.py
+++ b/platform/linuxbsd/detect.py
@@ -1,7 +1,7 @@
import os
import platform
import sys
-from methods import get_compiler_version, using_gcc
+from methods import print_warning, print_error, get_compiler_version, using_gcc
from platform_methods import detect_arch
from typing import TYPE_CHECKING
@@ -20,7 +20,7 @@ def can_build():
pkgconf_error = os.system("pkg-config --version > /dev/null")
if pkgconf_error:
- print("Error: pkg-config not found. Aborting.")
+ print_error("pkg-config not found. Aborting.")
return False
return True
@@ -75,7 +75,7 @@ def configure(env: "SConsEnvironment"):
# Validate arch.
supported_arches = ["x86_32", "x86_64", "arm32", "arm64", "rv64", "ppc32", "ppc64"]
if env["arch"] not in supported_arches:
- print(
+ print_error(
'Unsupported CPU architecture "%s" for Linux / *BSD. Supported architectures are: %s.'
% (env["arch"], ", ".join(supported_arches))
)
@@ -128,7 +128,9 @@ def configure(env: "SConsEnvironment"):
found_wrapper = True
break
if not found_wrapper:
- print("Couldn't locate mold installation path. Make sure it's installed in /usr or /usr/local.")
+ print_error(
+ "Couldn't locate mold installation path. Make sure it's installed in /usr or /usr/local."
+ )
sys.exit(255)
else:
env.Append(LINKFLAGS=["-fuse-ld=mold"])
@@ -185,7 +187,7 @@ def configure(env: "SConsEnvironment"):
if env["lto"] != "none":
if env["lto"] == "thin":
if not env["use_llvm"]:
- print("ThinLTO is only compatible with LLVM, use `use_llvm=yes` or `lto=full`.")
+ print_error("ThinLTO is only compatible with LLVM, use `use_llvm=yes` or `lto=full`.")
sys.exit(255)
env.Append(CCFLAGS=["-flto=thin"])
env.Append(LINKFLAGS=["-flto=thin"])
@@ -209,7 +211,7 @@ def configure(env: "SConsEnvironment"):
if env["wayland"]:
if os.system("wayland-scanner -v 2>/dev/null") != 0:
- print("wayland-scanner not found. Disabling Wayland support.")
+ print_warning("wayland-scanner not found. Disabling Wayland support.")
env["wayland"] = False
if env["touch"]:
@@ -227,7 +229,7 @@ def configure(env: "SConsEnvironment"):
env["builtin_harfbuzz"],
]
if (not all(ft_linked_deps)) and any(ft_linked_deps): # All or nothing.
- print(
+ print_error(
"These libraries should be either all builtin, or all system provided:\n"
"freetype, libpng, zlib, graphite, harfbuzz.\n"
"Please specify `builtin_<name>=no` for all of them, or none."
@@ -318,7 +320,7 @@ def configure(env: "SConsEnvironment"):
env.ParseConfig("pkg-config fontconfig --cflags --libs")
env.Append(CPPDEFINES=["FONTCONFIG_ENABLED"])
else:
- print("Warning: fontconfig development libraries not found. Disabling the system fonts support.")
+ print_warning("fontconfig development libraries not found. Disabling the system fonts support.")
env["fontconfig"] = False
else:
env.Append(CPPDEFINES=["FONTCONFIG_ENABLED"])
@@ -329,7 +331,7 @@ def configure(env: "SConsEnvironment"):
env.ParseConfig("pkg-config alsa --cflags --libs")
env.Append(CPPDEFINES=["ALSA_ENABLED", "ALSAMIDI_ENABLED"])
else:
- print("Warning: ALSA development libraries not found. Disabling the ALSA audio driver.")
+ print_warning("ALSA development libraries not found. Disabling the ALSA audio driver.")
env["alsa"] = False
else:
env.Append(CPPDEFINES=["ALSA_ENABLED", "ALSAMIDI_ENABLED"])
@@ -340,7 +342,7 @@ def configure(env: "SConsEnvironment"):
env.ParseConfig("pkg-config libpulse --cflags --libs")
env.Append(CPPDEFINES=["PULSEAUDIO_ENABLED"])
else:
- print("Warning: PulseAudio development libraries not found. Disabling the PulseAudio audio driver.")
+ print_warning("PulseAudio development libraries not found. Disabling the PulseAudio audio driver.")
env["pulseaudio"] = False
else:
env.Append(CPPDEFINES=["PULSEAUDIO_ENABLED", "_REENTRANT"])
@@ -351,7 +353,7 @@ def configure(env: "SConsEnvironment"):
env.ParseConfig("pkg-config dbus-1 --cflags --libs")
env.Append(CPPDEFINES=["DBUS_ENABLED"])
else:
- print("Warning: D-Bus development libraries not found. Disabling screensaver prevention.")
+ print_warning("D-Bus development libraries not found. Disabling screensaver prevention.")
env["dbus"] = False
else:
env.Append(CPPDEFINES=["DBUS_ENABLED"])
@@ -362,7 +364,7 @@ def configure(env: "SConsEnvironment"):
env.ParseConfig("pkg-config speech-dispatcher --cflags --libs")
env.Append(CPPDEFINES=["SPEECHD_ENABLED"])
else:
- print("Warning: speech-dispatcher development libraries not found. Disabling text to speech support.")
+ print_warning("speech-dispatcher development libraries not found. Disabling text to speech support.")
env["speechd"] = False
else:
env.Append(CPPDEFINES=["SPEECHD_ENABLED"])
@@ -373,11 +375,11 @@ def configure(env: "SConsEnvironment"):
env.Append(CPPDEFINES=["XKB_ENABLED"])
else:
if env["wayland"]:
- print("Error: libxkbcommon development libraries required by Wayland not found. Aborting.")
+ print_error("libxkbcommon development libraries required by Wayland not found. Aborting.")
sys.exit(255)
else:
- print(
- "Warning: libxkbcommon development libraries not found. Disabling dead key composition and key label support."
+ print_warning(
+ "libxkbcommon development libraries not found. Disabling dead key composition and key label support."
)
else:
env.Append(CPPDEFINES=["XKB_ENABLED"])
@@ -390,7 +392,7 @@ def configure(env: "SConsEnvironment"):
env.ParseConfig("pkg-config libudev --cflags --libs")
env.Append(CPPDEFINES=["UDEV_ENABLED"])
else:
- print("Warning: libudev development libraries not found. Disabling controller hotplugging support.")
+ print_warning("libudev development libraries not found. Disabling controller hotplugging support.")
env["udev"] = False
else:
env.Append(CPPDEFINES=["UDEV_ENABLED"])
@@ -416,31 +418,31 @@ def configure(env: "SConsEnvironment"):
if env["x11"]:
if not env["use_sowrap"]:
if os.system("pkg-config --exists x11"):
- print("Error: X11 libraries not found. Aborting.")
+ print_error("X11 libraries not found. Aborting.")
sys.exit(255)
env.ParseConfig("pkg-config x11 --cflags --libs")
if os.system("pkg-config --exists xcursor"):
- print("Error: Xcursor library not found. Aborting.")
+ print_error("Xcursor library not found. Aborting.")
sys.exit(255)
env.ParseConfig("pkg-config xcursor --cflags --libs")
if os.system("pkg-config --exists xinerama"):
- print("Error: Xinerama library not found. Aborting.")
+ print_error("Xinerama library not found. Aborting.")
sys.exit(255)
env.ParseConfig("pkg-config xinerama --cflags --libs")
if os.system("pkg-config --exists xext"):
- print("Error: Xext library not found. Aborting.")
+ print_error("Xext library not found. Aborting.")
sys.exit(255)
env.ParseConfig("pkg-config xext --cflags --libs")
if os.system("pkg-config --exists xrandr"):
- print("Error: XrandR library not found. Aborting.")
+ print_error("XrandR library not found. Aborting.")
sys.exit(255)
env.ParseConfig("pkg-config xrandr --cflags --libs")
if os.system("pkg-config --exists xrender"):
- print("Error: XRender library not found. Aborting.")
+ print_error("XRender library not found. Aborting.")
sys.exit(255)
env.ParseConfig("pkg-config xrender --cflags --libs")
if os.system("pkg-config --exists xi"):
- print("Error: Xi library not found. Aborting.")
+ print_error("Xi library not found. Aborting.")
sys.exit(255)
env.ParseConfig("pkg-config xi --cflags --libs")
env.Append(CPPDEFINES=["X11_ENABLED"])
@@ -448,20 +450,20 @@ def configure(env: "SConsEnvironment"):
if env["wayland"]:
if not env["use_sowrap"]:
if os.system("pkg-config --exists libdecor-0"):
- print("Warning: libdecor development libraries not found. Disabling client-side decorations.")
+ print_warning("libdecor development libraries not found. Disabling client-side decorations.")
env["libdecor"] = False
else:
env.ParseConfig("pkg-config libdecor-0 --cflags --libs")
if os.system("pkg-config --exists wayland-client"):
- print("Error: Wayland client library not found. Aborting.")
+ print_error("Wayland client library not found. Aborting.")
sys.exit(255)
env.ParseConfig("pkg-config wayland-client --cflags --libs")
if os.system("pkg-config --exists wayland-cursor"):
- print("Error: Wayland cursor library not found. Aborting.")
+ print_error("Wayland cursor library not found. Aborting.")
sys.exit(255)
env.ParseConfig("pkg-config wayland-cursor --cflags --libs")
if os.system("pkg-config --exists wayland-egl"):
- print("Error: Wayland EGL library not found. Aborting.")
+ print_error("Wayland EGL library not found. Aborting.")
sys.exit(255)
env.ParseConfig("pkg-config wayland-egl --cflags --libs")
diff --git a/platform/linuxbsd/wayland/wayland_thread.cpp b/platform/linuxbsd/wayland/wayland_thread.cpp
index 7f9008e952..3a63b87c7a 100644
--- a/platform/linuxbsd/wayland/wayland_thread.cpp
+++ b/platform/linuxbsd/wayland/wayland_thread.cpp
@@ -371,28 +371,22 @@ void WaylandThread::_wl_registry_on_global(void *data, struct wl_registry *wl_re
}
if (strcmp(interface, zxdg_exporter_v1_interface.name) == 0) {
- registry->wl_exporter = (struct zxdg_exporter_v1 *)wl_registry_bind(wl_registry, name, &zxdg_exporter_v1_interface, 1);
- registry->wl_exporter_name = name;
+ registry->xdg_exporter = (struct zxdg_exporter_v1 *)wl_registry_bind(wl_registry, name, &zxdg_exporter_v1_interface, 1);
+ registry->xdg_exporter_name = name;
return;
}
if (strcmp(interface, wl_compositor_interface.name) == 0) {
- registry->wl_compositor = (struct wl_compositor *)wl_registry_bind(wl_registry, name, &wl_compositor_interface, 4);
+ registry->wl_compositor = (struct wl_compositor *)wl_registry_bind(wl_registry, name, &wl_compositor_interface, CLAMP((int)version, 1, 6));
registry->wl_compositor_name = name;
return;
}
- if (strcmp(interface, wl_subcompositor_interface.name) == 0) {
- registry->wl_subcompositor = (struct wl_subcompositor *)wl_registry_bind(wl_registry, name, &wl_subcompositor_interface, 1);
- registry->wl_subcompositor_name = name;
- return;
- }
-
if (strcmp(interface, wl_data_device_manager_interface.name) == 0) {
- registry->wl_data_device_manager = (struct wl_data_device_manager *)wl_registry_bind(wl_registry, name, &wl_data_device_manager_interface, 3);
+ registry->wl_data_device_manager = (struct wl_data_device_manager *)wl_registry_bind(wl_registry, name, &wl_data_device_manager_interface, CLAMP((int)version, 1, 3));
registry->wl_data_device_manager_name = name;
- // This global creates some seats data. Let's do that for the ones already available.
+ // This global creates some seat data. Let's do that for the ones already available.
for (struct wl_seat *wl_seat : registry->wl_seats) {
SeatState *ss = wl_seat_get_seat_state(wl_seat);
ERR_FAIL_NULL(ss);
@@ -406,7 +400,7 @@ void WaylandThread::_wl_registry_on_global(void *data, struct wl_registry *wl_re
}
if (strcmp(interface, wl_output_interface.name) == 0) {
- struct wl_output *wl_output = (struct wl_output *)wl_registry_bind(wl_registry, name, &wl_output_interface, 2);
+ struct wl_output *wl_output = (struct wl_output *)wl_registry_bind(wl_registry, name, &wl_output_interface, CLAMP((int)version, 1, 4));
wl_proxy_tag_godot((struct wl_proxy *)wl_output);
registry->wl_outputs.push_back(wl_output);
@@ -421,7 +415,7 @@ void WaylandThread::_wl_registry_on_global(void *data, struct wl_registry *wl_re
}
if (strcmp(interface, wl_seat_interface.name) == 0) {
- struct wl_seat *wl_seat = (struct wl_seat *)wl_registry_bind(wl_registry, name, &wl_seat_interface, 5);
+ struct wl_seat *wl_seat = (struct wl_seat *)wl_registry_bind(wl_registry, name, &wl_seat_interface, CLAMP((int)version, 1, 9));
wl_proxy_tag_godot((struct wl_proxy *)wl_seat);
SeatState *ss = memnew(SeatState);
@@ -466,7 +460,7 @@ void WaylandThread::_wl_registry_on_global(void *data, struct wl_registry *wl_re
}
if (strcmp(interface, xdg_wm_base_interface.name) == 0) {
- registry->xdg_wm_base = (struct xdg_wm_base *)wl_registry_bind(wl_registry, name, &xdg_wm_base_interface, MAX(2, MIN(6, (int)version)));
+ registry->xdg_wm_base = (struct xdg_wm_base *)wl_registry_bind(wl_registry, name, &xdg_wm_base_interface, CLAMP((int)version, 1, 6));
registry->xdg_wm_base_name = name;
xdg_wm_base_add_listener(registry->xdg_wm_base, &xdg_wm_base_listener, nullptr);
@@ -502,7 +496,7 @@ void WaylandThread::_wl_registry_on_global(void *data, struct wl_registry *wl_re
if (strcmp(interface, zwp_primary_selection_device_manager_v1_interface.name) == 0) {
registry->wp_primary_selection_device_manager = (struct zwp_primary_selection_device_manager_v1 *)wl_registry_bind(wl_registry, name, &zwp_primary_selection_device_manager_v1_interface, 1);
- // This global creates some seats data. Let's do that for the ones already available.
+ // This global creates some seat data. Let's do that for the ones already available.
for (struct wl_seat *wl_seat : registry->wl_seats) {
SeatState *ss = wl_seat_get_seat_state(wl_seat);
ERR_FAIL_NULL(ss);
@@ -570,13 +564,13 @@ void WaylandThread::_wl_registry_on_global_remove(void *data, struct wl_registry
return;
}
- if (name == registry->wl_exporter_name) {
- if (registry->wl_exporter) {
- zxdg_exporter_v1_destroy(registry->wl_exporter);
- registry->wl_exporter = nullptr;
+ if (name == registry->xdg_exporter_name) {
+ if (registry->xdg_exporter) {
+ zxdg_exporter_v1_destroy(registry->xdg_exporter);
+ registry->xdg_exporter = nullptr;
}
- registry->wl_exporter_name = 0;
+ registry->xdg_exporter_name = 0;
return;
}
@@ -592,17 +586,6 @@ void WaylandThread::_wl_registry_on_global_remove(void *data, struct wl_registry
return;
}
- if (name == registry->wl_subcompositor_name) {
- if (registry->wl_subcompositor) {
- wl_subcompositor_destroy(registry->wl_subcompositor);
- registry->wl_subcompositor = nullptr;
- }
-
- registry->wl_subcompositor_name = 0;
-
- return;
- }
-
if (name == registry->wl_data_device_manager_name) {
if (registry->wl_data_device_manager) {
wl_data_device_manager_destroy(registry->wl_data_device_manager);
@@ -1000,6 +983,12 @@ void WaylandThread::_wl_output_on_geometry(void *data, struct wl_output *wl_outp
ss->pending_data.make.parse_utf8(make);
ss->pending_data.model.parse_utf8(model);
+
+ // `wl_output::done` is a version 2 addition. We'll directly update the data
+ // for compatibility.
+ if (wl_output_get_version(wl_output) == 1) {
+ ss->data = ss->pending_data;
+ }
}
void WaylandThread::_wl_output_on_mode(void *data, struct wl_output *wl_output, uint32_t flags, int32_t width, int32_t height, int32_t refresh) {
@@ -1010,8 +999,17 @@ void WaylandThread::_wl_output_on_mode(void *data, struct wl_output *wl_output,
ss->pending_data.size.height = height;
ss->pending_data.refresh_rate = refresh ? refresh / 1000.0f : -1;
+
+ // `wl_output::done` is a version 2 addition. We'll directly update the data
+ // for compatibility.
+ if (wl_output_get_version(wl_output) == 1) {
+ ss->data = ss->pending_data;
+ }
}
+// NOTE: The following `wl_output` events are only for version 2 onwards, so we
+// can assume that they're "atomic" (i.e. rely on the `wl_output::done` event).
+
void WaylandThread::_wl_output_on_done(void *data, struct wl_output *wl_output) {
ScreenState *ss = (ScreenState *)data;
ERR_FAIL_NULL(ss);
@@ -1523,7 +1521,7 @@ void WaylandThread::_wl_pointer_on_frame(void *data, struct wl_pointer *wl_point
wayland_thread->push_message(msg);
}
- if (pd.discrete_scroll_vector - old_pd.discrete_scroll_vector != Vector2i()) {
+ if (pd.discrete_scroll_vector_120 - old_pd.discrete_scroll_vector_120 != Vector2i()) {
// This is a discrete scroll (eg. from a scroll wheel), so we'll just emit
// scroll wheel buttons.
if (pd.scroll_vector.y != 0) {
@@ -1596,13 +1594,13 @@ void WaylandThread::_wl_pointer_on_frame(void *data, struct wl_pointer *wl_point
if (test_button == MouseButton::WHEEL_UP || test_button == MouseButton::WHEEL_DOWN) {
// If this is a discrete scroll, specify how many "clicks" it did for this
// pointer frame.
- mb->set_factor(abs(pd.discrete_scroll_vector.y));
+ mb->set_factor(Math::abs(pd.discrete_scroll_vector_120.y / (float)120));
}
if (test_button == MouseButton::WHEEL_RIGHT || test_button == MouseButton::WHEEL_LEFT) {
// If this is a discrete scroll, specify how many "clicks" it did for this
// pointer frame.
- mb->set_factor(abs(pd.discrete_scroll_vector.x));
+ mb->set_factor(fabs(pd.discrete_scroll_vector_120.x / (float)120));
}
mb->set_button_mask(pd.pressed_button_mask);
@@ -1661,7 +1659,7 @@ void WaylandThread::_wl_pointer_on_frame(void *data, struct wl_pointer *wl_point
// Reset the scroll vectors as we already handled them.
pd.scroll_vector = Vector2();
- pd.discrete_scroll_vector = Vector2();
+ pd.discrete_scroll_vector_120 = Vector2i();
// Update the data all getters read. Wayland's specification requires us to do
// this, since all pointer actions are sent in individual events.
@@ -1683,6 +1681,9 @@ void WaylandThread::_wl_pointer_on_axis_source(void *data, struct wl_pointer *wl
void WaylandThread::_wl_pointer_on_axis_stop(void *data, struct wl_pointer *wl_pointer, uint32_t time, uint32_t axis) {
}
+// NOTE: This event is deprecated since version 8 and superseded by
+// `wl_pointer::axis_value120`. This thus converts the data to its
+// fraction-of-120 format.
void WaylandThread::_wl_pointer_on_axis_discrete(void *data, struct wl_pointer *wl_pointer, uint32_t axis, int32_t discrete) {
SeatState *ss = (SeatState *)data;
ERR_FAIL_NULL(ss);
@@ -1694,17 +1695,37 @@ void WaylandThread::_wl_pointer_on_axis_discrete(void *data, struct wl_pointer *
PointerData &pd = ss->pointer_data_buffer;
+ // NOTE: We can allow ourselves to not accumulate this data (and thus just
+ // assign it) as the spec guarantees only one event per axis type.
+
if (axis == WL_POINTER_AXIS_VERTICAL_SCROLL) {
- pd.discrete_scroll_vector.y = discrete;
+ pd.discrete_scroll_vector_120.y = discrete * 120;
}
if (axis == WL_POINTER_AXIS_VERTICAL_SCROLL) {
- pd.discrete_scroll_vector.x = discrete;
+ pd.discrete_scroll_vector_120.x = discrete * 120;
}
}
-// TODO: Add support to this event.
+// Supersedes `wl_pointer::axis_discrete` Since version 8.
void WaylandThread::_wl_pointer_on_axis_value120(void *data, struct wl_pointer *wl_pointer, uint32_t axis, int32_t value120) {
+ SeatState *ss = (SeatState *)data;
+ ERR_FAIL_NULL(ss);
+
+ if (!ss->pointed_surface) {
+ // We're probably on a decoration or some other third-party thing.
+ return;
+ }
+
+ PointerData &pd = ss->pointer_data_buffer;
+
+ if (axis == WL_POINTER_AXIS_VERTICAL_SCROLL) {
+ pd.discrete_scroll_vector_120.y += value120;
+ }
+
+ if (axis == WL_POINTER_AXIS_VERTICAL_SCROLL) {
+ pd.discrete_scroll_vector_120.x += value120;
+ }
}
// TODO: Add support to this event.
@@ -1999,7 +2020,7 @@ void WaylandThread::_wp_relative_pointer_on_relative_motion(void *data, struct z
pd.relative_motion_time = uptime_lo;
}
-void WaylandThread::_wp_pointer_gesture_pinch_on_begin(void *data, struct zwp_pointer_gesture_pinch_v1 *zwp_pointer_gesture_pinch_v1, uint32_t serial, uint32_t time, struct wl_surface *surface, uint32_t fingers) {
+void WaylandThread::_wp_pointer_gesture_pinch_on_begin(void *data, struct zwp_pointer_gesture_pinch_v1 *wp_pointer_gesture_pinch_v1, uint32_t serial, uint32_t time, struct wl_surface *surface, uint32_t fingers) {
SeatState *ss = (SeatState *)data;
ERR_FAIL_NULL(ss);
@@ -2009,7 +2030,7 @@ void WaylandThread::_wp_pointer_gesture_pinch_on_begin(void *data, struct zwp_po
}
}
-void WaylandThread::_wp_pointer_gesture_pinch_on_update(void *data, struct zwp_pointer_gesture_pinch_v1 *zwp_pointer_gesture_pinch_v1, uint32_t time, wl_fixed_t dx, wl_fixed_t dy, wl_fixed_t scale, wl_fixed_t rotation) {
+void WaylandThread::_wp_pointer_gesture_pinch_on_update(void *data, struct zwp_pointer_gesture_pinch_v1 *wp_pointer_gesture_pinch_v1, uint32_t time, wl_fixed_t dx, wl_fixed_t dy, wl_fixed_t scale, wl_fixed_t rotation) {
SeatState *ss = (SeatState *)data;
ERR_FAIL_NULL(ss);
@@ -2068,7 +2089,7 @@ void WaylandThread::_wp_pointer_gesture_pinch_on_update(void *data, struct zwp_p
}
}
-void WaylandThread::_wp_pointer_gesture_pinch_on_end(void *data, struct zwp_pointer_gesture_pinch_v1 *zwp_pointer_gesture_pinch_v1, uint32_t serial, uint32_t time, int32_t cancelled) {
+void WaylandThread::_wp_pointer_gesture_pinch_on_end(void *data, struct zwp_pointer_gesture_pinch_v1 *wp_pointer_gesture_pinch_v1, uint32_t serial, uint32_t time, int32_t cancelled) {
SeatState *ss = (SeatState *)data;
ERR_FAIL_NULL(ss);
@@ -2093,7 +2114,7 @@ void WaylandThread::_wp_primary_selection_device_on_selection(void *data, struct
ss->wp_primary_selection_offer = id;
}
-void WaylandThread::_wp_primary_selection_offer_on_offer(void *data, struct zwp_primary_selection_offer_v1 *zwp_primary_selection_offer_v1, const char *mime_type) {
+void WaylandThread::_wp_primary_selection_offer_on_offer(void *data, struct zwp_primary_selection_offer_v1 *wp_primary_selection_offer_v1, const char *mime_type) {
OfferState *os = (OfferState *)data;
ERR_FAIL_NULL(os);
@@ -2147,10 +2168,10 @@ void WaylandThread::_wp_primary_selection_source_on_cancelled(void *data, struct
}
}
-void WaylandThread::_wp_tablet_seat_on_tablet_added(void *data, struct zwp_tablet_seat_v2 *zwp_tablet_seat_v2, struct zwp_tablet_v2 *id) {
+void WaylandThread::_wp_tablet_seat_on_tablet_added(void *data, struct zwp_tablet_seat_v2 *wp_tablet_seat_v2, struct zwp_tablet_v2 *id) {
}
-void WaylandThread::_wp_tablet_seat_on_tool_added(void *data, struct zwp_tablet_seat_v2 *zwp_tablet_seat_v2, struct zwp_tablet_tool_v2 *id) {
+void WaylandThread::_wp_tablet_seat_on_tool_added(void *data, struct zwp_tablet_seat_v2 *wp_tablet_seat_v2, struct zwp_tablet_tool_v2 *id) {
SeatState *ss = (SeatState *)data;
ERR_FAIL_NULL(ss);
@@ -2163,31 +2184,31 @@ void WaylandThread::_wp_tablet_seat_on_tool_added(void *data, struct zwp_tablet_
ss->tablet_tools.push_back(id);
}
-void WaylandThread::_wp_tablet_seat_on_pad_added(void *data, struct zwp_tablet_seat_v2 *zwp_tablet_seat_v2, struct zwp_tablet_pad_v2 *id) {
+void WaylandThread::_wp_tablet_seat_on_pad_added(void *data, struct zwp_tablet_seat_v2 *wp_tablet_seat_v2, struct zwp_tablet_pad_v2 *id) {
}
-void WaylandThread::_wp_tablet_tool_on_type(void *data, struct zwp_tablet_tool_v2 *zwp_tablet_tool_v2, uint32_t tool_type) {
- TabletToolState *state = wp_tablet_tool_get_state(zwp_tablet_tool_v2);
+void WaylandThread::_wp_tablet_tool_on_type(void *data, struct zwp_tablet_tool_v2 *wp_tablet_tool_v2, uint32_t tool_type) {
+ TabletToolState *state = wp_tablet_tool_get_state(wp_tablet_tool_v2);
if (state && tool_type == ZWP_TABLET_TOOL_V2_TYPE_ERASER) {
state->is_eraser = true;
}
}
-void WaylandThread::_wp_tablet_tool_on_hardware_serial(void *data, struct zwp_tablet_tool_v2 *zwp_tablet_tool_v2, uint32_t hardware_serial_hi, uint32_t hardware_serial_lo) {
+void WaylandThread::_wp_tablet_tool_on_hardware_serial(void *data, struct zwp_tablet_tool_v2 *wp_tablet_tool_v2, uint32_t hardware_serial_hi, uint32_t hardware_serial_lo) {
}
-void WaylandThread::_wp_tablet_tool_on_hardware_id_wacom(void *data, struct zwp_tablet_tool_v2 *zwp_tablet_tool_v2, uint32_t hardware_id_hi, uint32_t hardware_id_lo) {
+void WaylandThread::_wp_tablet_tool_on_hardware_id_wacom(void *data, struct zwp_tablet_tool_v2 *wp_tablet_tool_v2, uint32_t hardware_id_hi, uint32_t hardware_id_lo) {
}
-void WaylandThread::_wp_tablet_tool_on_capability(void *data, struct zwp_tablet_tool_v2 *zwp_tablet_tool_v2, uint32_t capability) {
+void WaylandThread::_wp_tablet_tool_on_capability(void *data, struct zwp_tablet_tool_v2 *wp_tablet_tool_v2, uint32_t capability) {
}
-void WaylandThread::_wp_tablet_tool_on_done(void *data, struct zwp_tablet_tool_v2 *zwp_tablet_tool_v2) {
+void WaylandThread::_wp_tablet_tool_on_done(void *data, struct zwp_tablet_tool_v2 *wp_tablet_tool_v2) {
}
-void WaylandThread::_wp_tablet_tool_on_removed(void *data, struct zwp_tablet_tool_v2 *zwp_tablet_tool_v2) {
- TabletToolState *ts = wp_tablet_tool_get_state(zwp_tablet_tool_v2);
+void WaylandThread::_wp_tablet_tool_on_removed(void *data, struct zwp_tablet_tool_v2 *wp_tablet_tool_v2) {
+ TabletToolState *ts = wp_tablet_tool_get_state(wp_tablet_tool_v2);
if (!ts) {
return;
@@ -2199,7 +2220,7 @@ void WaylandThread::_wp_tablet_tool_on_removed(void *data, struct zwp_tablet_too
return;
}
- List<struct zwp_tablet_tool_v2 *>::Element *E = ss->tablet_tools.find(zwp_tablet_tool_v2);
+ List<struct zwp_tablet_tool_v2 *>::Element *E = ss->tablet_tools.find(wp_tablet_tool_v2);
if (E && E->get()) {
struct zwp_tablet_tool_v2 *tool = E->get();
@@ -2213,8 +2234,8 @@ void WaylandThread::_wp_tablet_tool_on_removed(void *data, struct zwp_tablet_too
}
}
-void WaylandThread::_wp_tablet_tool_on_proximity_in(void *data, struct zwp_tablet_tool_v2 *zwp_tablet_tool_v2, uint32_t serial, struct zwp_tablet_v2 *tablet, struct wl_surface *surface) {
- TabletToolState *ts = wp_tablet_tool_get_state(zwp_tablet_tool_v2);
+void WaylandThread::_wp_tablet_tool_on_proximity_in(void *data, struct zwp_tablet_tool_v2 *wp_tablet_tool_v2, uint32_t serial, struct zwp_tablet_v2 *tablet, struct wl_surface *surface) {
+ TabletToolState *ts = wp_tablet_tool_get_state(wp_tablet_tool_v2);
if (!ts) {
return;
@@ -2241,8 +2262,8 @@ void WaylandThread::_wp_tablet_tool_on_proximity_in(void *data, struct zwp_table
DEBUG_LOG_WAYLAND_THREAD("Tablet tool entered window.");
}
-void WaylandThread::_wp_tablet_tool_on_proximity_out(void *data, struct zwp_tablet_tool_v2 *zwp_tablet_tool_v2) {
- TabletToolState *ts = wp_tablet_tool_get_state(zwp_tablet_tool_v2);
+void WaylandThread::_wp_tablet_tool_on_proximity_out(void *data, struct zwp_tablet_tool_v2 *wp_tablet_tool_v2) {
+ TabletToolState *ts = wp_tablet_tool_get_state(wp_tablet_tool_v2);
if (!ts) {
return;
@@ -2268,8 +2289,8 @@ void WaylandThread::_wp_tablet_tool_on_proximity_out(void *data, struct zwp_tabl
DEBUG_LOG_WAYLAND_THREAD("Tablet tool left window.");
}
-void WaylandThread::_wp_tablet_tool_on_down(void *data, struct zwp_tablet_tool_v2 *zwp_tablet_tool_v2, uint32_t serial) {
- TabletToolState *ts = wp_tablet_tool_get_state(zwp_tablet_tool_v2);
+void WaylandThread::_wp_tablet_tool_on_down(void *data, struct zwp_tablet_tool_v2 *wp_tablet_tool_v2, uint32_t serial) {
+ TabletToolState *ts = wp_tablet_tool_get_state(wp_tablet_tool_v2);
if (!ts) {
return;
@@ -2286,8 +2307,8 @@ void WaylandThread::_wp_tablet_tool_on_down(void *data, struct zwp_tablet_tool_v
td.button_time = OS::get_singleton()->get_ticks_msec();
}
-void WaylandThread::_wp_tablet_tool_on_up(void *data, struct zwp_tablet_tool_v2 *zwp_tablet_tool_v2) {
- TabletToolState *ts = wp_tablet_tool_get_state(zwp_tablet_tool_v2);
+void WaylandThread::_wp_tablet_tool_on_up(void *data, struct zwp_tablet_tool_v2 *wp_tablet_tool_v2) {
+ TabletToolState *ts = wp_tablet_tool_get_state(wp_tablet_tool_v2);
if (!ts) {
return;
@@ -2302,8 +2323,8 @@ void WaylandThread::_wp_tablet_tool_on_up(void *data, struct zwp_tablet_tool_v2
td.button_time = OS::get_singleton()->get_ticks_msec();
}
-void WaylandThread::_wp_tablet_tool_on_motion(void *data, struct zwp_tablet_tool_v2 *zwp_tablet_tool_v2, wl_fixed_t x, wl_fixed_t y) {
- TabletToolState *ts = wp_tablet_tool_get_state(zwp_tablet_tool_v2);
+void WaylandThread::_wp_tablet_tool_on_motion(void *data, struct zwp_tablet_tool_v2 *wp_tablet_tool_v2, wl_fixed_t x, wl_fixed_t y) {
+ TabletToolState *ts = wp_tablet_tool_get_state(wp_tablet_tool_v2);
if (!ts) {
return;
@@ -2323,8 +2344,8 @@ void WaylandThread::_wp_tablet_tool_on_motion(void *data, struct zwp_tablet_tool
td.motion_time = OS::get_singleton()->get_ticks_msec();
}
-void WaylandThread::_wp_tablet_tool_on_pressure(void *data, struct zwp_tablet_tool_v2 *zwp_tablet_tool_v2, uint32_t pressure) {
- TabletToolState *ts = wp_tablet_tool_get_state(zwp_tablet_tool_v2);
+void WaylandThread::_wp_tablet_tool_on_pressure(void *data, struct zwp_tablet_tool_v2 *wp_tablet_tool_v2, uint32_t pressure) {
+ TabletToolState *ts = wp_tablet_tool_get_state(wp_tablet_tool_v2);
if (!ts) {
return;
@@ -2333,12 +2354,12 @@ void WaylandThread::_wp_tablet_tool_on_pressure(void *data, struct zwp_tablet_to
ts->data_pending.pressure = pressure;
}
-void WaylandThread::_wp_tablet_tool_on_distance(void *data, struct zwp_tablet_tool_v2 *zwp_tablet_tool_v2, uint32_t distance) {
+void WaylandThread::_wp_tablet_tool_on_distance(void *data, struct zwp_tablet_tool_v2 *wp_tablet_tool_v2, uint32_t distance) {
// Unsupported
}
-void WaylandThread::_wp_tablet_tool_on_tilt(void *data, struct zwp_tablet_tool_v2 *zwp_tablet_tool_v2, wl_fixed_t tilt_x, wl_fixed_t tilt_y) {
- TabletToolState *ts = wp_tablet_tool_get_state(zwp_tablet_tool_v2);
+void WaylandThread::_wp_tablet_tool_on_tilt(void *data, struct zwp_tablet_tool_v2 *wp_tablet_tool_v2, wl_fixed_t tilt_x, wl_fixed_t tilt_y) {
+ TabletToolState *ts = wp_tablet_tool_get_state(wp_tablet_tool_v2);
if (!ts) {
return;
@@ -2350,20 +2371,20 @@ void WaylandThread::_wp_tablet_tool_on_tilt(void *data, struct zwp_tablet_tool_v
td.tilt.y = wl_fixed_to_double(tilt_y);
}
-void WaylandThread::_wp_tablet_tool_on_rotation(void *data, struct zwp_tablet_tool_v2 *zwp_tablet_tool_v2, wl_fixed_t degrees) {
+void WaylandThread::_wp_tablet_tool_on_rotation(void *data, struct zwp_tablet_tool_v2 *wp_tablet_tool_v2, wl_fixed_t degrees) {
// Unsupported.
}
-void WaylandThread::_wp_tablet_tool_on_slider(void *data, struct zwp_tablet_tool_v2 *zwp_tablet_tool_v2, int32_t position) {
+void WaylandThread::_wp_tablet_tool_on_slider(void *data, struct zwp_tablet_tool_v2 *wp_tablet_tool_v2, int32_t position) {
// Unsupported.
}
-void WaylandThread::_wp_tablet_tool_on_wheel(void *data, struct zwp_tablet_tool_v2 *zwp_tablet_tool_v2, wl_fixed_t degrees, int32_t clicks) {
+void WaylandThread::_wp_tablet_tool_on_wheel(void *data, struct zwp_tablet_tool_v2 *wp_tablet_tool_v2, wl_fixed_t degrees, int32_t clicks) {
// TODO
}
-void WaylandThread::_wp_tablet_tool_on_button(void *data, struct zwp_tablet_tool_v2 *zwp_tablet_tool_v2, uint32_t serial, uint32_t button, uint32_t state) {
- TabletToolState *ts = wp_tablet_tool_get_state(zwp_tablet_tool_v2);
+void WaylandThread::_wp_tablet_tool_on_button(void *data, struct zwp_tablet_tool_v2 *wp_tablet_tool_v2, uint32_t serial, uint32_t button, uint32_t state) {
+ TabletToolState *ts = wp_tablet_tool_get_state(wp_tablet_tool_v2);
if (!ts) {
return;
@@ -2398,8 +2419,8 @@ void WaylandThread::_wp_tablet_tool_on_button(void *data, struct zwp_tablet_tool
}
}
-void WaylandThread::_wp_tablet_tool_on_frame(void *data, struct zwp_tablet_tool_v2 *zwp_tablet_tool_v2, uint32_t time) {
- TabletToolState *ts = wp_tablet_tool_get_state(zwp_tablet_tool_v2);
+void WaylandThread::_wp_tablet_tool_on_frame(void *data, struct zwp_tablet_tool_v2 *wp_tablet_tool_v2, uint32_t time) {
+ TabletToolState *ts = wp_tablet_tool_get_state(wp_tablet_tool_v2);
if (!ts) {
return;
@@ -3071,8 +3092,8 @@ void WaylandThread::window_create(DisplayServer::WindowID p_window_id, int p_wid
// "loop".
wl_surface_commit(ws.wl_surface);
- if (registry.wl_exporter) {
- ws.xdg_exported = zxdg_exporter_v1_export(registry.wl_exporter, ws.wl_surface);
+ if (registry.xdg_exporter) {
+ ws.xdg_exported = zxdg_exporter_v1_export(registry.xdg_exporter, ws.wl_surface);
zxdg_exported_v1_add_listener(ws.xdg_exported, &xdg_exported_listener, &ws);
}
@@ -3529,9 +3550,6 @@ Error WaylandThread::init() {
ERR_FAIL_NULL_V_MSG(registry.wl_shm, ERR_UNAVAILABLE, "Can't obtain the Wayland shared memory global.");
ERR_FAIL_NULL_V_MSG(registry.wl_compositor, ERR_UNAVAILABLE, "Can't obtain the Wayland compositor global.");
- ERR_FAIL_NULL_V_MSG(registry.wl_subcompositor, ERR_UNAVAILABLE, "Can't obtain the Wayland subcompositor global.");
- ERR_FAIL_NULL_V_MSG(registry.wl_data_device_manager, ERR_UNAVAILABLE, "Can't obtain the Wayland data device manager global.");
- ERR_FAIL_NULL_V_MSG(registry.wp_pointer_constraints, ERR_UNAVAILABLE, "Can't obtain the Wayland pointer constraints global.");
ERR_FAIL_NULL_V_MSG(registry.xdg_wm_base, ERR_UNAVAILABLE, "Can't obtain the Wayland XDG shell global.");
if (!registry.xdg_decoration_manager) {
@@ -3660,7 +3678,10 @@ void WaylandThread::cursor_shape_set_custom_image(DisplayServer::CursorShape p_c
munmap(cursor.buffer_data, cursor.buffer_data_size);
}
- cursor.buffer_data = (uint32_t *)mmap(nullptr, data_size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
+ // NOTE: From `wl_keyboard`s of version 7 or later, the spec requires the mmap
+ // operation to be done with MAP_PRIVATE, as "MAP_SHARED may fail". We'll do it
+ // regardless of global version.
+ cursor.buffer_data = (uint32_t *)mmap(nullptr, data_size, PROT_READ | PROT_WRITE, MAP_PRIVATE, fd, 0);
if (cursor.wl_buffer) {
// Clean up the old Wayland buffer.
@@ -4179,18 +4200,14 @@ void WaylandThread::destroy() {
xdg_wm_base_destroy(registry.xdg_wm_base);
}
- if (registry.wl_exporter) {
- zxdg_exporter_v1_destroy(registry.wl_exporter);
+ if (registry.xdg_exporter) {
+ zxdg_exporter_v1_destroy(registry.xdg_exporter);
}
if (registry.wl_shm) {
wl_shm_destroy(registry.wl_shm);
}
- if (registry.wl_subcompositor) {
- wl_subcompositor_destroy(registry.wl_subcompositor);
- }
-
if (registry.wl_compositor) {
wl_compositor_destroy(registry.wl_compositor);
}
diff --git a/platform/linuxbsd/wayland/wayland_thread.h b/platform/linuxbsd/wayland/wayland_thread.h
index d49f0c9d34..d35a5b7139 100644
--- a/platform/linuxbsd/wayland/wayland_thread.h
+++ b/platform/linuxbsd/wayland/wayland_thread.h
@@ -133,8 +133,8 @@ public:
struct xdg_wm_base *xdg_wm_base = nullptr;
uint32_t xdg_wm_base_name = 0;
- struct zxdg_exporter_v1 *wl_exporter = nullptr;
- uint32_t wl_exporter_name = 0;
+ struct zxdg_exporter_v1 *xdg_exporter = nullptr;
+ uint32_t xdg_exporter_name = 0;
// wayland-protocols globals.
@@ -300,8 +300,8 @@ public:
// The amount "scrolled" in pixels, in each direction.
Vector2 scroll_vector;
- // The amount of scroll "clicks" in each direction.
- Vector2i discrete_scroll_vector;
+ // The amount of scroll "clicks" in each direction, in fractions of 120.
+ Vector2i discrete_scroll_vector_120;
uint32_t pinch_scale = 1;
};
@@ -579,41 +579,41 @@ private:
static void _wp_relative_pointer_on_relative_motion(void *data, struct zwp_relative_pointer_v1 *wp_relative_pointer_v1, uint32_t uptime_hi, uint32_t uptime_lo, wl_fixed_t dx, wl_fixed_t dy, wl_fixed_t dx_unaccel, wl_fixed_t dy_unaccel);
- static void _wp_pointer_gesture_pinch_on_begin(void *data, struct zwp_pointer_gesture_pinch_v1 *zwp_pointer_gesture_pinch_v1, uint32_t serial, uint32_t time, struct wl_surface *surface, uint32_t fingers);
- static void _wp_pointer_gesture_pinch_on_update(void *data, struct zwp_pointer_gesture_pinch_v1 *zwp_pointer_gesture_pinch_v1, uint32_t time, wl_fixed_t dx, wl_fixed_t dy, wl_fixed_t scale, wl_fixed_t rotation);
- static void _wp_pointer_gesture_pinch_on_end(void *data, struct zwp_pointer_gesture_pinch_v1 *zwp_pointer_gesture_pinch_v1, uint32_t serial, uint32_t time, int32_t cancelled);
+ static void _wp_pointer_gesture_pinch_on_begin(void *data, struct zwp_pointer_gesture_pinch_v1 *wp_pointer_gesture_pinch_v1, uint32_t serial, uint32_t time, struct wl_surface *surface, uint32_t fingers);
+ static void _wp_pointer_gesture_pinch_on_update(void *data, struct zwp_pointer_gesture_pinch_v1 *wp_pointer_gesture_pinch_v1, uint32_t time, wl_fixed_t dx, wl_fixed_t dy, wl_fixed_t scale, wl_fixed_t rotation);
+ static void _wp_pointer_gesture_pinch_on_end(void *data, struct zwp_pointer_gesture_pinch_v1 *zp_pointer_gesture_pinch_v1, uint32_t serial, uint32_t time, int32_t cancelled);
static void _wp_primary_selection_device_on_data_offer(void *data, struct zwp_primary_selection_device_v1 *wp_primary_selection_device_v1, struct zwp_primary_selection_offer_v1 *offer);
static void _wp_primary_selection_device_on_selection(void *data, struct zwp_primary_selection_device_v1 *wp_primary_selection_device_v1, struct zwp_primary_selection_offer_v1 *id);
- static void _wp_primary_selection_offer_on_offer(void *data, struct zwp_primary_selection_offer_v1 *zwp_primary_selection_offer_v1, const char *mime_type);
+ static void _wp_primary_selection_offer_on_offer(void *data, struct zwp_primary_selection_offer_v1 *wp_primary_selection_offer_v1, const char *mime_type);
static void _wp_primary_selection_source_on_send(void *data, struct zwp_primary_selection_source_v1 *wp_primary_selection_source_v1, const char *mime_type, int32_t fd);
static void _wp_primary_selection_source_on_cancelled(void *data, struct zwp_primary_selection_source_v1 *wp_primary_selection_source_v1);
- static void _wp_tablet_seat_on_tablet_added(void *data, struct zwp_tablet_seat_v2 *zwp_tablet_seat_v2, struct zwp_tablet_v2 *id);
- static void _wp_tablet_seat_on_tool_added(void *data, struct zwp_tablet_seat_v2 *zwp_tablet_seat_v2, struct zwp_tablet_tool_v2 *id);
- static void _wp_tablet_seat_on_pad_added(void *data, struct zwp_tablet_seat_v2 *zwp_tablet_seat_v2, struct zwp_tablet_pad_v2 *id);
-
- static void _wp_tablet_tool_on_type(void *data, struct zwp_tablet_tool_v2 *zwp_tablet_tool_v2, uint32_t tool_type);
- static void _wp_tablet_tool_on_hardware_serial(void *data, struct zwp_tablet_tool_v2 *zwp_tablet_tool_v2, uint32_t hardware_serial_hi, uint32_t hardware_serial_lo);
- static void _wp_tablet_tool_on_hardware_id_wacom(void *data, struct zwp_tablet_tool_v2 *zwp_tablet_tool_v2, uint32_t hardware_id_hi, uint32_t hardware_id_lo);
- static void _wp_tablet_tool_on_capability(void *data, struct zwp_tablet_tool_v2 *zwp_tablet_tool_v2, uint32_t capability);
- static void _wp_tablet_tool_on_done(void *data, struct zwp_tablet_tool_v2 *zwp_tablet_tool_v2);
- static void _wp_tablet_tool_on_removed(void *data, struct zwp_tablet_tool_v2 *zwp_tablet_tool_v2);
- static void _wp_tablet_tool_on_proximity_in(void *data, struct zwp_tablet_tool_v2 *zwp_tablet_tool_v2, uint32_t serial, struct zwp_tablet_v2 *tablet, struct wl_surface *surface);
- static void _wp_tablet_tool_on_proximity_out(void *data, struct zwp_tablet_tool_v2 *zwp_tablet_tool_v2);
- static void _wp_tablet_tool_on_down(void *data, struct zwp_tablet_tool_v2 *zwp_tablet_tool_v2, uint32_t serial);
- static void _wp_tablet_tool_on_up(void *data, struct zwp_tablet_tool_v2 *zwp_tablet_tool_v2);
- static void _wp_tablet_tool_on_motion(void *data, struct zwp_tablet_tool_v2 *zwp_tablet_tool_v2, wl_fixed_t x, wl_fixed_t y);
- static void _wp_tablet_tool_on_pressure(void *data, struct zwp_tablet_tool_v2 *zwp_tablet_tool_v2, uint32_t pressure);
- static void _wp_tablet_tool_on_distance(void *data, struct zwp_tablet_tool_v2 *zwp_tablet_tool_v2, uint32_t distance);
- static void _wp_tablet_tool_on_tilt(void *data, struct zwp_tablet_tool_v2 *zwp_tablet_tool_v2, wl_fixed_t tilt_x, wl_fixed_t tilt_y);
- static void _wp_tablet_tool_on_rotation(void *data, struct zwp_tablet_tool_v2 *zwp_tablet_tool_v2, wl_fixed_t degrees);
- static void _wp_tablet_tool_on_slider(void *data, struct zwp_tablet_tool_v2 *zwp_tablet_tool_v2, int32_t position);
- static void _wp_tablet_tool_on_wheel(void *data, struct zwp_tablet_tool_v2 *zwp_tablet_tool_v2, wl_fixed_t degrees, int32_t clicks);
- static void _wp_tablet_tool_on_button(void *data, struct zwp_tablet_tool_v2 *zwp_tablet_tool_v2, uint32_t serial, uint32_t button, uint32_t state);
- static void _wp_tablet_tool_on_frame(void *data, struct zwp_tablet_tool_v2 *zwp_tablet_tool_v2, uint32_t time);
+ static void _wp_tablet_seat_on_tablet_added(void *data, struct zwp_tablet_seat_v2 *wp_tablet_seat_v2, struct zwp_tablet_v2 *id);
+ static void _wp_tablet_seat_on_tool_added(void *data, struct zwp_tablet_seat_v2 *wp_tablet_seat_v2, struct zwp_tablet_tool_v2 *id);
+ static void _wp_tablet_seat_on_pad_added(void *data, struct zwp_tablet_seat_v2 *wp_tablet_seat_v2, struct zwp_tablet_pad_v2 *id);
+
+ static void _wp_tablet_tool_on_type(void *data, struct zwp_tablet_tool_v2 *wp_tablet_tool_v2, uint32_t tool_type);
+ static void _wp_tablet_tool_on_hardware_serial(void *data, struct zwp_tablet_tool_v2 *wp_tablet_tool_v2, uint32_t hardware_serial_hi, uint32_t hardware_serial_lo);
+ static void _wp_tablet_tool_on_hardware_id_wacom(void *data, struct zwp_tablet_tool_v2 *wp_tablet_tool_v2, uint32_t hardware_id_hi, uint32_t hardware_id_lo);
+ static void _wp_tablet_tool_on_capability(void *data, struct zwp_tablet_tool_v2 *wp_tablet_tool_v2, uint32_t capability);
+ static void _wp_tablet_tool_on_done(void *data, struct zwp_tablet_tool_v2 *wp_tablet_tool_v2);
+ static void _wp_tablet_tool_on_removed(void *data, struct zwp_tablet_tool_v2 *wp_tablet_tool_v2);
+ static void _wp_tablet_tool_on_proximity_in(void *data, struct zwp_tablet_tool_v2 *wp_tablet_tool_v2, uint32_t serial, struct zwp_tablet_v2 *tablet, struct wl_surface *surface);
+ static void _wp_tablet_tool_on_proximity_out(void *data, struct zwp_tablet_tool_v2 *wp_tablet_tool_v2);
+ static void _wp_tablet_tool_on_down(void *data, struct zwp_tablet_tool_v2 *wp_tablet_tool_v2, uint32_t serial);
+ static void _wp_tablet_tool_on_up(void *data, struct zwp_tablet_tool_v2 *wp_tablet_tool_v2);
+ static void _wp_tablet_tool_on_motion(void *data, struct zwp_tablet_tool_v2 *wp_tablet_tool_v2, wl_fixed_t x, wl_fixed_t y);
+ static void _wp_tablet_tool_on_pressure(void *data, struct zwp_tablet_tool_v2 *wp_tablet_tool_v2, uint32_t pressure);
+ static void _wp_tablet_tool_on_distance(void *data, struct zwp_tablet_tool_v2 *wp_tablet_tool_v2, uint32_t distance);
+ static void _wp_tablet_tool_on_tilt(void *data, struct zwp_tablet_tool_v2 *wp_tablet_tool_v2, wl_fixed_t tilt_x, wl_fixed_t tilt_y);
+ static void _wp_tablet_tool_on_rotation(void *data, struct zwp_tablet_tool_v2 *wp_tablet_tool_v2, wl_fixed_t degrees);
+ static void _wp_tablet_tool_on_slider(void *data, struct zwp_tablet_tool_v2 *wp_tablet_tool_v2, int32_t position);
+ static void _wp_tablet_tool_on_wheel(void *data, struct zwp_tablet_tool_v2 *wp_tablet_tool_v2, wl_fixed_t degrees, int32_t clicks);
+ static void _wp_tablet_tool_on_button(void *data, struct zwp_tablet_tool_v2 *wp_tablet_tool_v2, uint32_t serial, uint32_t button, uint32_t state);
+ static void _wp_tablet_tool_on_frame(void *data, struct zwp_tablet_tool_v2 *wp_tablet_tool_v2, uint32_t time);
static void _xdg_toplevel_decoration_on_configure(void *data, struct zxdg_toplevel_decoration_v1 *xdg_toplevel_decoration, uint32_t mode);
diff --git a/platform/linuxbsd/x11/display_server_x11.cpp b/platform/linuxbsd/x11/display_server_x11.cpp
index 0041b4c7f3..e854fe9274 100644
--- a/platform/linuxbsd/x11/display_server_x11.cpp
+++ b/platform/linuxbsd/x11/display_server_x11.cpp
@@ -4992,7 +4992,7 @@ void DisplayServerX11::process_events() {
files.write[i] = files[i].replace("file://", "").uri_decode();
}
- if (!windows[window_id].drop_files_callback.is_null()) {
+ if (windows[window_id].drop_files_callback.is_valid()) {
windows[window_id].drop_files_callback.call(files);
}
diff --git a/platform/macos/detect.py b/platform/macos/detect.py
index 3c8b1ebee1..a5ef29e34f 100644
--- a/platform/macos/detect.py
+++ b/platform/macos/detect.py
@@ -1,6 +1,6 @@
import os
import sys
-from methods import detect_darwin_sdk_path, get_compiler_version, is_vanilla_clang
+from methods import print_error, detect_darwin_sdk_path, get_compiler_version, is_vanilla_clang
from platform_methods import detect_arch, detect_mvk
from typing import TYPE_CHECKING
@@ -64,11 +64,11 @@ def configure(env: "SConsEnvironment"):
# Validate arch.
supported_arches = ["x86_64", "arm64"]
if env["arch"] not in supported_arches:
- print(
+ print_error(
'Unsupported CPU architecture "%s" for macOS. Supported architectures are: %s.'
% (env["arch"], ", ".join(supported_arches))
)
- sys.exit()
+ sys.exit(255)
## Build type
@@ -254,7 +254,7 @@ def configure(env: "SConsEnvironment"):
if mvk_path != "":
env.Append(LINKFLAGS=["-L" + mvk_path])
else:
- print(
+ print_error(
"MoltenVK SDK installation directory not found, use 'vulkan_sdk_path' SCons parameter to specify SDK path."
)
sys.exit(255)
diff --git a/platform/macos/display_server_macos.mm b/platform/macos/display_server_macos.mm
index cfe925e79b..6461f50818 100644
--- a/platform/macos/display_server_macos.mm
+++ b/platform/macos/display_server_macos.mm
@@ -938,7 +938,7 @@ Error DisplayServerMacOS::dialog_show(String p_title, String p_description, Vect
button_pressed = int64_t(2 + (ret - NSAlertThirdButtonReturn));
}
- if (!p_callback.is_null()) {
+ if (p_callback.is_valid()) {
Variant ret;
Callable::CallError ce;
const Variant *args[1] = { &button_pressed };
@@ -1018,7 +1018,7 @@ Error DisplayServerMacOS::_file_dialog_with_options_show(const String &p_title,
String url;
url.parse_utf8([[[panel URL] path] UTF8String]);
files.push_back(url);
- if (!callback.is_null()) {
+ if (callback.is_valid()) {
if (p_options_in_cb) {
Variant v_result = true;
Variant v_files = files;
@@ -1047,7 +1047,7 @@ Error DisplayServerMacOS::_file_dialog_with_options_show(const String &p_title,
}
}
} else {
- if (!callback.is_null()) {
+ if (callback.is_valid()) {
if (p_options_in_cb) {
Variant v_result = false;
Variant v_files = Vector<String>();
@@ -1134,7 +1134,7 @@ Error DisplayServerMacOS::_file_dialog_with_options_show(const String &p_title,
url.parse_utf8([[[urls objectAtIndex:i] path] UTF8String]);
files.push_back(url);
}
- if (!callback.is_null()) {
+ if (callback.is_valid()) {
if (p_options_in_cb) {
Variant v_result = true;
Variant v_files = files;
@@ -1163,7 +1163,7 @@ Error DisplayServerMacOS::_file_dialog_with_options_show(const String &p_title,
}
}
} else {
- if (!callback.is_null()) {
+ if (callback.is_valid()) {
if (p_options_in_cb) {
Variant v_result = false;
Variant v_files = Vector<String>();
@@ -1222,7 +1222,7 @@ Error DisplayServerMacOS::dialog_input_text(String p_title, String p_description
String ret;
ret.parse_utf8([[input stringValue] UTF8String]);
- if (!p_callback.is_null()) {
+ if (p_callback.is_valid()) {
Variant v_result = ret;
Variant ret;
Callable::CallError ce;
diff --git a/platform/macos/export/export_plugin.cpp b/platform/macos/export/export_plugin.cpp
index d75def9b50..5f52d33318 100644
--- a/platform/macos/export/export_plugin.cpp
+++ b/platform/macos/export/export_plugin.cpp
@@ -909,7 +909,7 @@ Error EditorExportPlatformMacOS::_notarize(const Ref<EditorExportPreset> &p_pres
return OK;
}
-Error EditorExportPlatformMacOS::_code_sign(const Ref<EditorExportPreset> &p_preset, const String &p_path, const String &p_ent_path, bool p_warn) {
+Error EditorExportPlatformMacOS::_code_sign(const Ref<EditorExportPreset> &p_preset, const String &p_path, const String &p_ent_path, bool p_warn, bool p_set_id) {
int codesign_tool = p_preset->get("codesign/codesign");
switch (codesign_tool) {
case 1: { // built-in ad-hoc
@@ -953,6 +953,12 @@ Error EditorExportPlatformMacOS::_code_sign(const Ref<EditorExportPreset> &p_pre
args.push_back("--code-signature-flags");
args.push_back("runtime");
+ if (p_set_id) {
+ String app_id = p_preset->get("application/bundle_identifier");
+ args.push_back("--binary-identifier");
+ args.push_back(app_id);
+ }
+
args.push_back("-v"); /* provide some more feedback */
args.push_back(p_path);
@@ -1012,6 +1018,12 @@ Error EditorExportPlatformMacOS::_code_sign(const Ref<EditorExportPreset> &p_pre
args.push_back(p_preset->get("codesign/identity"));
}
+ if (p_set_id) {
+ String app_id = p_preset->get("application/bundle_identifier");
+ args.push_back("-i");
+ args.push_back(app_id);
+ }
+
args.push_back("-v"); /* provide some more feedback */
args.push_back("-f");
@@ -1043,7 +1055,7 @@ Error EditorExportPlatformMacOS::_code_sign(const Ref<EditorExportPreset> &p_pre
}
Error EditorExportPlatformMacOS::_code_sign_directory(const Ref<EditorExportPreset> &p_preset, const String &p_path,
- const String &p_ent_path, bool p_should_error_on_non_code) {
+ const String &p_ent_path, const String &p_helper_ent_path, bool p_should_error_on_non_code) {
static Vector<String> extensions_to_sign;
if (extensions_to_sign.is_empty()) {
@@ -1070,7 +1082,8 @@ Error EditorExportPlatformMacOS::_code_sign_directory(const Ref<EditorExportPres
}
if (extensions_to_sign.find(current_file.get_extension()) > -1) {
- Error code_sign_error{ _code_sign(p_preset, current_file_path, p_ent_path, false) };
+ int ftype = MachO::get_filetype(current_file_path);
+ Error code_sign_error{ _code_sign(p_preset, current_file_path, (ftype == 2 || ftype == 5) ? p_helper_ent_path : p_ent_path, false, (ftype == 2 || ftype == 5)) };
if (code_sign_error != OK) {
return code_sign_error;
}
@@ -1079,7 +1092,7 @@ Error EditorExportPlatformMacOS::_code_sign_directory(const Ref<EditorExportPres
FileAccess::set_unix_permissions(current_file_path, 0755);
}
} else if (dir_access->current_is_dir()) {
- Error code_sign_error{ _code_sign_directory(p_preset, current_file_path, p_ent_path, p_should_error_on_non_code) };
+ Error code_sign_error{ _code_sign_directory(p_preset, current_file_path, p_ent_path, p_helper_ent_path, p_should_error_on_non_code) };
if (code_sign_error != OK) {
return code_sign_error;
}
@@ -1097,6 +1110,7 @@ Error EditorExportPlatformMacOS::_code_sign_directory(const Ref<EditorExportPres
Error EditorExportPlatformMacOS::_copy_and_sign_files(Ref<DirAccess> &dir_access, const String &p_src_path,
const String &p_in_app_path, bool p_sign_enabled,
const Ref<EditorExportPreset> &p_preset, const String &p_ent_path,
+ const String &p_helper_ent_path,
bool p_should_error_on_non_code_sign) {
static Vector<String> extensions_to_sign;
@@ -1186,10 +1200,11 @@ Error EditorExportPlatformMacOS::_copy_and_sign_files(Ref<DirAccess> &dir_access
if (err == OK && p_sign_enabled) {
if (dir_access->dir_exists(p_src_path) && p_src_path.get_extension().is_empty()) {
// If it is a directory, find and sign all dynamic libraries.
- err = _code_sign_directory(p_preset, p_in_app_path, p_ent_path, p_should_error_on_non_code_sign);
+ err = _code_sign_directory(p_preset, p_in_app_path, p_ent_path, p_helper_ent_path, p_should_error_on_non_code_sign);
} else {
if (extensions_to_sign.find(p_in_app_path.get_extension()) > -1) {
- err = _code_sign(p_preset, p_in_app_path, p_ent_path, false);
+ int ftype = MachO::get_filetype(p_in_app_path);
+ err = _code_sign(p_preset, p_in_app_path, (ftype == 2 || ftype == 5) ? p_helper_ent_path : p_ent_path, false, (ftype == 2 || ftype == 5));
}
if (dir_access->file_exists(p_in_app_path) && is_executable(p_in_app_path)) {
// chmod with 0755 if the file is executable.
@@ -1203,13 +1218,13 @@ Error EditorExportPlatformMacOS::_copy_and_sign_files(Ref<DirAccess> &dir_access
Error EditorExportPlatformMacOS::_export_macos_plugins_for(Ref<EditorExportPlugin> p_editor_export_plugin,
const String &p_app_path_name, Ref<DirAccess> &dir_access,
bool p_sign_enabled, const Ref<EditorExportPreset> &p_preset,
- const String &p_ent_path) {
+ const String &p_ent_path, const String &p_helper_ent_path) {
Error error{ OK };
const Vector<String> &macos_plugins{ p_editor_export_plugin->get_macos_plugin_files() };
for (int i = 0; i < macos_plugins.size(); ++i) {
String src_path{ ProjectSettings::get_singleton()->globalize_path(macos_plugins[i]) };
String path_in_app{ p_app_path_name + "/Contents/PlugIns/" + src_path.get_file() };
- error = _copy_and_sign_files(dir_access, src_path, path_in_app, p_sign_enabled, p_preset, p_ent_path, false);
+ error = _copy_and_sign_files(dir_access, src_path, path_in_app, p_sign_enabled, p_preset, p_ent_path, p_helper_ent_path, false);
if (error != OK) {
break;
}
@@ -1786,8 +1801,9 @@ Error EditorExportPlatformMacOS::export_project(const Ref<EditorExportPreset> &p
add_message(EXPORT_MESSAGE_ERROR, TTR("Code Signing"), TTR("'rcodesign' doesn't support signing applications with embedded dynamic libraries."));
}
+ bool sandbox = p_preset->get("codesign/entitlements/app_sandbox/enabled");
String ent_path = p_preset->get("codesign/entitlements/custom_file");
- String hlp_ent_path = EditorPaths::get_singleton()->get_cache_dir().path_join(pkg_name + "_helper.entitlements");
+ String hlp_ent_path = sandbox ? EditorPaths::get_singleton()->get_cache_dir().path_join(pkg_name + "_helper.entitlements") : ent_path;
if (sign_enabled && (ent_path.is_empty())) {
ent_path = EditorPaths::get_singleton()->get_cache_dir().path_join(pkg_name + ".entitlements");
@@ -1939,7 +1955,7 @@ Error EditorExportPlatformMacOS::export_project(const Ref<EditorExportPreset> &p
err = ERR_CANT_CREATE;
}
- if ((err == OK) && helpers.size() > 0) {
+ if ((err == OK) && sandbox && (helpers.size() > 0 || shared_objects.size() > 0)) {
ent_f = FileAccess::open(hlp_ent_path, FileAccess::WRITE);
if (ent_f.is_valid()) {
ent_f->store_line("<?xml version=\"1.0\" encoding=\"UTF-8\"?>");
@@ -1965,7 +1981,7 @@ Error EditorExportPlatformMacOS::export_project(const Ref<EditorExportPreset> &p
String hlp_path = helpers[i];
err = da->copy(hlp_path, tmp_app_path_name + "/Contents/Helpers/" + hlp_path.get_file());
if (err == OK && sign_enabled) {
- err = _code_sign(p_preset, tmp_app_path_name + "/Contents/Helpers/" + hlp_path.get_file(), hlp_ent_path, false);
+ err = _code_sign(p_preset, tmp_app_path_name + "/Contents/Helpers/" + hlp_path.get_file(), hlp_ent_path, false, true);
}
FileAccess::set_unix_permissions(tmp_app_path_name + "/Contents/Helpers/" + hlp_path.get_file(), 0755);
}
@@ -1977,11 +1993,11 @@ Error EditorExportPlatformMacOS::export_project(const Ref<EditorExportPreset> &p
String src_path = ProjectSettings::get_singleton()->globalize_path(shared_objects[i].path);
if (shared_objects[i].target.is_empty()) {
String path_in_app = tmp_app_path_name + "/Contents/Frameworks/" + src_path.get_file();
- err = _copy_and_sign_files(da, src_path, path_in_app, sign_enabled, p_preset, ent_path, true);
+ err = _copy_and_sign_files(da, src_path, path_in_app, sign_enabled, p_preset, ent_path, hlp_ent_path, true);
} else {
String path_in_app = tmp_app_path_name.path_join(shared_objects[i].target);
tmp_app_dir->make_dir_recursive(path_in_app);
- err = _copy_and_sign_files(da, src_path, path_in_app.path_join(src_path.get_file()), sign_enabled, p_preset, ent_path, false);
+ err = _copy_and_sign_files(da, src_path, path_in_app.path_join(src_path.get_file()), sign_enabled, p_preset, ent_path, hlp_ent_path, false);
}
if (err != OK) {
break;
@@ -1990,7 +2006,7 @@ Error EditorExportPlatformMacOS::export_project(const Ref<EditorExportPreset> &p
Vector<Ref<EditorExportPlugin>> export_plugins{ EditorExport::get_singleton()->get_export_plugins() };
for (int i = 0; i < export_plugins.size(); ++i) {
- err = _export_macos_plugins_for(export_plugins[i], tmp_app_path_name, da, sign_enabled, p_preset, ent_path);
+ err = _export_macos_plugins_for(export_plugins[i], tmp_app_path_name, da, sign_enabled, p_preset, ent_path, hlp_ent_path);
if (err != OK) {
break;
}
@@ -2010,7 +2026,7 @@ Error EditorExportPlatformMacOS::export_project(const Ref<EditorExportPreset> &p
if (ep.step(TTR("Code signing bundle"), 2)) {
return ERR_SKIP;
}
- err = _code_sign(p_preset, tmp_app_path_name, ent_path);
+ err = _code_sign(p_preset, tmp_app_path_name, ent_path, true, false);
}
String noto_path = p_path;
@@ -2028,7 +2044,7 @@ Error EditorExportPlatformMacOS::export_project(const Ref<EditorExportPreset> &p
if (ep.step(TTR("Code signing DMG"), 3)) {
return ERR_SKIP;
}
- err = _code_sign(p_preset, p_path, ent_path, false);
+ err = _code_sign(p_preset, p_path, ent_path, false, false);
}
} else if (export_format == "pkg") {
// Create a Installer.
diff --git a/platform/macos/export/export_plugin.h b/platform/macos/export/export_plugin.h
index 0764b63e8c..2d615abede 100644
--- a/platform/macos/export/export_plugin.h
+++ b/platform/macos/export/export_plugin.h
@@ -89,14 +89,14 @@ class EditorExportPlatformMacOS : public EditorExportPlatform {
void _make_icon(const Ref<EditorExportPreset> &p_preset, const Ref<Image> &p_icon, Vector<uint8_t> &p_data);
Error _notarize(const Ref<EditorExportPreset> &p_preset, const String &p_path);
- Error _code_sign(const Ref<EditorExportPreset> &p_preset, const String &p_path, const String &p_ent_path, bool p_warn = true);
- Error _code_sign_directory(const Ref<EditorExportPreset> &p_preset, const String &p_path, const String &p_ent_path, bool p_should_error_on_non_code = true);
+ Error _code_sign(const Ref<EditorExportPreset> &p_preset, const String &p_path, const String &p_ent_path, bool p_warn = true, bool p_set_id = false);
+ Error _code_sign_directory(const Ref<EditorExportPreset> &p_preset, const String &p_path, const String &p_ent_path, const String &p_helper_ent_path, bool p_should_error_on_non_code = true);
Error _copy_and_sign_files(Ref<DirAccess> &dir_access, const String &p_src_path, const String &p_in_app_path,
- bool p_sign_enabled, const Ref<EditorExportPreset> &p_preset, const String &p_ent_path,
+ bool p_sign_enabled, const Ref<EditorExportPreset> &p_preset, const String &p_ent_path, const String &p_helper_ent_path,
bool p_should_error_on_non_code_sign);
Error _export_macos_plugins_for(Ref<EditorExportPlugin> p_editor_export_plugin, const String &p_app_path_name,
Ref<DirAccess> &dir_access, bool p_sign_enabled, const Ref<EditorExportPreset> &p_preset,
- const String &p_ent_path);
+ const String &p_ent_path, const String &p_helper_ent_path);
Error _create_dmg(const String &p_dmg_path, const String &p_pkg_name, const String &p_app_path_name);
Error _create_pkg(const Ref<EditorExportPreset> &p_preset, const String &p_pkg_path, const String &p_app_path_name);
Error _export_debug_script(const Ref<EditorExportPreset> &p_preset, const String &p_app_name, const String &p_pkg_name, const String &p_path);
diff --git a/platform/macos/export/macho.cpp b/platform/macos/export/macho.cpp
index c7556c1964..a829774a88 100644
--- a/platform/macos/export/macho.cpp
+++ b/platform/macos/export/macho.cpp
@@ -105,6 +105,26 @@ bool MachO::is_macho(const String &p_path) {
return (magic == 0xcefaedfe || magic == 0xfeedface || magic == 0xcffaedfe || magic == 0xfeedfacf);
}
+uint32_t MachO::get_filetype(const String &p_path) {
+ Ref<FileAccess> fa = FileAccess::open(p_path, FileAccess::READ);
+ ERR_FAIL_COND_V_MSG(fa.is_null(), 0, vformat("MachO: Can't open file: \"%s\".", p_path));
+ uint32_t magic = fa->get_32();
+ MachHeader mach_header;
+
+ // Read MachO header.
+ if (magic == 0xcefaedfe || magic == 0xfeedface) {
+ // Thin 32-bit binary.
+ fa->get_buffer((uint8_t *)&mach_header, sizeof(MachHeader));
+ } else if (magic == 0xcffaedfe || magic == 0xfeedfacf) {
+ // Thin 64-bit binary.
+ fa->get_buffer((uint8_t *)&mach_header, sizeof(MachHeader));
+ fa->get_32(); // Skip extra reserved field.
+ } else {
+ ERR_FAIL_V_MSG(0, vformat("MachO: File is not a valid MachO binary: \"%s\".", p_path));
+ }
+ return mach_header.filetype;
+}
+
bool MachO::open_file(const String &p_path) {
fa = FileAccess::open(p_path, FileAccess::READ_WRITE);
ERR_FAIL_COND_V_MSG(fa.is_null(), false, vformat("MachO: Can't open file: \"%s\".", p_path));
diff --git a/platform/macos/export/macho.h b/platform/macos/export/macho.h
index 37975f0820..a84de7de60 100644
--- a/platform/macos/export/macho.h
+++ b/platform/macos/export/macho.h
@@ -181,6 +181,7 @@ class MachO : public RefCounted {
public:
static bool is_macho(const String &p_path);
+ static uint32_t get_filetype(const String &p_path);
bool open_file(const String &p_path);
diff --git a/platform/macos/godot_content_view.mm b/platform/macos/godot_content_view.mm
index 93bba84783..68a7288ad4 100644
--- a/platform/macos/godot_content_view.mm
+++ b/platform/macos/godot_content_view.mm
@@ -313,7 +313,7 @@
}
DisplayServerMacOS::WindowData &wd = ds->get_window(window_id);
- if (!wd.drop_files_callback.is_null()) {
+ if (wd.drop_files_callback.is_valid()) {
Vector<String> files;
NSPasteboard *pboard = [sender draggingPasteboard];
diff --git a/platform/macos/godot_window_delegate.mm b/platform/macos/godot_window_delegate.mm
index 2d83b46007..7749debfd6 100644
--- a/platform/macos/godot_window_delegate.mm
+++ b/platform/macos/godot_window_delegate.mm
@@ -268,7 +268,7 @@
ds->window_resize(window_id, wd.size.width, wd.size.height);
- if (!wd.rect_changed_callback.is_null()) {
+ if (wd.rect_changed_callback.is_valid()) {
wd.rect_changed_callback.call(Rect2i(ds->window_get_position(window_id), ds->window_get_size(window_id)));
}
}
@@ -291,7 +291,7 @@
DisplayServerMacOS::WindowData &wd = ds->get_window(window_id);
ds->release_pressed_events();
- if (!wd.rect_changed_callback.is_null()) {
+ if (wd.rect_changed_callback.is_valid()) {
wd.rect_changed_callback.call(Rect2i(ds->window_get_position(window_id), ds->window_get_size(window_id)));
}
}
diff --git a/platform/web/SCsub b/platform/web/SCsub
index 3e0cc9ac4a..bc5893ab3a 100644
--- a/platform/web/SCsub
+++ b/platform/web/SCsub
@@ -1,5 +1,7 @@
#!/usr/bin/env python
+from methods import print_error
+
Import("env")
# The HTTP server "targets". Run with "scons p=web serve", or "scons p=web run"
@@ -11,7 +13,7 @@ if "serve" in COMMAND_LINE_TARGETS or "run" in COMMAND_LINE_TARGETS:
try:
port = int(port)
except Exception:
- print("GODOT_WEB_TEST_PORT must be a valid integer")
+ print_error("GODOT_WEB_TEST_PORT must be a valid integer")
sys.exit(255)
serve(env.Dir(env.GetTemplateZipPath()).abspath, port, "run" in COMMAND_LINE_TARGETS)
sys.exit(0)
diff --git a/platform/web/api/web_tools_editor_plugin.h b/platform/web/api/web_tools_editor_plugin.h
index ac0d5e20ec..2902f60f24 100644
--- a/platform/web/api/web_tools_editor_plugin.h
+++ b/platform/web/api/web_tools_editor_plugin.h
@@ -34,7 +34,7 @@
#if defined(TOOLS_ENABLED) && defined(WEB_ENABLED)
#include "core/io/zip_io.h"
-#include "editor/editor_plugin.h"
+#include "editor/plugins/editor_plugin.h"
class WebToolsEditorPlugin : public EditorPlugin {
GDCLASS(WebToolsEditorPlugin, EditorPlugin);
diff --git a/platform/web/detect.py b/platform/web/detect.py
index 2d2cc288a1..ccd884b225 100644
--- a/platform/web/detect.py
+++ b/platform/web/detect.py
@@ -10,7 +10,7 @@ from emscripten_helpers import (
create_template_zip,
get_template_zip_path,
)
-from methods import get_compiler_version
+from methods import print_warning, print_error, get_compiler_version
from SCons.Util import WhereIs
from typing import TYPE_CHECKING
@@ -85,16 +85,16 @@ def configure(env: "SConsEnvironment"):
# Validate arch.
supported_arches = ["wasm32"]
if env["arch"] not in supported_arches:
- print(
+ print_error(
'Unsupported CPU architecture "%s" for Web. Supported architectures are: %s.'
% (env["arch"], ", ".join(supported_arches))
)
- sys.exit()
+ sys.exit(255)
try:
env["initial_memory"] = int(env["initial_memory"])
except Exception:
- print("Initial memory must be a valid integer")
+ print_error("Initial memory must be a valid integer")
sys.exit(255)
## Build type
@@ -109,7 +109,7 @@ def configure(env: "SConsEnvironment"):
env.Append(LINKFLAGS=["-s", "ASSERTIONS=1"])
if env.editor_build and env["initial_memory"] < 64:
- print('Note: Forcing "initial_memory=64" as it is required for the web editor.')
+ print("Note: Forcing `initial_memory=64` as it is required for the web editor.")
env["initial_memory"] = 64
env.Append(LINKFLAGS=["-s", "INITIAL_MEMORY=%sMB" % env["initial_memory"]])
@@ -227,7 +227,7 @@ def configure(env: "SConsEnvironment"):
env.Append(LINKFLAGS=["-s", "PTHREAD_POOL_SIZE=8"])
env.Append(LINKFLAGS=["-s", "WASM_MEM_MAX=2048MB"])
elif env["proxy_to_pthread"]:
- print('"threads=no" support requires "proxy_to_pthread=no", disabling proxy to pthread.')
+ print_warning('"threads=no" support requires "proxy_to_pthread=no", disabling proxy to pthread.')
env["proxy_to_pthread"] = False
if env["lto"] != "none":
@@ -240,11 +240,11 @@ def configure(env: "SConsEnvironment"):
if env["dlink_enabled"]:
if env["proxy_to_pthread"]:
- print("GDExtension support requires proxy_to_pthread=no, disabling proxy to pthread.")
+ print_warning("GDExtension support requires proxy_to_pthread=no, disabling proxy to pthread.")
env["proxy_to_pthread"] = False
if cc_semver < (3, 1, 14):
- print("GDExtension support requires emscripten >= 3.1.14, detected: %s.%s.%s" % cc_semver)
+ print_error("GDExtension support requires emscripten >= 3.1.14, detected: %s.%s.%s" % cc_semver)
sys.exit(255)
env.Append(CCFLAGS=["-s", "SIDE_MODULE=2"])
diff --git a/platform/web/display_server_web.cpp b/platform/web/display_server_web.cpp
index 06f5eb82f7..a51c161b9c 100644
--- a/platform/web/display_server_web.cpp
+++ b/platform/web/display_server_web.cpp
@@ -58,7 +58,7 @@ DisplayServerWeb *DisplayServerWeb::get_singleton() {
// Window (canvas)
bool DisplayServerWeb::check_size_force_redraw() {
bool size_changed = godot_js_display_size_update() != 0;
- if (size_changed && !rect_changed_callback.is_null()) {
+ if (size_changed && rect_changed_callback.is_valid()) {
Size2i window_size = window_get_size();
Variant size = Rect2i(Point2i(), window_size); // TODO use window_get_position if implemented.
rect_changed_callback.call(size);
@@ -109,7 +109,7 @@ void DisplayServerWeb::_drop_files_js_callback(const Vector<String> &p_files) {
if (!ds) {
ERR_FAIL_MSG("Unable to drop files because the DisplayServer is not active");
}
- if (ds->drop_files_callback.is_null()) {
+ if (!ds->drop_files_callback.is_valid()) {
return;
}
ds->drop_files_callback.call(p_files);
@@ -129,7 +129,7 @@ void DisplayServerWeb::request_quit_callback() {
void DisplayServerWeb::_request_quit_callback() {
DisplayServerWeb *ds = get_singleton();
- if (ds && !ds->window_event_callback.is_null()) {
+ if (ds && ds->window_event_callback.is_valid()) {
Variant event = int(DisplayServer::WINDOW_EVENT_CLOSE_REQUEST);
ds->window_event_callback.call(event);
}
@@ -722,7 +722,7 @@ void DisplayServerWeb::vk_input_text_callback(const char *p_text, int p_cursor)
void DisplayServerWeb::_vk_input_text_callback(const String &p_text, int p_cursor) {
DisplayServerWeb *ds = DisplayServerWeb::get_singleton();
- if (!ds || ds->input_text_callback.is_null()) {
+ if (!ds || !ds->input_text_callback.is_valid()) {
return;
}
// Call input_text
@@ -972,7 +972,7 @@ void DisplayServerWeb::_send_window_event_callback(int p_notification) {
if (godot_js_is_ime_focused() && (p_notification == DisplayServer::WINDOW_EVENT_FOCUS_IN || p_notification == DisplayServer::WINDOW_EVENT_FOCUS_OUT)) {
return;
}
- if (!ds->window_event_callback.is_null()) {
+ if (ds->window_event_callback.is_valid()) {
Variant event = int(p_notification);
ds->window_event_callback.call(event);
}
diff --git a/platform/web/javascript_bridge_singleton.cpp b/platform/web/javascript_bridge_singleton.cpp
index d72ad8331b..a2c83d2f2b 100644
--- a/platform/web/javascript_bridge_singleton.cpp
+++ b/platform/web/javascript_bridge_singleton.cpp
@@ -248,7 +248,7 @@ Variant JavaScriptObjectImpl::callp(const StringName &p_method, const Variant **
void JavaScriptObjectImpl::callback(void *p_ref, int p_args_id, int p_argc) {
const JavaScriptObjectImpl *obj = (JavaScriptObjectImpl *)p_ref;
- ERR_FAIL_COND_MSG(obj->_callable.is_null(), "JavaScript callback failed.");
+ ERR_FAIL_COND_MSG(!obj->_callable.is_valid(), "JavaScript callback failed.");
Vector<const Variant *> argp;
Array arg_arr;
diff --git a/platform/web/js/engine/features.js b/platform/web/js/engine/features.js
index 81bc82f3c6..263ea6ac88 100644
--- a/platform/web/js/engine/features.js
+++ b/platform/web/js/engine/features.js
@@ -72,8 +72,7 @@ const Features = { // eslint-disable-line no-unused-vars
*
* @returns {Array<string>} A list of human-readable missing features.
* @function Engine.getMissingFeatures
- * @typedef {{ threads: boolean }} SupportedFeatures
- * @param {SupportedFeatures} supportedFeatures
+ * @param {{threads: (boolean|undefined)}} supportedFeatures
*/
getMissingFeatures: function (supportedFeatures = {}) {
const {
diff --git a/platform/windows/SCsub b/platform/windows/SCsub
index 159a273e70..435c501956 100644
--- a/platform/windows/SCsub
+++ b/platform/windows/SCsub
@@ -10,7 +10,6 @@ sources = []
common_win = [
"godot_windows.cpp",
- "crash_handler_windows.cpp",
"os_windows.cpp",
"display_server_windows.cpp",
"key_mapping_windows.cpp",
@@ -25,6 +24,11 @@ common_win = [
"rendering_context_driver_vulkan_windows.cpp",
]
+if env.msvc:
+ common_win += ["crash_handler_windows_seh.cpp"]
+else:
+ common_win += ["crash_handler_windows_signal.cpp"]
+
common_win_wrap = [
"console_wrapper_windows.cpp",
]
diff --git a/platform/windows/console_wrapper_windows.cpp b/platform/windows/console_wrapper_windows.cpp
index de751580b7..133711a9ea 100644
--- a/platform/windows/console_wrapper_windows.cpp
+++ b/platform/windows/console_wrapper_windows.cpp
@@ -136,6 +136,10 @@ int main(int argc, char *argv[]) {
STARTUPINFOW si;
ZeroMemory(&si, sizeof(si));
si.cb = sizeof(si);
+ si.dwFlags = STARTF_USESTDHANDLES;
+ si.hStdInput = GetStdHandle(STD_INPUT_HANDLE);
+ si.hStdOutput = GetStdHandle(STD_OUTPUT_HANDLE);
+ si.hStdError = GetStdHandle(STD_ERROR_HANDLE);
WCHAR new_command_line[32767];
_snwprintf_s(new_command_line, 32767, _TRUNCATE, L"%ls %ls", exe_name, PathGetArgsW(GetCommandLineW()));
diff --git a/platform/windows/crash_handler_windows.h b/platform/windows/crash_handler_windows.h
index 3871210977..a0a0b610d0 100644
--- a/platform/windows/crash_handler_windows.h
+++ b/platform/windows/crash_handler_windows.h
@@ -35,12 +35,15 @@
#include <windows.h>
// Crash handler exception only enabled with MSVC
-#if defined(DEBUG_ENABLED) && defined(_MSC_VER)
+#if defined(DEBUG_ENABLED)
#define CRASH_HANDLER_EXCEPTION 1
+#ifdef _MSC_VER
extern DWORD CrashHandlerException(EXCEPTION_POINTERS *ep);
#endif
+#endif
+
class CrashHandler {
bool disabled;
diff --git a/platform/windows/crash_handler_windows.cpp b/platform/windows/crash_handler_windows_seh.cpp
index 133d36aa0d..2abe285d31 100644
--- a/platform/windows/crash_handler_windows.cpp
+++ b/platform/windows/crash_handler_windows_seh.cpp
@@ -1,5 +1,5 @@
/**************************************************************************/
-/* crash_handler_windows.cpp */
+/* crash_handler_windows_seh.cpp */
/**************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
diff --git a/platform/windows/crash_handler_windows_signal.cpp b/platform/windows/crash_handler_windows_signal.cpp
new file mode 100644
index 0000000000..e11a60bdc7
--- /dev/null
+++ b/platform/windows/crash_handler_windows_signal.cpp
@@ -0,0 +1,205 @@
+/**************************************************************************/
+/* crash_handler_windows_signal.cpp */
+/**************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/**************************************************************************/
+/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
+/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/**************************************************************************/
+
+#include "crash_handler_windows.h"
+
+#include "core/config/project_settings.h"
+#include "core/os/os.h"
+#include "core/string/print_string.h"
+#include "core/version.h"
+#include "main/main.h"
+
+#ifdef CRASH_HANDLER_EXCEPTION
+
+#include <cxxabi.h>
+#include <signal.h>
+#include <algorithm>
+#include <iterator>
+#include <string>
+#include <vector>
+
+#include <psapi.h>
+
+#include "thirdparty/libbacktrace/backtrace.h"
+
+struct CrashHandlerData {
+ int64_t index = 0;
+ backtrace_state *state = nullptr;
+ int64_t offset = 0;
+};
+
+int symbol_callback(void *data, uintptr_t pc, const char *filename, int lineno, const char *function) {
+ CrashHandlerData *ch_data = reinterpret_cast<CrashHandlerData *>(data);
+ if (!function) {
+ return 0;
+ }
+
+ char fname[1024];
+ snprintf(fname, 1024, "%s", function);
+
+ if (function[0] == '_') {
+ int status;
+ char *demangled = abi::__cxa_demangle(function, nullptr, nullptr, &status);
+
+ if (status == 0 && demangled) {
+ snprintf(fname, 1024, "%s", demangled);
+ }
+
+ if (demangled) {
+ free(demangled);
+ }
+ }
+
+ print_error(vformat("[%d] %s (%s:%d)", ch_data->index++, String::utf8(fname), String::utf8(filename), lineno));
+ return 0;
+}
+
+void error_callback(void *data, const char *msg, int errnum) {
+ CrashHandlerData *ch_data = reinterpret_cast<CrashHandlerData *>(data);
+ if (ch_data->index == 0) {
+ print_error(vformat("Error(%d): %s", errnum, String::utf8(msg)));
+ } else {
+ print_error(vformat("[%d] error(%d): %s", ch_data->index++, errnum, String::utf8(msg)));
+ }
+}
+
+int trace_callback(void *data, uintptr_t pc) {
+ CrashHandlerData *ch_data = reinterpret_cast<CrashHandlerData *>(data);
+ backtrace_pcinfo(ch_data->state, pc - ch_data->offset, &symbol_callback, &error_callback, data);
+ return 0;
+}
+
+int64_t get_image_base(const String &p_path) {
+ Ref<FileAccess> f = FileAccess::open(p_path, FileAccess::READ);
+ if (f.is_null()) {
+ return 0;
+ }
+ {
+ f->seek(0x3c);
+ uint32_t pe_pos = f->get_32();
+
+ f->seek(pe_pos);
+ uint32_t magic = f->get_32();
+ if (magic != 0x00004550) {
+ return 0;
+ }
+ }
+ int64_t opt_header_pos = f->get_position() + 0x14;
+ f->seek(opt_header_pos);
+
+ uint16_t opt_header_magic = f->get_16();
+ if (opt_header_magic == 0x10B) {
+ f->seek(opt_header_pos + 0x1C);
+ return f->get_32();
+ } else if (opt_header_magic == 0x20B) {
+ f->seek(opt_header_pos + 0x18);
+ return f->get_64();
+ } else {
+ return 0;
+ }
+}
+
+extern void CrashHandlerException(int signal) {
+ CrashHandlerData data;
+
+ if (OS::get_singleton() == nullptr || OS::get_singleton()->is_disable_crash_handler() || IsDebuggerPresent()) {
+ return;
+ }
+
+ String msg;
+ const ProjectSettings *proj_settings = ProjectSettings::get_singleton();
+ if (proj_settings) {
+ msg = proj_settings->get("debug/settings/crash_handler/message");
+ }
+
+ // Tell MainLoop about the crash. This can be handled by users too in Node.
+ if (OS::get_singleton()->get_main_loop()) {
+ OS::get_singleton()->get_main_loop()->notification(MainLoop::NOTIFICATION_CRASH);
+ }
+
+ print_error("\n================================================================");
+ print_error(vformat("%s: Program crashed with signal %d", __FUNCTION__, signal));
+
+ // Print the engine version just before, so that people are reminded to include the version in backtrace reports.
+ if (String(VERSION_HASH).is_empty()) {
+ print_error(vformat("Engine version: %s", VERSION_FULL_NAME));
+ } else {
+ print_error(vformat("Engine version: %s (%s)", VERSION_FULL_NAME, VERSION_HASH));
+ }
+ print_error(vformat("Dumping the backtrace. %s", msg));
+
+ String _execpath = OS::get_singleton()->get_executable_path();
+
+ // Load process and image info to determine ASLR addresses offset.
+ MODULEINFO mi;
+ GetModuleInformation(GetCurrentProcess(), GetModuleHandle(NULL), &mi, sizeof(mi));
+ int64_t image_mem_base = reinterpret_cast<int64_t>(mi.lpBaseOfDll);
+ int64_t image_file_base = get_image_base(_execpath);
+ data.offset = image_mem_base - image_file_base;
+
+ data.state = backtrace_create_state(_execpath.utf8().get_data(), 0, &error_callback, reinterpret_cast<void *>(&data));
+ if (data.state != nullptr) {
+ data.index = 1;
+ backtrace_simple(data.state, 1, &trace_callback, &error_callback, reinterpret_cast<void *>(&data));
+ }
+
+ print_error("-- END OF BACKTRACE --");
+ print_error("================================================================");
+}
+#endif
+
+CrashHandler::CrashHandler() {
+ disabled = false;
+}
+
+CrashHandler::~CrashHandler() {
+}
+
+void CrashHandler::disable() {
+ if (disabled) {
+ return;
+ }
+
+#if defined(CRASH_HANDLER_EXCEPTION)
+ signal(SIGSEGV, nullptr);
+ signal(SIGFPE, nullptr);
+ signal(SIGILL, nullptr);
+#endif
+
+ disabled = true;
+}
+
+void CrashHandler::initialize() {
+#if defined(CRASH_HANDLER_EXCEPTION)
+ signal(SIGSEGV, CrashHandlerException);
+ signal(SIGFPE, CrashHandlerException);
+ signal(SIGILL, CrashHandlerException);
+#endif
+}
diff --git a/platform/windows/detect.py b/platform/windows/detect.py
index f34d479345..93eb34001e 100644
--- a/platform/windows/detect.py
+++ b/platform/windows/detect.py
@@ -2,6 +2,7 @@ import methods
import os
import subprocess
import sys
+from methods import print_warning, print_error
from platform_methods import detect_arch
from typing import TYPE_CHECKING
@@ -293,16 +294,14 @@ def setup_msvc_manual(env: "SConsEnvironment"):
env_arch = detect_build_env_arch()
if env["arch"] != env_arch:
- print(
- """
- Arch argument (%s) is not matching Native/Cross Compile Tools Prompt/Developer Console (or Visual Studio settings) that is being used to run SCons (%s).
- Run SCons again without arch argument (example: scons p=windows) and SCons will attempt to detect what MSVC compiler will be executed and inform you.
- """
+ print_error(
+ "Arch argument (%s) is not matching Native/Cross Compile Tools Prompt/Developer Console (or Visual Studio settings) that is being used to run SCons (%s).\n"
+ "Run SCons again without arch argument (example: scons p=windows) and SCons will attempt to detect what MSVC compiler will be executed and inform you."
% (env["arch"], env_arch)
)
- sys.exit(200)
+ sys.exit(255)
- print("Found MSVC, arch %s" % (env_arch))
+ print("Using VCVARS-determined MSVC, arch %s" % (env_arch))
def setup_msvc_auto(env: "SConsEnvironment"):
@@ -338,7 +337,7 @@ def setup_msvc_auto(env: "SConsEnvironment"):
env.Tool("mssdk") # we want the MS SDK
# Note: actual compiler version can be found in env['MSVC_VERSION'], e.g. "14.1" for VS2015
- print("Found MSVC version %s, arch %s" % (env["MSVC_VERSION"], env["arch"]))
+ print("Using SCons-detected MSVC version %s, arch %s" % (env["MSVC_VERSION"], env["arch"]))
def setup_mingw(env: "SConsEnvironment"):
@@ -346,32 +345,24 @@ def setup_mingw(env: "SConsEnvironment"):
env_arch = detect_build_env_arch()
if os.getenv("MSYSTEM") == "MSYS":
- print(
- """
- Running from base MSYS2 console/environment, use target specific environment instead (e.g., mingw32, mingw64, clang32, clang64).
- """
+ print_error(
+ "Running from base MSYS2 console/environment, use target specific environment instead (e.g., mingw32, mingw64, clang32, clang64)."
)
- sys.exit(201)
+ sys.exit(255)
if env_arch != "" and env["arch"] != env_arch:
- print(
- """
- Arch argument (%s) is not matching MSYS2 console/environment that is being used to run SCons (%s).
- Run SCons again without arch argument (example: scons p=windows) and SCons will attempt to detect what MSYS2 compiler will be executed and inform you.
- """
+ print_error(
+ "Arch argument (%s) is not matching MSYS2 console/environment that is being used to run SCons (%s).\n"
+ "Run SCons again without arch argument (example: scons p=windows) and SCons will attempt to detect what MSYS2 compiler will be executed and inform you."
% (env["arch"], env_arch)
)
- sys.exit(202)
+ sys.exit(255)
if not try_cmd("gcc --version", env["mingw_prefix"], env["arch"]) and not try_cmd(
"clang --version", env["mingw_prefix"], env["arch"]
):
- print(
- """
- No valid compilers found, use MINGW_PREFIX environment variable to set MinGW path.
- """
- )
- sys.exit(202)
+ print_error("No valid compilers found, use MINGW_PREFIX environment variable to set MinGW path.")
+ sys.exit(255)
print("Using MinGW, arch %s" % (env["arch"]))
@@ -454,10 +445,10 @@ def configure_msvc(env: "SConsEnvironment", vcvars_msvc_config):
if os.getenv("WindowsSdkDir") is not None:
env.Prepend(CPPPATH=[str(os.getenv("WindowsSdkDir")) + "/Include"])
else:
- print("Missing environment variable: WindowsSdkDir")
+ print_warning("Missing environment variable: WindowsSdkDir")
if int(env["target_win_version"], 16) < 0x0601:
- print("`target_win_version` should be 0x0601 or higher (Windows 7).")
+ print_error("`target_win_version` should be 0x0601 or higher (Windows 7).")
sys.exit(255)
env.AppendUnique(
@@ -515,10 +506,10 @@ def configure_msvc(env: "SConsEnvironment", vcvars_msvc_config):
if env["d3d12"]:
# Check whether we have d3d12 dependencies installed.
if not os.path.exists(env["mesa_libs"]):
- print("The Direct3D 12 rendering driver requires dependencies to be installed.")
- print(r"You can install them by running `python misc\scripts\install_d3d12_sdk_windows.py`.")
- print("See the documentation for more information:")
- print(
+ print_error(
+ "The Direct3D 12 rendering driver requires dependencies to be installed.\n"
+ "You can install them by running `python misc\\scripts\\install_d3d12_sdk_windows.py`.\n"
+ "See the documentation for more information:\n\t"
"https://docs.godotengine.org/en/latest/contributing/development/compiling/compiling_for_windows.html"
)
sys.exit(255)
@@ -557,13 +548,16 @@ def configure_msvc(env: "SConsEnvironment", vcvars_msvc_config):
LIBS += ["dxgi", "d3d9", "d3d11"]
env.Prepend(CPPPATH=["#thirdparty/angle/include"])
+ if env["target"] in ["editor", "template_debug"]:
+ LIBS += ["psapi", "dbghelp"]
+
env.Append(LINKFLAGS=[p + env["LIBSUFFIX"] for p in LIBS])
if vcvars_msvc_config:
if os.getenv("WindowsSdkDir") is not None:
env.Append(LIBPATH=[str(os.getenv("WindowsSdkDir")) + "/Lib"])
else:
- print("Missing environment variable: WindowsSdkDir")
+ print_warning("Missing environment variable: WindowsSdkDir")
## LTO
@@ -572,7 +566,7 @@ def configure_msvc(env: "SConsEnvironment", vcvars_msvc_config):
if env["lto"] != "none":
if env["lto"] == "thin":
- print("ThinLTO is only compatible with LLVM, use `use_llvm=yes` or `lto=full`.")
+ print_error("ThinLTO is only compatible with LLVM, use `use_llvm=yes` or `lto=full`.")
sys.exit(255)
env.AppendUnique(CCFLAGS=["/GL"])
env.AppendUnique(ARFLAGS=["/LTCG"])
@@ -690,7 +684,7 @@ def configure_mingw(env: "SConsEnvironment"):
## Compile flags
if int(env["target_win_version"], 16) < 0x0601:
- print("`target_win_version` should be 0x0601 or higher (Windows 7).")
+ print_error("`target_win_version` should be 0x0601 or higher (Windows 7).")
sys.exit(255)
if not env["use_llvm"]:
@@ -744,10 +738,10 @@ def configure_mingw(env: "SConsEnvironment"):
if env["d3d12"]:
# Check whether we have d3d12 dependencies installed.
if not os.path.exists(env["mesa_libs"]):
- print("The Direct3D 12 rendering driver requires dependencies to be installed.")
- print(r"You can install them by running `python misc\scripts\install_d3d12_sdk_windows.py`.")
- print("See the documentation for more information:")
- print(
+ print_error(
+ "The Direct3D 12 rendering driver requires dependencies to be installed.\n"
+ "You can install them by running `python misc\\scripts\\install_d3d12_sdk_windows.py`.\n"
+ "See the documentation for more information:\n\t"
"https://docs.godotengine.org/en/latest/contributing/development/compiling/compiling_for_windows.html"
)
sys.exit(255)
@@ -794,11 +788,11 @@ def configure(env: "SConsEnvironment"):
# Validate arch.
supported_arches = ["x86_32", "x86_64", "arm32", "arm64"]
if env["arch"] not in supported_arches:
- print(
+ print_error(
'Unsupported CPU architecture "%s" for Windows. Supported architectures are: %s.'
% (env["arch"], ", ".join(supported_arches))
)
- sys.exit()
+ sys.exit(255)
# At this point the env has been set up with basic tools/compilers.
env.Prepend(CPPPATH=["#platform/windows"])
diff --git a/platform/windows/display_server_windows.cpp b/platform/windows/display_server_windows.cpp
index b6b713687f..ebae00017b 100644
--- a/platform/windows/display_server_windows.cpp
+++ b/platform/windows/display_server_windows.cpp
@@ -545,7 +545,7 @@ Error DisplayServerWindows::_file_dialog_with_options_show(const String &p_title
result->Release();
}
}
- if (!p_callback.is_null()) {
+ if (p_callback.is_valid()) {
if (p_options_in_cb) {
Variant v_result = true;
Variant v_files = file_names;
@@ -574,7 +574,7 @@ Error DisplayServerWindows::_file_dialog_with_options_show(const String &p_title
}
}
} else {
- if (!p_callback.is_null()) {
+ if (p_callback.is_valid()) {
if (p_options_in_cb) {
Variant v_result = false;
Variant v_files = Vector<String>();
@@ -2556,7 +2556,7 @@ Error DisplayServerWindows::dialog_show(String p_title, String p_description, Ve
int button_pressed;
if (task_dialog_indirect && SUCCEEDED(task_dialog_indirect(&config, &button_pressed, nullptr, nullptr))) {
- if (!p_callback.is_null()) {
+ if (p_callback.is_valid()) {
Variant button = button_pressed;
const Variant *args[1] = { &button };
Variant ret;
@@ -4591,7 +4591,7 @@ LRESULT DisplayServerWindows::WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARA
}
if (rect_changed) {
- if (!window.rect_changed_callback.is_null()) {
+ if (window.rect_changed_callback.is_valid()) {
window.rect_changed_callback.call(Rect2i(window.last_pos.x, window.last_pos.y, window.width, window.height));
}
@@ -4803,7 +4803,7 @@ LRESULT DisplayServerWindows::WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARA
files.push_back(file);
}
- if (files.size() && !windows[window_id].drop_files_callback.is_null()) {
+ if (files.size() && windows[window_id].drop_files_callback.is_valid()) {
windows[window_id].drop_files_callback.call(files);
}
} break;
diff --git a/platform/windows/godot_windows.cpp b/platform/windows/godot_windows.cpp
index 5f41b4e568..486c3120fc 100644
--- a/platform/windows/godot_windows.cpp
+++ b/platform/windows/godot_windows.cpp
@@ -215,7 +215,7 @@ int main(int argc, char **argv) {
// _argc and _argv are ignored
// we are going to use the WideChar version of them instead
-#ifdef CRASH_HANDLER_EXCEPTION
+#if defined(CRASH_HANDLER_EXCEPTION) && defined(_MSC_VER)
__try {
return _main();
} __except (CrashHandlerException(GetExceptionInformation())) {
diff --git a/platform/windows/os_windows.cpp b/platform/windows/os_windows.cpp
index abed93d414..157702655e 100644
--- a/platform/windows/os_windows.cpp
+++ b/platform/windows/os_windows.cpp
@@ -115,7 +115,24 @@ void RedirectStream(const char *p_file_name, const char *p_mode, FILE *p_cpp_str
}
void RedirectIOToConsole() {
+ // Save current handles.
+ HANDLE h_stdin = GetStdHandle(STD_INPUT_HANDLE);
+ HANDLE h_stdout = GetStdHandle(STD_OUTPUT_HANDLE);
+ HANDLE h_stderr = GetStdHandle(STD_ERROR_HANDLE);
+
if (AttachConsole(ATTACH_PARENT_PROCESS)) {
+ // Restore redirection (Note: if not redirected it's NULL handles not INVALID_HANDLE_VALUE).
+ if (h_stdin != 0) {
+ SetStdHandle(STD_INPUT_HANDLE, h_stdin);
+ }
+ if (h_stdout != 0) {
+ SetStdHandle(STD_OUTPUT_HANDLE, h_stdout);
+ }
+ if (h_stderr != 0) {
+ SetStdHandle(STD_ERROR_HANDLE, h_stderr);
+ }
+
+ // Update file handles.
RedirectStream("CONIN$", "r", stdin, STD_INPUT_HANDLE);
RedirectStream("CONOUT$", "w", stdout, STD_OUTPUT_HANDLE);
RedirectStream("CONOUT$", "w", stderr, STD_ERROR_HANDLE);
@@ -173,10 +190,6 @@ void OS_Windows::initialize() {
add_error_handler(&error_handlers);
#endif
-#ifndef WINDOWS_SUBSYSTEM_CONSOLE
- RedirectIOToConsole();
-#endif
-
FileAccess::make_default<FileAccessWindows>(FileAccess::ACCESS_RESOURCES);
FileAccess::make_default<FileAccessWindows>(FileAccess::ACCESS_USERDATA);
FileAccess::make_default<FileAccessWindows>(FileAccess::ACCESS_FILESYSTEM);
@@ -1521,10 +1534,10 @@ void OS_Windows::unset_environment(const String &p_var) const {
}
String OS_Windows::get_stdin_string() {
- WCHAR buff[1024];
+ char buff[1024];
DWORD count = 0;
- if (ReadConsoleW(GetStdHandle(STD_INPUT_HANDLE), buff, 1024, &count, nullptr)) {
- return String::utf16((const char16_t *)buff, count);
+ if (ReadFile(GetStdHandle(STD_INPUT_HANDLE), buff, 1024, &count, nullptr)) {
+ return String::utf8((const char *)buff, count);
}
return String();
@@ -1908,6 +1921,13 @@ String OS_Windows::get_system_ca_certificates() {
OS_Windows::OS_Windows(HINSTANCE _hInstance) {
hInstance = _hInstance;
+#ifndef WINDOWS_SUBSYSTEM_CONSOLE
+ RedirectIOToConsole();
+#endif
+
+ SetConsoleOutputCP(CP_UTF8);
+ SetConsoleCP(CP_UTF8);
+
CoInitializeEx(nullptr, COINIT_APARTMENTTHREADED);
#ifdef WASAPI_ENABLED
diff --git a/platform/windows/windows_terminal_logger.cpp b/platform/windows/windows_terminal_logger.cpp
index 6881a75596..6fc33afe99 100644
--- a/platform/windows/windows_terminal_logger.cpp
+++ b/platform/windows/windows_terminal_logger.cpp
@@ -53,26 +53,12 @@ void WindowsTerminalLogger::logv(const char *p_format, va_list p_list, bool p_er
}
buf[len] = 0;
- int wlen = MultiByteToWideChar(CP_UTF8, 0, buf, len, nullptr, 0);
- if (wlen < 0) {
- return;
- }
-
- wchar_t *wbuf = (wchar_t *)memalloc((len + 1) * sizeof(wchar_t));
- ERR_FAIL_NULL_MSG(wbuf, "Out of memory.");
- MultiByteToWideChar(CP_UTF8, 0, buf, len, wbuf, wlen);
- wbuf[wlen] = 0;
-
- if (p_err) {
- fwprintf(stderr, L"%ls", wbuf);
- } else {
- wprintf(L"%ls", wbuf);
- }
-
- memfree(wbuf);
+ DWORD written = 0;
+ HANDLE h = p_err ? GetStdHandle(STD_ERROR_HANDLE) : GetStdHandle(STD_OUTPUT_HANDLE);
+ WriteFile(h, &buf[0], len, &written, nullptr);
#ifdef DEBUG_ENABLED
- fflush(stdout);
+ FlushFileBuffers(h);
#endif
}