diff options
Diffstat (limited to 'platform')
-rw-r--r-- | platform/android/README.md | 7 | ||||
-rw-r--r-- | platform/android/SCsub | 8 | ||||
-rw-r--r-- | platform/android/android_input_handler.cpp | 270 | ||||
-rw-r--r-- | platform/android/android_input_handler.h | 24 | ||||
-rw-r--r-- | platform/android/android_keys_utils.cpp | 47 | ||||
-rw-r--r-- | platform/android/android_keys_utils.h | 251 | ||||
-rw-r--r-- | platform/android/detect.py | 56 | ||||
-rw-r--r-- | platform/android/dir_access_jandroid.cpp | 26 | ||||
-rw-r--r-- | platform/android/dir_access_jandroid.h | 4 | ||||
-rw-r--r-- | platform/android/display_server_android.cpp | 14 | ||||
-rw-r--r-- | platform/android/display_server_android.h | 6 | ||||
-rw-r--r-- | platform/android/export/export.cpp | 6 | ||||
-rw-r--r-- | platform/android/export/export_plugin.cpp | 82 | ||||
-rw-r--r-- | platform/android/export/export_plugin.h | 11 | ||||
-rw-r--r-- | platform/android/export/godot_plugin_config.cpp | 2 | ||||
-rw-r--r-- | platform/android/export/gradle_export_util.h | 8 | ||||
-rw-r--r-- | platform/android/file_access_android.h | 36 | ||||
-rw-r--r-- | platform/android/file_access_filesystem_jandroid.cpp | 61 | ||||
-rw-r--r-- | platform/android/file_access_filesystem_jandroid.h | 3 | ||||
-rw-r--r-- | platform/android/java/app/config.gradle | 26 | ||||
-rw-r--r-- | platform/android/java/build.gradle | 4 | ||||
-rw-r--r-- | platform/android/java/editor/build.gradle | 23 | ||||
-rw-r--r-- | platform/android/java/editor/src/main/AndroidManifest.xml | 2 | ||||
-rw-r--r-- | platform/android/java/editor/src/main/java/org/godotengine/editor/GodotEditor.kt | 16 | ||||
-rw-r--r-- | platform/android/java/editor/src/main/java/org/godotengine/editor/GodotGame.kt | 4 | ||||
-rw-r--r-- | platform/android/java/lib/build.gradle | 2 | ||||
-rw-r--r-- | platform/android/java/lib/res/values/strings.xml | 2 | ||||
-rw-r--r-- | platform/android/java/lib/src/org/godotengine/godot/Godot.java | 37 | ||||
-rw-r--r-- | platform/android/java/lib/src/org/godotengine/godot/GodotGLRenderView.java | 23 | ||||
-rw-r--r-- | platform/android/java/lib/src/org/godotengine/godot/GodotIO.java | 7 | ||||
-rw-r--r-- | platform/android/java/lib/src/org/godotengine/godot/GodotLib.java | 41 | ||||
-rw-r--r-- | platform/android/java/lib/src/org/godotengine/godot/GodotVulkanRenderView.java | 23 | ||||
-rw-r--r-- | platform/android/java/lib/src/org/godotengine/godot/input/GodotEditText.java | 49 | ||||
-rw-r--r-- | platform/android/java/lib/src/org/godotengine/godot/input/GodotGestureHandler.java | 87 | ||||
-rw-r--r-- | platform/android/java/lib/src/org/godotengine/godot/input/GodotGestureHandler.kt | 289 | ||||
-rw-r--r-- | platform/android/java/lib/src/org/godotengine/godot/input/GodotInputHandler.java | 298 | ||||
-rw-r--r-- | platform/android/java/lib/src/org/godotengine/godot/input/GodotTextInputWrapper.java | 22 | ||||
-rw-r--r-- | platform/android/java/lib/src/org/godotengine/godot/io/StorageScope.kt | 33 | ||||
-rw-r--r-- | platform/android/java/lib/src/org/godotengine/godot/io/directory/FilesystemDirectoryAccess.kt | 9 | ||||
-rw-r--r-- | platform/android/java/lib/src/org/godotengine/godot/io/file/DataAccess.kt | 7 | ||||
-rw-r--r-- | platform/android/java/lib/src/org/godotengine/godot/io/file/FileAccessHandler.kt | 24 | ||||
-rw-r--r-- | platform/android/java_godot_io_wrapper.cpp | 10 | ||||
-rw-r--r-- | platform/android/java_godot_io_wrapper.h | 6 | ||||
-rw-r--r-- | platform/android/java_godot_lib_jni.cpp | 62 | ||||
-rw-r--r-- | platform/android/java_godot_lib_jni.h | 16 | ||||
-rw-r--r-- | platform/android/java_godot_view_wrapper.h | 6 | ||||
-rw-r--r-- | platform/android/java_godot_wrapper.cpp | 9 | ||||
-rw-r--r-- | platform/android/java_godot_wrapper.h | 2 | ||||
-rw-r--r-- | platform/android/os_android.cpp | 8 | ||||
-rw-r--r-- | platform/ios/README.md | 14 | ||||
-rw-r--r-- | platform/ios/SCsub (renamed from platform/iphone/SCsub) | 18 | ||||
-rw-r--r-- | platform/ios/api/api.cpp (renamed from platform/iphone/api/api.cpp) | 10 | ||||
-rw-r--r-- | platform/ios/api/api.h (renamed from platform/iphone/api/api.h) | 12 | ||||
-rw-r--r-- | platform/ios/app_delegate.h (renamed from platform/iphone/app_delegate.h) | 0 | ||||
-rw-r--r-- | platform/ios/app_delegate.mm (renamed from platform/iphone/app_delegate.mm) | 18 | ||||
-rw-r--r-- | platform/ios/detect.py (renamed from platform/iphone/detect.py) | 63 | ||||
-rw-r--r-- | platform/ios/device_metrics.h (renamed from platform/iphone/device_metrics.h) | 0 | ||||
-rw-r--r-- | platform/ios/device_metrics.m (renamed from platform/iphone/device_metrics.m) | 0 | ||||
-rw-r--r-- | platform/ios/display_layer.h (renamed from platform/iphone/display_layer.h) | 0 | ||||
-rw-r--r-- | platform/ios/display_layer.mm (renamed from platform/iphone/display_layer.mm) | 4 | ||||
-rw-r--r-- | platform/ios/display_server_ios.h (renamed from platform/iphone/display_server_iphone.h) | 28 | ||||
-rw-r--r-- | platform/ios/display_server_ios.mm (renamed from platform/iphone/display_server_iphone.mm) | 237 | ||||
-rw-r--r-- | platform/ios/export/export.cpp (renamed from platform/iphone/export/export.cpp) | 3 | ||||
-rw-r--r-- | platform/ios/export/export.h (renamed from platform/osx/export/export.h) | 8 | ||||
-rw-r--r-- | platform/ios/export/export_plugin.cpp (renamed from platform/iphone/export/export_plugin.cpp) | 249 | ||||
-rw-r--r-- | platform/ios/export/export_plugin.h (renamed from platform/iphone/export/export_plugin.h) | 34 | ||||
-rw-r--r-- | platform/ios/export/godot_plugin_config.cpp (renamed from platform/iphone/export/godot_plugin_config.cpp) | 15 | ||||
-rw-r--r-- | platform/ios/export/godot_plugin_config.h (renamed from platform/iphone/export/godot_plugin_config.h) | 9 | ||||
-rw-r--r-- | platform/ios/godot_app_delegate.h (renamed from platform/iphone/godot_app_delegate.h) | 0 | ||||
-rw-r--r-- | platform/ios/godot_app_delegate.m (renamed from platform/iphone/godot_app_delegate.m) | 0 | ||||
-rw-r--r-- | platform/ios/godot_ios.mm (renamed from platform/iphone/godot_iphone.mm) | 18 | ||||
-rw-r--r-- | platform/ios/godot_view.h (renamed from platform/iphone/godot_view.h) | 0 | ||||
-rw-r--r-- | platform/ios/godot_view.mm (renamed from platform/iphone/godot_view.mm) | 46 | ||||
-rw-r--r-- | platform/ios/godot_view_gesture_recognizer.h (renamed from platform/iphone/godot_view_gesture_recognizer.h) | 0 | ||||
-rw-r--r-- | platform/ios/godot_view_gesture_recognizer.mm (renamed from platform/iphone/godot_view_gesture_recognizer.mm) | 0 | ||||
-rw-r--r-- | platform/ios/godot_view_renderer.h (renamed from platform/iphone/godot_view_renderer.h) | 0 | ||||
-rw-r--r-- | platform/ios/godot_view_renderer.mm (renamed from platform/iphone/godot_view_renderer.mm) | 10 | ||||
-rw-r--r-- | platform/ios/ios.h (renamed from platform/iphone/ios.h) | 2 | ||||
-rw-r--r-- | platform/ios/ios.mm (renamed from platform/iphone/ios.mm) | 0 | ||||
-rw-r--r-- | platform/ios/joypad_ios.h (renamed from platform/iphone/joypad_iphone.h) | 12 | ||||
-rw-r--r-- | platform/ios/joypad_ios.mm (renamed from platform/iphone/joypad_iphone.mm) | 18 | ||||
-rw-r--r-- | platform/ios/keyboard_input_view.h (renamed from platform/iphone/keyboard_input_view.h) | 2 | ||||
-rw-r--r-- | platform/ios/keyboard_input_view.mm (renamed from platform/iphone/keyboard_input_view.mm) | 14 | ||||
-rw-r--r-- | platform/ios/logo.png (renamed from platform/iphone/logo.png) | bin | 1297 -> 1297 bytes | |||
-rw-r--r-- | platform/ios/main.m (renamed from platform/iphone/main.m) | 0 | ||||
-rw-r--r-- | platform/ios/os_ios.h (renamed from platform/iphone/os_iphone.h) | 29 | ||||
-rw-r--r-- | platform/ios/os_ios.mm (renamed from platform/iphone/os_iphone.mm) | 173 | ||||
-rw-r--r-- | platform/ios/platform_config.h (renamed from platform/iphone/platform_config.h) | 2 | ||||
-rw-r--r-- | platform/ios/tts_ios.h (renamed from platform/iphone/tts_ios.h) | 0 | ||||
-rw-r--r-- | platform/ios/tts_ios.mm (renamed from platform/iphone/tts_ios.mm) | 6 | ||||
-rw-r--r-- | platform/ios/view_controller.h (renamed from platform/iphone/view_controller.h) | 0 | ||||
-rw-r--r-- | platform/ios/view_controller.mm (renamed from platform/iphone/view_controller.mm) | 20 | ||||
-rw-r--r-- | platform/ios/vulkan_context_ios.h (renamed from platform/iphone/vulkan_context_iphone.h) | 14 | ||||
-rw-r--r-- | platform/ios/vulkan_context_ios.mm (renamed from platform/iphone/vulkan_context_iphone.mm) | 12 | ||||
-rw-r--r-- | platform/javascript/README.md | 15 | ||||
-rw-r--r-- | platform/linuxbsd/README.md | 14 | ||||
-rw-r--r-- | platform/linuxbsd/SCsub | 17 | ||||
-rw-r--r-- | platform/linuxbsd/crash_handler_linuxbsd.h | 6 | ||||
-rw-r--r-- | platform/linuxbsd/dbus-so_wrap.c | 2641 | ||||
-rw-r--r-- | platform/linuxbsd/dbus-so_wrap.h | 970 | ||||
-rw-r--r-- | platform/linuxbsd/detect.py | 170 | ||||
-rw-r--r-- | platform/linuxbsd/detect_prime_x11.cpp | 5 | ||||
-rw-r--r-- | platform/linuxbsd/detect_prime_x11.h | 3 | ||||
-rw-r--r-- | platform/linuxbsd/display_server_x11.cpp | 319 | ||||
-rw-r--r-- | platform/linuxbsd/display_server_x11.h | 19 | ||||
-rw-r--r-- | platform/linuxbsd/export/export.cpp | 3 | ||||
-rw-r--r-- | platform/linuxbsd/export/export_plugin.cpp | 24 | ||||
-rw-r--r-- | platform/linuxbsd/export/export_plugin.h | 6 | ||||
-rw-r--r-- | platform/linuxbsd/fontconfig-so_wrap.c | 2091 | ||||
-rw-r--r-- | platform/linuxbsd/fontconfig-so_wrap.h | 770 | ||||
-rw-r--r-- | platform/linuxbsd/freedesktop_portal_desktop.cpp | 135 | ||||
-rw-r--r-- | platform/linuxbsd/freedesktop_portal_desktop.h | 59 | ||||
-rw-r--r-- | platform/linuxbsd/freedesktop_screensaver.cpp | 11 | ||||
-rw-r--r-- | platform/linuxbsd/freedesktop_screensaver.h | 8 | ||||
-rw-r--r-- | platform/linuxbsd/gl_manager_x11.cpp | 50 | ||||
-rw-r--r-- | platform/linuxbsd/gl_manager_x11.h | 3 | ||||
-rw-r--r-- | platform/linuxbsd/os_linuxbsd.cpp | 134 | ||||
-rw-r--r-- | platform/linuxbsd/os_linuxbsd.h | 9 | ||||
-rw-r--r-- | platform/linuxbsd/vulkan_context_x11.h | 6 | ||||
-rw-r--r-- | platform/macos/README.md | 19 | ||||
-rw-r--r-- | platform/macos/SCsub | 32 | ||||
-rw-r--r-- | platform/macos/crash_handler_macos.h (renamed from platform/osx/crash_handler_osx.h) | 8 | ||||
-rw-r--r-- | platform/macos/crash_handler_macos.mm (renamed from platform/osx/crash_handler_osx.mm) | 4 | ||||
-rw-r--r-- | platform/macos/detect.py (renamed from platform/osx/detect.py) | 57 | ||||
-rw-r--r-- | platform/macos/dir_access_macos.h (renamed from platform/osx/dir_access_osx.h) | 21 | ||||
-rw-r--r-- | platform/macos/dir_access_macos.mm (renamed from platform/osx/dir_access_osx.mm) | 16 | ||||
-rw-r--r-- | platform/macos/display_server_macos.h (renamed from platform/osx/display_server_osx.h) | 72 | ||||
-rw-r--r-- | platform/macos/display_server_macos.mm (renamed from platform/osx/display_server_osx.mm) | 1019 | ||||
-rw-r--r-- | platform/macos/export/codesign.cpp (renamed from platform/osx/export/codesign.cpp) | 82 | ||||
-rw-r--r-- | platform/macos/export/codesign.h (renamed from platform/osx/export/codesign.h) | 6 | ||||
-rw-r--r-- | platform/macos/export/export.cpp (renamed from platform/osx/export/export.cpp) | 14 | ||||
-rw-r--r-- | platform/macos/export/export.h (renamed from platform/iphone/export/export.h) | 8 | ||||
-rw-r--r-- | platform/macos/export/export_plugin.cpp (renamed from platform/osx/export/export_plugin.cpp) | 901 | ||||
-rw-r--r-- | platform/macos/export/export_plugin.h (renamed from platform/osx/export/export_plugin.h) | 31 | ||||
-rw-r--r-- | platform/macos/export/lipo.cpp (renamed from platform/osx/export/lipo.cpp) | 0 | ||||
-rw-r--r-- | platform/macos/export/lipo.h (renamed from platform/osx/export/lipo.h) | 6 | ||||
-rw-r--r-- | platform/macos/export/macho.cpp (renamed from platform/osx/export/macho.cpp) | 0 | ||||
-rw-r--r-- | platform/macos/export/macho.h (renamed from platform/osx/export/macho.h) | 6 | ||||
-rw-r--r-- | platform/macos/export/plist.cpp (renamed from platform/osx/export/plist.cpp) | 0 | ||||
-rw-r--r-- | platform/macos/export/plist.h (renamed from platform/osx/export/plist.h) | 6 | ||||
-rw-r--r-- | platform/macos/gl_manager_macos_legacy.h (renamed from platform/osx/gl_manager_osx_legacy.h) | 19 | ||||
-rw-r--r-- | platform/macos/gl_manager_macos_legacy.mm (renamed from platform/osx/gl_manager_osx_legacy.mm) | 47 | ||||
-rw-r--r-- | platform/macos/godot_application.h (renamed from platform/osx/godot_application.h) | 0 | ||||
-rw-r--r-- | platform/macos/godot_application.mm (renamed from platform/osx/godot_application.mm) | 4 | ||||
-rw-r--r-- | platform/macos/godot_application_delegate.h (renamed from platform/osx/godot_application_delegate.h) | 0 | ||||
-rw-r--r-- | platform/macos/godot_application_delegate.mm (renamed from platform/osx/godot_application_delegate.mm) | 18 | ||||
-rw-r--r-- | platform/macos/godot_content_view.h (renamed from platform/osx/godot_content_view.h) | 10 | ||||
-rw-r--r-- | platform/macos/godot_content_view.mm (renamed from platform/osx/godot_content_view.mm) | 169 | ||||
-rw-r--r-- | platform/macos/godot_main_macos.mm (renamed from platform/osx/godot_main_osx.mm) | 6 | ||||
-rw-r--r-- | platform/macos/godot_menu_delegate.h | 44 | ||||
-rw-r--r-- | platform/macos/godot_menu_delegate.mm | 76 | ||||
-rw-r--r-- | platform/macos/godot_menu_item.h (renamed from platform/osx/godot_menu_item.h) | 5 | ||||
-rw-r--r-- | platform/macos/godot_menu_item.mm | 34 | ||||
-rw-r--r-- | platform/macos/godot_window.h (renamed from platform/osx/godot_window.h) | 2 | ||||
-rw-r--r-- | platform/macos/godot_window.mm (renamed from platform/osx/godot_window.mm) | 12 | ||||
-rw-r--r-- | platform/macos/godot_window_delegate.h (renamed from platform/osx/godot_window_delegate.h) | 2 | ||||
-rw-r--r-- | platform/macos/godot_window_delegate.mm (renamed from platform/osx/godot_window_delegate.mm) | 70 | ||||
-rw-r--r-- | platform/macos/joypad_macos.cpp (renamed from platform/osx/joypad_osx.cpp) | 32 | ||||
-rw-r--r-- | platform/macos/joypad_macos.h (renamed from platform/osx/joypad_osx.h) | 14 | ||||
-rw-r--r-- | platform/macos/key_mapping_macos.h (renamed from platform/osx/key_mapping_osx.h) | 12 | ||||
-rw-r--r-- | platform/macos/key_mapping_macos.mm (renamed from platform/osx/key_mapping_osx.mm) | 24 | ||||
-rw-r--r-- | platform/macos/logo.png (renamed from platform/osx/logo.png) | bin | 7195 -> 7195 bytes | |||
-rw-r--r-- | platform/macos/macos_terminal_logger.h (renamed from platform/osx/osx_terminal_logger.h) | 15 | ||||
-rw-r--r-- | platform/macos/macos_terminal_logger.mm (renamed from platform/osx/osx_terminal_logger.mm) | 10 | ||||
-rw-r--r-- | platform/macos/os_macos.h (renamed from platform/osx/os_osx.h) | 24 | ||||
-rw-r--r-- | platform/macos/os_macos.mm (renamed from platform/osx/os_osx.mm) | 196 | ||||
-rw-r--r-- | platform/macos/platform_config.h (renamed from platform/osx/platform_config.h) | 0 | ||||
-rw-r--r-- | platform/macos/platform_macos_builders.py (renamed from platform/osx/platform_osx_builders.py) | 2 | ||||
-rw-r--r-- | platform/macos/tts_macos.h (renamed from platform/osx/tts_osx.h) | 10 | ||||
-rw-r--r-- | platform/macos/tts_macos.mm (renamed from platform/osx/tts_osx.mm) | 14 | ||||
-rw-r--r-- | platform/macos/vulkan_context_macos.h (renamed from platform/osx/vulkan_context_osx.h) | 14 | ||||
-rw-r--r-- | platform/macos/vulkan_context_macos.mm (renamed from platform/osx/vulkan_context_osx.mm) | 12 | ||||
-rw-r--r-- | platform/osx/SCsub | 30 | ||||
-rw-r--r-- | platform/register_platform_apis.h | 6 | ||||
-rw-r--r-- | platform/uwp/README.md | 20 | ||||
-rw-r--r-- | platform/uwp/app_uwp.h | 1 | ||||
-rw-r--r-- | platform/uwp/detect.py | 39 | ||||
-rw-r--r-- | platform/uwp/export/app_packager.cpp | 4 | ||||
-rw-r--r-- | platform/uwp/export/app_packager.h | 4 | ||||
-rw-r--r-- | platform/uwp/export/export.cpp | 1 | ||||
-rw-r--r-- | platform/uwp/export/export_plugin.cpp | 91 | ||||
-rw-r--r-- | platform/uwp/export/export_plugin.h | 23 | ||||
-rw-r--r-- | platform/uwp/joypad_uwp.h | 2 | ||||
-rw-r--r-- | platform/uwp/os_uwp.cpp | 45 | ||||
-rw-r--r-- | platform/uwp/os_uwp.h | 8 | ||||
-rw-r--r-- | platform/web/.eslintrc.engine.js (renamed from platform/javascript/.eslintrc.engine.js) | 0 | ||||
-rw-r--r-- | platform/web/.eslintrc.js (renamed from platform/javascript/.eslintrc.js) | 0 | ||||
-rw-r--r-- | platform/web/.eslintrc.libs.js (renamed from platform/javascript/.eslintrc.libs.js) | 0 | ||||
-rw-r--r-- | platform/web/README.md | 22 | ||||
-rw-r--r-- | platform/web/SCsub (renamed from platform/javascript/SCsub) | 48 | ||||
-rw-r--r-- | platform/web/api/api.cpp (renamed from platform/javascript/api/api.cpp) | 64 | ||||
-rw-r--r-- | platform/web/api/api.h (renamed from platform/javascript/api/api.h) | 10 | ||||
-rw-r--r-- | platform/web/api/javascript_bridge_singleton.h (renamed from platform/javascript/api/javascript_singleton.h) | 20 | ||||
-rw-r--r-- | platform/web/api/web_tools_editor_plugin.cpp (renamed from platform/javascript/api/javascript_tools_editor_plugin.cpp) | 30 | ||||
-rw-r--r-- | platform/web/api/web_tools_editor_plugin.h (renamed from platform/javascript/api/javascript_tools_editor_plugin.h) | 18 | ||||
-rw-r--r-- | platform/web/audio_driver_web.cpp (renamed from platform/javascript/audio_driver_javascript.cpp) | 38 | ||||
-rw-r--r-- | platform/web/audio_driver_web.h (renamed from platform/javascript/audio_driver_javascript.h) | 20 | ||||
-rw-r--r-- | platform/web/detect.py (renamed from platform/javascript/detect.py) | 104 | ||||
-rw-r--r-- | platform/web/display_server_web.cpp (renamed from platform/javascript/display_server_javascript.cpp) | 258 | ||||
-rw-r--r-- | platform/web/display_server_web.h (renamed from platform/javascript/display_server_javascript.h) | 22 | ||||
-rw-r--r-- | platform/web/dom_keys.inc (renamed from platform/javascript/dom_keys.inc) | 0 | ||||
-rw-r--r-- | platform/web/emscripten_helpers.py (renamed from platform/javascript/emscripten_helpers.py) | 17 | ||||
-rw-r--r-- | platform/web/export/editor_http_server.h (renamed from platform/javascript/export/export_server.h) | 55 | ||||
-rw-r--r-- | platform/web/export/export.cpp (renamed from platform/javascript/export/export.cpp) | 17 | ||||
-rw-r--r-- | platform/web/export/export.h (renamed from platform/javascript/export/export.h) | 8 | ||||
-rw-r--r-- | platform/web/export/export_plugin.cpp (renamed from platform/javascript/export/export_plugin.cpp) | 135 | ||||
-rw-r--r-- | platform/web/export/export_plugin.h (renamed from platform/javascript/export/export_plugin.h) | 49 | ||||
-rw-r--r-- | platform/web/godot_audio.h (renamed from platform/javascript/godot_audio.h) | 2 | ||||
-rw-r--r-- | platform/web/godot_js.h (renamed from platform/javascript/godot_js.h) | 5 | ||||
-rw-r--r-- | platform/web/godot_webgl2.h (renamed from platform/javascript/godot_webgl2.h) | 2 | ||||
-rw-r--r-- | platform/web/http_client_web.cpp (renamed from platform/javascript/http_client_javascript.cpp) | 70 | ||||
-rw-r--r-- | platform/web/http_client_web.h (renamed from platform/javascript/http_client_javascript.h) | 17 | ||||
-rw-r--r-- | platform/web/javascript_bridge_singleton.cpp (renamed from platform/javascript/javascript_singleton.cpp) | 28 | ||||
-rw-r--r-- | platform/web/js/engine/config.js (renamed from platform/javascript/js/engine/config.js) | 4 | ||||
-rw-r--r-- | platform/web/js/engine/engine.externs.js (renamed from platform/javascript/js/engine/engine.externs.js) | 0 | ||||
-rw-r--r-- | platform/web/js/engine/engine.js (renamed from platform/javascript/js/engine/engine.js) | 2 | ||||
-rw-r--r-- | platform/web/js/engine/preloader.js (renamed from platform/javascript/js/engine/preloader.js) | 0 | ||||
-rw-r--r-- | platform/web/js/jsdoc2rst/publish.js (renamed from platform/javascript/js/jsdoc2rst/publish.js) | 0 | ||||
-rw-r--r-- | platform/web/js/libs/audio.worklet.js (renamed from platform/javascript/js/libs/audio.worklet.js) | 2 | ||||
-rw-r--r-- | platform/web/js/libs/library_godot_audio.js (renamed from platform/javascript/js/libs/library_godot_audio.js) | 9 | ||||
-rw-r--r-- | platform/web/js/libs/library_godot_display.js (renamed from platform/javascript/js/libs/library_godot_display.js) | 77 | ||||
-rw-r--r-- | platform/web/js/libs/library_godot_fetch.js (renamed from platform/javascript/js/libs/library_godot_fetch.js) | 0 | ||||
-rw-r--r-- | platform/web/js/libs/library_godot_input.js (renamed from platform/javascript/js/libs/library_godot_input.js) | 9 | ||||
-rw-r--r-- | platform/web/js/libs/library_godot_javascript_singleton.js (renamed from platform/javascript/js/libs/library_godot_javascript_singleton.js) | 0 | ||||
-rw-r--r-- | platform/web/js/libs/library_godot_os.js (renamed from platform/javascript/js/libs/library_godot_os.js) | 14 | ||||
-rw-r--r-- | platform/web/js/libs/library_godot_runtime.js (renamed from platform/javascript/js/libs/library_godot_runtime.js) | 0 | ||||
-rw-r--r-- | platform/web/logo.png (renamed from platform/javascript/logo.png) | bin | 1234 -> 1234 bytes | |||
-rw-r--r-- | platform/web/os_web.cpp (renamed from platform/javascript/os_javascript.cpp) | 123 | ||||
-rw-r--r-- | platform/web/os_web.h (renamed from platform/javascript/os_javascript.h) | 23 | ||||
-rw-r--r-- | platform/web/package-lock.json (renamed from platform/javascript/package-lock.json) | 0 | ||||
-rw-r--r-- | platform/web/package.json (renamed from platform/javascript/package.json) | 2 | ||||
-rw-r--r-- | platform/web/platform_config.h (renamed from platform/javascript/platform_config.h) | 2 | ||||
-rw-r--r-- | platform/web/run_icon.png (renamed from platform/javascript/run_icon.png) | bin | 290 -> 290 bytes | |||
-rw-r--r-- | platform/web/serve.json (renamed from platform/javascript/serve.json) | 0 | ||||
-rw-r--r-- | platform/web/web_main.cpp (renamed from platform/javascript/javascript_main.cpp) | 42 | ||||
-rw-r--r-- | platform/web/web_runtime.cpp (renamed from platform/javascript/javascript_runtime.cpp) | 6 | ||||
-rw-r--r-- | platform/windows/README.md | 15 | ||||
-rw-r--r-- | platform/windows/crash_handler_windows.cpp | 10 | ||||
-rw-r--r-- | platform/windows/detect.py | 446 | ||||
-rw-r--r-- | platform/windows/display_server_windows.cpp | 299 | ||||
-rw-r--r-- | platform/windows/display_server_windows.h | 33 | ||||
-rw-r--r-- | platform/windows/export/export.cpp | 3 | ||||
-rw-r--r-- | platform/windows/export/export.h | 2 | ||||
-rw-r--r-- | platform/windows/export/export_plugin.cpp | 36 | ||||
-rw-r--r-- | platform/windows/export/export_plugin.h | 9 | ||||
-rw-r--r-- | platform/windows/gl_manager_windows.cpp | 7 | ||||
-rw-r--r-- | platform/windows/godot.natvis | 6 | ||||
-rw-r--r-- | platform/windows/os_windows.cpp | 197 | ||||
-rw-r--r-- | platform/windows/os_windows.h | 29 | ||||
-rw-r--r-- | platform/windows/platform_windows_builders.py | 2 | ||||
-rw-r--r-- | platform/windows/vulkan_context_win.h | 6 | ||||
-rw-r--r-- | platform/windows/windows_terminal_logger.h | 2 |
252 files changed, 12917 insertions, 3695 deletions
diff --git a/platform/android/README.md b/platform/android/README.md index 343e588553..f6aabab708 100644 --- a/platform/android/README.md +++ b/platform/android/README.md @@ -3,6 +3,13 @@ This folder contains the Java and C++ (JNI) code for the Android platform port, using [Gradle](https://gradle.org/) as a build system. +## Documentation + +- [Compiling for Android](https://docs.godotengine.org/en/latest/development/compiling/compiling_for_android.html) + - Instructions on building this platform port from source. +- [Exporting for Android](https://docs.godotengine.org/en/latest/tutorials/export/exporting_for_android.html) + - Instructions on using the compiled export templates to export a project. + ## Artwork license [`logo.png`](logo.png) and [`run_icon.png`](run_icon.png) are licensed under diff --git a/platform/android/SCsub b/platform/android/SCsub index d370a4d18d..344ca036de 100644 --- a/platform/android/SCsub +++ b/platform/android/SCsub @@ -41,13 +41,13 @@ lib = env_android.add_shared_library("#bin/libgodot", [android_objects], SHLIBSU env.Depends(lib, thirdparty_obj) lib_arch_dir = "" -if env["android_arch"] == "armv7": +if env["arch"] == "arm32": lib_arch_dir = "armeabi-v7a" -elif env["android_arch"] == "arm64v8": +elif env["arch"] == "arm64": lib_arch_dir = "arm64-v8a" -elif env["android_arch"] == "x86": +elif env["arch"] == "x86_32": lib_arch_dir = "x86" -elif env["android_arch"] == "x86_64": +elif env["arch"] == "x86_64": lib_arch_dir = "x86_64" else: print("WARN: Architecture not suitable for embedding into APK; keeping .so at \\bin") diff --git a/platform/android/android_input_handler.cpp b/platform/android/android_input_handler.cpp index 81802298d9..454bcd2eda 100644 --- a/platform/android/android_input_handler.cpp +++ b/platform/android/android_input_handler.cpp @@ -56,10 +56,10 @@ void AndroidInputHandler::_set_key_modifier_state(Ref<InputEventWithModifiers> e ev->set_ctrl_pressed(control_mem); } -void AndroidInputHandler::process_key_event(int p_keycode, int p_scancode, int p_unicode_char, bool p_pressed) { +void AndroidInputHandler::process_key_event(int p_keycode, int p_physical_keycode, int p_unicode, bool p_pressed) { static char32_t prev_wc = 0; - char32_t unicode = p_unicode_char; - if ((p_unicode_char & 0xfffffc00) == 0xd800) { + char32_t unicode = p_unicode; + if ((p_unicode & 0xfffffc00) == 0xd800) { if (prev_wc != 0) { ERR_PRINT("invalid utf16 surrogate input"); } @@ -78,39 +78,38 @@ void AndroidInputHandler::process_key_event(int p_keycode, int p_scancode, int p Ref<InputEventKey> ev; ev.instantiate(); - int val = unicode; - Key keycode = android_get_keysym(p_keycode); - Key phy_keycode = android_get_keysym(p_scancode); - if (keycode == Key::SHIFT) { - shift_mem = p_pressed; + Key physical_keycode = godot_code_from_android_code(p_physical_keycode); + Key keycode = physical_keycode; + if (p_keycode != 0) { + keycode = godot_code_from_unicode(p_keycode); } - if (keycode == Key::ALT) { - alt_mem = p_pressed; - } - if (keycode == Key::CTRL) { - control_mem = p_pressed; - } - if (keycode == Key::META) { - meta_mem = p_pressed; + + switch (physical_keycode) { + case Key::SHIFT: { + shift_mem = p_pressed; + } break; + case Key::ALT: { + alt_mem = p_pressed; + } break; + case Key::CTRL: { + control_mem = p_pressed; + } break; + case Key::META: { + meta_mem = p_pressed; + } break; + default: + break; } ev->set_keycode(keycode); - ev->set_physical_keycode(phy_keycode); - ev->set_unicode(val); + ev->set_physical_keycode(physical_keycode); + ev->set_unicode(unicode); ev->set_pressed(p_pressed); _set_key_modifier_state(ev); - if (val == '\n') { - ev->set_keycode(Key::ENTER); - } else if (val == 61448) { - ev->set_keycode(Key::BACKSPACE); - ev->set_unicode((char32_t)Key::BACKSPACE); - } else if (val == 61453) { - ev->set_keycode(Key::ENTER); - ev->set_unicode((char32_t)Key::ENTER); - } else if (p_keycode == 4) { + if (p_physical_keycode == AKEYCODE_BACK) { if (DisplayServerAndroid *dsa = Object::cast_to<DisplayServerAndroid>(DisplayServer::get_singleton())) { dsa->send_window_event(DisplayServer::WINDOW_EVENT_GO_BACK_REQUEST, true); } @@ -119,20 +118,31 @@ void AndroidInputHandler::process_key_event(int p_keycode, int p_scancode, int p Input::get_singleton()->parse_input_event(ev); } -void AndroidInputHandler::process_touch(int p_event, int p_pointer, const Vector<AndroidInputHandler::TouchPos> &p_points) { +void AndroidInputHandler::_parse_all_touch(bool p_pressed) { + if (touch.size()) { + //end all if exist + for (int i = 0; i < touch.size(); i++) { + Ref<InputEventScreenTouch> ev; + ev.instantiate(); + ev->set_index(touch[i].id); + ev->set_pressed(p_pressed); + ev->set_position(touch[i].pos); + Input::get_singleton()->parse_input_event(ev); + } + } +} + +void AndroidInputHandler::_release_all_touch() { + _parse_all_touch(false); + touch.clear(); +} + +void AndroidInputHandler::process_touch_event(int p_event, int p_pointer, const Vector<TouchPos> &p_points) { switch (p_event) { case AMOTION_EVENT_ACTION_DOWN: { //gesture begin - if (touch.size()) { - //end all if exist - for (int i = 0; i < touch.size(); i++) { - Ref<InputEventScreenTouch> ev; - ev.instantiate(); - ev->set_index(touch[i].id); - ev->set_pressed(false); - ev->set_position(touch[i].pos); - Input::get_singleton()->parse_input_event(ev); - } - } + // Release any remaining touches or mouse event + _release_mouse_event_info(); + _release_all_touch(); touch.resize(p_points.size()); for (int i = 0; i < p_points.size(); i++) { @@ -141,18 +151,13 @@ void AndroidInputHandler::process_touch(int p_event, int p_pointer, const Vector } //send touch - for (int i = 0; i < touch.size(); i++) { - Ref<InputEventScreenTouch> ev; - ev.instantiate(); - ev->set_index(touch[i].id); - ev->set_pressed(true); - ev->set_position(touch[i].pos); - Input::get_singleton()->parse_input_event(ev); - } + _parse_all_touch(true); } break; case AMOTION_EVENT_ACTION_MOVE: { //motion - ERR_FAIL_COND(touch.size() != p_points.size()); + if (touch.size() != p_points.size()) { + return; + } for (int i = 0; i < touch.size(); i++) { int idx = -1; @@ -181,18 +186,7 @@ void AndroidInputHandler::process_touch(int p_event, int p_pointer, const Vector } break; case AMOTION_EVENT_ACTION_CANCEL: case AMOTION_EVENT_ACTION_UP: { //release - if (touch.size()) { - //end all if exist - for (int i = 0; i < touch.size(); i++) { - Ref<InputEventScreenTouch> ev; - ev.instantiate(); - ev->set_index(touch[i].id); - ev->set_pressed(false); - ev->set_position(touch[i].pos); - Input::get_singleton()->parse_input_event(ev); - } - touch.clear(); - } + _release_all_touch(); } break; case AMOTION_EVENT_ACTION_POINTER_DOWN: { // add touch for (int i = 0; i < p_points.size(); i++) { @@ -230,88 +224,118 @@ void AndroidInputHandler::process_touch(int p_event, int p_pointer, const Vector } } -void AndroidInputHandler::process_hover(int p_type, Point2 p_pos) { - // https://developer.android.com/reference/android/view/MotionEvent.html#ACTION_HOVER_ENTER - switch (p_type) { +void AndroidInputHandler::_parse_mouse_event_info(MouseButton event_buttons_mask, bool p_pressed, bool p_double_click, bool p_source_mouse_relative) { + if (!mouse_event_info.valid) { + return; + } + + Ref<InputEventMouseButton> ev; + ev.instantiate(); + _set_key_modifier_state(ev); + if (p_source_mouse_relative) { + ev->set_position(hover_prev_pos); + ev->set_global_position(hover_prev_pos); + } else { + ev->set_position(mouse_event_info.pos); + ev->set_global_position(mouse_event_info.pos); + hover_prev_pos = mouse_event_info.pos; + } + ev->set_pressed(p_pressed); + MouseButton changed_button_mask = MouseButton(buttons_state ^ event_buttons_mask); + + buttons_state = event_buttons_mask; + + ev->set_button_index(_button_index_from_mask(changed_button_mask)); + ev->set_button_mask(event_buttons_mask); + ev->set_double_click(p_double_click); + Input::get_singleton()->parse_input_event(ev); +} + +void AndroidInputHandler::_release_mouse_event_info(bool p_source_mouse_relative) { + _parse_mouse_event_info(MouseButton::NONE, false, false, p_source_mouse_relative); + mouse_event_info.valid = false; +} + +void AndroidInputHandler::process_mouse_event(int p_event_action, int p_event_android_buttons_mask, Point2 p_event_pos, Vector2 p_delta, bool p_double_click, bool p_source_mouse_relative) { + MouseButton event_buttons_mask = _android_button_mask_to_godot_button_mask(p_event_android_buttons_mask); + switch (p_event_action) { case AMOTION_EVENT_ACTION_HOVER_MOVE: // hover move case AMOTION_EVENT_ACTION_HOVER_ENTER: // hover enter case AMOTION_EVENT_ACTION_HOVER_EXIT: { // hover exit + // https://developer.android.com/reference/android/view/MotionEvent.html#ACTION_HOVER_ENTER Ref<InputEventMouseMotion> ev; ev.instantiate(); _set_key_modifier_state(ev); - ev->set_position(p_pos); - ev->set_global_position(p_pos); - ev->set_relative(p_pos - hover_prev_pos); + ev->set_position(p_event_pos); + ev->set_global_position(p_event_pos); + ev->set_relative(p_event_pos - hover_prev_pos); Input::get_singleton()->parse_input_event(ev); - hover_prev_pos = p_pos; + hover_prev_pos = p_event_pos; } break; - } -} -void AndroidInputHandler::process_mouse_event(int input_device, int event_action, int event_android_buttons_mask, Point2 event_pos, float event_vertical_factor, float event_horizontal_factor) { - MouseButton event_buttons_mask = _android_button_mask_to_godot_button_mask(event_android_buttons_mask); - switch (event_action) { - case AMOTION_EVENT_ACTION_BUTTON_PRESS: - case AMOTION_EVENT_ACTION_BUTTON_RELEASE: { - Ref<InputEventMouseButton> ev; - ev.instantiate(); - _set_key_modifier_state(ev); - if ((input_device & AINPUT_SOURCE_MOUSE) == AINPUT_SOURCE_MOUSE) { - ev->set_position(event_pos); - ev->set_global_position(event_pos); - } else { - ev->set_position(hover_prev_pos); - ev->set_global_position(hover_prev_pos); - } - ev->set_pressed(event_action == AMOTION_EVENT_ACTION_BUTTON_PRESS); - MouseButton changed_button_mask = MouseButton(buttons_state ^ event_buttons_mask); + case AMOTION_EVENT_ACTION_DOWN: + case AMOTION_EVENT_ACTION_BUTTON_PRESS: { + // Release any remaining touches or mouse event + _release_mouse_event_info(); + _release_all_touch(); - buttons_state = event_buttons_mask; + mouse_event_info.valid = true; + mouse_event_info.pos = p_event_pos; + _parse_mouse_event_info(event_buttons_mask, true, p_double_click, p_source_mouse_relative); + } break; - ev->set_button_index(_button_index_from_mask(changed_button_mask)); - ev->set_button_mask(event_buttons_mask); - Input::get_singleton()->parse_input_event(ev); + case AMOTION_EVENT_ACTION_UP: + case AMOTION_EVENT_ACTION_CANCEL: + case AMOTION_EVENT_ACTION_BUTTON_RELEASE: { + _release_mouse_event_info(p_source_mouse_relative); } break; case AMOTION_EVENT_ACTION_MOVE: { + if (!mouse_event_info.valid) { + return; + } + Ref<InputEventMouseMotion> ev; ev.instantiate(); _set_key_modifier_state(ev); - if ((input_device & AINPUT_SOURCE_MOUSE) == AINPUT_SOURCE_MOUSE) { - ev->set_position(event_pos); - ev->set_global_position(event_pos); - ev->set_relative(event_pos - hover_prev_pos); - hover_prev_pos = event_pos; - } else { + if (p_source_mouse_relative) { ev->set_position(hover_prev_pos); ev->set_global_position(hover_prev_pos); - ev->set_relative(event_pos); + ev->set_relative(p_event_pos); + } else { + ev->set_position(p_event_pos); + ev->set_global_position(p_event_pos); + ev->set_relative(p_event_pos - hover_prev_pos); + mouse_event_info.pos = p_event_pos; + hover_prev_pos = p_event_pos; } ev->set_button_mask(event_buttons_mask); Input::get_singleton()->parse_input_event(ev); } break; + case AMOTION_EVENT_ACTION_SCROLL: { Ref<InputEventMouseButton> ev; ev.instantiate(); - if ((input_device & AINPUT_SOURCE_MOUSE) == AINPUT_SOURCE_MOUSE) { - ev->set_position(event_pos); - ev->set_global_position(event_pos); - } else { + _set_key_modifier_state(ev); + if (p_source_mouse_relative) { ev->set_position(hover_prev_pos); ev->set_global_position(hover_prev_pos); + } else { + ev->set_position(p_event_pos); + ev->set_global_position(p_event_pos); } ev->set_pressed(true); buttons_state = event_buttons_mask; - if (event_vertical_factor > 0) { - _wheel_button_click(event_buttons_mask, ev, MouseButton::WHEEL_UP, event_vertical_factor); - } else if (event_vertical_factor < 0) { - _wheel_button_click(event_buttons_mask, ev, MouseButton::WHEEL_DOWN, -event_vertical_factor); + if (p_delta.y > 0) { + _wheel_button_click(event_buttons_mask, ev, MouseButton::WHEEL_UP, p_delta.y); + } else if (p_delta.y < 0) { + _wheel_button_click(event_buttons_mask, ev, MouseButton::WHEEL_DOWN, -p_delta.y); } - if (event_horizontal_factor > 0) { - _wheel_button_click(event_buttons_mask, ev, MouseButton::WHEEL_RIGHT, event_horizontal_factor); - } else if (event_horizontal_factor < 0) { - _wheel_button_click(event_buttons_mask, ev, MouseButton::WHEEL_LEFT, -event_horizontal_factor); + if (p_delta.x > 0) { + _wheel_button_click(event_buttons_mask, ev, MouseButton::WHEEL_RIGHT, p_delta.x); + } else if (p_delta.x < 0) { + _wheel_button_click(event_buttons_mask, ev, MouseButton::WHEEL_LEFT, -p_delta.x); } } break; } @@ -330,18 +354,22 @@ void AndroidInputHandler::_wheel_button_click(MouseButton event_buttons_mask, co Input::get_singleton()->parse_input_event(evdd); } -void AndroidInputHandler::process_double_tap(int event_android_button_mask, Point2 p_pos) { - MouseButton event_button_mask = _android_button_mask_to_godot_button_mask(event_android_button_mask); - Ref<InputEventMouseButton> ev; - ev.instantiate(); - _set_key_modifier_state(ev); - ev->set_position(p_pos); - ev->set_global_position(p_pos); - ev->set_pressed(event_button_mask != MouseButton::NONE); - ev->set_button_index(_button_index_from_mask(event_button_mask)); - ev->set_button_mask(event_button_mask); - ev->set_double_click(true); - Input::get_singleton()->parse_input_event(ev); +void AndroidInputHandler::process_magnify(Point2 p_pos, float p_factor) { + Ref<InputEventMagnifyGesture> magnify_event; + magnify_event.instantiate(); + _set_key_modifier_state(magnify_event); + magnify_event->set_position(p_pos); + magnify_event->set_factor(p_factor); + Input::get_singleton()->parse_input_event(magnify_event); +} + +void AndroidInputHandler::process_pan(Point2 p_pos, Vector2 p_delta) { + Ref<InputEventPanGesture> pan_event; + pan_event.instantiate(); + _set_key_modifier_state(pan_event); + pan_event->set_position(p_pos); + pan_event->set_delta(p_delta); + Input::get_singleton()->parse_input_event(pan_event); } MouseButton AndroidInputHandler::_button_index_from_mask(MouseButton button_mask) { diff --git a/platform/android/android_input_handler.h b/platform/android/android_input_handler.h index 1397ca59e4..88490f0407 100644 --- a/platform/android/android_input_handler.h +++ b/platform/android/android_input_handler.h @@ -44,6 +44,11 @@ public: Point2 pos; }; + struct MouseEventInfo { + bool valid = false; + Point2 pos; + }; + enum { JOY_EVENT_BUTTON = 0, JOY_EVENT_AXIS = 1, @@ -68,6 +73,7 @@ private: MouseButton buttons_state = MouseButton::NONE; Vector<TouchPos> touch; + MouseEventInfo mouse_event_info; Point2 hover_prev_pos; // needed to calculate the relative position on hover events void _set_key_modifier_state(Ref<InputEventWithModifiers> ev); @@ -77,13 +83,21 @@ private: void _wheel_button_click(MouseButton event_buttons_mask, const Ref<InputEventMouseButton> &ev, MouseButton wheel_button, float factor); + void _parse_mouse_event_info(MouseButton event_buttons_mask, bool p_pressed, bool p_double_click, bool p_source_mouse_relative); + + void _release_mouse_event_info(bool p_source_mouse_relative = false); + + void _parse_all_touch(bool p_pressed); + + void _release_all_touch(); + public: - void process_touch(int p_event, int p_pointer, const Vector<TouchPos> &p_points); - void process_hover(int p_type, Point2 p_pos); - void process_mouse_event(int input_device, int event_action, int event_android_buttons_mask, Point2 event_pos, float event_vertical_factor = 0, float event_horizontal_factor = 0); - void process_double_tap(int event_android_button_mask, Point2 p_pos); + void process_mouse_event(int p_event_action, int p_event_android_buttons_mask, Point2 p_event_pos, Vector2 p_delta, bool p_double_click, bool p_source_mouse_relative); + void process_touch_event(int p_event, int p_pointer, const Vector<TouchPos> &p_points); + void process_magnify(Point2 p_pos, float p_factor); + void process_pan(Point2 p_pos, Vector2 p_delta); void process_joy_event(JoypadEvent p_event); - void process_key_event(int p_keycode, int p_scancode, int p_unicode_char, bool p_pressed); + void process_key_event(int p_keycode, int p_physical_keycode, int p_unicode, bool p_pressed); }; #endif // ANDROID_INPUT_HANDLER_H diff --git a/platform/android/android_keys_utils.cpp b/platform/android/android_keys_utils.cpp index 885e4ff145..d2c5fdfd6c 100644 --- a/platform/android/android_keys_utils.cpp +++ b/platform/android/android_keys_utils.cpp @@ -30,12 +30,49 @@ #include "android_keys_utils.h" -Key android_get_keysym(unsigned int p_code) { - for (int i = 0; _ak_to_keycode[i].keysym != Key::UNKNOWN; i++) { - if (_ak_to_keycode[i].keycode == p_code) { - return _ak_to_keycode[i].keysym; +Key godot_code_from_android_code(unsigned int p_code) { + for (int i = 0; android_godot_code_pairs[i].android_code != AKEYCODE_MAX; i++) { + if (android_godot_code_pairs[i].android_code == p_code) { + return android_godot_code_pairs[i].godot_code; } } - return Key::UNKNOWN; } + +Key godot_code_from_unicode(unsigned int p_code) { + unsigned int code = p_code; + if (code > 0xFF) { + return Key::UNKNOWN; + } + // Known control codes. + if (code == '\b') { // 0x08 + return Key::BACKSPACE; + } + if (code == '\t') { // 0x09 + return Key::TAB; + } + if (code == '\n') { // 0x0A + return Key::ENTER; + } + if (code == 0x1B) { + return Key::ESCAPE; + } + if (code == 0x1F) { + return Key::KEY_DELETE; + } + // Unknown control codes. + if (code <= 0x1F || (code >= 0x80 && code <= 0x9F)) { + return Key::UNKNOWN; + } + // Convert to uppercase. + if (code >= 'a' && code <= 'z') { // 0x61 - 0x7A + code -= ('a' - 'A'); + } + if (code >= u'à ' && code <= u'ö') { // 0xE0 - 0xF6 + code -= (u'à ' - u'À'); // 0xE0 - 0xC0 + } + if (code >= u'ø' && code <= u'þ') { // 0xF8 - 0xFF + code -= (u'ø' - u'Ø'); // 0xF8 - 0xD8 + } + return Key(code); +} diff --git a/platform/android/android_keys_utils.h b/platform/android/android_keys_utils.h index 24a6589fba..5ec3ee17aa 100644 --- a/platform/android/android_keys_utils.h +++ b/platform/android/android_keys_utils.h @@ -34,129 +34,140 @@ #include <android/input.h> #include <core/os/keyboard.h> -struct _WinTranslatePair { - Key keysym = Key::NONE; - unsigned int keycode = 0; +#define AKEYCODE_MAX 0xFFFF + +struct AndroidGodotCodePair { + unsigned int android_code = 0; + Key godot_code = Key::NONE; }; -static _WinTranslatePair _ak_to_keycode[] = { - { Key::TAB, AKEYCODE_TAB }, - { Key::ENTER, AKEYCODE_ENTER }, - { Key::SHIFT, AKEYCODE_SHIFT_LEFT }, - { Key::SHIFT, AKEYCODE_SHIFT_RIGHT }, - { Key::ALT, AKEYCODE_ALT_LEFT }, - { Key::ALT, AKEYCODE_ALT_RIGHT }, - { Key::MENU, AKEYCODE_MENU }, - { Key::PAUSE, AKEYCODE_MEDIA_PLAY_PAUSE }, - { Key::ESCAPE, AKEYCODE_BACK }, - { Key::SPACE, AKEYCODE_SPACE }, - { Key::PAGEUP, AKEYCODE_PAGE_UP }, - { Key::PAGEDOWN, AKEYCODE_PAGE_DOWN }, - { Key::HOME, AKEYCODE_HOME }, //(0x24) - { Key::LEFT, AKEYCODE_DPAD_LEFT }, - { Key::UP, AKEYCODE_DPAD_UP }, - { Key::RIGHT, AKEYCODE_DPAD_RIGHT }, - { Key::DOWN, AKEYCODE_DPAD_DOWN }, - { Key::PERIODCENTERED, AKEYCODE_DPAD_CENTER }, - { Key::BACKSPACE, AKEYCODE_DEL }, - { Key::KEY_0, AKEYCODE_0 }, - { Key::KEY_1, AKEYCODE_1 }, - { Key::KEY_2, AKEYCODE_2 }, - { Key::KEY_3, AKEYCODE_3 }, - { Key::KEY_4, AKEYCODE_4 }, - { Key::KEY_5, AKEYCODE_5 }, - { Key::KEY_6, AKEYCODE_6 }, - { Key::KEY_7, AKEYCODE_7 }, - { Key::KEY_8, AKEYCODE_8 }, - { Key::KEY_9, AKEYCODE_9 }, - { Key::A, AKEYCODE_A }, - { Key::B, AKEYCODE_B }, - { Key::C, AKEYCODE_C }, - { Key::D, AKEYCODE_D }, - { Key::E, AKEYCODE_E }, - { Key::F, AKEYCODE_F }, - { Key::G, AKEYCODE_G }, - { Key::H, AKEYCODE_H }, - { Key::I, AKEYCODE_I }, - { Key::J, AKEYCODE_J }, - { Key::K, AKEYCODE_K }, - { Key::L, AKEYCODE_L }, - { Key::M, AKEYCODE_M }, - { Key::N, AKEYCODE_N }, - { Key::O, AKEYCODE_O }, - { Key::P, AKEYCODE_P }, - { Key::Q, AKEYCODE_Q }, - { Key::R, AKEYCODE_R }, - { Key::S, AKEYCODE_S }, - { Key::T, AKEYCODE_T }, - { Key::U, AKEYCODE_U }, - { Key::V, AKEYCODE_V }, - { Key::W, AKEYCODE_W }, - { Key::X, AKEYCODE_X }, - { Key::Y, AKEYCODE_Y }, - { Key::Z, AKEYCODE_Z }, - { Key::HOMEPAGE, AKEYCODE_EXPLORER }, - { Key::LAUNCH0, AKEYCODE_BUTTON_A }, - { Key::LAUNCH1, AKEYCODE_BUTTON_B }, - { Key::LAUNCH2, AKEYCODE_BUTTON_C }, - { Key::LAUNCH3, AKEYCODE_BUTTON_X }, - { Key::LAUNCH4, AKEYCODE_BUTTON_Y }, - { Key::LAUNCH5, AKEYCODE_BUTTON_Z }, - { Key::LAUNCH6, AKEYCODE_BUTTON_L1 }, - { Key::LAUNCH7, AKEYCODE_BUTTON_R1 }, - { Key::LAUNCH8, AKEYCODE_BUTTON_L2 }, - { Key::LAUNCH9, AKEYCODE_BUTTON_R2 }, - { Key::LAUNCHA, AKEYCODE_BUTTON_THUMBL }, - { Key::LAUNCHB, AKEYCODE_BUTTON_THUMBR }, - { Key::LAUNCHC, AKEYCODE_BUTTON_START }, - { Key::LAUNCHD, AKEYCODE_BUTTON_SELECT }, - { Key::LAUNCHE, AKEYCODE_BUTTON_MODE }, - { Key::VOLUMEMUTE, AKEYCODE_MUTE }, - { Key::VOLUMEDOWN, AKEYCODE_VOLUME_DOWN }, - { Key::VOLUMEUP, AKEYCODE_VOLUME_UP }, - { Key::BACK, AKEYCODE_MEDIA_REWIND }, - { Key::FORWARD, AKEYCODE_MEDIA_FAST_FORWARD }, - { Key::MEDIANEXT, AKEYCODE_MEDIA_NEXT }, - { Key::MEDIAPREVIOUS, AKEYCODE_MEDIA_PREVIOUS }, - { Key::MEDIASTOP, AKEYCODE_MEDIA_STOP }, - { Key::PLUS, AKEYCODE_PLUS }, - { Key::EQUAL, AKEYCODE_EQUALS }, // the '+' key - { Key::COMMA, AKEYCODE_COMMA }, // the ',' key - { Key::MINUS, AKEYCODE_MINUS }, // the '-' key - { Key::SLASH, AKEYCODE_SLASH }, // the '/?' key - { Key::BACKSLASH, AKEYCODE_BACKSLASH }, - { Key::BRACKETLEFT, AKEYCODE_LEFT_BRACKET }, - { Key::BRACKETRIGHT, AKEYCODE_RIGHT_BRACKET }, - { Key::CTRL, AKEYCODE_CTRL_LEFT }, - { Key::CTRL, AKEYCODE_CTRL_RIGHT }, - { Key::UNKNOWN, 0 } +static AndroidGodotCodePair android_godot_code_pairs[] = { + { AKEYCODE_UNKNOWN, Key::UNKNOWN }, // (0) Unknown key code. + { AKEYCODE_HOME, Key::HOME }, // (3) Home key. + { AKEYCODE_BACK, Key::BACK }, // (4) Back key. + { AKEYCODE_0, Key::KEY_0 }, // (7) '0' key. + { AKEYCODE_1, Key::KEY_1 }, // (8) '1' key. + { AKEYCODE_2, Key::KEY_2 }, // (9) '2' key. + { AKEYCODE_3, Key::KEY_3 }, // (10) '3' key. + { AKEYCODE_4, Key::KEY_4 }, // (11) '4' key. + { AKEYCODE_5, Key::KEY_5 }, // (12) '5' key. + { AKEYCODE_6, Key::KEY_6 }, // (13) '6' key. + { AKEYCODE_7, Key::KEY_7 }, // (14) '7' key. + { AKEYCODE_8, Key::KEY_8 }, // (15) '8' key. + { AKEYCODE_9, Key::KEY_9 }, // (16) '9' key. + { AKEYCODE_STAR, Key::ASTERISK }, // (17) '*' key. + { AKEYCODE_POUND, Key::NUMBERSIGN }, // (18) '#' key. + { AKEYCODE_DPAD_UP, Key::UP }, // (19) Directional Pad Up key. + { AKEYCODE_DPAD_DOWN, Key::DOWN }, // (20) Directional Pad Down key. + { AKEYCODE_DPAD_LEFT, Key::LEFT }, // (21) Directional Pad Left key. + { AKEYCODE_DPAD_RIGHT, Key::RIGHT }, // (22) Directional Pad Right key. + { AKEYCODE_VOLUME_UP, Key::VOLUMEUP }, // (24) Volume Up key. + { AKEYCODE_VOLUME_DOWN, Key::VOLUMEDOWN }, // (25) Volume Down key. + { AKEYCODE_CLEAR, Key::CLEAR }, // (28) Clear key. + { AKEYCODE_A, Key::A }, // (29) 'A' key. + { AKEYCODE_B, Key::B }, // (30) 'B' key. + { AKEYCODE_C, Key::C }, // (31) 'C' key. + { AKEYCODE_D, Key::D }, // (32) 'D' key. + { AKEYCODE_E, Key::E }, // (33) 'E' key. + { AKEYCODE_F, Key::F }, // (34) 'F' key. + { AKEYCODE_G, Key::G }, // (35) 'G' key. + { AKEYCODE_H, Key::H }, // (36) 'H' key. + { AKEYCODE_I, Key::I }, // (37) 'I' key. + { AKEYCODE_J, Key::J }, // (38) 'J' key. + { AKEYCODE_K, Key::K }, // (39) 'K' key. + { AKEYCODE_L, Key::L }, // (40) 'L' key. + { AKEYCODE_M, Key::M }, // (41) 'M' key. + { AKEYCODE_N, Key::N }, // (42) 'N' key. + { AKEYCODE_O, Key::O }, // (43) 'O' key. + { AKEYCODE_P, Key::P }, // (44) 'P' key. + { AKEYCODE_Q, Key::Q }, // (45) 'Q' key. + { AKEYCODE_R, Key::R }, // (46) 'R' key. + { AKEYCODE_S, Key::S }, // (47) 'S' key. + { AKEYCODE_T, Key::T }, // (48) 'T' key. + { AKEYCODE_U, Key::U }, // (49) 'U' key. + { AKEYCODE_V, Key::V }, // (50) 'V' key. + { AKEYCODE_W, Key::W }, // (51) 'W' key. + { AKEYCODE_X, Key::X }, // (52) 'X' key. + { AKEYCODE_Y, Key::Y }, // (53) 'Y' key. + { AKEYCODE_Z, Key::Z }, // (54) 'Z' key. + { AKEYCODE_COMMA, Key::COMMA }, // (55) ',’ key. + { AKEYCODE_PERIOD, Key::PERIOD }, // (56) '.' key. + { AKEYCODE_ALT_LEFT, Key::ALT }, // (57) Left Alt modifier key. + { AKEYCODE_ALT_RIGHT, Key::ALT }, // (58) Right Alt modifier key. + { AKEYCODE_SHIFT_LEFT, Key::SHIFT }, // (59) Left Shift modifier key. + { AKEYCODE_SHIFT_RIGHT, Key::SHIFT }, // (60) Right Shift modifier key. + { AKEYCODE_TAB, Key::TAB }, // (61) Tab key. + { AKEYCODE_SPACE, Key::SPACE }, // (62) Space key. + { AKEYCODE_ENTER, Key::ENTER }, // (66) Enter key. + { AKEYCODE_DEL, Key::BACKSPACE }, // (67) Backspace key. + { AKEYCODE_GRAVE, Key::QUOTELEFT }, // (68) '`' (backtick) key. + { AKEYCODE_MINUS, Key::MINUS }, // (69) '-'. + { AKEYCODE_EQUALS, Key::EQUAL }, // (70) '=' key. + { AKEYCODE_LEFT_BRACKET, Key::BRACKETLEFT }, // (71) '[' key. + { AKEYCODE_RIGHT_BRACKET, Key::BRACKETRIGHT }, // (72) ']' key. + { AKEYCODE_BACKSLASH, Key::BACKSLASH }, // (73) '\' key. + { AKEYCODE_SEMICOLON, Key::SEMICOLON }, // (74) ';' key. + { AKEYCODE_APOSTROPHE, Key::APOSTROPHE }, // (75) ''' (apostrophe) key. + { AKEYCODE_SLASH, Key::SLASH }, // (76) '/' key. + { AKEYCODE_AT, Key::AT }, // (77) '@' key. + { AKEYCODE_PLUS, Key::PLUS }, // (81) '+' key. + { AKEYCODE_MENU, Key::MENU }, // (82) Menu key. + { AKEYCODE_SEARCH, Key::SEARCH }, // (84) Search key. + { AKEYCODE_MEDIA_STOP, Key::MEDIASTOP }, // (86) Stop media key. + { AKEYCODE_MEDIA_PREVIOUS, Key::MEDIAPREVIOUS }, // (88) Play Previous media key. + { AKEYCODE_PAGE_UP, Key::PAGEUP }, // (92) Page Up key. + { AKEYCODE_PAGE_DOWN, Key::PAGEDOWN }, // (93) Page Down key. + { AKEYCODE_ESCAPE, Key::ESCAPE }, // (111) Escape key. + { AKEYCODE_FORWARD_DEL, Key::KEY_DELETE }, // (112) Forward Delete key. + { AKEYCODE_CTRL_LEFT, Key::CTRL }, // (113) Left Control modifier key. + { AKEYCODE_CTRL_RIGHT, Key::CTRL }, // (114) Right Control modifier key. + { AKEYCODE_CAPS_LOCK, Key::CAPSLOCK }, // (115) Caps Lock key. + { AKEYCODE_SCROLL_LOCK, Key::SCROLLLOCK }, // (116) Scroll Lock key. + { AKEYCODE_META_LEFT, Key::META }, // (117) Left Meta modifier key. + { AKEYCODE_META_RIGHT, Key::META }, // (118) Right Meta modifier key. + { AKEYCODE_SYSRQ, Key::PRINT }, // (120) System Request / Print Screen key. + { AKEYCODE_BREAK, Key::PAUSE }, // (121) Break / Pause key. + { AKEYCODE_INSERT, Key::INSERT }, // (124) Insert key. + { AKEYCODE_FORWARD, Key::FORWARD }, // (125) Forward key. + { AKEYCODE_MEDIA_PLAY, Key::MEDIAPLAY }, // (126) Play media key. + { AKEYCODE_MEDIA_RECORD, Key::MEDIARECORD }, // (130) Record media key. + { AKEYCODE_F1, Key::F1 }, // (131) F1 key. + { AKEYCODE_F2, Key::F2 }, // (132) F2 key. + { AKEYCODE_F3, Key::F3 }, // (133) F3 key. + { AKEYCODE_F4, Key::F4 }, // (134) F4 key. + { AKEYCODE_F5, Key::F5 }, // (135) F5 key. + { AKEYCODE_F6, Key::F6 }, // (136) F6 key. + { AKEYCODE_F7, Key::F7 }, // (137) F7 key. + { AKEYCODE_F8, Key::F8 }, // (138) F8 key. + { AKEYCODE_F9, Key::F9 }, // (139) F9 key. + { AKEYCODE_F10, Key::F10 }, // (140) F10 key. + { AKEYCODE_F11, Key::F11 }, // (141) F11 key. + { AKEYCODE_F12, Key::F12 }, // (142) F12 key. + { AKEYCODE_NUM_LOCK, Key::NUMLOCK }, // (143) Num Lock key. + { AKEYCODE_NUMPAD_0, Key::KP_0 }, // (144) Numeric keypad '0' key. + { AKEYCODE_NUMPAD_1, Key::KP_1 }, // (145) Numeric keypad '1' key. + { AKEYCODE_NUMPAD_2, Key::KP_2 }, // (146) Numeric keypad '2' key. + { AKEYCODE_NUMPAD_3, Key::KP_3 }, // (147) Numeric keypad '3' key. + { AKEYCODE_NUMPAD_4, Key::KP_4 }, // (148) Numeric keypad '4' key. + { AKEYCODE_NUMPAD_5, Key::KP_5 }, // (149) Numeric keypad '5' key. + { AKEYCODE_NUMPAD_6, Key::KP_6 }, // (150) Numeric keypad '6' key. + { AKEYCODE_NUMPAD_7, Key::KP_7 }, // (151) Numeric keypad '7' key. + { AKEYCODE_NUMPAD_8, Key::KP_8 }, // (152) Numeric keypad '8' key. + { AKEYCODE_NUMPAD_9, Key::KP_9 }, // (153) Numeric keypad '9' key. + { AKEYCODE_NUMPAD_DIVIDE, Key::KP_DIVIDE }, // (154) Numeric keypad '/' key (for division). + { AKEYCODE_NUMPAD_MULTIPLY, Key::KP_MULTIPLY }, // (155) Numeric keypad '*' key (for multiplication). + { AKEYCODE_NUMPAD_SUBTRACT, Key::KP_SUBTRACT }, // (156) Numeric keypad '-' key (for subtraction). + { AKEYCODE_NUMPAD_ADD, Key::KP_ADD }, // (157) Numeric keypad '+' key (for addition). + { AKEYCODE_NUMPAD_DOT, Key::KP_PERIOD }, // (158) Numeric keypad '.' key (for decimals or digit grouping). + { AKEYCODE_NUMPAD_ENTER, Key::KP_ENTER }, // (160) Numeric keypad Enter key. + { AKEYCODE_VOLUME_MUTE, Key::VOLUMEMUTE }, // (164) Volume Mute key. + { AKEYCODE_YEN, Key::YEN }, // (216) Japanese Yen key. + { AKEYCODE_HELP, Key::HELP }, // (259) Help key. + { AKEYCODE_REFRESH, Key::REFRESH }, // (285) Refresh key. + { AKEYCODE_MAX, Key::UNKNOWN } }; -/* -TODO: map these android key: - AKEYCODE_SOFT_LEFT = 1, - AKEYCODE_SOFT_RIGHT = 2, - AKEYCODE_CALL = 5, - AKEYCODE_ENDCALL = 6, - AKEYCODE_STAR = 17, - AKEYCODE_POUND = 18, - AKEYCODE_POWER = 26, - AKEYCODE_CAMERA = 27, - AKEYCODE_CLEAR = 28, - AKEYCODE_SYM = 63, - AKEYCODE_ENVELOPE = 65, - AKEYCODE_GRAVE = 68, - AKEYCODE_SEMICOLON = 74, - AKEYCODE_APOSTROPHE = 75, - AKEYCODE_AT = 77, - AKEYCODE_NUM = 78, - AKEYCODE_HEADSETHOOK = 79, - AKEYCODE_FOCUS = 80, // *Camera* focus - AKEYCODE_NOTIFICATION = 83, - AKEYCODE_SEARCH = 84, - AKEYCODE_PICTSYMBOLS = 94, - AKEYCODE_SWITCH_CHARSET = 95, -*/ -Key android_get_keysym(unsigned int p_code); +Key godot_code_from_android_code(unsigned int p_code); +Key godot_code_from_unicode(unsigned int p_code); #endif // ANDROID_KEYS_UTILS_H diff --git a/platform/android/detect.py b/platform/android/detect.py index 2ff5bf59ea..1d9bcdd932 100644 --- a/platform/android/detect.py +++ b/platform/android/detect.py @@ -22,7 +22,6 @@ def get_opts(): return [ ("ANDROID_SDK_ROOT", "Path to the Android SDK", get_env_android_sdk_root()), ("ndk_platform", 'Target platform (android-<api>, e.g. "android-24")', "android-24"), - EnumVariable("android_arch", "Target architecture", "arm64v8", ("armv7", "arm64v8", "x86", "x86_64")), ] @@ -46,7 +45,11 @@ def get_ndk_version(): def get_flags(): return [ + ("arch", "arm64"), # Default for convenience. ("tools", False), + # Benefits of LTO for Android (size, performance) haven't been clearly established yet. + # So for now we override the default value which may be set when using `production=yes`. + ("lto", "none"), ] @@ -75,35 +78,37 @@ def install_ndk_if_needed(env): def configure(env): + # Validate arch. + supported_arches = ["x86_32", "x86_64", "arm32", "arm64"] + if env["arch"] not in supported_arches: + print( + 'Unsupported CPU architecture "%s" for Android. Supported architectures are: %s.' + % (env["arch"], ", ".join(supported_arches)) + ) + sys.exit() + install_ndk_if_needed(env) ndk_root = env["ANDROID_NDK_ROOT"] # Architecture - if env["android_arch"] not in ["armv7", "arm64v8", "x86", "x86_64"]: - env["android_arch"] = "arm64v8" - - print("Building for Android, platform " + env["ndk_platform"] + " (" + env["android_arch"] + ")") - - if get_min_sdk_version(env["ndk_platform"]) < 21: - if env["android_arch"] == "x86_64" or env["android_arch"] == "arm64v8": - print( - "WARNING: android_arch=" - + env["android_arch"] - + " is not supported by ndk_platform lower than android-21; setting ndk_platform=android-21" - ) - env["ndk_platform"] = "android-21" + if get_min_sdk_version(env["ndk_platform"]) < 21 and env["arch"] in ["x86_64", "arm64"]: + print( + 'WARNING: arch="%s" is not supported with "ndk_platform" lower than "android-21". Forcing platform 21.' + % env["arch"] + ) + env["ndk_platform"] = "android-21" - if env["android_arch"] == "armv7": + if env["arch"] == "arm32": target_triple = "armv7a-linux-androideabi" env.extra_suffix = ".armv7" + env.extra_suffix - elif env["android_arch"] == "arm64v8": + elif env["arch"] == "arm64": target_triple = "aarch64-linux-android" env.extra_suffix = ".armv8" + env.extra_suffix - elif env["android_arch"] == "x86": + elif env["arch"] == "x86_32": target_triple = "i686-linux-android" env.extra_suffix = ".x86" + env.extra_suffix - elif env["android_arch"] == "x86_64": + elif env["arch"] == "x86_64": target_triple = "x86_64-linux-android" env.extra_suffix = ".x86_64" + env.extra_suffix @@ -130,6 +135,15 @@ def configure(env): env.Append(CPPDEFINES=["_DEBUG"]) env.Append(CPPFLAGS=["-UNDEBUG"]) + # LTO + if env["lto"] != "none": + if env["lto"] == "thin": + env.Append(CCFLAGS=["-flto=thin"]) + env.Append(LINKFLAGS=["-flto=thin"]) + else: + env.Append(CCFLAGS=["-flto"]) + env.Append(LINKFLAGS=["-flto"]) + # Compiler configuration env["SHLIBSUFFIX"] = ".so" @@ -176,14 +190,14 @@ def configure(env): if get_min_sdk_version(env["ndk_platform"]) >= 24: env.Append(CPPDEFINES=[("_FILE_OFFSET_BITS", 64)]) - if env["android_arch"] == "x86": + if env["arch"] == "x86_32": # The NDK adds this if targeting API < 24, so we can drop it when Godot targets it at least env.Append(CCFLAGS=["-mstackrealign"]) - elif env["android_arch"] == "armv7": + elif env["arch"] == "arm32": env.Append(CCFLAGS="-march=armv7-a -mfloat-abi=softfp".split()) env.Append(CPPDEFINES=["__ARM_ARCH_7__", "__ARM_ARCH_7A__"]) env.Append(CPPDEFINES=["__ARM_NEON__"]) - elif env["android_arch"] == "arm64v8": + elif env["arch"] == "arm64": env.Append(CCFLAGS=["-mfix-cortex-a53-835769"]) env.Append(CPPDEFINES=["__ARM_ARCH_8A__"]) diff --git a/platform/android/dir_access_jandroid.cpp b/platform/android/dir_access_jandroid.cpp index eb344d3b43..4f1ac16975 100644 --- a/platform/android/dir_access_jandroid.cpp +++ b/platform/android/dir_access_jandroid.cpp @@ -135,6 +135,30 @@ String DirAccessJAndroid::get_drive(int p_drive) { } } +String DirAccessJAndroid::_get_root_string() const { + if (get_access_type() == ACCESS_FILESYSTEM) { + return "/"; + } + return DirAccessUnix::_get_root_string(); +} + +String DirAccessJAndroid::get_current_dir(bool p_include_drive) const { + String base = _get_root_path(); + String bd = current_dir; + if (!base.is_empty()) { + bd = current_dir.replace_first(base, ""); + } + + String root_string = _get_root_string(); + if (bd.begins_with(root_string)) { + return bd; + } else if (bd.begins_with("/")) { + return root_string + bd.substr(1, bd.length()); + } else { + return root_string + bd; + } +} + Error DirAccessJAndroid::change_dir(String p_dir) { String new_dir = get_absolute_path(p_dir); if (new_dir == current_dir) { @@ -155,7 +179,7 @@ String DirAccessJAndroid::get_absolute_path(String p_path) { } if (p_path.is_relative_path()) { - p_path = get_current_dir().plus_file(p_path); + p_path = get_current_dir().path_join(p_path); } p_path = fix_path(p_path); diff --git a/platform/android/dir_access_jandroid.h b/platform/android/dir_access_jandroid.h index d469c9d317..5c4f1852a9 100644 --- a/platform/android/dir_access_jandroid.h +++ b/platform/android/dir_access_jandroid.h @@ -67,6 +67,7 @@ public: virtual int get_drive_count() override; virtual String get_drive(int p_drive) override; + virtual String get_current_dir(bool p_include_drive = true) const override; ///< return current dir location virtual Error change_dir(String p_dir) override; ///< can be relative or absolute, return false on success @@ -90,6 +91,9 @@ public: DirAccessJAndroid(); ~DirAccessJAndroid(); +protected: + String _get_root_string() const override; + private: int id = 0; diff --git a/platform/android/display_server_android.cpp b/platform/android/display_server_android.cpp index 3be220d110..d3bce12de1 100644 --- a/platform/android/display_server_android.cpp +++ b/platform/android/display_server_android.cpp @@ -83,7 +83,7 @@ bool DisplayServerAndroid::tts_is_paused() const { return TTS_Android::is_paused(); } -Array DisplayServerAndroid::tts_get_voices() const { +TypedArray<Dictionary> DisplayServerAndroid::tts_get_voices() const { return TTS_Android::get_voices(); } @@ -136,7 +136,7 @@ bool DisplayServerAndroid::clipboard_has() const { } } -Array DisplayServerAndroid::get_display_cutouts() const { +TypedArray<Rect2> DisplayServerAndroid::get_display_cutouts() const { GodotIOJavaWrapper *godot_io_java = OS_Android::get_singleton()->get_godot_io_java(); ERR_FAIL_NULL_V(godot_io_java, Array()); return godot_io_java->get_display_cutouts(); @@ -221,12 +221,12 @@ bool DisplayServerAndroid::screen_is_touchscreen(int p_screen) const { return true; } -void DisplayServerAndroid::virtual_keyboard_show(const String &p_existing_text, const Rect2 &p_screen_rect, bool p_multiline, int p_max_length, int p_cursor_start, int p_cursor_end) { +void DisplayServerAndroid::virtual_keyboard_show(const String &p_existing_text, const Rect2 &p_screen_rect, VirtualKeyboardType p_type, int p_max_length, int p_cursor_start, int p_cursor_end) { GodotIOJavaWrapper *godot_io_java = OS_Android::get_singleton()->get_godot_io_java(); ERR_FAIL_NULL(godot_io_java); if (godot_io_java->has_vk()) { - godot_io_java->show_vk(p_existing_text, p_multiline, p_max_length, p_cursor_start, p_cursor_end); + godot_io_java->show_vk(p_existing_text, (int)p_type, p_max_length, p_cursor_start, p_cursor_end); } else { ERR_PRINT("Virtual keyboard not available"); } @@ -276,9 +276,9 @@ void DisplayServerAndroid::_window_callback(const Callable &p_callable, const Va Variant ret; Callable::CallError ce; if (p_deferred) { - p_callable.call((const Variant **)&argp, 1, ret, ce); + p_callable.callp((const Variant **)&argp, 1, ret, ce); } else { - p_callable.call_deferred((const Variant **)&argp, 1); + p_callable.call_deferredp((const Variant **)&argp, 1); } } } @@ -482,7 +482,7 @@ void DisplayServerAndroid::notify_surface_changed(int p_width, int p_height) { Variant ret; Callable::CallError ce; - rect_changed_callback.call(reinterpret_cast<const Variant **>(&sizep), 1, ret, ce); + rect_changed_callback.callp(reinterpret_cast<const Variant **>(&sizep), 1, ret, ce); } DisplayServerAndroid::DisplayServerAndroid(const String &p_rendering_driver, DisplayServer::WindowMode p_mode, DisplayServer::VSyncMode p_vsync_mode, uint32_t p_flags, const Vector2i &p_resolution, Error &r_error) { diff --git a/platform/android/display_server_android.h b/platform/android/display_server_android.h index 65bf2ec1a8..6e14ba3e23 100644 --- a/platform/android/display_server_android.h +++ b/platform/android/display_server_android.h @@ -93,7 +93,7 @@ public: virtual bool tts_is_speaking() const override; virtual bool tts_is_paused() const override; - virtual Array tts_get_voices() const override; + virtual TypedArray<Dictionary> tts_get_voices() const override; virtual void tts_speak(const String &p_text, const String &p_voice, int p_volume = 50, float p_pitch = 1.f, float p_rate = 1.f, int p_utterance_id = 0, bool p_interrupt = false) override; virtual void tts_pause() override; @@ -104,7 +104,7 @@ public: virtual String clipboard_get() const override; virtual bool clipboard_has() const override; - virtual Array get_display_cutouts() const override; + virtual TypedArray<Rect2> get_display_cutouts() const override; virtual Rect2i get_display_safe_area() const override; virtual void screen_set_keep_on(bool p_enable) override; @@ -122,7 +122,7 @@ public: virtual float screen_get_refresh_rate(int p_screen = SCREEN_OF_MAIN_WINDOW) const override; virtual bool screen_is_touchscreen(int p_screen = SCREEN_OF_MAIN_WINDOW) const override; - virtual void virtual_keyboard_show(const String &p_existing_text, const Rect2 &p_screen_rect = Rect2(), bool p_multiline = false, int p_max_length = -1, int p_cursor_start = -1, int p_cursor_end = -1) override; + virtual void virtual_keyboard_show(const String &p_existing_text, const Rect2 &p_screen_rect = Rect2(), VirtualKeyboardType p_type = KEYBOARD_TYPE_DEFAULT, int p_max_length = -1, int p_cursor_start = -1, int p_cursor_end = -1) override; virtual void virtual_keyboard_hide() override; virtual int virtual_keyboard_get_height() const override; diff --git a/platform/android/export/export.cpp b/platform/android/export/export.cpp index 560f188b82..f4c4e985fe 100644 --- a/platform/android/export/export.cpp +++ b/platform/android/export/export.cpp @@ -30,12 +30,13 @@ #include "export.h" -#include "export_plugin.h" - #include "core/os/os.h" #include "editor/editor_settings.h" +#include "editor/export/editor_export.h" +#include "export_plugin.h" void register_android_exporter() { +#ifndef ANDROID_ENABLED EDITOR_DEF("export/android/android_sdk_path", ""); EditorSettings::get_singleton()->add_property_hint(PropertyInfo(Variant::STRING, "export/android/android_sdk_path", PROPERTY_HINT_GLOBAL_DIR)); EDITOR_DEF("export/android/debug_keystore", ""); @@ -47,6 +48,7 @@ void register_android_exporter() { EDITOR_DEF("export/android/shutdown_adb_on_exit", true); EDITOR_DEF("export/android/one_click_deploy_clear_previous_install", false); +#endif Ref<EditorExportPlatformAndroid> exporter = Ref<EditorExportPlatformAndroid>(memnew(EditorExportPlatformAndroid)); EditorExport::get_singleton()->add_export_platform(exporter); diff --git a/platform/android/export/export_plugin.cpp b/platform/android/export/export_plugin.cpp index 2cfb152804..e5656bd00b 100644 --- a/platform/android/export/export_plugin.cpp +++ b/platform/android/export/export_plugin.cpp @@ -248,6 +248,7 @@ static const char *AAB_ASSETS_DIRECTORY = "res://android/build/assetPacks/instal static const int DEFAULT_MIN_SDK_VERSION = 19; // Should match the value in 'platform/android/java/app/config.gradle#minSdk' static const int DEFAULT_TARGET_SDK_VERSION = 32; // Should match the value in 'platform/android/java/app/config.gradle#targetSdk' +#ifndef ANDROID_ENABLED void EditorExportPlatformAndroid::_check_for_changes_poll_thread(void *ud) { EditorExportPlatformAndroid *ea = static_cast<EditorExportPlatformAndroid *>(ud); @@ -277,7 +278,6 @@ void EditorExportPlatformAndroid::_check_for_changes_poll_thread(void *ud) { } } -#ifndef ANDROID_ENABLED // Check for devices updates String adb = get_adb_path(); if (FileAccess::exists(adb)) { @@ -389,7 +389,6 @@ void EditorExportPlatformAndroid::_check_for_changes_poll_thread(void *ud) { ea->devices_changed.set(); } } -#endif uint64_t sleep = 200; uint64_t wait = 3000000; @@ -402,7 +401,6 @@ void EditorExportPlatformAndroid::_check_for_changes_poll_thread(void *ud) { } } -#ifndef ANDROID_ENABLED if (EditorSettings::get_singleton()->get("export/android/shutdown_adb_on_exit")) { String adb = get_adb_path(); if (!FileAccess::exists(adb)) { @@ -413,8 +411,8 @@ void EditorExportPlatformAndroid::_check_for_changes_poll_thread(void *ud) { args.push_back("kill-server"); OS::get_singleton()->execute(adb, args); } -#endif } +#endif String EditorExportPlatformAndroid::get_project_name(const String &p_name) const { String aname; @@ -571,16 +569,15 @@ bool EditorExportPlatformAndroid::_should_compress_asset(const String &p_path, c } zip_fileinfo EditorExportPlatformAndroid::get_zip_fileinfo() { - OS::Time time = OS::get_singleton()->get_time(); - OS::Date date = OS::get_singleton()->get_date(); + OS::DateTime dt = OS::get_singleton()->get_datetime(); zip_fileinfo zipfi; - zipfi.tmz_date.tm_hour = time.hour; - zipfi.tmz_date.tm_mday = date.day; - zipfi.tmz_date.tm_min = time.minute; - zipfi.tmz_date.tm_mon = date.month - 1; // tm_mon is zero indexed - zipfi.tmz_date.tm_sec = time.second; - zipfi.tmz_date.tm_year = date.year; + zipfi.tmz_date.tm_year = dt.year; + zipfi.tmz_date.tm_mon = dt.month - 1; // tm_mon is zero indexed + zipfi.tmz_date.tm_mday = dt.day; + zipfi.tmz_date.tm_hour = dt.hour; + zipfi.tmz_date.tm_min = dt.minute; + zipfi.tmz_date.tm_sec = dt.second; zipfi.dosDate = 0; zipfi.external_fa = 0; zipfi.internal_fa = 0; @@ -626,7 +623,7 @@ Vector<String> EditorExportPlatformAndroid::list_gdap_files(const String &p_path Vector<PluginConfigAndroid> EditorExportPlatformAndroid::get_plugins() { Vector<PluginConfigAndroid> loaded_plugins; - String plugins_dir = ProjectSettings::get_singleton()->get_resource_path().plus_file("android/plugins"); + String plugins_dir = ProjectSettings::get_singleton()->get_resource_path().path_join("android/plugins"); // Add the prebuilt plugins loaded_plugins.append_array(PluginConfigAndroid::get_prebuilt_plugins(plugins_dir)); @@ -637,7 +634,7 @@ Vector<PluginConfigAndroid> EditorExportPlatformAndroid::get_plugins() { if (!plugins_filenames.is_empty()) { Ref<ConfigFile> config_file = memnew(ConfigFile); for (int i = 0; i < plugins_filenames.size(); i++) { - PluginConfigAndroid config = PluginConfigAndroid::load_plugin_config(config_file, plugins_dir.plus_file(plugins_filenames[i])); + PluginConfigAndroid config = PluginConfigAndroid::load_plugin_config(config_file, plugins_dir.path_join(plugins_filenames[i])); if (config.valid_config) { loaded_plugins.push_back(config); } else { @@ -698,7 +695,7 @@ Error EditorExportPlatformAndroid::save_apk_so(void *p_userdata, const SharedObj if (abi_index != -1) { exported = true; String abi = abis[abi_index]; - String dst_path = String("lib").plus_file(abi).plus_file(p_so.path.get_file()); + String dst_path = String("lib").path_join(abi).path_join(p_so.path.get_file()); Vector<uint8_t> array = FileAccess::get_file_as_array(p_so.path); Error store_err = store_in_apk(ed, dst_path, array); ERR_FAIL_COND_V_MSG(store_err, store_err, "Cannot store in apk file '" + dst_path + "'."); @@ -739,7 +736,7 @@ Error EditorExportPlatformAndroid::copy_gradle_so(void *p_userdata, const Shared String type = export_data->debug ? "debug" : "release"; String abi = abis[abi_index]; String filename = p_so.path.get_file(); - String dst_path = base.plus_file(type).plus_file(abi).plus_file(filename); + String dst_path = base.path_join(type).path_join(abi).path_join(filename); Vector<uint8_t> data = FileAccess::get_file_as_array(p_so.path); print_verbose("Copying .so file from " + p_so.path + " to " + dst_path); Error err = store_file_at_path(dst_path, data); @@ -1671,7 +1668,7 @@ Vector<String> EditorExportPlatformAndroid::get_enabled_abis(const Ref<EditorExp return enabled_abis; } -void EditorExportPlatformAndroid::get_preset_features(const Ref<EditorExportPreset> &p_preset, List<String> *r_features) { +void EditorExportPlatformAndroid::get_preset_features(const Ref<EditorExportPreset> &p_preset, List<String> *r_features) const { String driver = ProjectSettings::get_singleton()->get("rendering/driver/driver_name"); if (driver == "opengl3") { r_features->push_back("etc"); @@ -1705,6 +1702,8 @@ void EditorExportPlatformAndroid::get_export_options(List<ExportOption> *r_optio } plugins_changed.clear(); + // Android supports multiple architectures in an app bundle, so + // we expose each option as a checkbox in the export dialog. const Vector<String> abis = get_abis(); for (int i = 0; i < abis.size(); ++i) { const String abi = abis[i]; @@ -1851,7 +1850,7 @@ Error EditorExportPlatformAndroid::run(const Ref<EditorExportPreset> &p_preset, p_debug_flags |= DEBUG_FLAG_REMOTE_DEBUG_LOCALHOST; } - String tmp_export_path = EditorPaths::get_singleton()->get_cache_dir().plus_file("tmpexport." + uitos(OS::get_singleton()->get_unix_time()) + ".apk"); + String tmp_export_path = EditorPaths::get_singleton()->get_cache_dir().path_join("tmpexport." + uitos(OS::get_singleton()->get_unix_time()) + ".apk"); #define CLEANUP_AND_RETURN(m_err) \ { \ @@ -2004,7 +2003,7 @@ String EditorExportPlatformAndroid::get_adb_path() { exe_ext = ".exe"; } String sdk_path = EditorSettings::get_singleton()->get("export/android/android_sdk_path"); - return sdk_path.plus_file("platform-tools/adb" + exe_ext); + return sdk_path.path_join("platform-tools/adb" + exe_ext); } String EditorExportPlatformAndroid::get_apksigner_path() { @@ -2017,7 +2016,7 @@ String EditorExportPlatformAndroid::get_apksigner_path() { String apksigner_path = ""; Error errn; - String build_tools_dir = sdk_path.plus_file("build-tools"); + String build_tools_dir = sdk_path.path_join("build-tools"); Ref<DirAccess> da = DirAccess::open(build_tools_dir, &errn); if (errn != OK) { print_error("Unable to open Android 'build-tools' directory."); @@ -2030,7 +2029,7 @@ String EditorExportPlatformAndroid::get_apksigner_path() { while (!sub_dir.is_empty()) { if (!sub_dir.begins_with(".") && da->current_is_dir()) { // Check if the tool is here. - String tool_path = build_tools_dir.plus_file(sub_dir).plus_file(apksigner_command_name); + String tool_path = build_tools_dir.path_join(sub_dir).path_join(apksigner_command_name); if (FileAccess::exists(tool_path)) { apksigner_path = tool_path; break; @@ -2047,7 +2046,7 @@ String EditorExportPlatformAndroid::get_apksigner_path() { return apksigner_path; } -bool EditorExportPlatformAndroid::can_export(const Ref<EditorExportPreset> &p_preset, String &r_error, bool &r_missing_templates) const { +bool EditorExportPlatformAndroid::has_valid_export_configuration(const Ref<EditorExportPreset> &p_preset, String &r_error, bool &r_missing_templates) const { String err; bool valid = false; const bool custom_build_enabled = p_preset->get("custom_build/use_custom_build"); @@ -2095,7 +2094,7 @@ bool EditorExportPlatformAndroid::can_export(const Ref<EditorExportPreset> &p_pr valid = installed_android_build_template && !r_missing_templates; } - // Validate the rest of the configuration. + // Validate the rest of the export configuration. String dk = p_preset->get("keystore/debug"); String dk_user = p_preset->get("keystore/debug_user"); @@ -2135,7 +2134,7 @@ bool EditorExportPlatformAndroid::can_export(const Ref<EditorExportPreset> &p_pr } else { Error errn; // Check for the platform-tools directory. - Ref<DirAccess> da = DirAccess::open(sdk_path.plus_file("platform-tools"), &errn); + Ref<DirAccess> da = DirAccess::open(sdk_path.path_join("platform-tools"), &errn); if (errn != OK) { err += TTR("Invalid Android SDK path in Editor Settings."); err += TTR("Missing 'platform-tools' directory!"); @@ -2153,7 +2152,7 @@ bool EditorExportPlatformAndroid::can_export(const Ref<EditorExportPreset> &p_pr } // Check for the build-tools directory. - Ref<DirAccess> build_tools_da = DirAccess::open(sdk_path.plus_file("build-tools"), &errn); + Ref<DirAccess> build_tools_da = DirAccess::open(sdk_path.path_join("build-tools"), &errn); if (errn != OK) { err += TTR("Invalid Android SDK path in Editor Settings."); err += TTR("Missing 'build-tools' directory!"); @@ -2171,6 +2170,19 @@ bool EditorExportPlatformAndroid::can_export(const Ref<EditorExportPreset> &p_pr } } + if (!err.is_empty()) { + r_error = err; + } + + return valid; +} + +bool EditorExportPlatformAndroid::has_valid_project_configuration(const Ref<EditorExportPreset> &p_preset, String &r_error) const { + String err; + bool valid = true; + const bool custom_build_enabled = p_preset->get("custom_build/use_custom_build"); + + // Validate the project configuration. bool apk_expansion = p_preset->get("apk_expansion/enable"); if (apk_expansion) { @@ -2297,7 +2309,7 @@ String EditorExportPlatformAndroid::get_apk_expansion_fullpath(const Ref<EditorE int version_code = p_preset->get("version/code"); String package_name = p_preset->get("package/unique_name"); String apk_file_name = "main." + itos(version_code) + "." + get_package_name(package_name) + ".obb"; - String fullpath = p_path.get_base_dir().plus_file(apk_file_name); + String fullpath = p_path.get_base_dir().path_join(apk_file_name); return fullpath; } @@ -2658,8 +2670,8 @@ Error EditorExportPlatformAndroid::export_project_helper(const Ref<EditorExportP build_command = "gradlew"; #endif - String build_path = ProjectSettings::get_singleton()->get_resource_path().plus_file("android/build"); - build_command = build_path.plus_file(build_command); + String build_path = ProjectSettings::get_singleton()->get_resource_path().path_join("android/build"); + build_command = build_path.path_join(build_command); String package_name = get_package_name(p_preset->get("package/unique_name")); String version_code = itos(p_preset->get("version/code")); @@ -2729,7 +2741,7 @@ Error EditorExportPlatformAndroid::export_project_helper(const Ref<EditorExportP debug_user = EditorSettings::get_singleton()->get("export/android/debug_keystore_user"); } if (debug_keystore.is_relative_path()) { - debug_keystore = OS::get_singleton()->get_resource_dir().plus_file(debug_keystore).simplify_path(); + debug_keystore = OS::get_singleton()->get_resource_dir().path_join(debug_keystore).simplify_path(); } if (!FileAccess::exists(debug_keystore)) { add_message(EXPORT_MESSAGE_ERROR, TTR("Code Signing"), TTR("Could not find keystore, unable to export.")); @@ -2745,7 +2757,7 @@ Error EditorExportPlatformAndroid::export_project_helper(const Ref<EditorExportP String release_username = p_preset->get("keystore/release_user"); String release_password = p_preset->get("keystore/release_password"); if (release_keystore.is_relative_path()) { - release_keystore = OS::get_singleton()->get_resource_dir().plus_file(release_keystore).simplify_path(); + release_keystore = OS::get_singleton()->get_resource_dir().path_join(release_keystore).simplify_path(); } if (!FileAccess::exists(release_keystore)) { add_message(EXPORT_MESSAGE_ERROR, TTR("Code Signing"), TTR("Could not find keystore, unable to export.")); @@ -2780,7 +2792,7 @@ Error EditorExportPlatformAndroid::export_project_helper(const Ref<EditorExportP String export_filename = p_path.get_file(); String export_path = p_path.get_base_dir(); if (export_path.is_relative_path()) { - export_path = OS::get_singleton()->get_resource_dir().plus_file(export_path); + export_path = OS::get_singleton()->get_resource_dir().path_join(export_path); } export_path = ProjectSettings::get_singleton()->globalize_path(export_path).simplify_path(); @@ -2839,7 +2851,7 @@ Error EditorExportPlatformAndroid::export_project_helper(const Ref<EditorExportP Ref<FileAccess> io2_fa; zlib_filefunc_def io2 = zipio_create_io(&io2_fa); - String tmp_unaligned_path = EditorPaths::get_singleton()->get_cache_dir().plus_file("tmpexport-unaligned." + uitos(OS::get_singleton()->get_unix_time()) + ".apk"); + String tmp_unaligned_path = EditorPaths::get_singleton()->get_cache_dir().path_join("tmpexport-unaligned." + uitos(OS::get_singleton()->get_unix_time()) + ".apk"); #define CLEANUP_AND_RETURN(m_err) \ { \ @@ -3109,7 +3121,7 @@ Error EditorExportPlatformAndroid::export_project_helper(const Ref<EditorExportP CLEANUP_AND_RETURN(OK); } -void EditorExportPlatformAndroid::get_platform_features(List<String> *r_features) { +void EditorExportPlatformAndroid::get_platform_features(List<String> *r_features) const { r_features->push_back("mobile"); r_features->push_back("android"); } @@ -3123,10 +3135,14 @@ EditorExportPlatformAndroid::EditorExportPlatformAndroid() { devices_changed.set(); plugins_changed.set(); +#ifndef ANDROID_ENABLED check_for_changes_thread.start(_check_for_changes_poll_thread, this); +#endif } EditorExportPlatformAndroid::~EditorExportPlatformAndroid() { +#ifndef ANDROID_ENABLED quit_request.set(); check_for_changes_thread.wait_to_finish(); +#endif } diff --git a/platform/android/export/export_plugin.h b/platform/android/export/export_plugin.h index 15ac8091be..46012bd46c 100644 --- a/platform/android/export/export_plugin.h +++ b/platform/android/export/export_plugin.h @@ -35,7 +35,7 @@ #include "core/io/zip_io.h" #include "core/os/os.h" -#include "editor/editor_export.h" +#include "editor/export/editor_export_platform.h" const String SPLASH_CONFIG_XML_CONTENT = R"SPLASH(<?xml version="1.0" encoding="utf-8"?> <layer-list xmlns:android="http://schemas.android.com/apk/res/android"> @@ -80,10 +80,12 @@ class EditorExportPlatformAndroid : public EditorExportPlatform { Vector<Device> devices; SafeFlag devices_changed; Mutex device_lock; +#ifndef ANDROID_ENABLED Thread check_for_changes_thread; SafeFlag quit_request; static void _check_for_changes_poll_thread(void *ud); +#endif String get_project_name(const String &p_name) const; @@ -156,7 +158,7 @@ public: typedef Error (*EditorExportSaveFunction)(void *p_userdata, const String &p_path, const Vector<uint8_t> &p_data, int p_file, int p_total, const Vector<String> &p_enc_in_filters, const Vector<String> &p_enc_ex_filters, const Vector<uint8_t> &p_key); public: - virtual void get_preset_features(const Ref<EditorExportPreset> &p_preset, List<String> *r_features) override; + virtual void get_preset_features(const Ref<EditorExportPreset> &p_preset, List<String> *r_features) const override; virtual void get_export_options(List<ExportOption> *r_options) override; @@ -186,7 +188,8 @@ public: static String get_apksigner_path(); - virtual bool can_export(const Ref<EditorExportPreset> &p_preset, String &r_error, bool &r_missing_templates) const override; + virtual bool has_valid_export_configuration(const Ref<EditorExportPreset> &p_preset, String &r_error, bool &r_missing_templates) const override; + virtual bool has_valid_project_configuration(const Ref<EditorExportPreset> &p_preset, String &r_error) const override; virtual List<String> get_binary_extensions(const Ref<EditorExportPreset> &p_preset) const override; @@ -231,7 +234,7 @@ public: Error export_project_helper(const Ref<EditorExportPreset> &p_preset, bool p_debug, const String &p_path, int export_format, bool should_sign, int p_flags); - virtual void get_platform_features(List<String> *r_features) override; + virtual void get_platform_features(List<String> *r_features) const override; virtual void resolve_platform_feature_priorities(const Ref<EditorExportPreset> &p_preset, HashSet<String> &p_features) override; diff --git a/platform/android/export/godot_plugin_config.cpp b/platform/android/export/godot_plugin_config.cpp index 3daf6e44cd..21580ae907 100644 --- a/platform/android/export/godot_plugin_config.cpp +++ b/platform/android/export/godot_plugin_config.cpp @@ -50,7 +50,7 @@ String PluginConfigAndroid::resolve_local_dependency_path(String plugin_config_d if (dependency_path.is_absolute_path()) { absolute_path = ProjectSettings::get_singleton()->globalize_path(dependency_path); } else { - absolute_path = plugin_config_dir.plus_file(dependency_path); + absolute_path = plugin_config_dir.path_join(dependency_path); } } diff --git a/platform/android/export/gradle_export_util.h b/platform/android/export/gradle_export_util.h index 7896392d16..232b4458c6 100644 --- a/platform/android/export/gradle_export_util.h +++ b/platform/android/export/gradle_export_util.h @@ -28,14 +28,14 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ -#ifndef GODOT_GRADLE_EXPORT_UTIL_H -#define GODOT_GRADLE_EXPORT_UTIL_H +#ifndef ANDROID_GRADLE_EXPORT_UTIL_H +#define ANDROID_GRADLE_EXPORT_UTIL_H #include "core/io/dir_access.h" #include "core/io/file_access.h" #include "core/io/zip_io.h" #include "core/os/os.h" -#include "editor/editor_export.h" +#include "editor/export/editor_export.h" const String godot_project_name_xml_string = R"(<?xml version="1.0" encoding="utf-8"?> <!--WARNING: THIS FILE WILL BE OVERWRITTEN AT BUILD TIME--> @@ -106,4 +106,4 @@ String _get_activity_tag(const Ref<EditorExportPreset> &p_preset); String _get_application_tag(const Ref<EditorExportPreset> &p_preset, bool p_has_read_write_storage_permission); -#endif // GODOT_GRADLE_EXPORT_UTIL_H +#endif // ANDROID_GRADLE_EXPORT_UTIL_H diff --git a/platform/android/file_access_android.h b/platform/android/file_access_android.h index e6fd8c857b..8d7ade8ead 100644 --- a/platform/android/file_access_android.h +++ b/platform/android/file_access_android.h @@ -49,34 +49,34 @@ class FileAccessAndroid : public FileAccess { public: static AAssetManager *asset_manager; - virtual Error _open(const String &p_path, int p_mode_flags); // open a file - virtual bool is_open() const; // true when file is open + virtual Error _open(const String &p_path, int p_mode_flags) override; // open a file + virtual bool is_open() const override; // true when file is open /// returns the path for the current open file - virtual String get_path() const; + virtual String get_path() const override; /// returns the absolute path for the current open file - virtual String get_path_absolute() const; + virtual String get_path_absolute() const override; - virtual void seek(uint64_t p_position); // seek to a given position - virtual void seek_end(int64_t p_position = 0); // seek from the end of file - virtual uint64_t get_position() const; // get position in the file - virtual uint64_t get_length() const; // get size of the file + virtual void seek(uint64_t p_position) override; // seek to a given position + virtual void seek_end(int64_t p_position = 0) override; // seek from the end of file + virtual uint64_t get_position() const override; // get position in the file + virtual uint64_t get_length() const override; // get size of the file - virtual bool eof_reached() const; // reading passed EOF + virtual bool eof_reached() const override; // reading passed EOF - virtual uint8_t get_8() const; // get a byte - virtual uint64_t get_buffer(uint8_t *p_dst, uint64_t p_length) const; + virtual uint8_t get_8() const override; // get a byte + virtual uint64_t get_buffer(uint8_t *p_dst, uint64_t p_length) const override; - virtual Error get_error() const; // get last error + virtual Error get_error() const override; // get last error - virtual void flush(); - virtual void store_8(uint8_t p_dest); // store a byte + virtual void flush() override; + virtual void store_8(uint8_t p_dest) override; // store a byte - virtual bool file_exists(const String &p_path); // return true if a file exists + virtual bool file_exists(const String &p_path) override; // return true if a file exists - virtual uint64_t _get_modified_time(const String &p_file) { return 0; } - virtual uint32_t _get_unix_permissions(const String &p_file) { return 0; } - virtual Error _set_unix_permissions(const String &p_file, uint32_t p_permissions) { return FAILED; } + virtual uint64_t _get_modified_time(const String &p_file) override { return 0; } + virtual uint32_t _get_unix_permissions(const String &p_file) override { return 0; } + virtual Error _set_unix_permissions(const String &p_file, uint32_t p_permissions) override { return FAILED; } ~FileAccessAndroid(); }; diff --git a/platform/android/file_access_filesystem_jandroid.cpp b/platform/android/file_access_filesystem_jandroid.cpp index c1a48e025e..56561cb616 100644 --- a/platform/android/file_access_filesystem_jandroid.cpp +++ b/platform/android/file_access_filesystem_jandroid.cpp @@ -29,8 +29,11 @@ /*************************************************************************/ #include "file_access_filesystem_jandroid.h" + #include "core/os/os.h" +#include "core/templates/local_vector.h" #include "thread_jandroid.h" + #include <unistd.h> jobject FileAccessFilesystemJAndroid::file_access_handler = nullptr; @@ -43,6 +46,7 @@ jmethodID FileAccessFilesystemJAndroid::_file_seek_end = nullptr; jmethodID FileAccessFilesystemJAndroid::_file_read = nullptr; jmethodID FileAccessFilesystemJAndroid::_file_tell = nullptr; jmethodID FileAccessFilesystemJAndroid::_file_eof = nullptr; +jmethodID FileAccessFilesystemJAndroid::_file_set_eof = nullptr; jmethodID FileAccessFilesystemJAndroid::_file_close = nullptr; jmethodID FileAccessFilesystemJAndroid::_file_write = nullptr; jmethodID FileAccessFilesystemJAndroid::_file_flush = nullptr; @@ -159,6 +163,16 @@ bool FileAccessFilesystemJAndroid::eof_reached() const { } } +void FileAccessFilesystemJAndroid::_set_eof(bool eof) { + if (_file_set_eof) { + ERR_FAIL_COND_MSG(!is_open(), "File must be opened before use."); + + JNIEnv *env = get_jni_env(); + ERR_FAIL_COND(env == nullptr); + env->CallVoidMethod(file_access_handler, _file_set_eof, id, eof); + } +} + uint8_t FileAccessFilesystemJAndroid::get_8() const { ERR_FAIL_COND_V_MSG(!is_open(), 0, "File must be opened before use."); uint8_t byte; @@ -166,6 +180,52 @@ uint8_t FileAccessFilesystemJAndroid::get_8() const { return byte; } +String FileAccessFilesystemJAndroid::get_line() const { + ERR_FAIL_COND_V_MSG(!is_open(), String(), "File must be opened before use."); + + const size_t buffer_size_limit = 2048; + const uint64_t file_size = get_length(); + const uint64_t start_position = get_position(); + + String result; + LocalVector<uint8_t> line_buffer; + size_t current_buffer_size = 0; + uint64_t line_buffer_position = 0; + + while (true) { + size_t line_buffer_size = MIN(buffer_size_limit, file_size - get_position()); + if (line_buffer_size <= 0) { + const_cast<FileAccessFilesystemJAndroid *>(this)->_set_eof(true); + break; + } + + current_buffer_size += line_buffer_size; + line_buffer.resize(current_buffer_size); + + uint64_t bytes_read = get_buffer(&line_buffer[line_buffer_position], current_buffer_size - line_buffer_position); + if (bytes_read <= 0) { + break; + } + + for (; bytes_read > 0; line_buffer_position++, bytes_read--) { + uint8_t elem = line_buffer[line_buffer_position]; + if (elem == '\n' || elem == '\0') { + // Found the end of the line + const_cast<FileAccessFilesystemJAndroid *>(this)->seek(start_position + line_buffer_position + 1); + if (result.parse_utf8((const char *)line_buffer.ptr(), line_buffer_position, true)) { + return String(); + } + return result; + } + } + } + + if (result.parse_utf8((const char *)line_buffer.ptr(), line_buffer_position, true)) { + return String(); + } + return result; +} + uint64_t FileAccessFilesystemJAndroid::get_buffer(uint8_t *p_dst, uint64_t p_length) const { if (_file_read) { ERR_FAIL_COND_V_MSG(!is_open(), 0, "File must be opened before use."); @@ -262,6 +322,7 @@ void FileAccessFilesystemJAndroid::setup(jobject p_file_access_handler) { _file_get_size = env->GetMethodID(cls, "fileGetSize", "(I)J"); _file_tell = env->GetMethodID(cls, "fileGetPosition", "(I)J"); _file_eof = env->GetMethodID(cls, "isFileEof", "(I)Z"); + _file_set_eof = env->GetMethodID(cls, "setFileEof", "(IZ)V"); _file_seek = env->GetMethodID(cls, "fileSeek", "(IJ)V"); _file_seek_end = env->GetMethodID(cls, "fileSeekFromEnd", "(IJ)V"); _file_read = env->GetMethodID(cls, "fileRead", "(ILjava/nio/ByteBuffer;)I"); diff --git a/platform/android/file_access_filesystem_jandroid.h b/platform/android/file_access_filesystem_jandroid.h index 18d5df1628..76d7db6e3a 100644 --- a/platform/android/file_access_filesystem_jandroid.h +++ b/platform/android/file_access_filesystem_jandroid.h @@ -44,6 +44,7 @@ class FileAccessFilesystemJAndroid : public FileAccess { static jmethodID _file_seek_end; static jmethodID _file_tell; static jmethodID _file_eof; + static jmethodID _file_set_eof; static jmethodID _file_read; static jmethodID _file_write; static jmethodID _file_flush; @@ -56,6 +57,7 @@ class FileAccessFilesystemJAndroid : public FileAccess { String path_src; void _close(); ///< close a file + void _set_eof(bool eof); public: virtual Error _open(const String &p_path, int p_mode_flags) override; ///< open a file @@ -74,6 +76,7 @@ public: virtual bool eof_reached() const override; ///< reading passed EOF virtual uint8_t get_8() const override; ///< get a byte + virtual String get_line() const override; ///< get a line virtual uint64_t get_buffer(uint8_t *p_dst, uint64_t p_length) const override; virtual Error get_error() const override; ///< get last error diff --git a/platform/android/java/app/config.gradle b/platform/android/java/app/config.gradle index fbd97fae0b..0346625e4b 100644 --- a/platform/android/java/app/config.gradle +++ b/platform/android/java/app/config.gradle @@ -127,16 +127,36 @@ ext.generateGodotLibraryVersion = { List<String> requiredKeys -> if (requiredKeys.empty) { libraryVersionName = map.values().join(".") try { + if (map.containsKey("status")) { + int statusCode = 0 + String statusValue = map["status"] + if (statusValue == null) { + statusCode = 0 + } else if (statusValue.startsWith("alpha")) { + statusCode = 1 + } else if (statusValue.startsWith("beta")) { + statusCode = 2 + } else if (statusValue.startsWith("rc")) { + statusCode = 3 + } else if (statusValue.startsWith("stable")) { + statusCode = 4 + } else { + statusCode = 0 + } + + libraryVersionCode = statusCode + } + if (map.containsKey("patch")) { - libraryVersionCode = Integer.parseInt(map["patch"]) + libraryVersionCode += Integer.parseInt(map["patch"]) * 10 } if (map.containsKey("minor")) { - libraryVersionCode += (Integer.parseInt(map["minor"]) * 100) + libraryVersionCode += (Integer.parseInt(map["minor"]) * 1000) } if (map.containsKey("major")) { - libraryVersionCode += (Integer.parseInt(map["major"]) * 10000) + libraryVersionCode += (Integer.parseInt(map["major"]) * 100000) } } catch (NumberFormatException ignore) { libraryVersionCode = 1 diff --git a/platform/android/java/build.gradle b/platform/android/java/build.gradle index da30bd3a95..81c7130c03 100644 --- a/platform/android/java/build.gradle +++ b/platform/android/java/build.gradle @@ -28,7 +28,7 @@ allprojects { } ext { - supportedAbis = ["armv7", "arm64v8", "x86", "x86_64"] + supportedAbis = ["arm32", "arm64", "x86_32", "x86_64"] supportedTargetsMap = [release: "release", dev: "debug", debug: "release_debug"] supportedFlavors = ["editor", "template"] @@ -37,7 +37,7 @@ ext { // If building manually on the command line, it's recommended to use the // `./gradlew generateGodotTemplates` build command instead after running the `scons` command(s). // The {selectedAbis} values must be from the {supportedAbis} values. - selectedAbis = ["arm64v8"] + selectedAbis = ["arm64"] } def rootDir = "../../.." diff --git a/platform/android/java/editor/build.gradle b/platform/android/java/editor/build.gradle index 729966ee69..9152492e9d 100644 --- a/platform/android/java/editor/build.gradle +++ b/platform/android/java/editor/build.gradle @@ -12,6 +12,25 @@ dependencies { implementation "androidx.window:window:1.0.0" } +ext { + // Build number added as a suffix to the version code, and incremented for each build/upload to + // the Google Play store. + // This should be reset on each stable release of Godot. + editorBuildNumber = 0 + // Value by which the Godot version code should be offset by to make room for the build number + editorBuildNumberOffset = 100 +} + +def generateVersionCode() { + int libraryVersionCode = getGodotLibraryVersionCode() + return (libraryVersionCode * editorBuildNumberOffset) + editorBuildNumber +} + +def generateVersionName() { + String libraryVersionName = getGodotLibraryVersionName() + return libraryVersionName + ".$editorBuildNumber" +} + android { compileSdkVersion versions.compileSdk buildToolsVersion versions.buildTools @@ -20,8 +39,8 @@ android { defaultConfig { // The 'applicationId' suffix allows to install Godot 3.x(v3) and 4.x(v4) on the same device applicationId "org.godotengine.editor.v4" - versionCode getGodotLibraryVersionCode() - versionName getGodotLibraryVersionName() + versionCode generateVersionCode() + versionName generateVersionName() minSdkVersion versions.minSdk targetSdkVersion versions.targetSdk diff --git a/platform/android/java/editor/src/main/AndroidManifest.xml b/platform/android/java/editor/src/main/AndroidManifest.xml index abf506a83c..6aa5f06f31 100644 --- a/platform/android/java/editor/src/main/AndroidManifest.xml +++ b/platform/android/java/editor/src/main/AndroidManifest.xml @@ -7,7 +7,7 @@ <supports-screens android:largeScreens="true" android:normalScreens="true" - android:smallScreens="true" + android:smallScreens="false" android:xlargeScreens="true" /> <uses-feature diff --git a/platform/android/java/editor/src/main/java/org/godotengine/editor/GodotEditor.kt b/platform/android/java/editor/src/main/java/org/godotengine/editor/GodotEditor.kt index 740f3f48d3..489a81fc1a 100644 --- a/platform/android/java/editor/src/main/java/org/godotengine/editor/GodotEditor.kt +++ b/platform/android/java/editor/src/main/java/org/godotengine/editor/GodotEditor.kt @@ -77,6 +77,12 @@ open class GodotEditor : FullScreenGodotApp() { } super.onCreate(savedInstanceState) + + // Enable long press, panning and scaling gestures + godotFragment?.renderView?.inputHandler?.apply { + enableLongPress(enableLongPressGestures()) + enablePanningAndScalingGestures(enablePanAndScaleGestures()) + } } private fun updateCommandLineParams(args: Array<String>?) { @@ -148,6 +154,16 @@ open class GodotEditor : FullScreenGodotApp() { */ protected open fun overrideOrientationRequest() = true + /** + * Enable long press gestures for the Godot Android editor. + */ + protected open fun enableLongPressGestures() = true + + /** + * Enable pan and scale gestures for the Godot Android editor. + */ + protected open fun enablePanAndScaleGestures() = true + override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) { super.onActivityResult(requestCode, resultCode, data) // Check if we got the MANAGE_EXTERNAL_STORAGE permission diff --git a/platform/android/java/editor/src/main/java/org/godotengine/editor/GodotGame.kt b/platform/android/java/editor/src/main/java/org/godotengine/editor/GodotGame.kt index 783095f93a..b9536a7066 100644 --- a/platform/android/java/editor/src/main/java/org/godotengine/editor/GodotGame.kt +++ b/platform/android/java/editor/src/main/java/org/godotengine/editor/GodotGame.kt @@ -35,4 +35,8 @@ package org.godotengine.editor */ class GodotGame : GodotEditor() { override fun overrideOrientationRequest() = false + + override fun enableLongPressGestures() = false + + override fun enablePanAndScaleGestures() = false } diff --git a/platform/android/java/lib/build.gradle b/platform/android/java/lib/build.gradle index 6b82326a27..318ae1143f 100644 --- a/platform/android/java/lib/build.gradle +++ b/platform/android/java/lib/build.gradle @@ -159,7 +159,7 @@ android { def taskName = getSconsTaskName(flavorName, buildType, selectedAbi) tasks.create(name: taskName, type: Exec) { executable sconsExecutableFile.absolutePath - args "--directory=${pathToRootDir}", "platform=android", "tools=${toolsFlag}", "target=${sconsTarget}", "android_arch=${selectedAbi}", "-j" + Runtime.runtime.availableProcessors() + args "--directory=${pathToRootDir}", "platform=android", "tools=${toolsFlag}", "target=${sconsTarget}", "arch=${selectedAbi}", "-j" + Runtime.runtime.availableProcessors() } // Schedule the tasks so the generated libs are present before the aar file is packaged. diff --git a/platform/android/java/lib/res/values/strings.xml b/platform/android/java/lib/res/values/strings.xml index 010006b81e..f5a4ab1071 100644 --- a/platform/android/java/lib/res/values/strings.xml +++ b/platform/android/java/lib/res/values/strings.xml @@ -12,6 +12,8 @@ <string name="text_button_resume">Resume Download</string> <string name="text_button_cancel">Cancel</string> <string name="text_button_cancel_verify">Cancel Verification</string> + <string name="text_error_title">Error!</string> + <string name="error_engine_setup_message">Unable to setup the Godot Engine! Aborting…</string> <!-- APK Expansion Strings --> diff --git a/platform/android/java/lib/src/org/godotengine/godot/Godot.java b/platform/android/java/lib/src/org/godotengine/godot/Godot.java index 28e689e63a..a75c69484c 100644 --- a/platform/android/java/lib/src/org/godotengine/godot/Godot.java +++ b/platform/android/java/lib/src/org/godotengine/godot/Godot.java @@ -57,6 +57,7 @@ import android.content.SharedPreferences.Editor; import android.content.pm.ConfigurationInfo; import android.content.pm.PackageManager; import android.content.pm.PackageManager.NameNotFoundException; +import android.content.res.Resources; import android.graphics.Point; import android.graphics.Rect; import android.hardware.Sensor; @@ -69,6 +70,7 @@ import android.os.Environment; import android.os.Messenger; import android.os.VibrationEffect; import android.os.Vibrator; +import android.util.Log; import android.view.Display; import android.view.LayoutInflater; import android.view.Surface; @@ -85,6 +87,8 @@ import android.widget.TextView; import androidx.annotation.CallSuper; import androidx.annotation.Keep; import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import androidx.annotation.StringRes; import androidx.fragment.app.Fragment; import com.google.android.vending.expansion.downloader.DownloadProgressInfo; @@ -105,6 +109,8 @@ import java.util.List; import java.util.Locale; public class Godot extends Fragment implements SensorEventListener, IDownloaderClient { + private static final String TAG = Godot.class.getSimpleName(); + private IStub mDownloaderClientStub; private TextView mStatusText; private TextView mProgressFraction; @@ -250,7 +256,7 @@ public class Godot extends Fragment implements SensorEventListener, IDownloaderC * Used by the native code (java_godot_lib_jni.cpp) to complete initialization of the GLSurfaceView view and renderer. */ @Keep - private void onVideoInit() { + private boolean onVideoInit() { final Activity activity = getActivity(); containerLayout = new FrameLayout(activity); containerLayout.setLayoutParams(new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT)); @@ -262,7 +268,11 @@ public class Godot extends Fragment implements SensorEventListener, IDownloaderC // ...add to FrameLayout containerLayout.addView(editText); - GodotLib.setup(command_line); + if (!GodotLib.setup(command_line)) { + Log.e(TAG, "Unable to setup the Godot engine! Aborting..."); + alert(R.string.error_engine_setup_message, R.string.text_error_title, this::forceQuit); + return false; + } final String videoDriver = GodotLib.getGlobal("rendering/driver/driver_name"); if (videoDriver.equals("vulkan")) { @@ -303,6 +313,7 @@ public class Godot extends Fragment implements SensorEventListener, IDownloaderC } } } + return true; } public void setKeepScreenOn(final boolean p_enabled) { @@ -344,13 +355,27 @@ public class Godot extends Fragment implements SensorEventListener, IDownloaderC } public void alert(final String message, final String title) { + alert(message, title, null); + } + + private void alert(@StringRes int messageResId, @StringRes int titleResId, @Nullable Runnable okCallback) { + Resources res = getResources(); + alert(res.getString(messageResId), res.getString(titleResId), okCallback); + } + + private void alert(final String message, final String title, @Nullable Runnable okCallback) { final Activity activity = getActivity(); runOnUiThread(() -> { AlertDialog.Builder builder = new AlertDialog.Builder(activity); builder.setMessage(message).setTitle(title); builder.setPositiveButton( "OK", - (dialog, id) -> dialog.cancel()); + (dialog, id) -> { + if (okCallback != null) { + okCallback.run(); + } + dialog.cancel(); + }); AlertDialog dialog = builder.create(); dialog.show(); }); @@ -471,7 +496,7 @@ public class Godot extends Fragment implements SensorEventListener, IDownloaderC mMagnetometer = mSensorManager.getDefaultSensor(Sensor.TYPE_MAGNETIC_FIELD); mGyroscope = mSensorManager.getDefaultSensor(Sensor.TYPE_GYROSCOPE); - GodotLib.initialize(activity, + godot_initialized = GodotLib.initialize(activity, this, activity.getAssets(), io, @@ -482,8 +507,6 @@ public class Godot extends Fragment implements SensorEventListener, IDownloaderC tts); result_callback = null; - - godot_initialized = true; } @Override @@ -1023,7 +1046,7 @@ public class Godot extends Fragment implements SensorEventListener, IDownloaderC } @Keep - private GodotRenderView getRenderView() { // used by native side to get renderView + public GodotRenderView getRenderView() { // used by native side to get renderView return mRenderView; } diff --git a/platform/android/java/lib/src/org/godotengine/godot/GodotGLRenderView.java b/platform/android/java/lib/src/org/godotengine/godot/GodotGLRenderView.java index 08da1b1832..513021f1d1 100644 --- a/platform/android/java/lib/src/org/godotengine/godot/GodotGLRenderView.java +++ b/platform/android/java/lib/src/org/godotengine/godot/GodotGLRenderView.java @@ -31,7 +31,6 @@ package org.godotengine.godot; import org.godotengine.godot.gl.GLSurfaceView; import org.godotengine.godot.gl.GodotRenderer; -import org.godotengine.godot.input.GodotGestureHandler; import org.godotengine.godot.input.GodotInputHandler; import org.godotengine.godot.utils.GLUtils; import org.godotengine.godot.xr.XRMode; @@ -46,7 +45,6 @@ import android.annotation.SuppressLint; import android.content.Context; import android.graphics.PixelFormat; import android.os.Build; -import android.view.GestureDetector; import android.view.KeyEvent; import android.view.MotionEvent; import android.view.PointerIcon; @@ -75,7 +73,6 @@ import androidx.annotation.Keep; public class GodotGLRenderView extends GLSurfaceView implements GodotRenderView { private final Godot godot; private final GodotInputHandler inputHandler; - private final GestureDetector detector; private final GodotRenderer godotRenderer; private PointerIcon pointerIcon; @@ -85,7 +82,6 @@ public class GodotGLRenderView extends GLSurfaceView implements GodotRenderView this.godot = godot; this.inputHandler = new GodotInputHandler(this); - this.detector = new GestureDetector(context, new GodotGestureHandler(this)); this.godotRenderer = new GodotRenderer(); if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { pointerIcon = PointerIcon.getSystemIcon(getContext(), PointerIcon.TYPE_DEFAULT); @@ -132,7 +128,6 @@ public class GodotGLRenderView extends GLSurfaceView implements GodotRenderView @Override public boolean onTouchEvent(MotionEvent event) { super.onTouchEvent(event); - this.detector.onTouchEvent(event); return inputHandler.onTouchEvent(event); } @@ -156,6 +151,24 @@ public class GodotGLRenderView extends GLSurfaceView implements GodotRenderView return inputHandler.onGenericMotionEvent(event); } + @Override + public void onPointerCaptureChange(boolean hasCapture) { + super.onPointerCaptureChange(hasCapture); + inputHandler.onPointerCaptureChange(hasCapture); + } + + @Override + public void requestPointerCapture() { + super.requestPointerCapture(); + inputHandler.onPointerCaptureChange(true); + } + + @Override + public void releasePointerCapture() { + super.releasePointerCapture(); + inputHandler.onPointerCaptureChange(false); + } + /** * called from JNI to change pointer icon */ diff --git a/platform/android/java/lib/src/org/godotengine/godot/GodotIO.java b/platform/android/java/lib/src/org/godotengine/godot/GodotIO.java index 0434efdf4c..d283de8ce8 100644 --- a/platform/android/java/lib/src/org/godotengine/godot/GodotIO.java +++ b/platform/android/java/lib/src/org/godotengine/godot/GodotIO.java @@ -203,9 +203,10 @@ public class GodotIO { return result; } - public void showKeyboard(String p_existing_text, boolean p_multiline, int p_max_input_length, int p_cursor_start, int p_cursor_end) { - if (edit != null) - edit.showKeyboard(p_existing_text, p_multiline, p_max_input_length, p_cursor_start, p_cursor_end); + public void showKeyboard(String p_existing_text, int p_type, int p_max_input_length, int p_cursor_start, int p_cursor_end) { + if (edit != null) { + edit.showKeyboard(p_existing_text, GodotEditText.VirtualKeyboardType.values()[p_type], p_max_input_length, p_cursor_start, p_cursor_end); + } //InputMethodManager inputMgr = (InputMethodManager)activity.getSystemService(Context.INPUT_METHOD_SERVICE); //inputMgr.toggleSoftInput(InputMethodManager.SHOW_FORCED, 0); diff --git a/platform/android/java/lib/src/org/godotengine/godot/GodotLib.java b/platform/android/java/lib/src/org/godotengine/godot/GodotLib.java index e2ae62d9cf..26aad867b1 100644 --- a/platform/android/java/lib/src/org/godotengine/godot/GodotLib.java +++ b/platform/android/java/lib/src/org/godotengine/godot/GodotLib.java @@ -54,7 +54,7 @@ public class GodotLib { /** * Invoked on the main thread to initialize Godot native layer. */ - public static native void initialize(Activity activity, + public static native boolean initialize(Activity activity, Godot p_instance, AssetManager p_asset_manager, GodotIO godotIO, @@ -74,7 +74,7 @@ public class GodotLib { * Invoked on the GL thread to complete setup for the Godot native layer logic. * @param p_cmdline Command line arguments used to configure Godot native layer components. */ - public static native void setup(String[] p_cmdline); + public static native boolean setup(String[] p_cmdline); /** * Invoked on the GL thread when the underlying Android surface has changed size. @@ -92,7 +92,7 @@ public class GodotLib { public static native void newcontext(Surface p_surface); /** - * Forward {@link Activity#onBackPressed()} event from the main thread to the GL thread. + * Forward {@link Activity#onBackPressed()} event. */ public static native void back(); @@ -108,63 +108,60 @@ public class GodotLib { public static native void ttsCallback(int event, int id, int pos); /** - * Forward touch events from the main thread to the GL thread. + * Forward touch events. */ - public static native void touch(int inputDevice, int event, int pointer, int pointerCount, float[] positions); - public static native void touch(int inputDevice, int event, int pointer, int pointerCount, float[] positions, int buttonsMask); - public static native void touch(int inputDevice, int event, int pointer, int pointerCount, float[] positions, int buttonsMask, float verticalFactor, float horizontalFactor); + public static native void dispatchTouchEvent(int event, int pointer, int pointerCount, float[] positions); /** - * Forward hover events from the main thread to the GL thread. + * Dispatch mouse events */ - public static native void hover(int type, float x, float y); + public static native void dispatchMouseEvent(int event, int buttonMask, float x, float y, float deltaX, float deltaY, boolean doubleClick, boolean sourceMouseRelative); - /** - * Forward double_tap events from the main thread to the GL thread. - */ - public static native void doubleTap(int buttonMask, int x, int y); + public static native void magnify(float x, float y, float factor); + + public static native void pan(float x, float y, float deltaX, float deltaY); /** - * Forward accelerometer sensor events from the main thread to the GL thread. + * Forward accelerometer sensor events. * @see android.hardware.SensorEventListener#onSensorChanged(SensorEvent) */ public static native void accelerometer(float x, float y, float z); /** - * Forward gravity sensor events from the main thread to the GL thread. + * Forward gravity sensor events. * @see android.hardware.SensorEventListener#onSensorChanged(SensorEvent) */ public static native void gravity(float x, float y, float z); /** - * Forward magnetometer sensor events from the main thread to the GL thread. + * Forward magnetometer sensor events. * @see android.hardware.SensorEventListener#onSensorChanged(SensorEvent) */ public static native void magnetometer(float x, float y, float z); /** - * Forward gyroscope sensor events from the main thread to the GL thread. + * Forward gyroscope sensor events. * @see android.hardware.SensorEventListener#onSensorChanged(SensorEvent) */ public static native void gyroscope(float x, float y, float z); /** - * Forward regular key events from the main thread to the GL thread. + * Forward regular key events. */ - public static native void key(int p_keycode, int p_scancode, int p_unicode_char, boolean p_pressed); + public static native void key(int p_keycode, int p_physical_keycode, int p_unicode, boolean p_pressed); /** - * Forward game device's key events from the main thread to the GL thread. + * Forward game device's key events. */ public static native void joybutton(int p_device, int p_but, boolean p_pressed); /** - * Forward joystick devices axis motion events from the main thread to the GL thread. + * Forward joystick devices axis motion events. */ public static native void joyaxis(int p_device, int p_axis, float p_value); /** - * Forward joystick devices hat motion events from the main thread to the GL thread. + * Forward joystick devices hat motion events. */ public static native void joyhat(int p_device, int p_hat_x, int p_hat_y); diff --git a/platform/android/java/lib/src/org/godotengine/godot/GodotVulkanRenderView.java b/platform/android/java/lib/src/org/godotengine/godot/GodotVulkanRenderView.java index c386a2d2eb..fa6c3280b9 100644 --- a/platform/android/java/lib/src/org/godotengine/godot/GodotVulkanRenderView.java +++ b/platform/android/java/lib/src/org/godotengine/godot/GodotVulkanRenderView.java @@ -30,7 +30,6 @@ package org.godotengine.godot; -import org.godotengine.godot.input.GodotGestureHandler; import org.godotengine.godot.input.GodotInputHandler; import org.godotengine.godot.vulkan.VkRenderer; import org.godotengine.godot.vulkan.VkSurfaceView; @@ -38,7 +37,6 @@ import org.godotengine.godot.vulkan.VkSurfaceView; import android.annotation.SuppressLint; import android.content.Context; import android.os.Build; -import android.view.GestureDetector; import android.view.KeyEvent; import android.view.MotionEvent; import android.view.PointerIcon; @@ -49,7 +47,6 @@ import androidx.annotation.Keep; public class GodotVulkanRenderView extends VkSurfaceView implements GodotRenderView { private final Godot godot; private final GodotInputHandler mInputHandler; - private final GestureDetector mGestureDetector; private final VkRenderer mRenderer; private PointerIcon pointerIcon; @@ -58,7 +55,6 @@ public class GodotVulkanRenderView extends VkSurfaceView implements GodotRenderV this.godot = godot; mInputHandler = new GodotInputHandler(this); - mGestureDetector = new GestureDetector(context, new GodotGestureHandler(this)); mRenderer = new VkRenderer(); if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { pointerIcon = PointerIcon.getSystemIcon(getContext(), PointerIcon.TYPE_DEFAULT); @@ -106,7 +102,6 @@ public class GodotVulkanRenderView extends VkSurfaceView implements GodotRenderV @Override public boolean onTouchEvent(MotionEvent event) { super.onTouchEvent(event); - mGestureDetector.onTouchEvent(event); return mInputHandler.onTouchEvent(event); } @@ -130,6 +125,24 @@ public class GodotVulkanRenderView extends VkSurfaceView implements GodotRenderV return mInputHandler.onGenericMotionEvent(event); } + @Override + public void requestPointerCapture() { + super.requestPointerCapture(); + mInputHandler.onPointerCaptureChange(true); + } + + @Override + public void releasePointerCapture() { + super.releasePointerCapture(); + mInputHandler.onPointerCaptureChange(false); + } + + @Override + public void onPointerCaptureChange(boolean hasCapture) { + super.onPointerCaptureChange(hasCapture); + mInputHandler.onPointerCaptureChange(hasCapture); + } + /** * called from JNI to change pointer icon */ diff --git a/platform/android/java/lib/src/org/godotengine/godot/input/GodotEditText.java b/platform/android/java/lib/src/org/godotengine/godot/input/GodotEditText.java index ecb2af0a7b..7925b54fc4 100644 --- a/platform/android/java/lib/src/org/godotengine/godot/input/GodotEditText.java +++ b/platform/android/java/lib/src/org/godotengine/godot/input/GodotEditText.java @@ -52,6 +52,18 @@ public class GodotEditText extends EditText { private final static int HANDLER_OPEN_IME_KEYBOARD = 2; private final static int HANDLER_CLOSE_IME_KEYBOARD = 3; + // Enum must be kept up-to-date with DisplayServer::VirtualKeyboardType + public enum VirtualKeyboardType { + KEYBOARD_TYPE_DEFAULT, + KEYBOARD_TYPE_MULTILINE, + KEYBOARD_TYPE_NUMBER, + KEYBOARD_TYPE_NUMBER_DECIMAL, + KEYBOARD_TYPE_PHONE, + KEYBOARD_TYPE_EMAIL_ADDRESS, + KEYBOARD_TYPE_PASSWORD, + KEYBOARD_TYPE_URL + } + // =========================================================== // Fields // =========================================================== @@ -60,7 +72,7 @@ public class GodotEditText extends EditText { private EditHandler sHandler = new EditHandler(this); private String mOriginText; private int mMaxInputLength = Integer.MAX_VALUE; - private boolean mMultiline = false; + private VirtualKeyboardType mKeyboardType = VirtualKeyboardType.KEYBOARD_TYPE_DEFAULT; private static class EditHandler extends Handler { private final WeakReference<GodotEditText> mEdit; @@ -100,8 +112,8 @@ public class GodotEditText extends EditText { setImeOptions(EditorInfo.IME_FLAG_NO_EXTRACT_UI | EditorInfo.IME_ACTION_DONE); } - public boolean isMultiline() { - return mMultiline; + public VirtualKeyboardType getKeyboardType() { + return mKeyboardType; } private void handleMessage(final Message msg) { @@ -122,8 +134,31 @@ public class GodotEditText extends EditText { } int inputType = InputType.TYPE_CLASS_TEXT; - if (edit.isMultiline()) { - inputType |= InputType.TYPE_TEXT_FLAG_MULTI_LINE; + switch (edit.getKeyboardType()) { + case KEYBOARD_TYPE_DEFAULT: + inputType = InputType.TYPE_CLASS_TEXT; + break; + case KEYBOARD_TYPE_MULTILINE: + inputType = InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_FLAG_MULTI_LINE; + break; + case KEYBOARD_TYPE_NUMBER: + inputType = InputType.TYPE_CLASS_NUMBER; + break; + case KEYBOARD_TYPE_NUMBER_DECIMAL: + inputType = InputType.TYPE_CLASS_NUMBER | InputType.TYPE_NUMBER_FLAG_SIGNED; + break; + case KEYBOARD_TYPE_PHONE: + inputType = InputType.TYPE_CLASS_PHONE; + break; + case KEYBOARD_TYPE_EMAIL_ADDRESS: + inputType = InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_VARIATION_EMAIL_ADDRESS; + break; + case KEYBOARD_TYPE_PASSWORD: + inputType = InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_VARIATION_PASSWORD; + break; + case KEYBOARD_TYPE_URL: + inputType = InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_VARIATION_URI; + break; } edit.setInputType(inputType); @@ -201,7 +236,7 @@ public class GodotEditText extends EditText { // =========================================================== // Methods // =========================================================== - public void showKeyboard(String p_existing_text, boolean p_multiline, int p_max_input_length, int p_cursor_start, int p_cursor_end) { + public void showKeyboard(String p_existing_text, VirtualKeyboardType p_type, int p_max_input_length, int p_cursor_start, int p_cursor_end) { int maxInputLength = (p_max_input_length <= 0) ? Integer.MAX_VALUE : p_max_input_length; if (p_cursor_start == -1) { // cursor position not given this.mOriginText = p_existing_text; @@ -214,7 +249,7 @@ public class GodotEditText extends EditText { this.mMaxInputLength = maxInputLength - (p_existing_text.length() - p_cursor_end); } - this.mMultiline = p_multiline; + this.mKeyboardType = p_type; final Message msg = new Message(); msg.what = HANDLER_OPEN_IME_KEYBOARD; diff --git a/platform/android/java/lib/src/org/godotengine/godot/input/GodotGestureHandler.java b/platform/android/java/lib/src/org/godotengine/godot/input/GodotGestureHandler.java deleted file mode 100644 index 778efa914a..0000000000 --- a/platform/android/java/lib/src/org/godotengine/godot/input/GodotGestureHandler.java +++ /dev/null @@ -1,87 +0,0 @@ -/*************************************************************************/ -/* GodotGestureHandler.java */ -/*************************************************************************/ -/* This file is part of: */ -/* GODOT ENGINE */ -/* https://godotengine.org */ -/*************************************************************************/ -/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */ -/* */ -/* Permission is hereby granted, free of charge, to any person obtaining */ -/* a copy of this software and associated documentation files (the */ -/* "Software"), to deal in the Software without restriction, including */ -/* without limitation the rights to use, copy, modify, merge, publish, */ -/* distribute, sublicense, and/or sell copies of the Software, and to */ -/* permit persons to whom the Software is furnished to do so, subject to */ -/* the following conditions: */ -/* */ -/* The above copyright notice and this permission notice shall be */ -/* included in all copies or substantial portions of the Software. */ -/* */ -/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ -/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ -/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ -/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ -/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ -/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ -/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -/*************************************************************************/ - -package org.godotengine.godot.input; - -import org.godotengine.godot.GodotLib; -import org.godotengine.godot.GodotRenderView; - -import android.view.GestureDetector; -import android.view.MotionEvent; - -/** - * Handles gesture input related events for the {@link GodotRenderView} view. - * https://developer.android.com/reference/android/view/GestureDetector.SimpleOnGestureListener - */ -public class GodotGestureHandler extends GestureDetector.SimpleOnGestureListener { - private final GodotRenderView mRenderView; - - public GodotGestureHandler(GodotRenderView godotView) { - mRenderView = godotView; - } - - private void queueEvent(Runnable task) { - mRenderView.queueOnRenderThread(task); - } - - @Override - public boolean onDown(MotionEvent event) { - super.onDown(event); - //Log.i("GodotGesture", "onDown"); - return true; - } - - @Override - public boolean onSingleTapConfirmed(MotionEvent event) { - super.onSingleTapConfirmed(event); - return true; - } - - @Override - public void onLongPress(MotionEvent event) { - //Log.i("GodotGesture", "onLongPress"); - } - - @Override - public boolean onDoubleTap(MotionEvent event) { - //Log.i("GodotGesture", "onDoubleTap"); - final int x = Math.round(event.getX()); - final int y = Math.round(event.getY()); - final int buttonMask = event.getButtonState(); - GodotLib.doubleTap(buttonMask, x, y); - return true; - } - - @Override - public boolean onFling(MotionEvent event1, MotionEvent event2, float velocityX, float velocityY) { - //Log.i("GodotGesture", "onFling"); - return true; - } -} diff --git a/platform/android/java/lib/src/org/godotengine/godot/input/GodotGestureHandler.kt b/platform/android/java/lib/src/org/godotengine/godot/input/GodotGestureHandler.kt new file mode 100644 index 0000000000..9715c31fc1 --- /dev/null +++ b/platform/android/java/lib/src/org/godotengine/godot/input/GodotGestureHandler.kt @@ -0,0 +1,289 @@ +/*************************************************************************/ +/* GodotGestureHandler.kt */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ + +package org.godotengine.godot.input + +import android.os.Build +import android.view.GestureDetector.SimpleOnGestureListener +import android.view.InputDevice +import android.view.MotionEvent +import android.view.ScaleGestureDetector +import android.view.ScaleGestureDetector.OnScaleGestureListener +import org.godotengine.godot.GodotLib + +/** + * Handles regular and scale gesture input related events for the [GodotView] view. + * + * @See https://developer.android.com/reference/android/view/GestureDetector.SimpleOnGestureListener + * @See https://developer.android.com/reference/android/view/ScaleGestureDetector.OnScaleGestureListener + */ +internal class GodotGestureHandler : SimpleOnGestureListener(), OnScaleGestureListener { + + companion object { + private val TAG = GodotGestureHandler::class.java.simpleName + } + + /** + * Enable pan and scale gestures + */ + var panningAndScalingEnabled = false + + private var doubleTapInProgress = false + private var dragInProgress = false + private var scaleInProgress = false + private var contextClickInProgress = false + private var pointerCaptureInProgress = false + + override fun onDown(event: MotionEvent): Boolean { + // Don't send / register a down event while we're in the middle of a double-tap + if (!doubleTapInProgress) { + // Send the down event + GodotInputHandler.handleMotionEvent(event) + } + return true + } + + override fun onSingleTapUp(event: MotionEvent): Boolean { + GodotInputHandler.handleMotionEvent(event) + return true + } + + override fun onLongPress(event: MotionEvent) { + contextClickRouter(event) + } + + private fun contextClickRouter(event: MotionEvent) { + if (scaleInProgress) { + return + } + + // Cancel the previous down event + GodotInputHandler.handleMotionEvent( + event.source, + MotionEvent.ACTION_CANCEL, + event.buttonState, + event.x, + event.y + ) + + // Turn a context click into a single tap right mouse button click. + GodotInputHandler.handleMouseEvent( + MotionEvent.ACTION_DOWN, + MotionEvent.BUTTON_SECONDARY, + event.x, + event.y + ) + contextClickInProgress = true + } + + fun onPointerCaptureChange(hasCapture: Boolean) { + if (pointerCaptureInProgress == hasCapture) { + return + } + + if (!hasCapture) { + // Dispatch a mouse relative ACTION_UP event to signal the end of the capture + GodotInputHandler.handleMouseEvent( + MotionEvent.ACTION_UP, + 0, + 0f, + 0f, + 0f, + 0f, + false, + true + ) + } + pointerCaptureInProgress = hasCapture + } + + fun onMotionEvent(event: MotionEvent): Boolean { + return when (event.actionMasked) { + MotionEvent.ACTION_UP, MotionEvent.ACTION_CANCEL, MotionEvent.ACTION_BUTTON_RELEASE -> { + onActionUp(event) + } + MotionEvent.ACTION_MOVE -> { + onActionMove(event) + } + else -> false + } + } + + private fun onActionUp(event: MotionEvent): Boolean { + val sourceMouseRelative = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { + event.isFromSource(InputDevice.SOURCE_MOUSE_RELATIVE) + } else { + false + } + when { + pointerCaptureInProgress -> { + return if (event.actionMasked == MotionEvent.ACTION_CANCEL) { + // Don't dispatch the ACTION_CANCEL while a capture is in progress + true + } else { + GodotInputHandler.handleMouseEvent( + MotionEvent.ACTION_UP, + event.buttonState, + event.x, + event.y, + 0f, + 0f, + false, + sourceMouseRelative + ) + pointerCaptureInProgress = false + true + } + } + dragInProgress -> { + GodotInputHandler.handleMotionEvent(event) + dragInProgress = false + return true + } + contextClickInProgress -> { + GodotInputHandler.handleMouseEvent( + event.actionMasked, + 0, + event.x, + event.y, + 0f, + 0f, + false, + sourceMouseRelative + ) + contextClickInProgress = false + return true + } + else -> return false + } + } + + private fun onActionMove(event: MotionEvent): Boolean { + if (contextClickInProgress) { + val sourceMouseRelative = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { + event.isFromSource(InputDevice.SOURCE_MOUSE_RELATIVE) + } else { + false + } + GodotInputHandler.handleMouseEvent( + event.actionMasked, + MotionEvent.BUTTON_SECONDARY, + event.x, + event.y, + 0f, + 0f, + false, + sourceMouseRelative + ) + return true + } + return false + } + + override fun onDoubleTapEvent(event: MotionEvent): Boolean { + if (event.actionMasked == MotionEvent.ACTION_UP) { + doubleTapInProgress = false + } + return true + } + + override fun onDoubleTap(event: MotionEvent): Boolean { + doubleTapInProgress = true + val x = event.x + val y = event.y + val buttonMask = + if (GodotInputHandler.isMouseEvent(event)) { + event.buttonState + } else { + MotionEvent.BUTTON_PRIMARY + } + GodotInputHandler.handleMouseEvent(MotionEvent.ACTION_DOWN, buttonMask, x, y, true) + GodotInputHandler.handleMouseEvent(MotionEvent.ACTION_UP, 0, x, y, false) + + return true + } + + override fun onScroll( + originEvent: MotionEvent, + terminusEvent: MotionEvent, + distanceX: Float, + distanceY: Float + ): Boolean { + if (scaleInProgress) { + if (dragInProgress) { + // Cancel the drag + GodotInputHandler.handleMotionEvent( + originEvent.source, + MotionEvent.ACTION_CANCEL, + originEvent.buttonState, + originEvent.x, + originEvent.y + ) + dragInProgress = false + } + return true + } + + dragInProgress = true + + val x = terminusEvent.x + val y = terminusEvent.y + if (terminusEvent.pointerCount >= 2 && panningAndScalingEnabled) { + GodotLib.pan(x, y, distanceX / 5f, distanceY / 5f) + } else { + GodotInputHandler.handleMotionEvent(terminusEvent) + } + return true + } + + override fun onScale(detector: ScaleGestureDetector?): Boolean { + if (detector == null || !panningAndScalingEnabled) { + return false + } + GodotLib.magnify( + detector.focusX, + detector.focusY, + detector.scaleFactor + ) + return true + } + + override fun onScaleBegin(detector: ScaleGestureDetector?): Boolean { + if (detector == null || !panningAndScalingEnabled) { + return false + } + scaleInProgress = true + return true + } + + override fun onScaleEnd(detector: ScaleGestureDetector?) { + scaleInProgress = false + } +} diff --git a/platform/android/java/lib/src/org/godotengine/godot/input/GodotInputHandler.java b/platform/android/java/lib/src/org/godotengine/godot/input/GodotInputHandler.java index ccfb865b1a..03cb8034fa 100644 --- a/platform/android/java/lib/src/org/godotengine/godot/input/GodotInputHandler.java +++ b/platform/android/java/lib/src/org/godotengine/godot/input/GodotInputHandler.java @@ -41,13 +41,13 @@ import android.os.Build; import android.util.Log; import android.util.SparseArray; import android.util.SparseIntArray; +import android.view.GestureDetector; import android.view.InputDevice; -import android.view.InputDevice.MotionRange; import android.view.KeyEvent; import android.view.MotionEvent; +import android.view.ScaleGestureDetector; import java.util.Collections; -import java.util.Comparator; import java.util.HashSet; import java.util.Set; @@ -55,21 +55,49 @@ import java.util.Set; * Handles input related events for the {@link GodotRenderView} view. */ public class GodotInputHandler implements InputManager.InputDeviceListener { - private final GodotRenderView mRenderView; - private final InputManager mInputManager; - - private final String tag = this.getClass().getSimpleName(); + private static final String TAG = GodotInputHandler.class.getSimpleName(); private final SparseIntArray mJoystickIds = new SparseIntArray(4); private final SparseArray<Joystick> mJoysticksDevices = new SparseArray<>(4); + private final GodotRenderView mRenderView; + private final InputManager mInputManager; + private final GestureDetector gestureDetector; + private final ScaleGestureDetector scaleGestureDetector; + private final GodotGestureHandler godotGestureHandler; + public GodotInputHandler(GodotRenderView godotView) { + final Context context = godotView.getView().getContext(); mRenderView = godotView; - mInputManager = (InputManager)mRenderView.getView().getContext().getSystemService(Context.INPUT_SERVICE); + mInputManager = (InputManager)context.getSystemService(Context.INPUT_SERVICE); mInputManager.registerInputDeviceListener(this, null); + + this.godotGestureHandler = new GodotGestureHandler(); + this.gestureDetector = new GestureDetector(context, godotGestureHandler); + this.gestureDetector.setIsLongpressEnabled(false); + this.scaleGestureDetector = new ScaleGestureDetector(context, godotGestureHandler); + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { + this.scaleGestureDetector.setStylusScaleEnabled(true); + } } - private boolean isKeyEvent_GameDevice(int source) { + /** + * Enable long press events. This is false by default. + */ + public void enableLongPress(boolean enable) { + this.gestureDetector.setIsLongpressEnabled(enable); + } + + /** + * Enable multi-fingers pan & scale gestures. This is false by default. + * + * Note: This may interfere with multi-touch handling / support. + */ + public void enablePanningAndScalingGestures(boolean enable) { + this.godotGestureHandler.setPanningAndScalingEnabled(enable); + } + + private boolean isKeyEventGameDevice(int source) { // Note that keyboards are often (SOURCE_KEYBOARD | SOURCE_DPAD) if (source == (InputDevice.SOURCE_KEYBOARD | InputDevice.SOURCE_DPAD)) return false; @@ -77,6 +105,10 @@ public class GodotInputHandler implements InputManager.InputDeviceListener { return (source & InputDevice.SOURCE_JOYSTICK) == InputDevice.SOURCE_JOYSTICK || (source & InputDevice.SOURCE_DPAD) == InputDevice.SOURCE_DPAD || (source & InputDevice.SOURCE_GAMEPAD) == InputDevice.SOURCE_GAMEPAD; } + public void onPointerCaptureChange(boolean hasCapture) { + godotGestureHandler.onPointerCaptureChange(hasCapture); + } + public boolean onKeyUp(final int keyCode, KeyEvent event) { if (keyCode == KeyEvent.KEYCODE_BACK) { return true; @@ -87,7 +119,7 @@ public class GodotInputHandler implements InputManager.InputDeviceListener { } int source = event.getSource(); - if (isKeyEvent_GameDevice(source)) { + if (isKeyEventGameDevice(source)) { // Check if the device exists final int deviceId = event.getDeviceId(); if (mJoystickIds.indexOfKey(deviceId) >= 0) { @@ -96,10 +128,14 @@ public class GodotInputHandler implements InputManager.InputDeviceListener { GodotLib.joybutton(godotJoyId, button, false); } } else { - final int scanCode = event.getScanCode(); - final int chr = event.getUnicodeChar(0); - GodotLib.key(keyCode, scanCode, chr, false); - } + // getKeyCode(): The physical key that was pressed. + // Godot's keycodes match the ASCII codes, so for single byte unicode characters, + // we can use the unmodified unicode character to determine Godot's keycode. + final int keycode = event.getUnicodeChar(0); + final int physical_keycode = event.getKeyCode(); + final int unicode = event.getUnicodeChar(); + GodotLib.key(keycode, physical_keycode, unicode, false); + }; return true; } @@ -117,11 +153,10 @@ public class GodotInputHandler implements InputManager.InputDeviceListener { } int source = event.getSource(); - //Log.e(TAG, String.format("Key down! source %d, device %d, joystick %d, %d, %d", event.getDeviceId(), source, (source & InputDevice.SOURCE_JOYSTICK), (source & InputDevice.SOURCE_DPAD), (source & InputDevice.SOURCE_GAMEPAD))); final int deviceId = event.getDeviceId(); // Check if source is a game device and that the device is a registered gamepad - if (isKeyEvent_GameDevice(source)) { + if (isKeyEventGameDevice(source)) { if (event.getRepeatCount() > 0) // ignore key echo return true; @@ -131,56 +166,51 @@ public class GodotInputHandler implements InputManager.InputDeviceListener { GodotLib.joybutton(godotJoyId, button, true); } } else { - final int scanCode = event.getScanCode(); - final int chr = event.getUnicodeChar(0); - GodotLib.key(keyCode, scanCode, chr, true); + final int keycode = event.getUnicodeChar(0); + final int physical_keycode = event.getKeyCode(); + final int unicode = event.getUnicodeChar(); + GodotLib.key(keycode, physical_keycode, unicode, true); } return true; } public boolean onTouchEvent(final MotionEvent event) { - // Mouse drag (mouse pressed and move) doesn't fire onGenericMotionEvent so this is needed - if (event.isFromSource(InputDevice.SOURCE_MOUSE)) { - if (event.getAction() != MotionEvent.ACTION_MOVE) { - // we return true because every time a mouse event is fired, the event is already handled - // in onGenericMotionEvent, so by touch event we can say that the event is also handled - return true; - } - return handleMouseEvent(event); + this.scaleGestureDetector.onTouchEvent(event); + if (this.gestureDetector.onTouchEvent(event)) { + // The gesture detector has handled the event. + return true; } - final int evcount = event.getPointerCount(); - if (evcount == 0) + if (godotGestureHandler.onMotionEvent(event)) { + // The gesture handler has handled the event. return true; + } - if (mRenderView != null) { - final float[] arr = new float[event.getPointerCount() * 3]; // pointerId1, x1, y1, pointerId2, etc... + // Drag events are handled by the [GodotGestureHandler] + if (event.getActionMasked() == MotionEvent.ACTION_MOVE) { + return true; + } - for (int i = 0; i < event.getPointerCount(); i++) { - arr[i * 3 + 0] = event.getPointerId(i); - arr[i * 3 + 1] = event.getX(i); - arr[i * 3 + 2] = event.getY(i); - } - final int action = event.getActionMasked(); - final int pointer_idx = event.getPointerId(event.getActionIndex()); - - switch (action) { - case MotionEvent.ACTION_DOWN: - case MotionEvent.ACTION_CANCEL: - case MotionEvent.ACTION_UP: - case MotionEvent.ACTION_MOVE: - case MotionEvent.ACTION_POINTER_UP: - case MotionEvent.ACTION_POINTER_DOWN: { - GodotLib.touch(event.getSource(), action, pointer_idx, evcount, arr); - } break; - } + if (isMouseEvent(event)) { + return handleMouseEvent(event); } - return true; + + return handleTouchEvent(event); } public boolean onGenericMotionEvent(MotionEvent event) { - if (event.isFromSource(InputDevice.SOURCE_JOYSTICK) && event.getAction() == MotionEvent.ACTION_MOVE) { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M && gestureDetector.onGenericMotionEvent(event)) { + // The gesture detector has handled the event. + return true; + } + + if (godotGestureHandler.onMotionEvent(event)) { + // The gesture handler has handled the event. + return true; + } + + if (event.isFromSource(InputDevice.SOURCE_JOYSTICK) && event.getActionMasked() == MotionEvent.ACTION_MOVE) { // Check if the device exists final int deviceId = event.getDeviceId(); if (mJoystickIds.indexOfKey(deviceId) >= 0) { @@ -193,15 +223,14 @@ public class GodotInputHandler implements InputManager.InputDeviceListener { for (int i = 0; i < joystick.axes.size(); i++) { final int axis = joystick.axes.get(i); final float value = event.getAxisValue(axis); - /** - * As all axes are polled for each event, only fire an axis event if the value has actually changed. - * Prevents flooding Godot with repeated events. + /* + As all axes are polled for each event, only fire an axis event if the value has actually changed. + Prevents flooding Godot with repeated events. */ if (joystick.axesValues.indexOfKey(axis) < 0 || (float)joystick.axesValues.get(axis) != value) { // save value to prevent repeats joystick.axesValues.put(axis, value); - final int godotAxisIdx = i; - GodotLib.joyaxis(godotJoyId, godotAxisIdx, value); + GodotLib.joyaxis(godotJoyId, i, value); } } @@ -216,17 +245,8 @@ public class GodotInputHandler implements InputManager.InputDeviceListener { } return true; } - } else if (event.isFromSource(InputDevice.SOURCE_STYLUS)) { - final float x = event.getX(); - final float y = event.getY(); - final int type = event.getAction(); - GodotLib.hover(type, x, y); - return true; - - } else if (event.isFromSource(InputDevice.SOURCE_MOUSE) || event.isFromSource(InputDevice.SOURCE_MOUSE_RELATIVE)) { - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { - return handleMouseEvent(event); - } + } else if (isMouseEvent(event)) { + return handleMouseEvent(event); } return false; @@ -238,7 +258,7 @@ public class GodotInputHandler implements InputManager.InputDeviceListener { for (int deviceId : deviceIds) { InputDevice device = mInputManager.getInputDevice(deviceId); if (DEBUG) { - Log.v("GodotInputHandler", String.format("init() deviceId:%d, Name:%s\n", deviceId, device.getName())); + Log.v(TAG, String.format("init() deviceId:%d, Name:%s\n", deviceId, device.getName())); } onInputDeviceAdded(deviceId); } @@ -283,13 +303,12 @@ public class GodotInputHandler implements InputManager.InputDeviceListener { joystick.name = device.getName(); //Helps with creating new joypad mappings. - Log.i(tag, "=== New Input Device: " + joystick.name); + Log.i(TAG, "=== New Input Device: " + joystick.name); Set<Integer> already = new HashSet<>(); for (InputDevice.MotionRange range : device.getMotionRanges()) { boolean isJoystick = range.isFromSource(InputDevice.SOURCE_JOYSTICK); boolean isGamepad = range.isFromSource(InputDevice.SOURCE_GAMEPAD); - //Log.i(tag, "axis: "+range.getAxis()+ ", isJoystick: "+isJoystick+", isGamepad: "+isGamepad); if (!isJoystick && !isGamepad) { continue; } @@ -301,14 +320,14 @@ public class GodotInputHandler implements InputManager.InputDeviceListener { already.add(axis); joystick.axes.add(axis); } else { - Log.w(tag, " - DUPLICATE AXIS VALUE IN LIST: " + axis); + Log.w(TAG, " - DUPLICATE AXIS VALUE IN LIST: " + axis); } } } Collections.sort(joystick.axes); for (int idx = 0; idx < joystick.axes.size(); idx++) { //Helps with creating new joypad mappings. - Log.i(tag, " - Mapping Android axis " + joystick.axes.get(idx) + " to Godot axis " + idx); + Log.i(TAG, " - Mapping Android axis " + joystick.axes.get(idx) + " to Godot axis " + idx); } mJoysticksDevices.put(deviceId, joystick); @@ -333,13 +352,6 @@ public class GodotInputHandler implements InputManager.InputDeviceListener { onInputDeviceAdded(deviceId); } - private static class RangeComparator implements Comparator<MotionRange> { - @Override - public int compare(MotionRange arg0, MotionRange arg1) { - return arg0.getAxis() - arg1.getAxis(); - } - } - public static int getGodotButton(int keyCode) { int button; switch (keyCode) { @@ -405,39 +417,113 @@ public class GodotInputHandler implements InputManager.InputDeviceListener { return button; } - private boolean handleMouseEvent(final MotionEvent event) { - switch (event.getActionMasked()) { + static boolean isMouseEvent(MotionEvent event) { + return isMouseEvent(event.getSource()); + } + + private static boolean isMouseEvent(int eventSource) { + boolean mouseSource = ((eventSource & InputDevice.SOURCE_MOUSE) == InputDevice.SOURCE_MOUSE) || ((eventSource & InputDevice.SOURCE_STYLUS) == InputDevice.SOURCE_STYLUS); + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { + mouseSource = mouseSource || ((eventSource & InputDevice.SOURCE_MOUSE_RELATIVE) == InputDevice.SOURCE_MOUSE_RELATIVE); + } + return mouseSource; + } + + static boolean handleMotionEvent(final MotionEvent event) { + if (isMouseEvent(event)) { + return handleMouseEvent(event); + } + + return handleTouchEvent(event); + } + + static boolean handleMotionEvent(int eventSource, int eventAction, int buttonsMask, float x, float y) { + return handleMotionEvent(eventSource, eventAction, buttonsMask, x, y, 0, 0); + } + + static boolean handleMotionEvent(int eventSource, int eventAction, int buttonsMask, float x, float y, float deltaX, float deltaY) { + if (isMouseEvent(eventSource)) { + return handleMouseEvent(eventAction, buttonsMask, x, y, deltaX, deltaY, false, false); + } + + return handleTouchEvent(eventAction, x, y); + } + + static boolean handleMouseEvent(final MotionEvent event) { + final int eventAction = event.getActionMasked(); + final float x = event.getX(); + final float y = event.getY(); + final int buttonsMask = event.getButtonState(); + + final float verticalFactor = event.getAxisValue(MotionEvent.AXIS_VSCROLL); + final float horizontalFactor = event.getAxisValue(MotionEvent.AXIS_HSCROLL); + boolean sourceMouseRelative = false; + if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.O) { + sourceMouseRelative = event.isFromSource(InputDevice.SOURCE_MOUSE_RELATIVE); + } + return handleMouseEvent(eventAction, buttonsMask, x, y, horizontalFactor, verticalFactor, false, sourceMouseRelative); + } + + static boolean handleMouseEvent(int eventAction, int buttonsMask, float x, float y) { + return handleMouseEvent(eventAction, buttonsMask, x, y, 0, 0, false, false); + } + + static boolean handleMouseEvent(int eventAction, int buttonsMask, float x, float y, boolean doubleClick) { + return handleMouseEvent(eventAction, buttonsMask, x, y, 0, 0, doubleClick, false); + } + + static boolean handleMouseEvent(int eventAction, int buttonsMask, float x, float y, float deltaX, float deltaY, boolean doubleClick, boolean sourceMouseRelative) { + switch (eventAction) { + case MotionEvent.ACTION_CANCEL: + case MotionEvent.ACTION_UP: + // Zero-up the button state + buttonsMask = 0; + // FALL THROUGH + case MotionEvent.ACTION_DOWN: case MotionEvent.ACTION_HOVER_ENTER: + case MotionEvent.ACTION_HOVER_EXIT: case MotionEvent.ACTION_HOVER_MOVE: - case MotionEvent.ACTION_HOVER_EXIT: { - final float x = event.getX(); - final float y = event.getY(); - final int type = event.getAction(); - GodotLib.hover(type, x, y); - return true; - } - case MotionEvent.ACTION_BUTTON_PRESS: - case MotionEvent.ACTION_BUTTON_RELEASE: - case MotionEvent.ACTION_MOVE: { - final float x = event.getX(); - final float y = event.getY(); - final int buttonsMask = event.getButtonState(); - final int action = event.getAction(); - GodotLib.touch(event.getSource(), action, 0, 1, new float[] { 0, x, y }, buttonsMask); - return true; - } + case MotionEvent.ACTION_MOVE: case MotionEvent.ACTION_SCROLL: { - final float x = event.getX(); - final float y = event.getY(); - final int buttonsMask = event.getButtonState(); - final int action = event.getAction(); - final float verticalFactor = event.getAxisValue(MotionEvent.AXIS_VSCROLL); - final float horizontalFactor = event.getAxisValue(MotionEvent.AXIS_HSCROLL); - GodotLib.touch(event.getSource(), action, 0, 1, new float[] { 0, x, y }, buttonsMask, verticalFactor, horizontalFactor); + GodotLib.dispatchMouseEvent(eventAction, buttonsMask, x, y, deltaX, deltaY, doubleClick, sourceMouseRelative); + return true; } + } + return false; + } + + static boolean handleTouchEvent(final MotionEvent event) { + final int pointerCount = event.getPointerCount(); + if (pointerCount == 0) { + return true; + } + + final float[] positions = new float[pointerCount * 3]; // pointerId1, x1, y1, pointerId2, etc... + + for (int i = 0; i < pointerCount; i++) { + positions[i * 3 + 0] = event.getPointerId(i); + positions[i * 3 + 1] = event.getX(i); + positions[i * 3 + 2] = event.getY(i); + } + final int action = event.getActionMasked(); + final int actionPointerId = event.getPointerId(event.getActionIndex()); + + return handleTouchEvent(action, actionPointerId, pointerCount, positions); + } + + static boolean handleTouchEvent(int eventAction, float x, float y) { + return handleTouchEvent(eventAction, 0, 1, new float[] { 0, x, y }); + } + + static boolean handleTouchEvent(int eventAction, int actionPointerId, int pointerCount, float[] positions) { + switch (eventAction) { case MotionEvent.ACTION_DOWN: - case MotionEvent.ACTION_UP: { - // we can safely ignore these cases because they are always come beside ACTION_BUTTON_PRESS and ACTION_BUTTON_RELEASE + case MotionEvent.ACTION_CANCEL: + case MotionEvent.ACTION_UP: + case MotionEvent.ACTION_MOVE: + case MotionEvent.ACTION_POINTER_UP: + case MotionEvent.ACTION_POINTER_DOWN: { + GodotLib.dispatchTouchEvent(eventAction, actionPointerId, pointerCount, positions); return true; } } diff --git a/platform/android/java/lib/src/org/godotengine/godot/input/GodotTextInputWrapper.java b/platform/android/java/lib/src/org/godotengine/godot/input/GodotTextInputWrapper.java index e940aafa9e..c959b5f28c 100644 --- a/platform/android/java/lib/src/org/godotengine/godot/input/GodotTextInputWrapper.java +++ b/platform/android/java/lib/src/org/godotengine/godot/input/GodotTextInputWrapper.java @@ -92,11 +92,9 @@ public class GodotTextInputWrapper implements TextWatcher, OnEditorActionListene @Override public void beforeTextChanged(final CharSequence pCharSequence, final int start, final int count, final int after) { - //Log.d(TAG, "beforeTextChanged(" + pCharSequence + ")start: " + start + ",count: " + count + ",after: " + after); - for (int i = 0; i < count; ++i) { - GodotLib.key(KeyEvent.KEYCODE_DEL, KeyEvent.KEYCODE_DEL, 0, true); - GodotLib.key(KeyEvent.KEYCODE_DEL, KeyEvent.KEYCODE_DEL, 0, false); + GodotLib.key(0, KeyEvent.KEYCODE_DEL, 0, true); + GodotLib.key(0, KeyEvent.KEYCODE_DEL, 0, false); if (mHasSelection) { mHasSelection = false; @@ -107,20 +105,18 @@ public class GodotTextInputWrapper implements TextWatcher, OnEditorActionListene @Override public void onTextChanged(final CharSequence pCharSequence, final int start, final int before, final int count) { - //Log.d(TAG, "onTextChanged(" + pCharSequence + ")start: " + start + ",count: " + count + ",before: " + before); - final int[] newChars = new int[count]; for (int i = start; i < start + count; ++i) { newChars[i - start] = pCharSequence.charAt(i); } for (int i = 0; i < count; ++i) { int key = newChars[i]; - if ((key == '\n') && !mEdit.isMultiline()) { + if ((key == '\n') && !(mEdit.getKeyboardType() == GodotEditText.VirtualKeyboardType.KEYBOARD_TYPE_MULTILINE)) { // Return keys are handled through action events continue; } - GodotLib.key(0, 0, key, true); - GodotLib.key(0, 0, key, false); + GodotLib.key(key, 0, key, true); + GodotLib.key(key, 0, key, false); } } @@ -131,16 +127,16 @@ public class GodotTextInputWrapper implements TextWatcher, OnEditorActionListene for (int i = 0; i < characters.length(); i++) { final int ch = characters.codePointAt(i); - GodotLib.key(0, 0, ch, true); - GodotLib.key(0, 0, ch, false); + GodotLib.key(ch, 0, ch, true); + GodotLib.key(ch, 0, ch, false); } } if (pActionID == EditorInfo.IME_ACTION_DONE) { // Enter key has been pressed mRenderView.queueOnRenderThread(() -> { - GodotLib.key(KeyEvent.KEYCODE_ENTER, KeyEvent.KEYCODE_ENTER, 0, true); - GodotLib.key(KeyEvent.KEYCODE_ENTER, KeyEvent.KEYCODE_ENTER, 0, false); + GodotLib.key(0, KeyEvent.KEYCODE_ENTER, 0, true); + GodotLib.key(0, KeyEvent.KEYCODE_ENTER, 0, false); }); mRenderView.getView().requestFocus(); return true; diff --git a/platform/android/java/lib/src/org/godotengine/godot/io/StorageScope.kt b/platform/android/java/lib/src/org/godotengine/godot/io/StorageScope.kt index c7bd55b620..c9282dd247 100644 --- a/platform/android/java/lib/src/org/godotengine/godot/io/StorageScope.kt +++ b/platform/android/java/lib/src/org/godotengine/godot/io/StorageScope.kt @@ -54,11 +54,19 @@ internal enum class StorageScope { */ UNKNOWN; - companion object { + class Identifier(context: Context) { + + private val internalAppDir: String? = context.filesDir.canonicalPath + private val internalCacheDir: String? = context.cacheDir.canonicalPath + private val externalAppDir: String? = context.getExternalFilesDir(null)?.canonicalPath + private val sharedDir : String? = Environment.getExternalStorageDirectory().canonicalPath + private val downloadsSharedDir: String? = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS).canonicalPath + private val documentsSharedDir: String? = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOCUMENTS).canonicalPath + /** * Determines which [StorageScope] the given path falls under. */ - fun getStorageScope(context: Context, path: String?): StorageScope { + fun identifyStorageScope(path: String?): StorageScope { if (path == null) { return UNKNOWN } @@ -70,23 +78,19 @@ internal enum class StorageScope { val canonicalPathFile = pathFile.canonicalPath - val internalAppDir = context.filesDir.canonicalPath ?: return UNKNOWN - if (canonicalPathFile.startsWith(internalAppDir)) { + if (internalAppDir != null && canonicalPathFile.startsWith(internalAppDir)) { return APP } - val internalCacheDir = context.cacheDir.canonicalPath ?: return UNKNOWN - if (canonicalPathFile.startsWith(internalCacheDir)) { + if (internalCacheDir != null && canonicalPathFile.startsWith(internalCacheDir)) { return APP } - val externalAppDir = context.getExternalFilesDir(null)?.canonicalPath ?: return UNKNOWN - if (canonicalPathFile.startsWith(externalAppDir)) { + if (externalAppDir != null && canonicalPathFile.startsWith(externalAppDir)) { return APP } - val sharedDir = Environment.getExternalStorageDirectory().canonicalPath ?: return UNKNOWN - if (canonicalPathFile.startsWith(sharedDir)) { + if (sharedDir != null && canonicalPathFile.startsWith(sharedDir)) { if (Build.VERSION.SDK_INT < Build.VERSION_CODES.R) { // Before R, apps had access to shared storage so long as they have the right // permissions (and flag on Q). @@ -95,13 +99,8 @@ internal enum class StorageScope { // Post R, access is limited based on the target destination // 'Downloads' and 'Documents' are still accessible - val downloadsSharedDir = - Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS).canonicalPath - ?: return SHARED - val documentsSharedDir = - Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOCUMENTS).canonicalPath - ?: return SHARED - if (canonicalPathFile.startsWith(downloadsSharedDir) || canonicalPathFile.startsWith(documentsSharedDir)) { + if ((downloadsSharedDir != null && canonicalPathFile.startsWith(downloadsSharedDir)) + || (documentsSharedDir != null && canonicalPathFile.startsWith(documentsSharedDir))) { return APP } diff --git a/platform/android/java/lib/src/org/godotengine/godot/io/directory/FilesystemDirectoryAccess.kt b/platform/android/java/lib/src/org/godotengine/godot/io/directory/FilesystemDirectoryAccess.kt index c3acf42568..54fc56fa3e 100644 --- a/platform/android/java/lib/src/org/godotengine/godot/io/directory/FilesystemDirectoryAccess.kt +++ b/platform/android/java/lib/src/org/godotengine/godot/io/directory/FilesystemDirectoryAccess.kt @@ -54,6 +54,7 @@ internal class FilesystemDirectoryAccess(private val context: Context): private data class DirData(val dirFile: File, val files: Array<File>, var current: Int = 0) + private val storageScopeIdentifier = StorageScope.Identifier(context) private val storageManager = context.getSystemService(Context.STORAGE_SERVICE) as StorageManager private var lastDirId = STARTING_DIR_ID private val dirs = SparseArray<DirData>() @@ -62,7 +63,7 @@ internal class FilesystemDirectoryAccess(private val context: Context): // Directory access is available for shared storage on Android 11+ // On Android 10, access is also available as long as the `requestLegacyExternalStorage` // tag is available. - return StorageScope.getStorageScope(context, path) != StorageScope.UNKNOWN + return storageScopeIdentifier.identifyStorageScope(path) != StorageScope.UNKNOWN } override fun hasDirId(dirId: Int) = dirs.indexOfKey(dirId) >= 0 @@ -102,7 +103,7 @@ internal class FilesystemDirectoryAccess(private val context: Context): } } - override fun fileExists(path: String) = FileAccessHandler.fileExists(context, path) + override fun fileExists(path: String) = FileAccessHandler.fileExists(context, storageScopeIdentifier, path) override fun dirNext(dirId: Int): String { val dirData = dirs[dirId] @@ -199,7 +200,7 @@ internal class FilesystemDirectoryAccess(private val context: Context): if (fromFile.isDirectory) { fromFile.renameTo(File(to)) } else { - FileAccessHandler.renameFile(context, from, to) + FileAccessHandler.renameFile(context, storageScopeIdentifier, from, to) } } catch (e: SecurityException) { false @@ -218,7 +219,7 @@ internal class FilesystemDirectoryAccess(private val context: Context): if (deleteFile.isDirectory) { deleteFile.delete() } else { - FileAccessHandler.removeFile(context, filename) + FileAccessHandler.removeFile(context, storageScopeIdentifier, filename) } } else { true diff --git a/platform/android/java/lib/src/org/godotengine/godot/io/file/DataAccess.kt b/platform/android/java/lib/src/org/godotengine/godot/io/file/DataAccess.kt index aef1bed8ce..f23537a29e 100644 --- a/platform/android/java/lib/src/org/godotengine/godot/io/file/DataAccess.kt +++ b/platform/android/java/lib/src/org/godotengine/godot/io/file/DataAccess.kt @@ -104,7 +104,6 @@ internal abstract class DataAccess(private val filePath: String) { protected abstract val fileChannel: FileChannel internal var endOfFile = false - private set fun close() { try { @@ -125,9 +124,7 @@ internal abstract class DataAccess(private val filePath: String) { fun seek(position: Long) { try { fileChannel.position(position) - if (position <= size()) { - endOfFile = false - } + endOfFile = position >= fileChannel.size() } catch (e: Exception) { Log.w(TAG, "Exception when seeking file $filePath.", e) } @@ -161,8 +158,8 @@ internal abstract class DataAccess(private val filePath: String) { fun read(buffer: ByteBuffer): Int { return try { val readBytes = fileChannel.read(buffer) + endOfFile = readBytes == -1 || (fileChannel.position() >= fileChannel.size()) if (readBytes == -1) { - endOfFile = true 0 } else { readBytes diff --git a/platform/android/java/lib/src/org/godotengine/godot/io/file/FileAccessHandler.kt b/platform/android/java/lib/src/org/godotengine/godot/io/file/FileAccessHandler.kt index a4e0a82d6e..83da3a24b3 100644 --- a/platform/android/java/lib/src/org/godotengine/godot/io/file/FileAccessHandler.kt +++ b/platform/android/java/lib/src/org/godotengine/godot/io/file/FileAccessHandler.kt @@ -49,8 +49,8 @@ class FileAccessHandler(val context: Context) { private const val INVALID_FILE_ID = 0 private const val STARTING_FILE_ID = 1 - fun fileExists(context: Context, path: String?): Boolean { - val storageScope = StorageScope.getStorageScope(context, path) + internal fun fileExists(context: Context, storageScopeIdentifier: StorageScope.Identifier, path: String?): Boolean { + val storageScope = storageScopeIdentifier.identifyStorageScope(path) if (storageScope == StorageScope.UNKNOWN) { return false } @@ -62,8 +62,8 @@ class FileAccessHandler(val context: Context) { } } - fun removeFile(context: Context, path: String?): Boolean { - val storageScope = StorageScope.getStorageScope(context, path) + internal fun removeFile(context: Context, storageScopeIdentifier: StorageScope.Identifier, path: String?): Boolean { + val storageScope = storageScopeIdentifier.identifyStorageScope(path) if (storageScope == StorageScope.UNKNOWN) { return false } @@ -75,8 +75,8 @@ class FileAccessHandler(val context: Context) { } } - fun renameFile(context: Context, from: String?, to: String?): Boolean { - val storageScope = StorageScope.getStorageScope(context, from) + internal fun renameFile(context: Context, storageScopeIdentifier: StorageScope.Identifier, from: String?, to: String?): Boolean { + val storageScope = storageScopeIdentifier.identifyStorageScope(from) if (storageScope == StorageScope.UNKNOWN) { return false } @@ -89,13 +89,14 @@ class FileAccessHandler(val context: Context) { } } + private val storageScopeIdentifier = StorageScope.Identifier(context) private val files = SparseArray<DataAccess>() private var lastFileId = STARTING_FILE_ID private fun hasFileId(fileId: Int) = files.indexOfKey(fileId) >= 0 fun fileOpen(path: String?, modeFlags: Int): Int { - val storageScope = StorageScope.getStorageScope(context, path) + val storageScope = storageScopeIdentifier.identifyStorageScope(path) if (storageScope == StorageScope.UNKNOWN) { return INVALID_FILE_ID } @@ -162,10 +163,10 @@ class FileAccessHandler(val context: Context) { files[fileId].flush() } - fun fileExists(path: String?) = Companion.fileExists(context, path) + fun fileExists(path: String?) = Companion.fileExists(context, storageScopeIdentifier, path) fun fileLastModified(filepath: String?): Long { - val storageScope = StorageScope.getStorageScope(context, filepath) + val storageScope = storageScopeIdentifier.identifyStorageScope(filepath) if (storageScope == StorageScope.UNKNOWN) { return 0L } @@ -193,6 +194,11 @@ class FileAccessHandler(val context: Context) { return files[fileId].endOfFile } + fun setFileEof(fileId: Int, eof: Boolean) { + val file = files[fileId] ?: return + file.endOfFile = eof + } + fun fileClose(fileId: Int) { if (hasFileId(fileId)) { files[fileId].close() diff --git a/platform/android/java_godot_io_wrapper.cpp b/platform/android/java_godot_io_wrapper.cpp index b71c6ef1e6..cea64a7f22 100644 --- a/platform/android/java_godot_io_wrapper.cpp +++ b/platform/android/java_godot_io_wrapper.cpp @@ -61,7 +61,7 @@ GodotIOJavaWrapper::GodotIOJavaWrapper(JNIEnv *p_env, jobject p_godot_io_instanc _get_scaled_density = p_env->GetMethodID(cls, "getScaledDensity", "()F"); _get_screen_refresh_rate = p_env->GetMethodID(cls, "getScreenRefreshRate", "(D)D"); _get_unique_id = p_env->GetMethodID(cls, "getUniqueID", "()Ljava/lang/String;"); - _show_keyboard = p_env->GetMethodID(cls, "showKeyboard", "(Ljava/lang/String;ZIII)V"); + _show_keyboard = p_env->GetMethodID(cls, "showKeyboard", "(Ljava/lang/String;IIII)V"); _hide_keyboard = p_env->GetMethodID(cls, "hideKeyboard", "()V"); _set_screen_orientation = p_env->GetMethodID(cls, "setScreenOrientation", "(I)V"); _get_screen_orientation = p_env->GetMethodID(cls, "getScreenOrientation", "()I"); @@ -165,8 +165,8 @@ float GodotIOJavaWrapper::get_screen_refresh_rate(float fallback) { return fallback; } -Array GodotIOJavaWrapper::get_display_cutouts() { - Array result; +TypedArray<Rect2> GodotIOJavaWrapper::get_display_cutouts() { + TypedArray<Rect2> result; ERR_FAIL_NULL_V(_get_display_cutouts, result); JNIEnv *env = get_jni_env(); ERR_FAIL_NULL_V(env, result); @@ -214,12 +214,12 @@ bool GodotIOJavaWrapper::has_vk() { return (_show_keyboard != nullptr) && (_hide_keyboard != nullptr); } -void GodotIOJavaWrapper::show_vk(const String &p_existing, bool p_multiline, int p_max_input_length, int p_cursor_start, int p_cursor_end) { +void GodotIOJavaWrapper::show_vk(const String &p_existing, int p_type, int p_max_input_length, int p_cursor_start, int p_cursor_end) { if (_show_keyboard) { JNIEnv *env = get_jni_env(); ERR_FAIL_NULL(env); jstring jStr = env->NewStringUTF(p_existing.utf8().get_data()); - env->CallVoidMethod(godot_io_instance, _show_keyboard, jStr, p_multiline, p_max_input_length, p_cursor_start, p_cursor_end); + env->CallVoidMethod(godot_io_instance, _show_keyboard, jStr, p_type, p_max_input_length, p_cursor_start, p_cursor_end); } } diff --git a/platform/android/java_godot_io_wrapper.h b/platform/android/java_godot_io_wrapper.h index aec7d1db97..9a1a877b6f 100644 --- a/platform/android/java_godot_io_wrapper.h +++ b/platform/android/java_godot_io_wrapper.h @@ -38,7 +38,7 @@ #include <jni.h> #include "core/math/rect2i.h" -#include "core/variant/array.h" +#include "core/variant/typed_array.h" #include "string_android.h" // Class that makes functions in java/src/org/godotengine/godot/GodotIO.java callable from C++ @@ -78,11 +78,11 @@ public: int get_screen_dpi(); float get_scaled_density(); float get_screen_refresh_rate(float fallback); - Array get_display_cutouts(); + TypedArray<Rect2> get_display_cutouts(); Rect2i get_display_safe_area(); String get_unique_id(); bool has_vk(); - void show_vk(const String &p_existing, bool p_multiline, int p_max_input_length, int p_cursor_start, int p_cursor_end); + void show_vk(const String &p_existing, int p_type, int p_max_input_length, int p_cursor_start, int p_cursor_end); void hide_vk(); int get_vk_height(); void set_vk_height(int p_height); diff --git a/platform/android/java_godot_lib_jni.cpp b/platform/android/java_godot_lib_jni.cpp index f4de4acfad..04b69d5b86 100644 --- a/platform/android/java_godot_lib_jni.cpp +++ b/platform/android/java_godot_lib_jni.cpp @@ -79,7 +79,7 @@ JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_setVirtualKeyboardHei } } -JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_initialize(JNIEnv *env, jclass clazz, jobject p_activity, jobject p_godot_instance, jobject p_asset_manager, jobject p_godot_io, jobject p_net_utils, jobject p_directory_access_handler, jobject p_file_access_handler, jboolean p_use_apk_expansion, jobject p_godot_tts) { +JNIEXPORT jboolean JNICALL Java_org_godotengine_godot_GodotLib_initialize(JNIEnv *env, jclass clazz, jobject p_activity, jobject p_godot_instance, jobject p_asset_manager, jobject p_godot_io, jobject p_net_utils, jobject p_directory_access_handler, jobject p_file_access_handler, jboolean p_use_apk_expansion, jobject p_godot_tts) { JavaVM *jvm; env->GetJavaVM(&jvm); @@ -100,7 +100,7 @@ JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_initialize(JNIEnv *en os_android = new OS_Android(godot_java, godot_io_java, p_use_apk_expansion); - godot_java->on_video_init(env); + return godot_java->on_video_init(env); } JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_ondestroy(JNIEnv *env, jclass clazz) { @@ -123,7 +123,7 @@ JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_ondestroy(JNIEnv *env } } -JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_setup(JNIEnv *env, jclass clazz, jobjectArray p_cmdline) { +JNIEXPORT jboolean JNICALL Java_org_godotengine_godot_GodotLib_setup(JNIEnv *env, jclass clazz, jobjectArray p_cmdline) { setup_android_thread(); const char **cmdline = nullptr; @@ -133,10 +133,10 @@ JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_setup(JNIEnv *env, jc cmdlen = env->GetArrayLength(p_cmdline); if (cmdlen) { cmdline = (const char **)memalloc((cmdlen + 1) * sizeof(const char *)); - ERR_FAIL_NULL_MSG(cmdline, "Out of memory."); + ERR_FAIL_NULL_V_MSG(cmdline, false, "Out of memory."); cmdline[cmdlen] = nullptr; j_cmdline = (jstring *)memalloc(cmdlen * sizeof(jstring)); - ERR_FAIL_NULL_MSG(j_cmdline, "Out of memory."); + ERR_FAIL_NULL_V_MSG(j_cmdline, false, "Out of memory."); for (int i = 0; i < cmdlen; i++) { jstring string = (jstring)env->GetObjectArrayElement(p_cmdline, i); @@ -161,11 +161,12 @@ JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_setup(JNIEnv *env, jc // Note: --help and --version return ERR_HELP, but this should be translated to 0 if exit codes are propagated. if (err != OK) { - return; // should exit instead and print the error + return false; } java_class_wrapper = memnew(JavaClassWrapper(godot_java->get_activity())); GDREGISTER_CLASS(JNISingleton); + return true; } JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_resize(JNIEnv *env, jclass clazz, jobject p_surface, jint p_width, jint p_height) { @@ -254,7 +255,17 @@ JNIEXPORT jboolean JNICALL Java_org_godotengine_godot_GodotLib_step(JNIEnv *env, return should_swap_buffers; } -void touch_preprocessing(JNIEnv *env, jclass clazz, jint input_device, jint ev, jint pointer, jint pointer_count, jfloatArray positions, jint buttons_mask, jfloat vertical_factor, jfloat horizontal_factor) { +// Called on the UI thread +JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_dispatchMouseEvent(JNIEnv *env, jclass clazz, jint p_event_type, jint p_button_mask, jfloat p_x, jfloat p_y, jfloat p_delta_x, jfloat p_delta_y, jboolean p_double_click, jboolean p_source_mouse_relative) { + if (step.get() <= 0) { + return; + } + + input_handler->process_mouse_event(p_event_type, p_button_mask, Point2(p_x, p_y), Vector2(p_delta_x, p_delta_y), p_double_click, p_source_mouse_relative); +} + +// Called on the UI thread +JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_dispatchTouchEvent(JNIEnv *env, jclass clazz, jint ev, jint pointer, jint pointer_count, jfloatArray position) { if (step.get() <= 0) { return; } @@ -262,50 +273,30 @@ void touch_preprocessing(JNIEnv *env, jclass clazz, jint input_device, jint ev, Vector<AndroidInputHandler::TouchPos> points; for (int i = 0; i < pointer_count; i++) { jfloat p[3]; - env->GetFloatArrayRegion(positions, i * 3, 3, p); + env->GetFloatArrayRegion(position, i * 3, 3, p); AndroidInputHandler::TouchPos tp; tp.pos = Point2(p[1], p[2]); tp.id = (int)p[0]; points.push_back(tp); } - if ((input_device & AINPUT_SOURCE_MOUSE) == AINPUT_SOURCE_MOUSE || (input_device & AINPUT_SOURCE_MOUSE_RELATIVE) == AINPUT_SOURCE_MOUSE_RELATIVE) { - input_handler->process_mouse_event(input_device, ev, buttons_mask, points[0].pos, vertical_factor, horizontal_factor); - } else { - input_handler->process_touch(ev, pointer, points); - } -} -// Called on the UI thread -JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_touch__IIII_3F(JNIEnv *env, jclass clazz, jint input_device, jint ev, jint pointer, jint pointer_count, jfloatArray position) { - touch_preprocessing(env, clazz, input_device, ev, pointer, pointer_count, position); -} - -// Called on the UI thread -JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_touch__IIII_3FI(JNIEnv *env, jclass clazz, jint input_device, jint ev, jint pointer, jint pointer_count, jfloatArray position, jint buttons_mask) { - touch_preprocessing(env, clazz, input_device, ev, pointer, pointer_count, position, buttons_mask); -} - -// Called on the UI thread -JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_touch__IIII_3FIFF(JNIEnv *env, jclass clazz, jint input_device, jint ev, jint pointer, jint pointer_count, jfloatArray position, jint buttons_mask, jfloat vertical_factor, jfloat horizontal_factor) { - touch_preprocessing(env, clazz, input_device, ev, pointer, pointer_count, position, buttons_mask, vertical_factor, horizontal_factor); + input_handler->process_touch_event(ev, pointer, points); } // Called on the UI thread -JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_hover(JNIEnv *env, jclass clazz, jint p_type, jfloat p_x, jfloat p_y) { +JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_magnify(JNIEnv *env, jclass clazz, jfloat p_x, jfloat p_y, jfloat p_factor) { if (step.get() <= 0) { return; } - - input_handler->process_hover(p_type, Point2(p_x, p_y)); + input_handler->process_magnify(Point2(p_x, p_y), p_factor); } // Called on the UI thread -JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_doubleTap(JNIEnv *env, jclass clazz, jint p_button_mask, jint p_x, jint p_y) { +JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_pan(JNIEnv *env, jclass clazz, jfloat p_x, jfloat p_y, jfloat p_delta_x, jfloat p_delta_y) { if (step.get() <= 0) { return; } - - input_handler->process_double_tap(p_button_mask, Point2(p_x, p_y)); + input_handler->process_pan(Point2(p_x, p_y), Vector2(p_delta_x, p_delta_y)); } // Called on the UI thread @@ -376,12 +367,11 @@ JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_joyconnectionchanged( } // Called on the UI thread -JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_key(JNIEnv *env, jclass clazz, jint p_keycode, jint p_scancode, jint p_unicode_char, jboolean p_pressed) { +JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_key(JNIEnv *env, jclass clazz, jint p_keycode, jint p_physical_keycode, jint p_unicode, jboolean p_pressed) { if (step.get() <= 0) { return; } - - input_handler->process_key_event(p_keycode, p_scancode, p_unicode_char, p_pressed); + input_handler->process_key_event(p_keycode, p_physical_keycode, p_unicode, p_pressed); } JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_accelerometer(JNIEnv *env, jclass clazz, jfloat x, jfloat y, jfloat z) { diff --git a/platform/android/java_godot_lib_jni.h b/platform/android/java_godot_lib_jni.h index de16f197b8..09fed15690 100644 --- a/platform/android/java_godot_lib_jni.h +++ b/platform/android/java_godot_lib_jni.h @@ -37,21 +37,19 @@ // These functions can be called from within JAVA and are the means by which our JAVA implementation calls back into our C++ code. // See java/src/org/godotengine/godot/GodotLib.java for the JAVA side of this (yes that's why we have the long names) extern "C" { -JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_initialize(JNIEnv *env, jclass clazz, jobject p_activity, jobject p_godot_instance, jobject p_asset_manager, jobject p_godot_io, jobject p_net_utils, jobject p_directory_access_handler, jobject p_file_access_handler, jboolean p_use_apk_expansion, jobject p_godot_tts); +JNIEXPORT jboolean JNICALL Java_org_godotengine_godot_GodotLib_initialize(JNIEnv *env, jclass clazz, jobject p_activity, jobject p_godot_instance, jobject p_asset_manager, jobject p_godot_io, jobject p_net_utils, jobject p_directory_access_handler, jobject p_file_access_handler, jboolean p_use_apk_expansion, jobject p_godot_tts); JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_ondestroy(JNIEnv *env, jclass clazz); -JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_setup(JNIEnv *env, jclass clazz, jobjectArray p_cmdline); +JNIEXPORT jboolean JNICALL Java_org_godotengine_godot_GodotLib_setup(JNIEnv *env, jclass clazz, jobjectArray p_cmdline); JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_resize(JNIEnv *env, jclass clazz, jobject p_surface, jint p_width, jint p_height); JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_newcontext(JNIEnv *env, jclass clazz, jobject p_surface); JNIEXPORT jboolean JNICALL Java_org_godotengine_godot_GodotLib_step(JNIEnv *env, jclass clazz); JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_ttsCallback(JNIEnv *env, jclass clazz, jint event, jint id, jint pos); JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_back(JNIEnv *env, jclass clazz); -void touch_preprocessing(JNIEnv *env, jclass clazz, jint input_device, jint ev, jint pointer, jint pointer_count, jfloatArray positions, jint buttons_mask = 0, jfloat vertical_factor = 0, jfloat horizontal_factor = 0); -JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_touch__IIII_3F(JNIEnv *env, jclass clazz, jint input_device, jint ev, jint pointer, jint pointer_count, jfloatArray positions); -JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_touch__IIII_3FI(JNIEnv *env, jclass clazz, jint input_device, jint ev, jint pointer, jint pointer_count, jfloatArray positions, jint buttons_mask); -JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_touch__IIII_3FIFF(JNIEnv *env, jclass clazz, jint input_device, jint ev, jint pointer, jint pointer_count, jfloatArray positions, jint buttons_mask, jfloat vertical_factor, jfloat horizontal_factor); -JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_hover(JNIEnv *env, jclass clazz, jint p_type, jfloat p_x, jfloat p_y); -JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_doubleTap(JNIEnv *env, jclass clazz, jint p_button_mask, jint p_x, jint p_y); -JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_key(JNIEnv *env, jclass clazz, jint p_keycode, jint p_scancode, jint p_unicode_char, jboolean p_pressed); +JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_dispatchMouseEvent(JNIEnv *env, jclass clazz, jint p_event_type, jint p_button_mask, jfloat p_x, jfloat p_y, jfloat p_delta_x, jfloat p_delta_y, jboolean p_double_click, jboolean p_source_mouse_relative); +JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_dispatchTouchEvent(JNIEnv *env, jclass clazz, jint ev, jint pointer, jint pointer_count, jfloatArray positions); +JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_magnify(JNIEnv *env, jclass clazz, jfloat p_x, jfloat p_y, jfloat p_factor); +JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_pan(JNIEnv *env, jclass clazz, jfloat p_x, jfloat p_y, jfloat p_delta_x, jfloat p_delta_y); +JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_key(JNIEnv *env, jclass clazz, jint p_keycode, jint p_physical_keycode, jint p_unicode, jboolean p_pressed); JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_joybutton(JNIEnv *env, jclass clazz, jint p_device, jint p_button, jboolean p_pressed); JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_joyaxis(JNIEnv *env, jclass clazz, jint p_device, jint p_axis, jfloat p_value); JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_joyhat(JNIEnv *env, jclass clazz, jint p_device, jint p_hat_x, jint p_hat_y); diff --git a/platform/android/java_godot_view_wrapper.h b/platform/android/java_godot_view_wrapper.h index b1f258bbb5..c52f459d64 100644 --- a/platform/android/java_godot_view_wrapper.h +++ b/platform/android/java_godot_view_wrapper.h @@ -28,8 +28,8 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ -#ifndef GODOT_JAVA_GODOT_VIEW_WRAPPER_H -#define GODOT_JAVA_GODOT_VIEW_WRAPPER_H +#ifndef JAVA_GODOT_VIEW_WRAPPER_H +#define JAVA_GODOT_VIEW_WRAPPER_H #include <android/log.h> #include <jni.h> @@ -57,4 +57,4 @@ public: ~GodotJavaViewWrapper(); }; -#endif // GODOT_JAVA_GODOT_VIEW_WRAPPER_H +#endif // JAVA_GODOT_VIEW_WRAPPER_H diff --git a/platform/android/java_godot_wrapper.cpp b/platform/android/java_godot_wrapper.cpp index e3456fe4e4..07b0d75921 100644 --- a/platform/android/java_godot_wrapper.cpp +++ b/platform/android/java_godot_wrapper.cpp @@ -58,7 +58,7 @@ GodotJavaWrapper::GodotJavaWrapper(JNIEnv *p_env, jobject p_activity, jobject p_ } // get some Godot method pointers... - _on_video_init = p_env->GetMethodID(godot_class, "onVideoInit", "()V"); + _on_video_init = p_env->GetMethodID(godot_class, "onVideoInit", "()Z"); _restart = p_env->GetMethodID(godot_class, "restart", "()V"); _finish = p_env->GetMethodID(godot_class, "forceQuit", "()V"); _set_keep_screen_on = p_env->GetMethodID(godot_class, "setKeepScreenOn", "(Z)V"); @@ -125,14 +125,15 @@ GodotJavaViewWrapper *GodotJavaWrapper::get_godot_view() { return _godot_view; } -void GodotJavaWrapper::on_video_init(JNIEnv *p_env) { +bool GodotJavaWrapper::on_video_init(JNIEnv *p_env) { if (_on_video_init) { if (p_env == nullptr) { p_env = get_jni_env(); } - ERR_FAIL_NULL(p_env); - p_env->CallVoidMethod(godot_instance, _on_video_init); + ERR_FAIL_NULL_V(p_env, false); + return p_env->CallBooleanMethod(godot_instance, _on_video_init); } + return false; } void GodotJavaWrapper::on_godot_setup_completed(JNIEnv *p_env) { diff --git a/platform/android/java_godot_wrapper.h b/platform/android/java_godot_wrapper.h index bbf7c0ae33..a6c7853107 100644 --- a/platform/android/java_godot_wrapper.h +++ b/platform/android/java_godot_wrapper.h @@ -83,7 +83,7 @@ public: jobject get_class_loader(); GodotJavaViewWrapper *get_godot_view(); - void on_video_init(JNIEnv *p_env = nullptr); + bool on_video_init(JNIEnv *p_env = nullptr); void on_godot_setup_completed(JNIEnv *p_env = nullptr); void on_godot_main_loop_started(JNIEnv *p_env = nullptr); void restart(JNIEnv *p_env = nullptr); diff --git a/platform/android/os_android.cpp b/platform/android/os_android.cpp index 0f551e7f4f..142dc54c45 100644 --- a/platform/android/os_android.cpp +++ b/platform/android/os_android.cpp @@ -362,7 +362,7 @@ void OS_Android::vibrate_handheld(int p_duration_ms) { } String OS_Android::get_config_path() const { - return get_user_data_dir().plus_file("config"); + return get_user_data_dir().path_join("config"); } bool OS_Android::_check_internal_feature_support(const String &p_feature) { @@ -370,15 +370,15 @@ bool OS_Android::_check_internal_feature_support(const String &p_feature) { return true; } #if defined(__aarch64__) - if (p_feature == "arm64-v8a") { + if (p_feature == "arm64-v8a" || p_feature == "arm64") { return true; } #elif defined(__ARM_ARCH_7A__) - if (p_feature == "armeabi-v7a" || p_feature == "armeabi") { + if (p_feature == "armeabi-v7a" || p_feature == "armeabi" || p_feature == "arm32") { return true; } #elif defined(__arm__) - if (p_feature == "armeabi") { + if (p_feature == "armeabi" || p_feature == "arm") { return true; } #endif diff --git a/platform/ios/README.md b/platform/ios/README.md new file mode 100644 index 0000000000..82c275ad31 --- /dev/null +++ b/platform/ios/README.md @@ -0,0 +1,14 @@ +# iOS platform port + +This folder contains the C++, Objective-C and Objective-C++ code for the iOS +platform port. + +See also [`misc/dist/ios_xcode`](/misc/dist/ios_xcode) folder for the Xcode +project template used for packaging the iOS export templates. + +## Documentation + +- [Compiling for iOS](https://docs.godotengine.org/en/latest/development/compiling/compiling_for_ios.html) + - Instructions on building this platform port from source. +- [Exporting for iOS](https://docs.godotengine.org/en/latest/tutorials/export/exporting_for_ios.html) + - Instructions on using the compiled export templates to export a project. diff --git a/platform/iphone/SCsub b/platform/ios/SCsub index 5e10bf5646..bf12ab6dd7 100644 --- a/platform/iphone/SCsub +++ b/platform/ios/SCsub @@ -2,16 +2,16 @@ Import("env") -iphone_lib = [ - "godot_iphone.mm", - "os_iphone.mm", +ios_lib = [ + "godot_ios.mm", + "os_ios.mm", "main.m", "app_delegate.mm", "view_controller.mm", "ios.mm", - "vulkan_context_iphone.mm", - "display_server_iphone.mm", - "joypad_iphone.mm", + "vulkan_context_ios.mm", + "display_server_ios.mm", + "joypad_ios.mm", "godot_view.mm", "tts_ios.mm", "display_layer.mm", @@ -23,7 +23,7 @@ iphone_lib = [ ] env_ios = env.Clone() -ios_lib = env_ios.add_library("iphone", iphone_lib) +ios_lib = env_ios.add_library("ios", ios_lib) # (iOS) Enable module support env_ios.Append(CCFLAGS=["-fmodules", "-fcxx-modules"]) @@ -32,9 +32,9 @@ env_ios.Append(CCFLAGS=["-fmodules", "-fcxx-modules"]) def combine_libs(target=None, source=None, env=None): lib_path = target[0].srcnode().abspath if "osxcross" in env: - libtool = "$IPHONEPATH/usr/bin/${ios_triple}libtool" + libtool = "$IOS_TOOLCHAIN_PATH/usr/bin/${ios_triple}libtool" else: - libtool = "$IPHONEPATH/usr/bin/libtool" + libtool = "$IOS_TOOLCHAIN_PATH/usr/bin/libtool" env.Execute( libtool + ' -static -o "' + lib_path + '" ' + " ".join([('"' + lib.srcnode().abspath + '"') for lib in source]) ) diff --git a/platform/iphone/api/api.cpp b/platform/ios/api/api.cpp index f2e6fd7a7a..00c76a9256 100644 --- a/platform/iphone/api/api.cpp +++ b/platform/ios/api/api.cpp @@ -30,19 +30,19 @@ #include "api.h" -#if defined(IPHONE_ENABLED) +#if defined(IOS_ENABLED) -void register_iphone_api() { +void register_ios_api() { godot_ios_plugins_initialize(); } -void unregister_iphone_api() { +void unregister_ios_api() { godot_ios_plugins_deinitialize(); } #else -void register_iphone_api() {} -void unregister_iphone_api() {} +void register_ios_api() {} +void unregister_ios_api() {} #endif diff --git a/platform/iphone/api/api.h b/platform/ios/api/api.h index ece91a9f1a..c7fd4ce77b 100644 --- a/platform/iphone/api/api.h +++ b/platform/ios/api/api.h @@ -28,15 +28,15 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ -#ifndef IPHONE_API_H -#define IPHONE_API_H +#ifndef IOS_API_H +#define IOS_API_H -#if defined(IPHONE_ENABLED) +#if defined(IOS_ENABLED) extern void godot_ios_plugins_initialize(); extern void godot_ios_plugins_deinitialize(); #endif -void register_iphone_api(); -void unregister_iphone_api(); +void register_ios_api(); +void unregister_ios_api(); -#endif // IPHONE_API_H +#endif // IOS_API_H diff --git a/platform/iphone/app_delegate.h b/platform/ios/app_delegate.h index 0ec1dc071b..0ec1dc071b 100644 --- a/platform/iphone/app_delegate.h +++ b/platform/ios/app_delegate.h diff --git a/platform/iphone/app_delegate.mm b/platform/ios/app_delegate.mm index c5c9b5a5f9..fb183d52d4 100644 --- a/platform/iphone/app_delegate.mm +++ b/platform/ios/app_delegate.mm @@ -34,7 +34,7 @@ #include "drivers/coreaudio/audio_driver_coreaudio.h" #import "godot_view.h" #include "main/main.h" -#include "os_iphone.h" +#include "os_ios.h" #import "view_controller.h" #import <AVFoundation/AVFoundation.h> @@ -45,8 +45,8 @@ extern int gargc; extern char **gargv; -extern int iphone_main(int, char **, String, String); -extern void iphone_finish(); +extern int ios_main(int, char **, String, String); +extern void ios_finish(); @implementation AppDelegate @@ -71,7 +71,7 @@ static ViewController *mainViewController = nil; paths = NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES); NSString *cacheDirectory = [paths objectAtIndex:0]; - int err = iphone_main(gargc, gargv, String::utf8([documentsDirectory UTF8String]), String::utf8([cacheDirectory UTF8String])); + int err = ios_main(gargc, gargv, String::utf8([documentsDirectory UTF8String]), String::utf8([cacheDirectory UTF8String])); if (err != 0) { // bail, things did not go very well for us, should probably output a message on screen with our error code... @@ -106,10 +106,10 @@ static ViewController *mainViewController = nil; if ([notification.name isEqualToString:AVAudioSessionInterruptionNotification]) { if ([[notification.userInfo valueForKey:AVAudioSessionInterruptionTypeKey] isEqualToNumber:[NSNumber numberWithInt:AVAudioSessionInterruptionTypeBegan]]) { NSLog(@"Audio interruption began"); - OSIPhone::get_singleton()->on_focus_out(); + OS_IOS::get_singleton()->on_focus_out(); } else if ([[notification.userInfo valueForKey:AVAudioSessionInterruptionTypeKey] isEqualToNumber:[NSNumber numberWithInt:AVAudioSessionInterruptionTypeEnded]]) { NSLog(@"Audio interruption ended"); - OSIPhone::get_singleton()->on_focus_in(); + OS_IOS::get_singleton()->on_focus_in(); } } } @@ -121,7 +121,7 @@ static ViewController *mainViewController = nil; } - (void)applicationWillTerminate:(UIApplication *)application { - iphone_finish(); + ios_finish(); } // When application goes to background (e.g. user switches to another app or presses Home), @@ -135,11 +135,11 @@ static ViewController *mainViewController = nil; // notification panel by swiping from the upper part of the screen. - (void)applicationWillResignActive:(UIApplication *)application { - OSIPhone::get_singleton()->on_focus_out(); + OS_IOS::get_singleton()->on_focus_out(); } - (void)applicationDidBecomeActive:(UIApplication *)application { - OSIPhone::get_singleton()->on_focus_in(); + OS_IOS::get_singleton()->on_focus_in(); } - (void)dealloc { diff --git a/platform/iphone/detect.py b/platform/ios/detect.py index 862f1fe50b..ed7e714c4e 100644 --- a/platform/iphone/detect.py +++ b/platform/ios/detect.py @@ -23,11 +23,11 @@ def get_opts(): return [ ( - "IPHONEPATH", - "Path to iPhone toolchain", + "IOS_TOOLCHAIN_PATH", + "Path to iOS toolchain", "/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain", ), - ("IPHONESDK", "Path to the iPhone SDK", ""), + ("IOS_SDK_PATH", "Path to the iOS SDK", ""), BoolVariable("ios_simulator", "Build for iOS Simulator", False), BoolVariable("ios_exceptions", "Enable exceptions", False), ("ios_triple", "Triple for ios toolchain", ""), @@ -36,12 +36,25 @@ def get_opts(): def get_flags(): return [ + ("arch", "arm64"), # Default for convenience. ("tools", False), ("use_volk", False), + # Disable by default even if production is set, as it makes linking in Xcode + # on exports very slow and that's not what most users expect. + ("lto", "none"), ] def configure(env): + # Validate arch. + supported_arches = ["x86_64", "arm64"] + if env["arch"] not in supported_arches: + print( + 'Unsupported CPU architecture "%s" for iOS. Supported architectures are: %s.' + % (env["arch"], ", ".join(supported_arches)) + ) + sys.exit() + ## Build type if env["target"].startswith("release"): @@ -60,14 +73,14 @@ def configure(env): env.Append(CCFLAGS=["-gdwarf-2", "-O0"]) env.Append(CPPDEFINES=["_DEBUG", ("DEBUG", 1)]) - if env["use_lto"]: - env.Append(CCFLAGS=["-flto"]) - env.Append(LINKFLAGS=["-flto"]) - - ## Architecture - env["bits"] = "64" - if env["arch"] != "x86_64": - env["arch"] = "arm64" + # LTO + if env["lto"] != "none": + if env["lto"] == "thin": + env.Append(CCFLAGS=["-flto=thin"]) + env.Append(LINKFLAGS=["-flto=thin"]) + else: + env.Append(CCFLAGS=["-flto"]) + env.Append(LINKFLAGS=["-flto"]) ## Compiler configuration @@ -75,10 +88,10 @@ def configure(env): if "OSXCROSS_IOS" in os.environ: env["osxcross"] = True - env["ENV"]["PATH"] = env["IPHONEPATH"] + "/Developer/usr/bin/:" + env["ENV"]["PATH"] + env["ENV"]["PATH"] = env["IOS_TOOLCHAIN_PATH"] + "/Developer/usr/bin/:" + env["ENV"]["PATH"] - compiler_path = "$IPHONEPATH/usr/bin/${ios_triple}" - s_compiler_path = "$IPHONEPATH/Developer/usr/bin/" + compiler_path = "$IOS_TOOLCHAIN_PATH/usr/bin/${ios_triple}" + s_compiler_path = "$IOS_TOOLCHAIN_PATH/Developer/usr/bin/" ccache_path = os.environ.get("CCACHE") if ccache_path is None: @@ -97,22 +110,26 @@ def configure(env): ## Compile flags if env["ios_simulator"]: - detect_darwin_sdk_path("iphonesimulator", env) + detect_darwin_sdk_path("iossimulator", env) env.Append(ASFLAGS=["-mios-simulator-version-min=13.0"]) env.Append(CCFLAGS=["-mios-simulator-version-min=13.0"]) env.extra_suffix = ".simulator" + env.extra_suffix else: - detect_darwin_sdk_path("iphone", env) + detect_darwin_sdk_path("ios", env) env.Append(ASFLAGS=["-miphoneos-version-min=11.0"]) env.Append(CCFLAGS=["-miphoneos-version-min=11.0"]) if env["arch"] == "x86_64": + if not env["ios_simulator"]: + print("ERROR: Building for iOS with 'arch=x86_64' requires 'ios_simulator=yes'.") + sys.exit(255) + env["ENV"]["MACOSX_DEPLOYMENT_TARGET"] = "10.9" env.Append( CCFLAGS=( "-fobjc-arc -arch x86_64" " -fobjc-abi-version=2 -fobjc-legacy-dispatch -fmessage-length=0 -fpascal-strings -fblocks" - " -fasm-blocks -isysroot $IPHONESDK" + " -fasm-blocks -isysroot $IOS_SDK_PATH" ).split() ) env.Append(ASFLAGS=["-arch", "x86_64"]) @@ -122,7 +139,7 @@ def configure(env): "-fobjc-arc -arch arm64 -fmessage-length=0 -fno-strict-aliasing" " -fdiagnostics-print-source-range-info -fdiagnostics-show-category=id -fdiagnostics-parseable-fixits" " -fpascal-strings -fblocks -fvisibility=hidden -MMD -MT dependencies" - " -isysroot $IPHONESDK".split() + " -isysroot $IOS_SDK_PATH".split() ) ) env.Append(ASFLAGS=["-arch", "arm64"]) @@ -135,18 +152,18 @@ def configure(env): else: env.Append(CCFLAGS=["-fno-exceptions"]) - # Temp fix for ABS/MAX/MIN macros in iPhone SDK blocking compilation + # Temp fix for ABS/MAX/MIN macros in iOS SDK blocking compilation env.Append(CCFLAGS=["-Wno-ambiguous-macro"]) env.Prepend( CPPPATH=[ - "$IPHONESDK/usr/include", - "$IPHONESDK/System/Library/Frameworks/AudioUnit.framework/Headers", + "$IOS_SDK_PATH/usr/include", + "$IOS_SDK_PATH/System/Library/Frameworks/AudioUnit.framework/Headers", ] ) - env.Prepend(CPPPATH=["#platform/iphone"]) - env.Append(CPPDEFINES=["IPHONE_ENABLED", "UNIX_ENABLED", "COREAUDIO_ENABLED"]) + env.Prepend(CPPPATH=["#platform/ios"]) + env.Append(CPPDEFINES=["IOS_ENABLED", "UNIX_ENABLED", "COREAUDIO_ENABLED"]) if env["vulkan"]: env.Append(CPPDEFINES=["VULKAN_ENABLED"]) diff --git a/platform/iphone/device_metrics.h b/platform/ios/device_metrics.h index b9fb9b2fd9..b9fb9b2fd9 100644 --- a/platform/iphone/device_metrics.h +++ b/platform/ios/device_metrics.h diff --git a/platform/iphone/device_metrics.m b/platform/ios/device_metrics.m index ec4dd8130d..ec4dd8130d 100644 --- a/platform/iphone/device_metrics.m +++ b/platform/ios/device_metrics.m diff --git a/platform/iphone/display_layer.h b/platform/ios/display_layer.h index a17c75dba1..a17c75dba1 100644 --- a/platform/iphone/display_layer.h +++ b/platform/ios/display_layer.h diff --git a/platform/iphone/display_layer.mm b/platform/ios/display_layer.mm index 92e81448ac..7c83494768 100644 --- a/platform/iphone/display_layer.mm +++ b/platform/ios/display_layer.mm @@ -32,9 +32,9 @@ #include "core/config/project_settings.h" #include "core/os/keyboard.h" -#include "display_server_iphone.h" +#include "display_server_ios.h" #include "main/main.h" -#include "os_iphone.h" +#include "os_ios.h" #include "servers/audio_server.h" #import <AudioToolbox/AudioServices.h> diff --git a/platform/iphone/display_server_iphone.h b/platform/ios/display_server_ios.h index 7af222e3f8..f3624f24ab 100644 --- a/platform/iphone/display_server_iphone.h +++ b/platform/ios/display_server_ios.h @@ -1,5 +1,5 @@ /*************************************************************************/ -/* display_server_iphone.h */ +/* display_server_ios.h */ /*************************************************************************/ /* This file is part of: */ /* GODOT ENGINE */ @@ -28,8 +28,8 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ -#ifndef display_server_iphone_h -#define display_server_iphone_h +#ifndef DISPLAY_SERVER_IOS_H +#define DISPLAY_SERVER_IOS_H #include "core/input/input.h" #include "servers/display_server.h" @@ -38,7 +38,7 @@ #include "drivers/vulkan/rendering_device_vulkan.h" #include "servers/rendering/renderer_rd/renderer_compositor_rd.h" -#include "vulkan_context_iphone.h" +#include "vulkan_context_ios.h" #import <QuartzCore/CAMetalLayer.h> #ifdef USE_VOLK @@ -48,13 +48,13 @@ #endif #endif -class DisplayServerIPhone : public DisplayServer { - GDCLASS(DisplayServerIPhone, DisplayServer) +class DisplayServerIOS : public DisplayServer { + GDCLASS(DisplayServerIOS, DisplayServer) _THREAD_SAFE_CLASS_ #if defined(VULKAN_ENABLED) - VulkanContextIPhone *context_vulkan = nullptr; + VulkanContextIOS *context_vulkan = nullptr; RenderingDeviceVulkan *rendering_device_vulkan = nullptr; #endif @@ -73,15 +73,15 @@ class DisplayServerIPhone : public DisplayServer { void perform_event(const Ref<InputEvent> &p_event); - DisplayServerIPhone(const String &p_rendering_driver, DisplayServer::WindowMode p_mode, DisplayServer::VSyncMode p_vsync_mode, uint32_t p_flags, const Vector2i &p_resolution, Error &r_error); - ~DisplayServerIPhone(); + DisplayServerIOS(const String &p_rendering_driver, DisplayServer::WindowMode p_mode, DisplayServer::VSyncMode p_vsync_mode, uint32_t p_flags, const Vector2i &p_resolution, Error &r_error); + ~DisplayServerIOS(); public: String rendering_driver; - static DisplayServerIPhone *get_singleton(); + static DisplayServerIOS *get_singleton(); - static void register_iphone_driver(); + static void register_ios_driver(); static DisplayServer *create_func(const String &p_rendering_driver, WindowMode p_mode, DisplayServer::VSyncMode p_vsync_mode, uint32_t p_flags, const Vector2i &p_resolution, Error &r_error); static Vector<String> get_rendering_drivers_func(); @@ -127,7 +127,7 @@ public: virtual bool tts_is_speaking() const override; virtual bool tts_is_paused() const override; - virtual Array tts_get_voices() const override; + virtual TypedArray<Dictionary> tts_get_voices() const override; virtual void tts_speak(const String &p_text, const String &p_voice, int p_volume = 50, float p_pitch = 1.f, float p_rate = 1.f, int p_utterance_id = 0, bool p_interrupt = false) override; virtual void tts_pause() override; @@ -199,7 +199,7 @@ public: virtual bool screen_is_touchscreen(int p_screen) const override; - virtual void virtual_keyboard_show(const String &p_existing_text, const Rect2 &p_screen_rect, bool p_multiline, int p_max_length, int p_cursor_start, int p_cursor_end) override; + virtual void virtual_keyboard_show(const String &p_existing_text, const Rect2 &p_screen_rect, VirtualKeyboardType p_type, int p_max_length, int p_cursor_start, int p_cursor_end) override; virtual void virtual_keyboard_hide() override; void virtual_keyboard_set_height(int height); @@ -214,4 +214,4 @@ public: void resize_window(CGSize size); }; -#endif /* display_server_iphone_h */ +#endif // DISPLAY_SERVER_IOS_H diff --git a/platform/iphone/display_server_iphone.mm b/platform/ios/display_server_ios.mm index 573ee9b7a8..74d6bc2e97 100644 --- a/platform/iphone/display_server_iphone.mm +++ b/platform/ios/display_server_ios.mm @@ -1,5 +1,5 @@ /*************************************************************************/ -/* display_server_iphone.mm */ +/* display_server_ios.mm */ /*************************************************************************/ /* This file is part of: */ /* GODOT ENGINE */ @@ -28,7 +28,7 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ -#include "display_server_iphone.h" +#include "display_server_ios.h" #import "app_delegate.h" #include "core/config/project_settings.h" @@ -37,20 +37,20 @@ #import "godot_view.h" #include "ios.h" #import "keyboard_input_view.h" -#include "os_iphone.h" +#include "os_ios.h" #include "tts_ios.h" #import "view_controller.h" #import <Foundation/Foundation.h> #import <sys/utsname.h> -static const float kDisplayServerIPhoneAcceleration = 1; +static const float kDisplayServerIOSAcceleration = 1.f; -DisplayServerIPhone *DisplayServerIPhone::get_singleton() { - return (DisplayServerIPhone *)DisplayServer::get_singleton(); +DisplayServerIOS *DisplayServerIOS::get_singleton() { + return (DisplayServerIOS *)DisplayServer::get_singleton(); } -DisplayServerIPhone::DisplayServerIPhone(const String &p_rendering_driver, WindowMode p_mode, DisplayServer::VSyncMode p_vsync_mode, uint32_t p_flags, const Vector2i &p_resolution, Error &r_error) { +DisplayServerIOS::DisplayServerIOS(const String &p_rendering_driver, WindowMode p_mode, DisplayServer::VSyncMode p_vsync_mode, uint32_t p_flags, const Vector2i &p_resolution, Error &r_error) { rendering_driver = p_rendering_driver; // Init TTS @@ -101,7 +101,7 @@ DisplayServerIPhone::DisplayServerIPhone(const String &p_rendering_driver, Windo rendering_device_vulkan = nullptr; if (rendering_driver == "vulkan") { - context_vulkan = memnew(VulkanContextIPhone); + context_vulkan = memnew(VulkanContextIOS); if (context_vulkan->initialize() != OK) { memdelete(context_vulkan); context_vulkan = nullptr; @@ -128,7 +128,7 @@ DisplayServerIPhone::DisplayServerIPhone(const String &p_rendering_driver, Windo } #endif - bool keep_screen_on = bool(GLOBAL_DEF("display/window/energy_saving/keep_screen_on", true)); + bool keep_screen_on = bool(GLOBAL_GET("display/window/energy_saving/keep_screen_on")); screen_set_keep_on(keep_screen_on); Input::get_singleton()->set_event_dispatch_function(_dispatch_input_events); @@ -136,7 +136,7 @@ DisplayServerIPhone::DisplayServerIPhone(const String &p_rendering_driver, Windo r_error = OK; } -DisplayServerIPhone::~DisplayServerIPhone() { +DisplayServerIOS::~DisplayServerIOS() { #if defined(VULKAN_ENABLED) if (rendering_device_vulkan) { rendering_device_vulkan->finalize(); @@ -152,11 +152,11 @@ DisplayServerIPhone::~DisplayServerIPhone() { #endif } -DisplayServer *DisplayServerIPhone::create_func(const String &p_rendering_driver, WindowMode p_mode, DisplayServer::VSyncMode p_vsync_mode, uint32_t p_flags, const Vector2i &p_resolution, Error &r_error) { - return memnew(DisplayServerIPhone(p_rendering_driver, p_mode, p_vsync_mode, p_flags, p_resolution, r_error)); +DisplayServer *DisplayServerIOS::create_func(const String &p_rendering_driver, WindowMode p_mode, DisplayServer::VSyncMode p_vsync_mode, uint32_t p_flags, const Vector2i &p_resolution, Error &r_error) { + return memnew(DisplayServerIOS(p_rendering_driver, p_mode, p_vsync_mode, p_flags, p_resolution, r_error)); } -Vector<String> DisplayServerIPhone::get_rendering_drivers_func() { +Vector<String> DisplayServerIOS::get_rendering_drivers_func() { Vector<String> drivers; #if defined(VULKAN_ENABLED) @@ -169,56 +169,57 @@ Vector<String> DisplayServerIPhone::get_rendering_drivers_func() { return drivers; } -void DisplayServerIPhone::register_iphone_driver() { - register_create_function("iphone", create_func, get_rendering_drivers_func); +void DisplayServerIOS::register_ios_driver() { + register_create_function("iOS", create_func, get_rendering_drivers_func); } // MARK: Events -void DisplayServerIPhone::window_set_rect_changed_callback(const Callable &p_callable, WindowID p_window) { +void DisplayServerIOS::window_set_rect_changed_callback(const Callable &p_callable, WindowID p_window) { window_resize_callback = p_callable; } -void DisplayServerIPhone::window_set_window_event_callback(const Callable &p_callable, WindowID p_window) { +void DisplayServerIOS::window_set_window_event_callback(const Callable &p_callable, WindowID p_window) { window_event_callback = p_callable; } -void DisplayServerIPhone::window_set_input_event_callback(const Callable &p_callable, WindowID p_window) { +void DisplayServerIOS::window_set_input_event_callback(const Callable &p_callable, WindowID p_window) { input_event_callback = p_callable; } -void DisplayServerIPhone::window_set_input_text_callback(const Callable &p_callable, WindowID p_window) { +void DisplayServerIOS::window_set_input_text_callback(const Callable &p_callable, WindowID p_window) { input_text_callback = p_callable; } -void DisplayServerIPhone::window_set_drop_files_callback(const Callable &p_callable, WindowID p_window) { +void DisplayServerIOS::window_set_drop_files_callback(const Callable &p_callable, WindowID p_window) { // Probably not supported for iOS } -void DisplayServerIPhone::process_events() { +void DisplayServerIOS::process_events() { + Input::get_singleton()->flush_buffered_events(); } -void DisplayServerIPhone::_dispatch_input_events(const Ref<InputEvent> &p_event) { - DisplayServerIPhone::get_singleton()->send_input_event(p_event); +void DisplayServerIOS::_dispatch_input_events(const Ref<InputEvent> &p_event) { + DisplayServerIOS::get_singleton()->send_input_event(p_event); } -void DisplayServerIPhone::send_input_event(const Ref<InputEvent> &p_event) const { +void DisplayServerIOS::send_input_event(const Ref<InputEvent> &p_event) const { _window_callback(input_event_callback, p_event); } -void DisplayServerIPhone::send_input_text(const String &p_text) const { +void DisplayServerIOS::send_input_text(const String &p_text) const { _window_callback(input_text_callback, p_text); } -void DisplayServerIPhone::send_window_event(DisplayServer::WindowEvent p_event) const { +void DisplayServerIOS::send_window_event(DisplayServer::WindowEvent p_event) const { _window_callback(window_event_callback, int(p_event)); } -void DisplayServerIPhone::_window_callback(const Callable &p_callable, const Variant &p_arg) const { +void DisplayServerIOS::_window_callback(const Callable &p_callable, const Variant &p_arg) const { if (!p_callable.is_null()) { const Variant *argp = &p_arg; Variant ret; Callable::CallError ce; - p_callable.call((const Variant **)&argp, 1, ret, ce); + p_callable.callp((const Variant **)&argp, 1, ret, ce); } } @@ -226,7 +227,7 @@ void DisplayServerIPhone::_window_callback(const Callable &p_callable, const Var // MARK: Touches -void DisplayServerIPhone::touch_press(int p_idx, int p_x, int p_y, bool p_pressed, bool p_double_click) { +void DisplayServerIOS::touch_press(int p_idx, int p_x, int p_y, bool p_pressed, bool p_double_click) { if (!GLOBAL_DEF("debug/disable_touch", false)) { Ref<InputEventScreenTouch> ev; ev.instantiate(); @@ -238,7 +239,7 @@ void DisplayServerIPhone::touch_press(int p_idx, int p_x, int p_y, bool p_presse } } -void DisplayServerIPhone::touch_drag(int p_idx, int p_prev_x, int p_prev_y, int p_x, int p_y) { +void DisplayServerIOS::touch_drag(int p_idx, int p_prev_x, int p_prev_y, int p_x, int p_y) { if (!GLOBAL_DEF("debug/disable_touch", false)) { Ref<InputEventScreenDrag> ev; ev.instantiate(); @@ -249,17 +250,17 @@ void DisplayServerIPhone::touch_drag(int p_idx, int p_prev_x, int p_prev_y, int } } -void DisplayServerIPhone::perform_event(const Ref<InputEvent> &p_event) { +void DisplayServerIOS::perform_event(const Ref<InputEvent> &p_event) { Input::get_singleton()->parse_input_event(p_event); } -void DisplayServerIPhone::touches_cancelled(int p_idx) { +void DisplayServerIOS::touches_cancelled(int p_idx) { touch_press(p_idx, -1, -1, false, false); } // MARK: Keyboard -void DisplayServerIPhone::key(Key p_key, bool p_pressed) { +void DisplayServerIOS::key(Key p_key, bool p_pressed) { Ref<InputEventKey> ev; ev.instantiate(); ev->set_echo(false); @@ -272,31 +273,31 @@ void DisplayServerIPhone::key(Key p_key, bool p_pressed) { // MARK: Motion -void DisplayServerIPhone::update_gravity(float p_x, float p_y, float p_z) { +void DisplayServerIOS::update_gravity(float p_x, float p_y, float p_z) { Input::get_singleton()->set_gravity(Vector3(p_x, p_y, p_z)); } -void DisplayServerIPhone::update_accelerometer(float p_x, float p_y, float p_z) { +void DisplayServerIOS::update_accelerometer(float p_x, float p_y, float p_z) { // Found out the Z should not be negated! Pass as is! Vector3 v_accelerometer = Vector3( - p_x / kDisplayServerIPhoneAcceleration, - p_y / kDisplayServerIPhoneAcceleration, - p_z / kDisplayServerIPhoneAcceleration); + p_x / kDisplayServerIOSAcceleration, + p_y / kDisplayServerIOSAcceleration, + p_z / kDisplayServerIOSAcceleration); Input::get_singleton()->set_accelerometer(v_accelerometer); } -void DisplayServerIPhone::update_magnetometer(float p_x, float p_y, float p_z) { +void DisplayServerIOS::update_magnetometer(float p_x, float p_y, float p_z) { Input::get_singleton()->set_magnetometer(Vector3(p_x, p_y, p_z)); } -void DisplayServerIPhone::update_gyroscope(float p_x, float p_y, float p_z) { +void DisplayServerIOS::update_gyroscope(float p_x, float p_y, float p_z) { Input::get_singleton()->set_gyroscope(Vector3(p_x, p_y, p_z)); } // MARK: - -bool DisplayServerIPhone::has_feature(Feature p_feature) const { +bool DisplayServerIOS::has_feature(Feature p_feature) const { switch (p_feature) { // case FEATURE_CURSOR_SHAPE: // case FEATURE_CUSTOM_CURSOR_SHAPE: @@ -321,46 +322,46 @@ bool DisplayServerIPhone::has_feature(Feature p_feature) const { } } -String DisplayServerIPhone::get_name() const { - return "iPhone"; +String DisplayServerIOS::get_name() const { + return "iOS"; } -bool DisplayServerIPhone::tts_is_speaking() const { +bool DisplayServerIOS::tts_is_speaking() const { ERR_FAIL_COND_V(!tts, false); return [tts isSpeaking]; } -bool DisplayServerIPhone::tts_is_paused() const { +bool DisplayServerIOS::tts_is_paused() const { ERR_FAIL_COND_V(!tts, false); return [tts isPaused]; } -Array DisplayServerIPhone::tts_get_voices() const { - ERR_FAIL_COND_V(!tts, Array()); +TypedArray<Dictionary> DisplayServerIOS::tts_get_voices() const { + ERR_FAIL_COND_V(!tts, TypedArray<Dictionary>()); return [tts getVoices]; } -void DisplayServerIPhone::tts_speak(const String &p_text, const String &p_voice, int p_volume, float p_pitch, float p_rate, int p_utterance_id, bool p_interrupt) { +void DisplayServerIOS::tts_speak(const String &p_text, const String &p_voice, int p_volume, float p_pitch, float p_rate, int p_utterance_id, bool p_interrupt) { ERR_FAIL_COND(!tts); [tts speak:p_text voice:p_voice volume:p_volume pitch:p_pitch rate:p_rate utterance_id:p_utterance_id interrupt:p_interrupt]; } -void DisplayServerIPhone::tts_pause() { +void DisplayServerIOS::tts_pause() { ERR_FAIL_COND(!tts); [tts pauseSpeaking]; } -void DisplayServerIPhone::tts_resume() { +void DisplayServerIOS::tts_resume() { ERR_FAIL_COND(!tts); [tts resumeSpeaking]; } -void DisplayServerIPhone::tts_stop() { +void DisplayServerIOS::tts_stop() { ERR_FAIL_COND(!tts); [tts stopSpeaking]; } -Rect2i DisplayServerIPhone::get_display_safe_area() const { +Rect2i DisplayServerIOS::get_display_safe_area() const { if (@available(iOS 11, *)) { UIEdgeInsets insets = UIEdgeInsetsZero; UIView *view = AppDelegate.viewController.godotView; @@ -376,15 +377,15 @@ Rect2i DisplayServerIPhone::get_display_safe_area() const { } } -int DisplayServerIPhone::get_screen_count() const { +int DisplayServerIOS::get_screen_count() const { return 1; } -Point2i DisplayServerIPhone::screen_get_position(int p_screen) const { +Point2i DisplayServerIOS::screen_get_position(int p_screen) const { return Size2i(); } -Size2i DisplayServerIPhone::screen_get_size(int p_screen) const { +Size2i DisplayServerIOS::screen_get_size(int p_screen) const { CALayer *layer = AppDelegate.viewController.godotView.renderingLayer; if (!layer) { @@ -394,11 +395,11 @@ Size2i DisplayServerIPhone::screen_get_size(int p_screen) const { return Size2i(layer.bounds.size.width, layer.bounds.size.height) * screen_get_scale(p_screen); } -Rect2i DisplayServerIPhone::screen_get_usable_rect(int p_screen) const { +Rect2i DisplayServerIOS::screen_get_usable_rect(int p_screen) const { return Rect2i(screen_get_position(p_screen), screen_get_size(p_screen)); } -int DisplayServerIPhone::screen_get_dpi(int p_screen) const { +int DisplayServerIOS::screen_get_dpi(int p_screen) const { struct utsname systemInfo; uname(&systemInfo); @@ -435,25 +436,25 @@ int DisplayServerIPhone::screen_get_dpi(int p_screen) const { } } -float DisplayServerIPhone::screen_get_refresh_rate(int p_screen) const { +float DisplayServerIOS::screen_get_refresh_rate(int p_screen) const { return [UIScreen mainScreen].maximumFramesPerSecond; } -float DisplayServerIPhone::screen_get_scale(int p_screen) const { +float DisplayServerIOS::screen_get_scale(int p_screen) const { return [UIScreen mainScreen].nativeScale; } -Vector<DisplayServer::WindowID> DisplayServerIPhone::get_window_list() const { +Vector<DisplayServer::WindowID> DisplayServerIOS::get_window_list() const { Vector<DisplayServer::WindowID> list; list.push_back(MAIN_WINDOW_ID); return list; } -DisplayServer::WindowID DisplayServerIPhone::get_window_at_screen_position(const Point2i &p_position) const { +DisplayServer::WindowID DisplayServerIOS::get_window_at_screen_position(const Point2i &p_position) const { return MAIN_WINDOW_ID; } -int64_t DisplayServerIPhone::window_get_native_handle(HandleType p_handle_type, WindowID p_window) const { +int64_t DisplayServerIOS::window_get_native_handle(HandleType p_handle_type, WindowID p_window) const { ERR_FAIL_COND_V(p_window != MAIN_WINDOW_ID, 0); switch (p_handle_type) { case DISPLAY_HANDLE: { @@ -471,160 +472,192 @@ int64_t DisplayServerIPhone::window_get_native_handle(HandleType p_handle_type, } } -void DisplayServerIPhone::window_attach_instance_id(ObjectID p_instance, WindowID p_window) { +void DisplayServerIOS::window_attach_instance_id(ObjectID p_instance, WindowID p_window) { window_attached_instance_id = p_instance; } -ObjectID DisplayServerIPhone::window_get_attached_instance_id(WindowID p_window) const { +ObjectID DisplayServerIOS::window_get_attached_instance_id(WindowID p_window) const { return window_attached_instance_id; } -void DisplayServerIPhone::window_set_title(const String &p_title, WindowID p_window) { +void DisplayServerIOS::window_set_title(const String &p_title, WindowID p_window) { // Probably not supported for iOS } -int DisplayServerIPhone::window_get_current_screen(WindowID p_window) const { +int DisplayServerIOS::window_get_current_screen(WindowID p_window) const { return SCREEN_OF_MAIN_WINDOW; } -void DisplayServerIPhone::window_set_current_screen(int p_screen, WindowID p_window) { +void DisplayServerIOS::window_set_current_screen(int p_screen, WindowID p_window) { // Probably not supported for iOS } -Point2i DisplayServerIPhone::window_get_position(WindowID p_window) const { +Point2i DisplayServerIOS::window_get_position(WindowID p_window) const { return Point2i(); } -void DisplayServerIPhone::window_set_position(const Point2i &p_position, WindowID p_window) { +void DisplayServerIOS::window_set_position(const Point2i &p_position, WindowID p_window) { // Probably not supported for single window iOS app } -void DisplayServerIPhone::window_set_transient(WindowID p_window, WindowID p_parent) { +void DisplayServerIOS::window_set_transient(WindowID p_window, WindowID p_parent) { // Probably not supported for iOS } -void DisplayServerIPhone::window_set_max_size(const Size2i p_size, WindowID p_window) { +void DisplayServerIOS::window_set_max_size(const Size2i p_size, WindowID p_window) { // Probably not supported for iOS } -Size2i DisplayServerIPhone::window_get_max_size(WindowID p_window) const { +Size2i DisplayServerIOS::window_get_max_size(WindowID p_window) const { return Size2i(); } -void DisplayServerIPhone::window_set_min_size(const Size2i p_size, WindowID p_window) { +void DisplayServerIOS::window_set_min_size(const Size2i p_size, WindowID p_window) { // Probably not supported for iOS } -Size2i DisplayServerIPhone::window_get_min_size(WindowID p_window) const { +Size2i DisplayServerIOS::window_get_min_size(WindowID p_window) const { return Size2i(); } -void DisplayServerIPhone::window_set_size(const Size2i p_size, WindowID p_window) { +void DisplayServerIOS::window_set_size(const Size2i p_size, WindowID p_window) { // Probably not supported for iOS } -Size2i DisplayServerIPhone::window_get_size(WindowID p_window) const { +Size2i DisplayServerIOS::window_get_size(WindowID p_window) const { CGRect screenBounds = [UIScreen mainScreen].bounds; return Size2i(screenBounds.size.width, screenBounds.size.height) * screen_get_max_scale(); } -Size2i DisplayServerIPhone::window_get_real_size(WindowID p_window) const { +Size2i DisplayServerIOS::window_get_real_size(WindowID p_window) const { return window_get_size(p_window); } -void DisplayServerIPhone::window_set_mode(WindowMode p_mode, WindowID p_window) { +void DisplayServerIOS::window_set_mode(WindowMode p_mode, WindowID p_window) { // Probably not supported for iOS } -DisplayServer::WindowMode DisplayServerIPhone::window_get_mode(WindowID p_window) const { +DisplayServer::WindowMode DisplayServerIOS::window_get_mode(WindowID p_window) const { return WindowMode::WINDOW_MODE_FULLSCREEN; } -bool DisplayServerIPhone::window_is_maximize_allowed(WindowID p_window) const { +bool DisplayServerIOS::window_is_maximize_allowed(WindowID p_window) const { return false; } -void DisplayServerIPhone::window_set_flag(WindowFlags p_flag, bool p_enabled, WindowID p_window) { +void DisplayServerIOS::window_set_flag(WindowFlags p_flag, bool p_enabled, WindowID p_window) { // Probably not supported for iOS } -bool DisplayServerIPhone::window_get_flag(WindowFlags p_flag, WindowID p_window) const { +bool DisplayServerIOS::window_get_flag(WindowFlags p_flag, WindowID p_window) const { return false; } -void DisplayServerIPhone::window_request_attention(WindowID p_window) { +void DisplayServerIOS::window_request_attention(WindowID p_window) { // Probably not supported for iOS } -void DisplayServerIPhone::window_move_to_foreground(WindowID p_window) { +void DisplayServerIOS::window_move_to_foreground(WindowID p_window) { // Probably not supported for iOS } -float DisplayServerIPhone::screen_get_max_scale() const { +float DisplayServerIOS::screen_get_max_scale() const { return screen_get_scale(SCREEN_OF_MAIN_WINDOW); } -void DisplayServerIPhone::screen_set_orientation(DisplayServer::ScreenOrientation p_orientation, int p_screen) { +void DisplayServerIOS::screen_set_orientation(DisplayServer::ScreenOrientation p_orientation, int p_screen) { screen_orientation = p_orientation; } -DisplayServer::ScreenOrientation DisplayServerIPhone::screen_get_orientation(int p_screen) const { +DisplayServer::ScreenOrientation DisplayServerIOS::screen_get_orientation(int p_screen) const { return screen_orientation; } -bool DisplayServerIPhone::window_can_draw(WindowID p_window) const { +bool DisplayServerIOS::window_can_draw(WindowID p_window) const { return true; } -bool DisplayServerIPhone::can_any_window_draw() const { +bool DisplayServerIOS::can_any_window_draw() const { return true; } -bool DisplayServerIPhone::screen_is_touchscreen(int p_screen) const { +bool DisplayServerIOS::screen_is_touchscreen(int p_screen) const { return true; } -void DisplayServerIPhone::virtual_keyboard_show(const String &p_existing_text, const Rect2 &p_screen_rect, bool p_multiline, int p_max_length, int p_cursor_start, int p_cursor_end) { +void DisplayServerIOS::virtual_keyboard_show(const String &p_existing_text, const Rect2 &p_screen_rect, VirtualKeyboardType p_type, int p_max_length, int p_cursor_start, int p_cursor_end) { NSString *existingString = [[NSString alloc] initWithUTF8String:p_existing_text.utf8().get_data()]; + AppDelegate.viewController.keyboardView.keyboardType = UIKeyboardTypeDefault; + AppDelegate.viewController.keyboardView.textContentType = nil; + switch (p_type) { + case KEYBOARD_TYPE_DEFAULT: { + AppDelegate.viewController.keyboardView.keyboardType = UIKeyboardTypeDefault; + } break; + case KEYBOARD_TYPE_MULTILINE: { + AppDelegate.viewController.keyboardView.keyboardType = UIKeyboardTypeDefault; + } break; + case KEYBOARD_TYPE_NUMBER: { + AppDelegate.viewController.keyboardView.keyboardType = UIKeyboardTypeNumberPad; + } break; + case KEYBOARD_TYPE_NUMBER_DECIMAL: { + AppDelegate.viewController.keyboardView.keyboardType = UIKeyboardTypeDecimalPad; + } break; + case KEYBOARD_TYPE_PHONE: { + AppDelegate.viewController.keyboardView.keyboardType = UIKeyboardTypePhonePad; + AppDelegate.viewController.keyboardView.textContentType = UITextContentTypeTelephoneNumber; + } break; + case KEYBOARD_TYPE_EMAIL_ADDRESS: { + AppDelegate.viewController.keyboardView.keyboardType = UIKeyboardTypeEmailAddress; + AppDelegate.viewController.keyboardView.textContentType = UITextContentTypeEmailAddress; + } break; + case KEYBOARD_TYPE_PASSWORD: { + AppDelegate.viewController.keyboardView.keyboardType = UIKeyboardTypeDefault; + AppDelegate.viewController.keyboardView.textContentType = UITextContentTypePassword; + } break; + case KEYBOARD_TYPE_URL: { + AppDelegate.viewController.keyboardView.keyboardType = UIKeyboardTypeWebSearch; + AppDelegate.viewController.keyboardView.textContentType = UITextContentTypeURL; + } break; + } + [AppDelegate.viewController.keyboardView becomeFirstResponderWithString:existingString - multiline:p_multiline cursorStart:p_cursor_start cursorEnd:p_cursor_end]; } -void DisplayServerIPhone::virtual_keyboard_hide() { +void DisplayServerIOS::virtual_keyboard_hide() { [AppDelegate.viewController.keyboardView resignFirstResponder]; } -void DisplayServerIPhone::virtual_keyboard_set_height(int height) { +void DisplayServerIOS::virtual_keyboard_set_height(int height) { virtual_keyboard_height = height * screen_get_max_scale(); } -int DisplayServerIPhone::virtual_keyboard_get_height() const { +int DisplayServerIOS::virtual_keyboard_get_height() const { return virtual_keyboard_height; } -void DisplayServerIPhone::clipboard_set(const String &p_text) { +void DisplayServerIOS::clipboard_set(const String &p_text) { [UIPasteboard generalPasteboard].string = [NSString stringWithUTF8String:p_text.utf8()]; } -String DisplayServerIPhone::clipboard_get() const { +String DisplayServerIOS::clipboard_get() const { NSString *text = [UIPasteboard generalPasteboard].string; return String::utf8([text UTF8String]); } -void DisplayServerIPhone::screen_set_keep_on(bool p_enable) { +void DisplayServerIOS::screen_set_keep_on(bool p_enable) { [UIApplication sharedApplication].idleTimerDisabled = p_enable; } -bool DisplayServerIPhone::screen_is_kept_on() const { +bool DisplayServerIOS::screen_is_kept_on() const { return [UIApplication sharedApplication].idleTimerDisabled; } -void DisplayServerIPhone::resize_window(CGSize viewSize) { +void DisplayServerIOS::resize_window(CGSize viewSize) { Size2i size = Size2i(viewSize.width, viewSize.height) * screen_get_max_scale(); #if defined(VULKAN_ENABLED) @@ -637,14 +670,14 @@ void DisplayServerIPhone::resize_window(CGSize viewSize) { _window_callback(window_resize_callback, resize_rect); } -void DisplayServerIPhone::window_set_vsync_mode(DisplayServer::VSyncMode p_vsync_mode, WindowID p_window) { +void DisplayServerIOS::window_set_vsync_mode(DisplayServer::VSyncMode p_vsync_mode, WindowID p_window) { _THREAD_SAFE_METHOD_ #if defined(VULKAN_ENABLED) context_vulkan->set_vsync_mode(p_window, p_vsync_mode); #endif } -DisplayServer::VSyncMode DisplayServerIPhone::window_get_vsync_mode(WindowID p_window) const { +DisplayServer::VSyncMode DisplayServerIOS::window_get_vsync_mode(WindowID p_window) const { _THREAD_SAFE_METHOD_ #if defined(VULKAN_ENABLED) return context_vulkan->get_vsync_mode(p_window); diff --git a/platform/iphone/export/export.cpp b/platform/ios/export/export.cpp index 3b02e661c1..6024db2f2c 100644 --- a/platform/iphone/export/export.cpp +++ b/platform/ios/export/export.cpp @@ -30,9 +30,10 @@ #include "export.h" +#include "editor/export/editor_export.h" #include "export_plugin.h" -void register_iphone_exporter() { +void register_ios_exporter() { Ref<EditorExportPlatformIOS> platform; platform.instantiate(); diff --git a/platform/osx/export/export.h b/platform/ios/export/export.h index b386337a09..756a1356ea 100644 --- a/platform/osx/export/export.h +++ b/platform/ios/export/export.h @@ -28,9 +28,9 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ -#ifndef OSX_EXPORT_H -#define OSX_EXPORT_H +#ifndef IOS_EXPORT_H +#define IOS_EXPORT_H -void register_osx_exporter(); +void register_ios_exporter(); -#endif // OSX_EXPORT_H +#endif // IOS_EXPORT_H diff --git a/platform/iphone/export/export_plugin.cpp b/platform/ios/export/export_plugin.cpp index 3b92bd19be..7aacb2de85 100644 --- a/platform/iphone/export/export_plugin.cpp +++ b/platform/ios/export/export_plugin.cpp @@ -30,9 +30,10 @@ #include "export_plugin.h" +#include "core/string/translation.h" #include "editor/editor_node.h" -void EditorExportPlatformIOS::get_preset_features(const Ref<EditorExportPreset> &p_preset, List<String> *r_features) { +void EditorExportPlatformIOS::get_preset_features(const Ref<EditorExportPreset> &p_preset, List<String> *r_features) const { String driver = ProjectSettings::get_singleton()->get("rendering/driver/driver_name"); // Vulkan and OpenGL ES 3.0 both mandate ETC2 support. r_features->push_back("etc2"); @@ -43,7 +44,7 @@ void EditorExportPlatformIOS::get_preset_features(const Ref<EditorExportPreset> } } -Vector<EditorExportPlatformIOS::ExportArchitecture> EditorExportPlatformIOS::_get_supported_architectures() { +Vector<EditorExportPlatformIOS::ExportArchitecture> EditorExportPlatformIOS::_get_supported_architectures() const { Vector<ExportArchitecture> archs; archs.push_back(ExportArchitecture("arm64", true)); return archs; @@ -139,27 +140,27 @@ 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())); - r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "icons/iphone_120x120", PROPERTY_HINT_FILE, "*.png"), "")); // Home screen on iPhone/iPod Touch with Retina display - r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "icons/iphone_180x180", PROPERTY_HINT_FILE, "*.png"), "")); // Home screen on iPhone with Retina HD display + r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "icons/iphone_120x120", PROPERTY_HINT_FILE, "*.png,*.jpg,*.jpeg"), "")); // Home screen on iPhone/iPod Touch with Retina display + r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "icons/iphone_180x180", PROPERTY_HINT_FILE, "*.png,*.jpg,*.jpeg"), "")); // Home screen on iPhone with Retina HD display - r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "icons/ipad_76x76", PROPERTY_HINT_FILE, "*.png"), "")); // Home screen on iPad - r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "icons/ipad_152x152", PROPERTY_HINT_FILE, "*.png"), "")); // Home screen on iPad with Retina display - r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "icons/ipad_167x167", PROPERTY_HINT_FILE, "*.png"), "")); // Home screen on iPad Pro + r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "icons/ipad_76x76", PROPERTY_HINT_FILE, "*.png,*.jpg,*.jpeg"), "")); // Home screen on iPad + r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "icons/ipad_152x152", PROPERTY_HINT_FILE, "*.png,*.jpg,*.jpeg"), "")); // Home screen on iPad with Retina display + r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "icons/ipad_167x167", PROPERTY_HINT_FILE, "*.png,*.jpg,*.jpeg"), "")); // Home screen on iPad Pro - r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "icons/app_store_1024x1024", PROPERTY_HINT_FILE, "*.png"), "")); // App Store + r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "icons/app_store_1024x1024", PROPERTY_HINT_FILE, "*.png,*.jpg,*.jpeg"), "")); // App Store - r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "icons/spotlight_40x40", PROPERTY_HINT_FILE, "*.png"), "")); // Spotlight - r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "icons/spotlight_80x80", PROPERTY_HINT_FILE, "*.png"), "")); // Spotlight on devices with Retina display + r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "icons/spotlight_40x40", PROPERTY_HINT_FILE, "*.png,*.jpg,*.jpeg"), "")); // Spotlight + r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "icons/spotlight_80x80", PROPERTY_HINT_FILE, "*.png,*.jpg,*.jpeg"), "")); // Spotlight on devices with Retina display r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "storyboard/use_launch_screen_storyboard"), false)); r_options->push_back(ExportOption(PropertyInfo(Variant::INT, "storyboard/image_scale_mode", PROPERTY_HINT_ENUM, "Same as Logo,Center,Scale to Fit,Scale to Fill,Scale"), 0)); - r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "storyboard/custom_image@2x", PROPERTY_HINT_FILE, "*.png"), "")); - r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "storyboard/custom_image@3x", PROPERTY_HINT_FILE, "*.png"), "")); + r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "storyboard/custom_image@2x", PROPERTY_HINT_FILE, "*.png,*.jpg,*.jpeg"), "")); + r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "storyboard/custom_image@3x", PROPERTY_HINT_FILE, "*.png,*.jpg,*.jpeg"), "")); r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "storyboard/use_custom_bg_color"), false)); r_options->push_back(ExportOption(PropertyInfo(Variant::COLOR, "storyboard/custom_bg_color"), Color())); for (uint64_t i = 0; i < sizeof(loading_screen_infos) / sizeof(loading_screen_infos[0]); ++i) { - r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, loading_screen_infos[i].preset_key, PROPERTY_HINT_FILE, "*.png"), "")); + r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, loading_screen_infos[i].preset_key, PROPERTY_HINT_FILE, "*.png,*.jpg,*.jpeg"), "")); } } @@ -386,13 +387,17 @@ void EditorExportPlatformIOS::_fix_config_file(const Ref<EditorExportPreset> &p_ String locale_files; Vector<String> translations = ProjectSettings::get_singleton()->get("internationalization/locale/translations"); if (translations.size() > 0) { - int index = 0; + HashSet<String> languages; for (const String &E : translations) { Ref<Translation> tr = ResourceLoader::load(E); - if (tr.is_valid()) { - String lang = tr->get_locale(); - locale_files += "D0BCFE4518AEBDA2004A" + itos(index).pad_zeros(4) + " /* " + lang + " */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = " + lang + "; path = " + lang + ".lproj/InfoPlist.strings; sourceTree = \"<group>\"; };"; + if (tr.is_valid() && tr->get_locale() != "en") { + languages.insert(tr->get_locale()); } + } + + int index = 0; + for (const String &lang : languages) { + locale_files += "D0BCFE4518AEBDA2004A" + itos(index).pad_zeros(4) + " /* " + lang + " */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = " + lang + "; path = " + lang + ".lproj/InfoPlist.strings; sourceTree = \"<group>\"; };\n"; index++; } } @@ -401,24 +406,57 @@ void EditorExportPlatformIOS::_fix_config_file(const Ref<EditorExportPreset> &p_ String locale_files; Vector<String> translations = ProjectSettings::get_singleton()->get("internationalization/locale/translations"); if (translations.size() > 0) { - int index = 0; + HashSet<String> languages; for (const String &E : translations) { Ref<Translation> tr = ResourceLoader::load(E); - if (tr.is_valid()) { - String lang = tr->get_locale(); - locale_files += "D0BCFE4518AEBDA2004A" + itos(index).pad_zeros(4) + " /* " + lang + " */,"; + if (tr.is_valid() && tr->get_locale() != "en") { + languages.insert(tr->get_locale()); } + } + + int index = 0; + for (const String &lang : languages) { + locale_files += "D0BCFE4518AEBDA2004A" + itos(index).pad_zeros(4) + " /* " + lang + " */,\n"; index++; } } strnew += lines[i].replace("$pbx_locale_build_reference", locale_files); + } else if (lines[i].find("$swift_runtime_migration") != -1) { + String value = !p_config.use_swift_runtime ? "" : "LastSwiftMigration = 1250;"; + strnew += lines[i].replace("$swift_runtime_migration", value) + "\n"; + } else if (lines[i].find("$swift_runtime_build_settings") != -1) { + String value = !p_config.use_swift_runtime ? "" : R"( + CLANG_ENABLE_MODULES = YES; + SWIFT_OBJC_BRIDGING_HEADER = "$binary/dummy.h"; + SWIFT_VERSION = 5.0; + )"; + value = value.replace("$binary", p_config.binary_name); + strnew += lines[i].replace("$swift_runtime_build_settings", value) + "\n"; + } else if (lines[i].find("$swift_runtime_fileref") != -1) { + String value = !p_config.use_swift_runtime ? "" : R"( + 90B4C2AA2680BC560039117A /* dummy.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "dummy.h"; sourceTree = "<group>"; }; + 90B4C2B52680C7E90039117A /* dummy.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "dummy.swift"; sourceTree = "<group>"; }; + )"; + strnew += lines[i].replace("$swift_runtime_fileref", value) + "\n"; + } else if (lines[i].find("$swift_runtime_binary_files") != -1) { + String value = !p_config.use_swift_runtime ? "" : R"( + 90B4C2AA2680BC560039117A /* dummy.h */, + 90B4C2B52680C7E90039117A /* dummy.swift */, + )"; + strnew += lines[i].replace("$swift_runtime_binary_files", value) + "\n"; + } else if (lines[i].find("$swift_runtime_buildfile") != -1) { + String value = !p_config.use_swift_runtime ? "" : "90B4C2B62680C7E90039117A /* dummy.swift in Sources */ = {isa = PBXBuildFile; fileRef = 90B4C2B52680C7E90039117A /* dummy.swift */; };"; + strnew += lines[i].replace("$swift_runtime_buildfile", value) + "\n"; + } 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 { strnew += lines[i] + "\n"; } } // !BAS! I'm assuming the 9 in the original code was a typo. I've added -1 or else it seems to also be adding our terminating zero... - // should apply the same fix in our OSX export. + // should apply the same fix in our macOS export. CharString cs = strnew.utf8(); pfile.resize(cs.size() - 1); for (int i = 0; i < cs.size() - 1; i++) { @@ -501,26 +539,27 @@ struct IconInfo { const char *actual_size_side; const char *scale; const char *unscaled_size; + const bool force_opaque; }; static const IconInfo icon_infos[] = { // Home screen on iPhone - { "icons/iphone_120x120", "iphone", "Icon-120.png", "120", "2x", "60x60" }, - { "icons/iphone_120x120", "iphone", "Icon-120.png", "120", "3x", "40x40" }, - { "icons/iphone_180x180", "iphone", "Icon-180.png", "180", "3x", "60x60" }, + { "icons/iphone_120x120", "iphone", "Icon-120.png", "120", "2x", "60x60", false }, + { "icons/iphone_120x120", "iphone", "Icon-120.png", "120", "3x", "40x40", false }, + { "icons/iphone_180x180", "iphone", "Icon-180.png", "180", "3x", "60x60", false }, // Home screen on iPad - { "icons/ipad_76x76", "ipad", "Icon-76.png", "76", "1x", "76x76" }, - { "icons/ipad_152x152", "ipad", "Icon-152.png", "152", "2x", "76x76" }, - { "icons/ipad_167x167", "ipad", "Icon-167.png", "167", "2x", "83.5x83.5" }, + { "icons/ipad_76x76", "ipad", "Icon-76.png", "76", "1x", "76x76", false }, + { "icons/ipad_152x152", "ipad", "Icon-152.png", "152", "2x", "76x76", false }, + { "icons/ipad_167x167", "ipad", "Icon-167.png", "167", "2x", "83.5x83.5", false }, // App Store - { "icons/app_store_1024x1024", "ios-marketing", "Icon-1024.png", "1024", "1x", "1024x1024" }, + { "icons/app_store_1024x1024", "ios-marketing", "Icon-1024.png", "1024", "1x", "1024x1024", true }, // Spotlight - { "icons/spotlight_40x40", "ipad", "Icon-40.png", "40", "1x", "40x40" }, - { "icons/spotlight_80x80", "iphone", "Icon-80.png", "80", "2x", "40x40" }, - { "icons/spotlight_80x80", "ipad", "Icon-80.png", "80", "2x", "40x40" } + { "icons/spotlight_40x40", "ipad", "Icon-40.png", "40", "1x", "40x40", false }, + { "icons/spotlight_80x80", "iphone", "Icon-80.png", "80", "2x", "40x40", false }, + { "icons/spotlight_80x80", "ipad", "Icon-80.png", "80", "2x", "40x40", false } }; Error EditorExportPlatformIOS::_export_icons(const Ref<EditorExportPreset> &p_preset, const String &p_iconset_dir) { @@ -540,14 +579,17 @@ Error EditorExportPlatformIOS::_export_icons(const Ref<EditorExportPreset> &p_pr Ref<Image> img = memnew(Image); Error err = ImageLoader::load_image(icon_path, img); if (err != OK) { - ERR_PRINT("Invalid icon (" + String(info.preset_key) + "): '" + icon_path + "'."); + add_message(EXPORT_MESSAGE_ERROR, TTR("Export Icons"), vformat("Invalid icon (%s): '%s'.", info.preset_key, icon_path)); + return ERR_UNCONFIGURED; + } + if (info.force_opaque && img->detect_alpha() != Image::ALPHA_NONE) { + add_message(EXPORT_MESSAGE_ERROR, TTR("Export Icons"), vformat("Icon (%s) must be opaque.", info.preset_key)); return ERR_UNCONFIGURED; } img->resize(side_size, side_size); err = img->save_png(p_iconset_dir + info.export_name); if (err) { - String err_str = String("Failed to export icon(" + String(info.preset_key) + "): '" + icon_path + "'."); - ERR_PRINT(err_str.utf8().get_data()); + add_message(EXPORT_MESSAGE_ERROR, TTR("Export Icons"), vformat("Failed to export icon (%s): '%s'.", info.preset_key, icon_path)); return err; } } else { @@ -555,11 +597,15 @@ Error EditorExportPlatformIOS::_export_icons(const Ref<EditorExportPreset> &p_pr Ref<Image> img = memnew(Image); Error err = ImageLoader::load_image(icon_path, img); if (err != OK) { - ERR_PRINT("Invalid icon (" + String(info.preset_key) + "): '" + icon_path + "'."); + add_message(EXPORT_MESSAGE_ERROR, TTR("Export Icons"), vformat("Invalid icon (%s): '%s'.", info.preset_key, icon_path)); + return ERR_UNCONFIGURED; + } + if (info.force_opaque && img->detect_alpha() != Image::ALPHA_NONE) { + add_message(EXPORT_MESSAGE_ERROR, TTR("Export Icons"), vformat("Icon (%s) must be opaque.", info.preset_key)); return ERR_UNCONFIGURED; } if (img->get_width() != side_size || img->get_height() != side_size) { - WARN_PRINT("Icon (" + String(info.preset_key) + "): '" + icon_path + "' has incorrect size (" + String::num_int64(img->get_width()) + "x" + String::num_int64(img->get_height()) + ") and was automatically resized to " + String::num_int64(side_size) + "x" + String::num_int64(side_size) + "."); + add_message(EXPORT_MESSAGE_WARNING, TTR("Export Icons"), vformat("Icon (%s): '%s' has incorrect size %s and was automatically resized to %s.", info.preset_key, icon_path, img->get_size(), Vector2i(side_size, side_size))); img->resize(side_size, side_size); err = img->save_png(p_iconset_dir + info.export_name); } else { @@ -567,8 +613,7 @@ Error EditorExportPlatformIOS::_export_icons(const Ref<EditorExportPreset> &p_pr } if (err) { - String err_str = String("Failed to export icon(" + String(info.preset_key) + "): '" + icon_path + "'."); - ERR_PRINT(err_str.utf8().get_data()); + add_message(EXPORT_MESSAGE_ERROR, TTR("Export Icons"), vformat("Failed to export icon (%s): '%s'.", info.preset_key, icon_path)); return err; } } @@ -604,7 +649,7 @@ Error EditorExportPlatformIOS::_export_loading_screen_file(const Ref<EditorExpor if (custom_launch_image_2x.length() > 0 && custom_launch_image_3x.length() > 0) { Ref<Image> image; - String image_path = p_dest_dir.plus_file("splash@2x.png"); + String image_path = p_dest_dir.path_join("splash@2x.png"); image.instantiate(); Error err = image->load(custom_launch_image_2x); @@ -618,7 +663,7 @@ Error EditorExportPlatformIOS::_export_loading_screen_file(const Ref<EditorExpor } image.unref(); - image_path = p_dest_dir.plus_file("splash@3x.png"); + image_path = p_dest_dir.path_join("splash@3x.png"); image.instantiate(); err = image->load(custom_launch_image_3x); @@ -651,8 +696,8 @@ Error EditorExportPlatformIOS::_export_loading_screen_file(const Ref<EditorExpor // because Godot's own boot logo uses single image for all resolutions. // Also not using @1x image, because devices using this image variant // are not supported by iOS 9, which is minimal target. - const String splash_png_path_2x = p_dest_dir.plus_file("splash@2x.png"); - const String splash_png_path_3x = p_dest_dir.plus_file("splash@3x.png"); + const String splash_png_path_2x = p_dest_dir.path_join("splash@2x.png"); + const String splash_png_path_3x = p_dest_dir.path_join("splash@3x.png"); if (splash->save_png(splash_png_path_2x) != OK) { return ERR_FILE_CANT_WRITE; @@ -767,7 +812,7 @@ Error EditorExportPlatformIOS::_walk_dir_recursive(Ref<DirAccess> &p_da, FileHan dirs.push_back(path); } } else { - Error err = p_handler(current_dir.plus_file(path), p_userdata); + Error err = p_handler(current_dir.path_join(path), p_userdata); if (err) { p_da->list_dir_end(); return err; @@ -983,7 +1028,7 @@ Error EditorExportPlatformIOS::_copy_asset(const String &p_out_dir, const String if (p_is_framework && p_asset.ends_with(".dylib")) { // For iOS we need to turn .dylib into .framework // to be able to send application to AppStore - asset_path = String("dylibs").plus_file(base_dir); + asset_path = String("dylibs").path_join(base_dir); String file_name; @@ -995,12 +1040,12 @@ Error EditorExportPlatformIOS::_copy_asset(const String &p_out_dir, const String String framework_name = file_name + ".framework"; - asset_path = asset_path.plus_file(framework_name); - destination_dir = p_out_dir.plus_file(asset_path); - destination = destination_dir.plus_file(file_name); + asset_path = asset_path.path_join(framework_name); + destination_dir = p_out_dir.path_join(asset_path); + destination = destination_dir.path_join(file_name); create_framework = true; } else if (p_is_framework && (p_asset.ends_with(".framework") || p_asset.ends_with(".xcframework"))) { - asset_path = String("dylibs").plus_file(base_dir); + asset_path = String("dylibs").path_join(base_dir); String file_name; @@ -1010,8 +1055,8 @@ Error EditorExportPlatformIOS::_copy_asset(const String &p_out_dir, const String file_name = *p_custom_file_name; } - asset_path = asset_path.plus_file(file_name); - destination_dir = p_out_dir.plus_file(asset_path); + asset_path = asset_path.path_join(file_name); + destination_dir = p_out_dir.path_join(asset_path); destination = destination_dir; } else { asset_path = base_dir; @@ -1024,9 +1069,9 @@ Error EditorExportPlatformIOS::_copy_asset(const String &p_out_dir, const String file_name = *p_custom_file_name; } - destination_dir = p_out_dir.plus_file(asset_path); - asset_path = asset_path.plus_file(file_name); - destination = p_out_dir.plus_file(asset_path); + destination_dir = p_out_dir.path_join(asset_path); + asset_path = asset_path.path_join(file_name); + destination = p_out_dir.path_join(asset_path); } Ref<DirAccess> filesystem_da = DirAccess::create(DirAccess::ACCESS_FILESYSTEM); @@ -1043,7 +1088,7 @@ Error EditorExportPlatformIOS::_copy_asset(const String &p_out_dir, const String if (err) { return err; } - IOSExportAsset exported_asset = { binary_name.plus_file(asset_path), p_is_framework, p_should_embed }; + IOSExportAsset exported_asset = { binary_name.path_join(asset_path), p_is_framework, p_should_embed }; r_exported_assets.push_back(exported_asset); if (create_framework) { @@ -1061,7 +1106,7 @@ Error EditorExportPlatformIOS::_copy_asset(const String &p_out_dir, const String { List<String> install_name_args; install_name_args.push_back("-id"); - install_name_args.push_back(String("@rpath").plus_file(framework_name).plus_file(file_name)); + install_name_args.push_back(String("@rpath").path_join(framework_name).path_join(file_name)); install_name_args.push_back(destination); OS::get_singleton()->execute("install_name_tool", install_name_args); @@ -1096,7 +1141,7 @@ Error EditorExportPlatformIOS::_copy_asset(const String &p_out_dir, const String String info_plist = info_plist_format.replace("$name", file_name); - Ref<FileAccess> f = FileAccess::open(destination_dir.plus_file("Info.plist"), FileAccess::WRITE); + Ref<FileAccess> f = FileAccess::open(destination_dir.path_join("Info.plist"), FileAccess::WRITE); if (f.is_valid()) { f->store_string(info_plist); } @@ -1155,7 +1200,7 @@ Error EditorExportPlatformIOS::_export_additional_assets(const String &p_out_dir return OK; } -Vector<String> EditorExportPlatformIOS::_get_preset_architectures(const Ref<EditorExportPreset> &p_preset) { +Vector<String> EditorExportPlatformIOS::_get_preset_architectures(const Ref<EditorExportPreset> &p_preset) const { Vector<ExportArchitecture> all_archs = _get_supported_architectures(); Vector<String> enabled_archs; for (int i = 0; i < all_archs.size(); ++i) { @@ -1297,6 +1342,10 @@ Error EditorExportPlatformIOS::_export_ios_plugins(const Ref<EditorExportPreset> plugin_initialization_cpp_code += "\t" + initialization_method; plugin_deinitialization_cpp_code += "\t" + deinitialization_method; + + if (plugin.use_swift_runtime) { + p_config_data.use_swift_runtime = true; + } } // Updating `Info.plist` @@ -1394,7 +1443,7 @@ Error EditorExportPlatformIOS::export_project(const Ref<EditorExportPreset> &p_p if (src_pkg_name.is_empty()) { String err; - src_pkg_name = find_export_template("iphone.zip", &err); + src_pkg_name = find_export_template("ios.zip", &err); if (src_pkg_name.is_empty()) { add_message(EXPORT_MESSAGE_ERROR, TTR("Prepare Templates"), TTR("Export template not found.")); return ERR_FILE_NOT_FOUND; @@ -1444,7 +1493,7 @@ Error EditorExportPlatformIOS::export_project(const Ref<EditorExportPreset> &p_p return ERR_SKIP; } - String library_to_use = "libgodot.iphone." + String(p_debug ? "debug" : "release") + ".xcframework"; + String library_to_use = "libgodot.ios." + String(p_debug ? "debug" : "release") + ".xcframework"; print_line("Static framework: " + library_to_use); String pkg_name; @@ -1478,7 +1527,8 @@ Error EditorExportPlatformIOS::export_project(const Ref<EditorExportPreset> &p_p "", "", "", - Vector<String>() + Vector<String>(), + false }; Vector<IOSExportAsset> assets; @@ -1502,7 +1552,7 @@ Error EditorExportPlatformIOS::export_project(const Ref<EditorExportPreset> &p_p int ret = unzGoToFirstFile(src_pkg_zip); Vector<uint8_t> project_file_data; while (ret == UNZ_OK) { -#if defined(OSX_ENABLED) || defined(X11_ENABLED) +#if defined(MACOS_ENABLED) || defined(X11_ENABLED) bool is_execute = false; #endif @@ -1527,17 +1577,15 @@ Error EditorExportPlatformIOS::export_project(const Ref<EditorExportPreset> &p_p //write - file = file.replace_first("iphone/", ""); - if (files_to_parse.has(file)) { _fix_config_file(p_preset, data, config_data, p_debug); - } else if (file.begins_with("libgodot.iphone")) { + } else if (file.begins_with("libgodot.ios")) { if (!file.begins_with(library_to_use) || file.ends_with(String("/empty"))) { ret = unzGoToNextFile(src_pkg_zip); continue; //ignore! } found_library = true; -#if defined(OSX_ENABLED) || defined(X11_ENABLED) +#if defined(MACOS_ENABLED) || defined(X11_ENABLED) is_execute = true; #endif file = file.replace(library_to_use, binary_name + ".xcframework"); @@ -1580,7 +1628,7 @@ Error EditorExportPlatformIOS::export_project(const Ref<EditorExportPreset> &p_p f->store_buffer(data.ptr(), data.size()); } -#if defined(OSX_ENABLED) || defined(X11_ENABLED) +#if defined(MACOS_ENABLED) || defined(X11_ENABLED) if (is_execute) { // we need execute rights on this file chmod(file.utf8().get_data(), 0755); @@ -1618,27 +1666,31 @@ Error EditorExportPlatformIOS::export_project(const Ref<EditorExportPreset> &p_p f->store_line("NSPhotoLibraryUsageDescription = \"" + p_preset->get("privacy/photolibrary_usage_description").operator String() + "\";"); } + HashSet<String> languages; for (const String &E : translations) { Ref<Translation> tr = ResourceLoader::load(E); - if (tr.is_valid()) { - String lang = tr->get_locale(); - String fname = dest_dir + binary_name + "/" + lang + ".lproj"; - tmp_app_path->make_dir_recursive(fname); - Ref<FileAccess> f = FileAccess::open(fname + "/InfoPlist.strings", FileAccess::WRITE); - f->store_line("/* Localized versions of Info.plist keys */"); - f->store_line(""); - if (appnames.has(lang)) { - f->store_line("CFBundleDisplayName = \"" + appnames[lang].operator String() + "\";"); - } - if (camera_usage_descriptions.has(lang)) { - f->store_line("NSCameraUsageDescription = \"" + camera_usage_descriptions[lang].operator String() + "\";"); - } - if (microphone_usage_descriptions.has(lang)) { - f->store_line("NSMicrophoneUsageDescription = \"" + microphone_usage_descriptions[lang].operator String() + "\";"); - } - if (photolibrary_usage_descriptions.has(lang)) { - f->store_line("NSPhotoLibraryUsageDescription = \"" + photolibrary_usage_descriptions[lang].operator String() + "\";"); - } + if (tr.is_valid() && tr->get_locale() != "en") { + languages.insert(tr->get_locale()); + } + } + + for (const String &lang : languages) { + String fname = dest_dir + binary_name + "/" + lang + ".lproj"; + tmp_app_path->make_dir_recursive(fname); + Ref<FileAccess> f = FileAccess::open(fname + "/InfoPlist.strings", FileAccess::WRITE); + f->store_line("/* Localized versions of Info.plist keys */"); + f->store_line(""); + if (appnames.has(lang)) { + f->store_line("CFBundleDisplayName = \"" + appnames[lang].operator String() + "\";"); + } + if (camera_usage_descriptions.has(lang)) { + f->store_line("NSCameraUsageDescription = \"" + camera_usage_descriptions[lang].operator String() + "\";"); + } + if (microphone_usage_descriptions.has(lang)) { + f->store_line("NSMicrophoneUsageDescription = \"" + microphone_usage_descriptions[lang].operator String() + "\";"); + } + if (photolibrary_usage_descriptions.has(lang)) { + f->store_line("NSPhotoLibraryUsageDescription = \"" + photolibrary_usage_descriptions[lang].operator String() + "\";"); } } } @@ -1725,7 +1777,7 @@ Error EditorExportPlatformIOS::export_project(const Ref<EditorExportPreset> &p_p f->store_buffer(project_file_data.ptr(), project_file_data.size()); } -#ifdef OSX_ENABLED +#ifdef MACOS_ENABLED { if (ep.step("Code-signing dylibs", 2)) { return ERR_SKIP; @@ -1784,13 +1836,13 @@ Error EditorExportPlatformIOS::export_project(const Ref<EditorExportPreset> &p_p return OK; } -bool EditorExportPlatformIOS::can_export(const Ref<EditorExportPreset> &p_preset, String &r_error, bool &r_missing_templates) const { +bool EditorExportPlatformIOS::has_valid_export_configuration(const Ref<EditorExportPreset> &p_preset, String &r_error, bool &r_missing_templates) const { String err; bool valid = false; // Look for export templates (first official, and if defined custom templates). - bool dvalid = exists_export_template("iphone.zip", &err); + bool dvalid = exists_export_template("ios.zip", &err); bool rvalid = dvalid; // Both in the same ZIP. if (p_preset->get("custom_template/debug") != "") { @@ -1809,7 +1861,18 @@ bool EditorExportPlatformIOS::can_export(const Ref<EditorExportPreset> &p_preset valid = dvalid || rvalid; r_missing_templates = !valid; - // Validate the rest of the configuration. + if (!err.is_empty()) { + r_error = err; + } + + return valid; +} + +bool EditorExportPlatformIOS::has_valid_project_configuration(const Ref<EditorExportPreset> &p_preset, String &r_error) const { + String err; + bool valid = true; + + // Validate the project configuration. String team_id = p_preset->get("application/app_store_team_id"); if (team_id.length() == 0) { @@ -1838,12 +1901,16 @@ bool EditorExportPlatformIOS::can_export(const Ref<EditorExportPreset> &p_preset } EditorExportPlatformIOS::EditorExportPlatformIOS() { - logo = ImageTexture::create_from_image(memnew(Image(_iphone_logo))); + logo = ImageTexture::create_from_image(memnew(Image(_ios_logo))); plugins_changed.set(); +#ifndef ANDROID_ENABLED check_for_changes_thread.start(_check_for_changes_poll_thread, this); +#endif } EditorExportPlatformIOS::~EditorExportPlatformIOS() { +#ifndef ANDROID_ENABLED quit_request.set(); check_for_changes_thread.wait_to_finish(); +#endif } diff --git a/platform/iphone/export/export_plugin.h b/platform/ios/export/export_plugin.h index 1db7418e3f..639f2416a5 100644 --- a/platform/iphone/export/export_plugin.h +++ b/platform/ios/export/export_plugin.h @@ -28,8 +28,8 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ -#ifndef IPHONE_EXPORT_PLUGIN_H -#define IPHONE_EXPORT_PLUGIN_H +#ifndef IOS_EXPORT_PLUGIN_H +#define IOS_EXPORT_PLUGIN_H #include "core/config/project_settings.h" #include "core/io/file_access.h" @@ -40,10 +40,10 @@ #include "core/os/os.h" #include "core/templates/safe_refcount.h" #include "core/version.h" -#include "editor/editor_export.h" #include "editor/editor_settings.h" +#include "editor/export/editor_export_platform.h" #include "main/splash.gen.h" -#include "platform/iphone/logo.gen.h" +#include "platform/ios/logo.gen.h" #include "string.h" #include "godot_plugin_config.h" @@ -57,8 +57,10 @@ class EditorExportPlatformIOS : public EditorExportPlatform { // Plugins SafeFlag plugins_changed; +#ifndef ANDROID_ENABLED Thread check_for_changes_thread; SafeFlag quit_request; +#endif Mutex plugins_lock; Vector<PluginConfigIOS> plugins; @@ -79,6 +81,7 @@ class EditorExportPlatformIOS : public EditorExportPlatform { String modules_buildphase; String modules_buildgrp; Vector<String> capabilities; + bool use_swift_runtime; }; struct ExportArchitecture { String name; @@ -106,8 +109,8 @@ class EditorExportPlatformIOS : public EditorExportPlatform { Error _export_loading_screen_file(const Ref<EditorExportPreset> &p_preset, const String &p_dest_dir); Error _export_icons(const Ref<EditorExportPreset> &p_preset, const String &p_iconset_dir); - Vector<ExportArchitecture> _get_supported_architectures(); - Vector<String> _get_preset_architectures(const Ref<EditorExportPreset> &p_preset); + Vector<ExportArchitecture> _get_supported_architectures() const; + Vector<String> _get_preset_architectures(const Ref<EditorExportPreset> &p_preset) const; void _add_assets_to_project(const Ref<EditorExportPreset> &p_preset, Vector<uint8_t> &p_project_data, const Vector<IOSExportAsset> &p_additional_assets); Error _export_additional_assets(const String &p_out_dir, const Vector<String> &p_assets, bool p_is_framework, bool p_should_embed, Vector<IOSExportAsset> &r_exported_assets); @@ -138,6 +141,7 @@ class EditorExportPlatformIOS : public EditorExportPlatform { return true; } +#ifndef ANDROID_ENABLED static void _check_for_changes_poll_thread(void *ud) { EditorExportPlatformIOS *ea = static_cast<EditorExportPlatformIOS *>(ud); @@ -171,9 +175,10 @@ class EditorExportPlatformIOS : public EditorExportPlatform { } } } +#endif protected: - virtual void get_preset_features(const Ref<EditorExportPreset> &p_preset, List<String> *r_features) override; + virtual void get_preset_features(const Ref<EditorExportPreset> &p_preset, List<String> *r_features) const override; virtual void get_export_options(List<ExportOption> *r_options) override; public: @@ -197,9 +202,10 @@ public: } virtual Error export_project(const Ref<EditorExportPreset> &p_preset, bool p_debug, const String &p_path, int p_flags = 0) override; - virtual bool can_export(const Ref<EditorExportPreset> &p_preset, String &r_error, bool &r_missing_templates) const override; + virtual bool has_valid_export_configuration(const Ref<EditorExportPreset> &p_preset, String &r_error, bool &r_missing_templates) const override; + virtual bool has_valid_project_configuration(const Ref<EditorExportPreset> &p_preset, String &r_error) const override; - virtual void get_platform_features(List<String> *r_features) override { + virtual void get_platform_features(List<String> *r_features) const override { r_features->push_back("mobile"); r_features->push_back("ios"); } @@ -232,9 +238,9 @@ public: if (da->current_is_dir()) { if (p_check_directories) { - Vector<String> directory_files = list_plugin_config_files(p_path.plus_file(file), false); + Vector<String> directory_files = list_plugin_config_files(p_path.path_join(file), false); for (int i = 0; i < directory_files.size(); ++i) { - dir_files.push_back(file.plus_file(directory_files[i])); + dir_files.push_back(file.path_join(directory_files[i])); } } @@ -254,7 +260,7 @@ public: static Vector<PluginConfigIOS> get_plugins() { Vector<PluginConfigIOS> loaded_plugins; - String plugins_dir = ProjectSettings::get_singleton()->get_resource_path().plus_file("ios/plugins"); + String plugins_dir = ProjectSettings::get_singleton()->get_resource_path().path_join("ios/plugins"); if (DirAccess::exists(plugins_dir)) { Vector<String> plugins_filenames = list_plugin_config_files(plugins_dir, true); @@ -262,7 +268,7 @@ public: if (!plugins_filenames.is_empty()) { Ref<ConfigFile> config_file = memnew(ConfigFile); for (int i = 0; i < plugins_filenames.size(); i++) { - PluginConfigIOS config = PluginConfigIOS::load_plugin_config(config_file, plugins_dir.plus_file(plugins_filenames[i])); + PluginConfigIOS config = PluginConfigIOS::load_plugin_config(config_file, plugins_dir.path_join(plugins_filenames[i])); if (config.valid_config) { loaded_plugins.push_back(config); } else { @@ -290,4 +296,4 @@ public: } }; -#endif +#endif // IOS_EXPORT_PLUGIN_H diff --git a/platform/iphone/export/godot_plugin_config.cpp b/platform/ios/export/godot_plugin_config.cpp index 9118b95337..42797d449b 100644 --- a/platform/iphone/export/godot_plugin_config.cpp +++ b/platform/ios/export/godot_plugin_config.cpp @@ -46,7 +46,7 @@ String PluginConfigIOS::resolve_local_dependency_path(String plugin_config_dir, } String res_path = ProjectSettings::get_singleton()->globalize_path("res://"); - absolute_path = plugin_config_dir.plus_file(dependency_path); + absolute_path = plugin_config_dir.path_join(dependency_path); return absolute_path.replace(res_path, "res://"); } @@ -64,7 +64,7 @@ String PluginConfigIOS::resolve_system_dependency_path(String dependency_path) { String system_path = "/System/Library/Frameworks"; - return system_path.plus_file(dependency_path); + return system_path.path_join(dependency_path); } Vector<String> PluginConfigIOS::resolve_local_dependencies(String plugin_config_dir, Vector<String> p_paths) { @@ -121,8 +121,8 @@ bool PluginConfigIOS::validate_plugin(PluginConfigIOS &plugin_config) { String file_path = plugin_config.binary.get_base_dir(); String file_name = plugin_config.binary.get_basename().get_file(); String file_extension = plugin_config.binary.get_extension(); - String release_file_name = file_path.plus_file(file_name + ".release." + file_extension); - String debug_file_name = file_path.plus_file(file_name + ".debug." + file_extension); + String release_file_name = file_path.path_join(file_name + ".release." + file_extension); + String debug_file_name = file_path.path_join(file_name + ".debug." + file_extension); if ((plugin_extension == "a" && FileAccess::exists(release_file_name) && FileAccess::exists(debug_file_name)) || (plugin_extension == "xcframework" && DirAccess::exists(release_file_name) && DirAccess::exists(debug_file_name))) { @@ -144,7 +144,7 @@ String PluginConfigIOS::get_plugin_main_binary(PluginConfigIOS &plugin_config, b String plugin_extension = plugin_config.binary.get_extension(); String plugin_file = plugin_name_prefix + "." + (p_debug ? "debug" : "release") + "." + plugin_extension; - return plugin_binary_dir.plus_file(plugin_file); + return plugin_binary_dir.path_join(plugin_file); } uint64_t PluginConfigIOS::get_plugin_modification_time(const PluginConfigIOS &plugin_config, const String &config_path) { @@ -156,8 +156,8 @@ uint64_t PluginConfigIOS::get_plugin_modification_time(const PluginConfigIOS &pl String file_path = plugin_config.binary.get_base_dir(); String file_name = plugin_config.binary.get_basename().get_file(); String plugin_extension = plugin_config.binary.get_extension(); - String release_file_name = file_path.plus_file(file_name + ".release." + plugin_extension); - String debug_file_name = file_path.plus_file(file_name + ".debug." + plugin_extension); + String release_file_name = file_path.path_join(file_name + ".release." + plugin_extension); + String debug_file_name = file_path.path_join(file_name + ".debug." + plugin_extension); last_updated = MAX(last_updated, FileAccess::get_modified_time(release_file_name)); last_updated = MAX(last_updated, FileAccess::get_modified_time(debug_file_name)); @@ -184,6 +184,7 @@ PluginConfigIOS PluginConfigIOS::load_plugin_config(Ref<ConfigFile> config_file, String config_base_dir = path.get_base_dir(); plugin_config.name = config_file->get_value(PluginConfigIOS::CONFIG_SECTION, PluginConfigIOS::CONFIG_NAME_KEY, String()); + plugin_config.use_swift_runtime = config_file->get_value(PluginConfigIOS::CONFIG_SECTION, PluginConfigIOS::CONFIG_USE_SWIFT_KEY, false); plugin_config.initialization_method = config_file->get_value(PluginConfigIOS::CONFIG_SECTION, PluginConfigIOS::CONFIG_INITIALIZE_KEY, String()); plugin_config.deinitialization_method = config_file->get_value(PluginConfigIOS::CONFIG_SECTION, PluginConfigIOS::CONFIG_DEINITIALIZE_KEY, String()); diff --git a/platform/iphone/export/godot_plugin_config.h b/platform/ios/export/godot_plugin_config.h index 9ef8aa8c6d..98e8456ed5 100644 --- a/platform/iphone/export/godot_plugin_config.h +++ b/platform/ios/export/godot_plugin_config.h @@ -28,8 +28,8 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ -#ifndef IPHONE_GODOT_PLUGIN_CONFIG_H -#define IPHONE_GODOT_PLUGIN_CONFIG_H +#ifndef IOS_GODOT_PLUGIN_CONFIG_H +#define IOS_GODOT_PLUGIN_CONFIG_H #include "core/error/error_list.h" #include "core/io/config_file.h" @@ -39,6 +39,7 @@ The `config` section and fields are required and defined as follow: - **name**: name of the plugin - **binary**: path to static `.a` library +- **use_swift_runtime**: optional boolean field used to determine if Swift runtime is used The `dependencies` and fields are optional. - **linked**: dependencies that should only be linked. @@ -57,6 +58,7 @@ struct PluginConfigIOS { inline static const char *CONFIG_SECTION = "config"; inline static const char *CONFIG_NAME_KEY = "name"; inline static const char *CONFIG_BINARY_KEY = "binary"; + inline static const char *CONFIG_USE_SWIFT_KEY = "use_swift_runtime"; inline static const char *CONFIG_INITIALIZE_KEY = "initialization"; inline static const char *CONFIG_DEINITIALIZE_KEY = "deinitialization"; @@ -93,6 +95,7 @@ struct PluginConfigIOS { // Required config section String name; String binary; + bool use_swift_runtime; String initialization_method; String deinitialization_method; @@ -129,4 +132,4 @@ struct PluginConfigIOS { static PluginConfigIOS load_plugin_config(Ref<ConfigFile> config_file, const String &path); }; -#endif // GODOT_PLUGIN_CONFIG_H +#endif // IOS_GODOT_PLUGIN_CONFIG_H diff --git a/platform/iphone/godot_app_delegate.h b/platform/ios/godot_app_delegate.h index 703a906bda..703a906bda 100644 --- a/platform/iphone/godot_app_delegate.h +++ b/platform/ios/godot_app_delegate.h diff --git a/platform/iphone/godot_app_delegate.m b/platform/ios/godot_app_delegate.m index 84347f9a30..84347f9a30 100644 --- a/platform/iphone/godot_app_delegate.m +++ b/platform/ios/godot_app_delegate.m diff --git a/platform/iphone/godot_iphone.mm b/platform/ios/godot_ios.mm index 59fdfa9dcd..5f3e786b8a 100644 --- a/platform/iphone/godot_iphone.mm +++ b/platform/ios/godot_ios.mm @@ -1,5 +1,5 @@ /*************************************************************************/ -/* godot_iphone.mm */ +/* godot_ios.mm */ /*************************************************************************/ /* This file is part of: */ /* GODOT ENGINE */ @@ -30,17 +30,17 @@ #include "core/string/ustring.h" #include "main/main.h" -#include "os_iphone.h" +#include "os_ios.h" #include <stdio.h> #include <string.h> #include <unistd.h> -static OSIPhone *os = nullptr; +static OS_IOS *os = nullptr; int add_path(int, char **); int add_cmdline(int, char **); -int iphone_main(int, char **, String); +int ios_main(int, char **, String); int add_path(int p_argc, char **p_args) { NSString *str = [[[NSBundle mainBundle] infoDictionary] objectForKey:@"godot_path"]; @@ -74,7 +74,7 @@ int add_cmdline(int p_argc, char **p_args) { return p_argc; } -int iphone_main(int argc, char **argv, String data_dir, String cache_dir) { +int ios_main(int argc, char **argv, String data_dir, String cache_dir) { size_t len = strlen(argv[0]); while (len--) { @@ -91,11 +91,11 @@ int iphone_main(int argc, char **argv, String data_dir, String cache_dir) { chdir(path); } - printf("godot_iphone %s\n", argv[0]); + printf("godot_ios %s\n", argv[0]); char cwd[512]; getcwd(cwd, sizeof(cwd)); printf("cwd %s\n", cwd); - os = new OSIPhone(data_dir, cache_dir); + os = new OS_IOS(data_dir, cache_dir); // We must override main when testing is enabled TEST_MAIN_OVERRIDE @@ -124,8 +124,8 @@ int iphone_main(int argc, char **argv, String data_dir, String cache_dir) { return 0; } -void iphone_finish() { - printf("iphone_finish\n"); +void ios_finish() { + printf("ios_finish\n"); Main::cleanup(); delete os; } diff --git a/platform/iphone/godot_view.h b/platform/ios/godot_view.h index fcb97fa63a..fcb97fa63a 100644 --- a/platform/iphone/godot_view.h +++ b/platform/ios/godot_view.h diff --git a/platform/iphone/godot_view.mm b/platform/ios/godot_view.mm index e48dd2e507..9ed219508c 100644 --- a/platform/iphone/godot_view.mm +++ b/platform/ios/godot_view.mm @@ -33,7 +33,7 @@ #include "core/os/keyboard.h" #include "core/string/ustring.h" #import "display_layer.h" -#include "display_server_iphone.h" +#include "display_server_ios.h" #import "godot_view_gesture_recognizer.h" #import "godot_view_renderer.h" @@ -281,8 +281,8 @@ static const float earth_gravity = 9.80665; self.renderingLayer.frame = self.bounds; [self.renderingLayer layoutDisplayLayer]; - if (DisplayServerIPhone::get_singleton()) { - DisplayServerIPhone::get_singleton()->resize_window(self.bounds.size); + if (DisplayServerIOS::get_singleton()) { + DisplayServerIOS::get_singleton()->resize_window(self.bounds.size); } } @@ -348,7 +348,7 @@ static const float earth_gravity = 9.80665; int tid = [self getTouchIDForTouch:touch]; ERR_FAIL_COND(tid == -1); CGPoint touchPoint = [touch locationInView:self]; - DisplayServerIPhone::get_singleton()->touch_press(tid, touchPoint.x * self.contentScaleFactor, touchPoint.y * self.contentScaleFactor, true, touch.tapCount > 1); + DisplayServerIOS::get_singleton()->touch_press(tid, touchPoint.x * self.contentScaleFactor, touchPoint.y * self.contentScaleFactor, true, touch.tapCount > 1); } } } @@ -362,7 +362,7 @@ static const float earth_gravity = 9.80665; ERR_FAIL_COND(tid == -1); CGPoint touchPoint = [touch locationInView:self]; CGPoint prev_point = [touch previousLocationInView:self]; - DisplayServerIPhone::get_singleton()->touch_drag(tid, prev_point.x * self.contentScaleFactor, prev_point.y * self.contentScaleFactor, touchPoint.x * self.contentScaleFactor, touchPoint.y * self.contentScaleFactor); + DisplayServerIOS::get_singleton()->touch_drag(tid, prev_point.x * self.contentScaleFactor, prev_point.y * self.contentScaleFactor, touchPoint.x * self.contentScaleFactor, touchPoint.y * self.contentScaleFactor); } } } @@ -376,7 +376,7 @@ static const float earth_gravity = 9.80665; ERR_FAIL_COND(tid == -1); [self removeTouch:touch]; CGPoint touchPoint = [touch locationInView:self]; - DisplayServerIPhone::get_singleton()->touch_press(tid, touchPoint.x * self.contentScaleFactor, touchPoint.y * self.contentScaleFactor, false, false); + DisplayServerIOS::get_singleton()->touch_press(tid, touchPoint.x * self.contentScaleFactor, touchPoint.y * self.contentScaleFactor, false, false); } } } @@ -388,7 +388,7 @@ static const float earth_gravity = 9.80665; UITouch *touch = [tlist objectAtIndex:i]; int tid = [self getTouchIDForTouch:touch]; ERR_FAIL_COND(tid == -1); - DisplayServerIPhone::get_singleton()->touches_cancelled(tid); + DisplayServerIOS::get_singleton()->touches_cancelled(tid); } } [self clearTouches]; @@ -452,28 +452,28 @@ static const float earth_gravity = 9.80665; switch (interfaceOrientation) { case UIInterfaceOrientationLandscapeLeft: { - DisplayServerIPhone::get_singleton()->update_gravity(-gravity.y, gravity.x, gravity.z); - DisplayServerIPhone::get_singleton()->update_accelerometer(-(acceleration.y + gravity.y), (acceleration.x + gravity.x), acceleration.z + gravity.z); - DisplayServerIPhone::get_singleton()->update_magnetometer(-magnetic.y, magnetic.x, magnetic.z); - DisplayServerIPhone::get_singleton()->update_gyroscope(-rotation.y, rotation.x, rotation.z); + DisplayServerIOS::get_singleton()->update_gravity(-gravity.y, gravity.x, gravity.z); + DisplayServerIOS::get_singleton()->update_accelerometer(-(acceleration.y + gravity.y), (acceleration.x + gravity.x), acceleration.z + gravity.z); + DisplayServerIOS::get_singleton()->update_magnetometer(-magnetic.y, magnetic.x, magnetic.z); + DisplayServerIOS::get_singleton()->update_gyroscope(-rotation.y, rotation.x, rotation.z); } break; case UIInterfaceOrientationLandscapeRight: { - DisplayServerIPhone::get_singleton()->update_gravity(gravity.y, -gravity.x, gravity.z); - DisplayServerIPhone::get_singleton()->update_accelerometer((acceleration.y + gravity.y), -(acceleration.x + gravity.x), acceleration.z + gravity.z); - DisplayServerIPhone::get_singleton()->update_magnetometer(magnetic.y, -magnetic.x, magnetic.z); - DisplayServerIPhone::get_singleton()->update_gyroscope(rotation.y, -rotation.x, rotation.z); + DisplayServerIOS::get_singleton()->update_gravity(gravity.y, -gravity.x, gravity.z); + DisplayServerIOS::get_singleton()->update_accelerometer((acceleration.y + gravity.y), -(acceleration.x + gravity.x), acceleration.z + gravity.z); + DisplayServerIOS::get_singleton()->update_magnetometer(magnetic.y, -magnetic.x, magnetic.z); + DisplayServerIOS::get_singleton()->update_gyroscope(rotation.y, -rotation.x, rotation.z); } break; case UIInterfaceOrientationPortraitUpsideDown: { - DisplayServerIPhone::get_singleton()->update_gravity(-gravity.x, gravity.y, gravity.z); - DisplayServerIPhone::get_singleton()->update_accelerometer(-(acceleration.x + gravity.x), (acceleration.y + gravity.y), acceleration.z + gravity.z); - DisplayServerIPhone::get_singleton()->update_magnetometer(-magnetic.x, magnetic.y, magnetic.z); - DisplayServerIPhone::get_singleton()->update_gyroscope(-rotation.x, rotation.y, rotation.z); + DisplayServerIOS::get_singleton()->update_gravity(-gravity.x, gravity.y, gravity.z); + DisplayServerIOS::get_singleton()->update_accelerometer(-(acceleration.x + gravity.x), (acceleration.y + gravity.y), acceleration.z + gravity.z); + DisplayServerIOS::get_singleton()->update_magnetometer(-magnetic.x, magnetic.y, magnetic.z); + DisplayServerIOS::get_singleton()->update_gyroscope(-rotation.x, rotation.y, rotation.z); } break; default: { // assume portrait - DisplayServerIPhone::get_singleton()->update_gravity(gravity.x, gravity.y, gravity.z); - DisplayServerIPhone::get_singleton()->update_accelerometer(acceleration.x + gravity.x, acceleration.y + gravity.y, acceleration.z + gravity.z); - DisplayServerIPhone::get_singleton()->update_magnetometer(magnetic.x, magnetic.y, magnetic.z); - DisplayServerIPhone::get_singleton()->update_gyroscope(rotation.x, rotation.y, rotation.z); + DisplayServerIOS::get_singleton()->update_gravity(gravity.x, gravity.y, gravity.z); + DisplayServerIOS::get_singleton()->update_accelerometer(acceleration.x + gravity.x, acceleration.y + gravity.y, acceleration.z + gravity.z); + DisplayServerIOS::get_singleton()->update_magnetometer(magnetic.x, magnetic.y, magnetic.z); + DisplayServerIOS::get_singleton()->update_gyroscope(rotation.x, rotation.y, rotation.z); } break; } } diff --git a/platform/iphone/godot_view_gesture_recognizer.h b/platform/ios/godot_view_gesture_recognizer.h index 9fd8a6b222..9fd8a6b222 100644 --- a/platform/iphone/godot_view_gesture_recognizer.h +++ b/platform/ios/godot_view_gesture_recognizer.h diff --git a/platform/iphone/godot_view_gesture_recognizer.mm b/platform/ios/godot_view_gesture_recognizer.mm index 49a92add5e..49a92add5e 100644 --- a/platform/iphone/godot_view_gesture_recognizer.mm +++ b/platform/ios/godot_view_gesture_recognizer.mm diff --git a/platform/iphone/godot_view_renderer.h b/platform/ios/godot_view_renderer.h index b3ee23ae4f..b3ee23ae4f 100644 --- a/platform/iphone/godot_view_renderer.h +++ b/platform/ios/godot_view_renderer.h diff --git a/platform/iphone/godot_view_renderer.mm b/platform/ios/godot_view_renderer.mm index 32477ae41c..140410fbef 100644 --- a/platform/iphone/godot_view_renderer.mm +++ b/platform/ios/godot_view_renderer.mm @@ -32,9 +32,9 @@ #include "core/config/project_settings.h" #include "core/os/keyboard.h" -#import "display_server_iphone.h" +#import "display_server_ios.h" #include "main/main.h" -#include "os_iphone.h" +#include "os_ios.h" #include "servers/audio_server.h" #import <AudioToolbox/AudioServices.h> @@ -69,7 +69,7 @@ if (!self.hasStartedMain) { self.hasStartedMain = YES; - OSIPhone::get_singleton()->start(); + OS_IOS::get_singleton()->start(); return YES; } @@ -108,11 +108,11 @@ } - (void)renderOnView:(UIView *)view { - if (!OSIPhone::get_singleton()) { + if (!OS_IOS::get_singleton()) { return; } - OSIPhone::get_singleton()->iterate(); + OS_IOS::get_singleton()->iterate(); } @end diff --git a/platform/iphone/ios.h b/platform/ios/ios.h index 0607d7b395..0b3842b233 100644 --- a/platform/iphone/ios.h +++ b/platform/ios/ios.h @@ -58,4 +58,4 @@ public: iOS(); }; -#endif +#endif // IOS_H diff --git a/platform/iphone/ios.mm b/platform/ios/ios.mm index 79baae028a..79baae028a 100644 --- a/platform/iphone/ios.mm +++ b/platform/ios/ios.mm diff --git a/platform/iphone/joypad_iphone.h b/platform/ios/joypad_ios.h index 37e272a2c9..66c4b090bc 100644 --- a/platform/iphone/joypad_iphone.h +++ b/platform/ios/joypad_ios.h @@ -1,5 +1,5 @@ /*************************************************************************/ -/* joypad_iphone.h */ +/* joypad_ios.h */ /*************************************************************************/ /* This file is part of: */ /* GODOT ENGINE */ @@ -30,7 +30,7 @@ #import <GameController/GameController.h> -@interface JoypadIPhoneObserver : NSObject +@interface JoypadIOSObserver : NSObject - (void)startObserving; - (void)startProcessing; @@ -38,13 +38,13 @@ @end -class JoypadIPhone { +class JoypadIOS { private: - JoypadIPhoneObserver *observer; + JoypadIOSObserver *observer; public: - JoypadIPhone(); - ~JoypadIPhone(); + JoypadIOS(); + ~JoypadIOS(); void start_processing(); }; diff --git a/platform/iphone/joypad_iphone.mm b/platform/ios/joypad_ios.mm index 9c2feeaaca..e147cb2527 100644 --- a/platform/iphone/joypad_iphone.mm +++ b/platform/ios/joypad_ios.mm @@ -1,5 +1,5 @@ /*************************************************************************/ -/* joypad_iphone.mm */ +/* joypad_ios.mm */ /*************************************************************************/ /* This file is part of: */ /* GODOT ENGINE */ @@ -28,7 +28,7 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ -#import "joypad_iphone.h" +#import "joypad_ios.h" #include "core/config/project_settings.h" #include "drivers/coreaudio/audio_driver_coreaudio.h" @@ -36,27 +36,27 @@ #import "godot_view.h" -#include "os_iphone.h" +#include "os_ios.h" -JoypadIPhone::JoypadIPhone() { - observer = [[JoypadIPhoneObserver alloc] init]; +JoypadIOS::JoypadIOS() { + observer = [[JoypadIOSObserver alloc] init]; [observer startObserving]; } -JoypadIPhone::~JoypadIPhone() { +JoypadIOS::~JoypadIOS() { if (observer) { [observer finishObserving]; observer = nil; } } -void JoypadIPhone::start_processing() { +void JoypadIOS::start_processing() { if (observer) { [observer startProcessing]; } } -@interface JoypadIPhoneObserver () +@interface JoypadIOSObserver () @property(assign, nonatomic) BOOL isObserving; @property(assign, nonatomic) BOOL isProcessing; @@ -65,7 +65,7 @@ void JoypadIPhone::start_processing() { @end -@implementation JoypadIPhoneObserver +@implementation JoypadIOSObserver - (instancetype)init { self = [super init]; diff --git a/platform/iphone/keyboard_input_view.h b/platform/ios/keyboard_input_view.h index 33fa5d571a..fc34e6a11b 100644 --- a/platform/iphone/keyboard_input_view.h +++ b/platform/ios/keyboard_input_view.h @@ -32,6 +32,6 @@ @interface GodotKeyboardInputView : UITextView -- (BOOL)becomeFirstResponderWithString:(NSString *)existingString multiline:(BOOL)flag cursorStart:(NSInteger)start cursorEnd:(NSInteger)end; +- (BOOL)becomeFirstResponderWithString:(NSString *)existingString cursorStart:(NSInteger)start cursorEnd:(NSInteger)end; @end diff --git a/platform/iphone/keyboard_input_view.mm b/platform/ios/keyboard_input_view.mm index f2a7b22483..f031a1de22 100644 --- a/platform/iphone/keyboard_input_view.mm +++ b/platform/ios/keyboard_input_view.mm @@ -31,8 +31,8 @@ #import "keyboard_input_view.h" #include "core/os/keyboard.h" -#include "display_server_iphone.h" -#include "os_iphone.h" +#include "display_server_ios.h" +#include "os_ios.h" @interface GodotKeyboardInputView () <UITextViewDelegate> @@ -84,7 +84,7 @@ return YES; } -- (BOOL)becomeFirstResponderWithString:(NSString *)existingString multiline:(BOOL)flag cursorStart:(NSInteger)start cursorEnd:(NSInteger)end { +- (BOOL)becomeFirstResponderWithString:(NSString *)existingString cursorStart:(NSInteger)start cursorEnd:(NSInteger)end { self.text = existingString; self.previousText = existingString; @@ -115,8 +115,8 @@ - (void)deleteText:(NSInteger)charactersToDelete { for (int i = 0; i < charactersToDelete; i++) { - DisplayServerIPhone::get_singleton()->key(Key::BACKSPACE, true); - DisplayServerIPhone::get_singleton()->key(Key::BACKSPACE, false); + DisplayServerIOS::get_singleton()->key(Key::BACKSPACE, true); + DisplayServerIOS::get_singleton()->key(Key::BACKSPACE, false); } } @@ -138,8 +138,8 @@ break; } - DisplayServerIPhone::get_singleton()->key((Key)character, true); - DisplayServerIPhone::get_singleton()->key((Key)character, false); + DisplayServerIOS::get_singleton()->key((Key)character, true); + DisplayServerIOS::get_singleton()->key((Key)character, false); } } diff --git a/platform/iphone/logo.png b/platform/ios/logo.png Binary files differindex 966d8aa70a..966d8aa70a 100644 --- a/platform/iphone/logo.png +++ b/platform/ios/logo.png diff --git a/platform/iphone/main.m b/platform/ios/main.m index acfa7ab731..acfa7ab731 100644 --- a/platform/iphone/main.m +++ b/platform/ios/main.m diff --git a/platform/iphone/os_iphone.h b/platform/ios/os_ios.h index d03403bbb4..3b88f53b6a 100644 --- a/platform/iphone/os_iphone.h +++ b/platform/ios/os_ios.h @@ -1,5 +1,5 @@ /*************************************************************************/ -/* os_iphone.h */ +/* os_ios.h */ /*************************************************************************/ /* This file is part of: */ /* GODOT ENGINE */ @@ -28,24 +28,24 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ -#ifdef IPHONE_ENABLED +#ifdef IOS_ENABLED -#ifndef OS_IPHONE_H -#define OS_IPHONE_H +#ifndef OS_IOS_H +#define OS_IOS_H #include "drivers/coreaudio/audio_driver_coreaudio.h" #include "drivers/unix/os_unix.h" #include "ios.h" -#include "joypad_iphone.h" +#include "joypad_ios.h" #include "servers/audio_server.h" #include "servers/rendering/renderer_compositor.h" #if defined(VULKAN_ENABLED) #include "drivers/vulkan/rendering_device_vulkan.h" -#include "platform/iphone/vulkan_context_iphone.h" +#include "platform/ios/vulkan_context_ios.h" #endif -class OSIPhone : public OS_Unix { +class OS_IOS : public OS_Unix { private: static HashMap<String, void *> dynamic_symbol_lookup_table; friend void register_dynamic_symbol(char *name, void *address); @@ -54,7 +54,7 @@ private: iOS *ios = nullptr; - JoypadIPhone *joypad_iphone = nullptr; + JoypadIOS *joypad_ios = nullptr; MainLoop *main_loop = nullptr; @@ -79,10 +79,10 @@ private: void deinitialize_modules(); public: - static OSIPhone *get_singleton(); + static OS_IOS *get_singleton(); - OSIPhone(String p_data_dir, String p_cache_dir); - ~OSIPhone(); + OS_IOS(String p_data_dir, String p_cache_dir); + ~OS_IOS(); void initialize_modules(); @@ -92,6 +92,9 @@ public: virtual void alert(const String &p_alert, const String &p_title = "ALERT!") override; + virtual Vector<String> get_system_fonts() const override; + virtual String get_system_font_path(const String &p_font_name, bool p_bold = false, bool p_italic = false) const override; + virtual Error open_dynamic_library(const String p_path, void *&p_library_handle, bool p_also_set_library_path = false, String *r_resolved_path = nullptr) override; virtual Error close_dynamic_library(void *p_library_handle) override; virtual Error get_dynamic_library_symbol_handle(void *p_library_handle, const String p_name, void *&p_symbol_handle, bool p_optional = false) override; @@ -119,6 +122,6 @@ public: void on_focus_in(); }; -#endif // OS_IPHONE_H +#endif // OS_IOS_H -#endif // IPHONE_ENABLED +#endif // OS_IOS_H diff --git a/platform/iphone/os_iphone.mm b/platform/ios/os_ios.mm index 95b06b728e..b9d186f355 100644 --- a/platform/iphone/os_iphone.mm +++ b/platform/ios/os_ios.mm @@ -1,5 +1,5 @@ /*************************************************************************/ -/* os_iphone.mm */ +/* os_ios.mm */ /*************************************************************************/ /* This file is part of: */ /* GODOT ENGINE */ @@ -28,22 +28,23 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ -#ifdef IPHONE_ENABLED +#ifdef IOS_ENABLED -#include "os_iphone.h" +#include "os_ios.h" #import "app_delegate.h" #include "core/config/project_settings.h" #include "core/io/dir_access.h" #include "core/io/file_access.h" #include "core/io/file_access_pack.h" -#include "display_server_iphone.h" +#include "display_server_ios.h" #include "drivers/unix/syslog_logger.h" #import "godot_view.h" #include "main/main.h" #import "view_controller.h" #import <AudioToolbox/AudioServices.h> +#import <CoreText/CoreText.h> #import <UIKit/UIKit.h> #import <dlfcn.h> #include <sys/sysctl.h> @@ -65,7 +66,7 @@ typedef void (*init_callback)(); static init_callback *ios_init_callbacks = nullptr; static int ios_init_callbacks_count = 0; static int ios_init_callbacks_capacity = 0; -HashMap<String, void *> OSIPhone::dynamic_symbol_lookup_table; +HashMap<String, void *> OS_IOS::dynamic_symbol_lookup_table; void add_ios_init_callback(init_callback cb) { if (ios_init_callbacks_count == ios_init_callbacks_capacity) { @@ -82,14 +83,14 @@ void add_ios_init_callback(init_callback cb) { } void register_dynamic_symbol(char *name, void *address) { - OSIPhone::dynamic_symbol_lookup_table[String(name)] = address; + OS_IOS::dynamic_symbol_lookup_table[String(name)] = address; } -OSIPhone *OSIPhone::get_singleton() { - return (OSIPhone *)OS::get_singleton(); +OS_IOS *OS_IOS::get_singleton() { + return (OS_IOS *)OS::get_singleton(); } -OSIPhone::OSIPhone(String p_data_dir, String p_cache_dir) { +OS_IOS::OS_IOS(String p_data_dir, String p_cache_dir) { for (int i = 0; i < ios_init_callbacks_count; ++i) { ios_init_callbacks[i](); } @@ -116,37 +117,37 @@ OSIPhone::OSIPhone(String p_data_dir, String p_cache_dir) { AudioDriverManager::add_driver(&audio_driver); - DisplayServerIPhone::register_iphone_driver(); + DisplayServerIOS::register_ios_driver(); } -OSIPhone::~OSIPhone() {} +OS_IOS::~OS_IOS() {} -void OSIPhone::alert(const String &p_alert, const String &p_title) { +void OS_IOS::alert(const String &p_alert, const String &p_title) { const CharString utf8_alert = p_alert.utf8(); const CharString utf8_title = p_title.utf8(); iOS::alert(utf8_alert.get_data(), utf8_title.get_data()); } -void OSIPhone::initialize_core() { +void OS_IOS::initialize_core() { OS_Unix::initialize_core(); set_user_data_dir(user_data_dir); } -void OSIPhone::initialize() { +void OS_IOS::initialize() { initialize_core(); } -void OSIPhone::initialize_modules() { +void OS_IOS::initialize_modules() { ios = memnew(iOS); Engine::get_singleton()->add_singleton(Engine::Singleton("iOS", ios)); - joypad_iphone = memnew(JoypadIPhone); + joypad_ios = memnew(JoypadIOS); } -void OSIPhone::deinitialize_modules() { - if (joypad_iphone) { - memdelete(joypad_iphone); +void OS_IOS::deinitialize_modules() { + if (joypad_ios) { + memdelete(joypad_ios); } if (ios) { @@ -154,7 +155,7 @@ void OSIPhone::deinitialize_modules() { } } -void OSIPhone::set_main_loop(MainLoop *p_main_loop) { +void OS_IOS::set_main_loop(MainLoop *p_main_loop) { main_loop = p_main_loop; if (main_loop) { @@ -162,11 +163,11 @@ void OSIPhone::set_main_loop(MainLoop *p_main_loop) { } } -MainLoop *OSIPhone::get_main_loop() const { +MainLoop *OS_IOS::get_main_loop() const { return main_loop; } -void OSIPhone::delete_main_loop() { +void OS_IOS::delete_main_loop() { if (main_loop) { main_loop->finalize(); memdelete(main_loop); @@ -175,7 +176,7 @@ void OSIPhone::delete_main_loop() { main_loop = nullptr; } -bool OSIPhone::iterate() { +bool OS_IOS::iterate() { if (!main_loop) { return true; } @@ -187,15 +188,15 @@ bool OSIPhone::iterate() { return Main::iteration(); } -void OSIPhone::start() { +void OS_IOS::start() { Main::start(); - if (joypad_iphone) { - joypad_iphone->start_processing(); + if (joypad_ios) { + joypad_ios->start_processing(); } } -void OSIPhone::finalize() { +void OS_IOS::finalize() { deinitialize_modules(); // Already gets called @@ -204,7 +205,7 @@ void OSIPhone::finalize() { // MARK: Dynamic Libraries -Error OSIPhone::open_dynamic_library(const String p_path, void *&p_library_handle, bool p_also_set_library_path, String *r_resolved_path) { +Error OS_IOS::open_dynamic_library(const String p_path, void *&p_library_handle, bool p_also_set_library_path, String *r_resolved_path) { if (p_path.length() == 0) { p_library_handle = RTLD_SELF; @@ -217,16 +218,16 @@ Error OSIPhone::open_dynamic_library(const String p_path, void *&p_library_handl return OS_Unix::open_dynamic_library(p_path, p_library_handle, p_also_set_library_path, r_resolved_path); } -Error OSIPhone::close_dynamic_library(void *p_library_handle) { +Error OS_IOS::close_dynamic_library(void *p_library_handle) { if (p_library_handle == RTLD_SELF) { return OK; } return OS_Unix::close_dynamic_library(p_library_handle); } -Error OSIPhone::get_dynamic_library_symbol_handle(void *p_library_handle, const String p_name, void *&p_symbol_handle, bool p_optional) { +Error OS_IOS::get_dynamic_library_symbol_handle(void *p_library_handle, const String p_name, void *&p_symbol_handle, bool p_optional) { if (p_library_handle == RTLD_SELF) { - void **ptr = OSIPhone::dynamic_symbol_lookup_table.getptr(p_name); + void **ptr = OS_IOS::dynamic_symbol_lookup_table.getptr(p_name); if (ptr) { p_symbol_handle = *ptr; return OK; @@ -235,11 +236,11 @@ Error OSIPhone::get_dynamic_library_symbol_handle(void *p_library_handle, const return OS_Unix::get_dynamic_library_symbol_handle(p_library_handle, p_name, p_symbol_handle, p_optional); } -String OSIPhone::get_name() const { +String OS_IOS::get_name() const { return "iOS"; } -String OSIPhone::get_model_name() const { +String OS_IOS::get_model_name() const { String model = ios->get_model(); if (model != "") { return model; @@ -248,7 +249,7 @@ String OSIPhone::get_model_name() const { return OS_Unix::get_model_name(); } -Error OSIPhone::shell_open(String p_uri) { +Error OS_IOS::shell_open(String p_uri) { NSString *urlPath = [[NSString alloc] initWithUTF8String:p_uri.utf8().get_data()]; NSURL *url = [NSURL URLWithString:urlPath]; @@ -263,21 +264,21 @@ Error OSIPhone::shell_open(String p_uri) { return OK; } -void OSIPhone::set_user_data_dir(String p_dir) { +void OS_IOS::set_user_data_dir(String p_dir) { Ref<DirAccess> da = DirAccess::open(p_dir); user_data_dir = da->get_current_dir(); printf("setting data dir to %s from %s\n", user_data_dir.utf8().get_data(), p_dir.utf8().get_data()); } -String OSIPhone::get_user_data_dir() const { +String OS_IOS::get_user_data_dir() const { return user_data_dir; } -String OSIPhone::get_cache_path() const { +String OS_IOS::get_cache_path() const { return cache_dir; } -String OSIPhone::get_locale() const { +String OS_IOS::get_locale() const { NSString *preferedLanguage = [NSLocale preferredLanguages].firstObject; if (preferedLanguage) { @@ -288,12 +289,12 @@ String OSIPhone::get_locale() const { return String::utf8([localeIdentifier UTF8String]).replace("-", "_"); } -String OSIPhone::get_unique_id() const { +String OS_IOS::get_unique_id() const { NSString *uuid = [UIDevice currentDevice].identifierForVendor.UUIDString; return String::utf8([uuid UTF8String]); } -String OSIPhone::get_processor_name() const { +String OS_IOS::get_processor_name() const { char buffer[256]; size_t buffer_len = 256; if (sysctlbyname("machdep.cpu.brand_string", &buffer, &buffer_len, NULL, 0) == 0) { @@ -302,7 +303,81 @@ String OSIPhone::get_processor_name() const { ERR_FAIL_V_MSG("", String("Couldn't get the CPU model name. Returning an empty string.")); } -void OSIPhone::vibrate_handheld(int p_duration_ms) { +Vector<String> OS_IOS::get_system_fonts() const { + HashSet<String> font_names; + CFArrayRef fonts = CTFontManagerCopyAvailableFontFamilyNames(); + if (fonts) { + for (CFIndex i = 0; i < CFArrayGetCount(fonts); i++) { + CFStringRef cf_name = (CFStringRef)CFArrayGetValueAtIndex(fonts, i); + if (cf_name && (CFStringGetLength(cf_name) > 0) && (CFStringCompare(cf_name, CFSTR("LastResort"), kCFCompareCaseInsensitive) != kCFCompareEqualTo) && (CFStringGetCharacterAtIndex(cf_name, 0) != '.')) { + NSString *ns_name = (__bridge NSString *)cf_name; + font_names.insert(String::utf8([ns_name UTF8String])); + } + } + CFRelease(fonts); + } + + Vector<String> ret; + for (const String &E : font_names) { + ret.push_back(E); + } + return ret; +} + +String OS_IOS::get_system_font_path(const String &p_font_name, bool p_bold, bool p_italic) const { + String ret; + + String font_name = p_font_name; + if (font_name.to_lower() == "sans-serif") { + font_name = "Helvetica"; + } else if (font_name.to_lower() == "serif") { + font_name = "Times"; + } else if (font_name.to_lower() == "monospace") { + font_name = "Courier"; + } else if (font_name.to_lower() == "fantasy") { + font_name = "Papyrus"; + } else if (font_name.to_lower() == "cursive") { + font_name = "Apple Chancery"; + }; + + CFStringRef name = CFStringCreateWithCString(kCFAllocatorDefault, font_name.utf8().get_data(), kCFStringEncodingUTF8); + + CTFontSymbolicTraits traits = 0; + if (p_bold) { + traits |= kCTFontBoldTrait; + } + if (p_italic) { + traits |= kCTFontItalicTrait; + } + + CFNumberRef sym_traits = CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt32Type, &traits); + CFMutableDictionaryRef traits_dict = CFDictionaryCreateMutable(kCFAllocatorDefault, 0, nullptr, nullptr); + CFDictionaryAddValue(traits_dict, kCTFontSymbolicTrait, sym_traits); + + CFMutableDictionaryRef attributes = CFDictionaryCreateMutable(kCFAllocatorDefault, 0, nullptr, nullptr); + CFDictionaryAddValue(attributes, kCTFontFamilyNameAttribute, name); + CFDictionaryAddValue(attributes, kCTFontTraitsAttribute, traits_dict); + + CTFontDescriptorRef font = CTFontDescriptorCreateWithAttributes(attributes); + if (font) { + CFURLRef url = (CFURLRef)CTFontDescriptorCopyAttribute(font, kCTFontURLAttribute); + if (url) { + NSString *font_path = [NSString stringWithString:[(__bridge NSURL *)url path]]; + ret = String::utf8([font_path UTF8String]); + CFRelease(url); + } + CFRelease(font); + } + + CFRelease(attributes); + CFRelease(traits_dict); + CFRelease(sym_traits); + CFRelease(name); + + return ret; +} + +void OS_IOS::vibrate_handheld(int p_duration_ms) { if (ios->supports_haptic_engine()) { ios->vibrate_haptic_engine((float)p_duration_ms / 1000.f); } else { @@ -311,16 +386,16 @@ void OSIPhone::vibrate_handheld(int p_duration_ms) { } } -bool OSIPhone::_check_internal_feature_support(const String &p_feature) { +bool OS_IOS::_check_internal_feature_support(const String &p_feature) { return p_feature == "mobile"; } -void OSIPhone::on_focus_out() { +void OS_IOS::on_focus_out() { if (is_focused) { is_focused = false; - if (DisplayServerIPhone::get_singleton()) { - DisplayServerIPhone::get_singleton()->send_window_event(DisplayServer::WINDOW_EVENT_FOCUS_OUT); + if (DisplayServerIOS::get_singleton()) { + DisplayServerIOS::get_singleton()->send_window_event(DisplayServer::WINDOW_EVENT_FOCUS_OUT); } [AppDelegate.viewController.godotView stopRendering]; @@ -329,12 +404,12 @@ void OSIPhone::on_focus_out() { } } -void OSIPhone::on_focus_in() { +void OS_IOS::on_focus_in() { if (!is_focused) { is_focused = true; - if (DisplayServerIPhone::get_singleton()) { - DisplayServerIPhone::get_singleton()->send_window_event(DisplayServer::WINDOW_EVENT_FOCUS_IN); + if (DisplayServerIOS::get_singleton()) { + DisplayServerIOS::get_singleton()->send_window_event(DisplayServer::WINDOW_EVENT_FOCUS_IN); } [AppDelegate.viewController.godotView startRendering]; @@ -343,4 +418,4 @@ void OSIPhone::on_focus_in() { } } -#endif // IPHONE_ENABLED +#endif // IOS_ENABLED diff --git a/platform/iphone/platform_config.h b/platform/ios/platform_config.h index fed77d8932..3af08b0d65 100644 --- a/platform/iphone/platform_config.h +++ b/platform/ios/platform_config.h @@ -32,8 +32,6 @@ #define OPENGL_INCLUDE_H <ES3/gl.h> -#define PLATFORM_REFCOUNT - #define PTHREAD_RENAME_SELF #define _weakify(var) __weak typeof(var) GDWeak_##var = var; diff --git a/platform/iphone/tts_ios.h b/platform/ios/tts_ios.h index 064316b0b2..064316b0b2 100644 --- a/platform/iphone/tts_ios.h +++ b/platform/ios/tts_ios.h diff --git a/platform/iphone/tts_ios.mm b/platform/ios/tts_ios.mm index a079d02add..8319cad117 100644 --- a/platform/iphone/tts_ios.mm +++ b/platform/ios/tts_ios.mm @@ -78,12 +78,12 @@ AVSpeechUtterance *new_utterance = [[AVSpeechUtterance alloc] initWithString:[NSString stringWithUTF8String:message.text.utf8().get_data()]]; [new_utterance setVoice:[AVSpeechSynthesisVoice voiceWithIdentifier:[NSString stringWithUTF8String:message.voice.utf8().get_data()]]]; if (message.rate > 1.f) { - [new_utterance setRate:Math::range_lerp(message.rate, 1.f, 10.f, AVSpeechUtteranceDefaultSpeechRate, AVSpeechUtteranceMaximumSpeechRate)]; + [new_utterance setRate:Math::remap(message.rate, 1.f, 10.f, AVSpeechUtteranceDefaultSpeechRate, AVSpeechUtteranceMaximumSpeechRate)]; } else if (message.rate < 1.f) { - [new_utterance setRate:Math::range_lerp(message.rate, 0.1f, 1.f, AVSpeechUtteranceMinimumSpeechRate, AVSpeechUtteranceDefaultSpeechRate)]; + [new_utterance setRate:Math::remap(message.rate, 0.1f, 1.f, AVSpeechUtteranceMinimumSpeechRate, AVSpeechUtteranceDefaultSpeechRate)]; } [new_utterance setPitchMultiplier:message.pitch]; - [new_utterance setVolume:(Math::range_lerp(message.volume, 0.f, 100.f, 0.f, 1.f))]; + [new_utterance setVolume:(Math::remap(message.volume, 0.f, 100.f, 0.f, 1.f))]; ids[new_utterance] = message.id; [av_synth speakUtterance:new_utterance]; diff --git a/platform/iphone/view_controller.h b/platform/ios/view_controller.h index c8b37a4d11..c8b37a4d11 100644 --- a/platform/iphone/view_controller.h +++ b/platform/ios/view_controller.h diff --git a/platform/iphone/view_controller.mm b/platform/ios/view_controller.mm index 4f4ef4f046..43669d3f94 100644 --- a/platform/iphone/view_controller.mm +++ b/platform/ios/view_controller.mm @@ -30,11 +30,11 @@ #import "view_controller.h" #include "core/config/project_settings.h" -#include "display_server_iphone.h" +#include "display_server_ios.h" #import "godot_view.h" #import "godot_view_renderer.h" #import "keyboard_input_view.h" -#include "os_iphone.h" +#include "os_ios.h" #import <AVFoundation/AVFoundation.h> #import <GameController/GameController.h> @@ -168,11 +168,11 @@ } - (BOOL)shouldAutorotate { - if (!DisplayServerIPhone::get_singleton()) { + if (!DisplayServerIOS::get_singleton()) { return NO; } - switch (DisplayServerIPhone::get_singleton()->screen_get_orientation(DisplayServer::SCREEN_OF_MAIN_WINDOW)) { + switch (DisplayServerIOS::get_singleton()->screen_get_orientation(DisplayServer::SCREEN_OF_MAIN_WINDOW)) { case DisplayServer::SCREEN_SENSOR: case DisplayServer::SCREEN_SENSOR_LANDSCAPE: case DisplayServer::SCREEN_SENSOR_PORTRAIT: @@ -183,11 +183,11 @@ } - (UIInterfaceOrientationMask)supportedInterfaceOrientations { - if (!DisplayServerIPhone::get_singleton()) { + if (!DisplayServerIOS::get_singleton()) { return UIInterfaceOrientationMaskAll; } - switch (DisplayServerIPhone::get_singleton()->screen_get_orientation(DisplayServer::SCREEN_OF_MAIN_WINDOW)) { + switch (DisplayServerIOS::get_singleton()->screen_get_orientation(DisplayServer::SCREEN_OF_MAIN_WINDOW)) { case DisplayServer::SCREEN_PORTRAIT: return UIInterfaceOrientationMaskPortrait; case DisplayServer::SCREEN_REVERSE_LANDSCAPE: @@ -226,14 +226,14 @@ CGRect rawFrame = [value CGRectValue]; CGRect keyboardFrame = [self.view convertRect:rawFrame fromView:nil]; - if (DisplayServerIPhone::get_singleton()) { - DisplayServerIPhone::get_singleton()->virtual_keyboard_set_height(keyboardFrame.size.height); + if (DisplayServerIOS::get_singleton()) { + DisplayServerIOS::get_singleton()->virtual_keyboard_set_height(keyboardFrame.size.height); } } - (void)keyboardHidden:(NSNotification *)notification { - if (DisplayServerIPhone::get_singleton()) { - DisplayServerIPhone::get_singleton()->virtual_keyboard_set_height(0); + if (DisplayServerIOS::get_singleton()) { + DisplayServerIOS::get_singleton()->virtual_keyboard_set_height(0); } } diff --git a/platform/iphone/vulkan_context_iphone.h b/platform/ios/vulkan_context_ios.h index 7576525755..e9c09e087a 100644 --- a/platform/iphone/vulkan_context_iphone.h +++ b/platform/ios/vulkan_context_ios.h @@ -1,5 +1,5 @@ /*************************************************************************/ -/* vulkan_context_iphone.h */ +/* vulkan_context_ios.h */ /*************************************************************************/ /* This file is part of: */ /* GODOT ENGINE */ @@ -28,21 +28,21 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ -#ifndef VULKAN_CONTEXT_IPHONE_H -#define VULKAN_CONTEXT_IPHONE_H +#ifndef VULKAN_CONTEXT_IOS_H +#define VULKAN_CONTEXT_IOS_H #include "drivers/vulkan/vulkan_context.h" #import <UIKit/UIKit.h> -class VulkanContextIPhone : public VulkanContext { +class VulkanContextIOS : public VulkanContext { virtual const char *_get_platform_surface_extension() const; public: Error window_create(DisplayServer::WindowID p_window_id, DisplayServer::VSyncMode p_vsync_mode, CALayer *p_metal_layer, int p_width, int p_height); - VulkanContextIPhone(); - ~VulkanContextIPhone(); + VulkanContextIOS(); + ~VulkanContextIOS(); }; -#endif // VULKAN_CONTEXT_IPHONE_H +#endif // VULKAN_CONTEXT_IOS_H diff --git a/platform/iphone/vulkan_context_iphone.mm b/platform/ios/vulkan_context_ios.mm index 17cb0f6009..09cd369aa5 100644 --- a/platform/iphone/vulkan_context_iphone.mm +++ b/platform/ios/vulkan_context_ios.mm @@ -1,5 +1,5 @@ /*************************************************************************/ -/* vulkan_context_iphone.mm */ +/* vulkan_context_ios.mm */ /*************************************************************************/ /* This file is part of: */ /* GODOT ENGINE */ @@ -28,18 +28,18 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ -#include "vulkan_context_iphone.h" +#include "vulkan_context_ios.h" #ifdef USE_VOLK #include <volk.h> #else #include <vulkan/vulkan.h> #endif -const char *VulkanContextIPhone::_get_platform_surface_extension() const { +const char *VulkanContextIOS::_get_platform_surface_extension() const { return VK_MVK_IOS_SURFACE_EXTENSION_NAME; } -Error VulkanContextIPhone::window_create(DisplayServer::WindowID p_window_id, DisplayServer::VSyncMode p_vsync_mode, CALayer *p_metal_layer, int p_width, int p_height) { +Error VulkanContextIOS::window_create(DisplayServer::WindowID p_window_id, DisplayServer::VSyncMode p_vsync_mode, CALayer *p_metal_layer, int p_width, int p_height) { VkIOSSurfaceCreateInfoMVK createInfo; createInfo.sType = VK_STRUCTURE_TYPE_IOS_SURFACE_CREATE_INFO_MVK; createInfo.pNext = nullptr; @@ -54,6 +54,6 @@ Error VulkanContextIPhone::window_create(DisplayServer::WindowID p_window_id, Di return _window_create(p_window_id, p_vsync_mode, surface, p_width, p_height); } -VulkanContextIPhone::VulkanContextIPhone() {} +VulkanContextIOS::VulkanContextIOS() {} -VulkanContextIPhone::~VulkanContextIPhone() {} +VulkanContextIOS::~VulkanContextIOS() {} diff --git a/platform/javascript/README.md b/platform/javascript/README.md deleted file mode 100644 index f181bea9e0..0000000000 --- a/platform/javascript/README.md +++ /dev/null @@ -1,15 +0,0 @@ -# HTML5 platform port - -This folder contains the C++ and JavaScript code for the HTML5/WebAssembly platform port, -compiled using [Emscripten](https://emscripten.org/). - -It also contains a ESLint linting setup (see [`package.json`](package.json)). - -See also [`misc/dist/html`](/misc/dist/html) folder for files used by this platform -such as the HTML5 shell. - -## Artwork license - -[`logo.png`](logo.png) and [`run_icon.png`](run_icon.png) are licensed under -[Creative Commons Attribution 3.0 Unported](https://www.w3.org/html/logo/faq.html#how-licenced) -per the HTML5 logo usage guidelines. diff --git a/platform/linuxbsd/README.md b/platform/linuxbsd/README.md index 0d3fb37be5..efa8682062 100644 --- a/platform/linuxbsd/README.md +++ b/platform/linuxbsd/README.md @@ -2,10 +2,20 @@ This folder contains the C++ code for the Linux/*BSD platform port. +See also [`misc/dist/linux`](/misc/dist/linux) folder for additional files +used by this platform. + +## Documentation + +- [Compiling for Linux/*BSD](https://docs.godotengine.org/en/latest/development/compiling/compiling_for_linuxbsd.html) + - Instructions on building this platform port from source. +- [Exporting for Linux/*BSD](https://docs.godotengine.org/en/latest/tutorials/export/exporting_for_linux.html) + - Instructions on using the compiled export templates to export a project. + ## Artwork license [`logo.png`](logo.png) is derived from the [Linux logo](https://isc.tamu.edu/~lewing/linux/): > Permission to use and/or modify this image is granted provided you acknowledge me - <lewing@isc.tamu.edu> and [The GIMP](https://isc.tamu.edu/~lewing/gimp/) - if someone asks. +> <lewing@isc.tamu.edu> and [The GIMP](https://isc.tamu.edu/~lewing/gimp/) +> if someone asks. diff --git a/platform/linuxbsd/SCsub b/platform/linuxbsd/SCsub index 09a432eae2..91d45627b9 100644 --- a/platform/linuxbsd/SCsub +++ b/platform/linuxbsd/SCsub @@ -9,10 +9,11 @@ common_linuxbsd = [ "crash_handler_linuxbsd.cpp", "os_linuxbsd.cpp", "joypad_linux.cpp", + "freedesktop_portal_desktop.cpp", "freedesktop_screensaver.cpp", ] -if "x11" in env and env["x11"]: +if env["x11"]: common_linuxbsd += [ "gl_manager_x11.cpp", "detect_prime_x11.cpp", @@ -20,15 +21,21 @@ if "x11" in env and env["x11"]: "key_mapping_x11.cpp", ] -if "speechd" in env and env["speechd"]: + if env["vulkan"]: + common_linuxbsd.append("vulkan_context_x11.cpp") + +if env["speechd"]: common_linuxbsd.append(["speechd-so_wrap.c", "tts_linux.cpp"]) -if "vulkan" in env and env["vulkan"]: - common_linuxbsd.append("vulkan_context_x11.cpp") +if env["fontconfig"]: + common_linuxbsd.append("fontconfig-so_wrap.c") -if "udev" in env and env["udev"]: +if env["udev"]: common_linuxbsd.append("libudev-so_wrap.c") +if env["dbus"]: + common_linuxbsd.append("dbus-so_wrap.c") + prog = env.add_program("#bin/godot", ["godot_linuxbsd.cpp"] + common_linuxbsd) if env["debug_symbols"] and env["separate_debug_symbols"]: diff --git a/platform/linuxbsd/crash_handler_linuxbsd.h b/platform/linuxbsd/crash_handler_linuxbsd.h index 2e44476c3f..1b77352cca 100644 --- a/platform/linuxbsd/crash_handler_linuxbsd.h +++ b/platform/linuxbsd/crash_handler_linuxbsd.h @@ -28,8 +28,8 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ -#ifndef CRASH_HANDLER_X11_H -#define CRASH_HANDLER_X11_H +#ifndef CRASH_HANDLER_LINUXBSD_H +#define CRASH_HANDLER_LINUXBSD_H class CrashHandler { bool disabled; @@ -44,4 +44,4 @@ public: ~CrashHandler(); }; -#endif // CRASH_HANDLER_X11_H +#endif // CRASH_HANDLER_LINUXBSD_H diff --git a/platform/linuxbsd/dbus-so_wrap.c b/platform/linuxbsd/dbus-so_wrap.c new file mode 100644 index 0000000000..0876bc88b0 --- /dev/null +++ b/platform/linuxbsd/dbus-so_wrap.c @@ -0,0 +1,2641 @@ +// This file is generated. Do not edit! +// see https://github.com/hpvb/dynload-wrapper for details +// generated by ./generate-wrapper.py 0.3 on 2022-07-29 07:23:21 +// flags: ./generate-wrapper.py --include /usr/include/dbus-1.0/dbus/dbus.h --sys-include <dbus/dbus.h> --soname libdbus-1.so --init-name dbus --output-header dbus-so_wrap.h --output-implementation dbus-so_wrap.c +// +#include <stdint.h> + +#define dbus_error_init dbus_error_init_dylibloader_orig_dbus +#define dbus_error_free dbus_error_free_dylibloader_orig_dbus +#define dbus_set_error dbus_set_error_dylibloader_orig_dbus +#define dbus_set_error_const dbus_set_error_const_dylibloader_orig_dbus +#define dbus_move_error dbus_move_error_dylibloader_orig_dbus +#define dbus_error_has_name dbus_error_has_name_dylibloader_orig_dbus +#define dbus_error_is_set dbus_error_is_set_dylibloader_orig_dbus +#define dbus_parse_address dbus_parse_address_dylibloader_orig_dbus +#define dbus_address_entry_get_value dbus_address_entry_get_value_dylibloader_orig_dbus +#define dbus_address_entry_get_method dbus_address_entry_get_method_dylibloader_orig_dbus +#define dbus_address_entries_free dbus_address_entries_free_dylibloader_orig_dbus +#define dbus_address_escape_value dbus_address_escape_value_dylibloader_orig_dbus +#define dbus_address_unescape_value dbus_address_unescape_value_dylibloader_orig_dbus +#define dbus_malloc dbus_malloc_dylibloader_orig_dbus +#define dbus_malloc0 dbus_malloc0_dylibloader_orig_dbus +#define dbus_realloc dbus_realloc_dylibloader_orig_dbus +#define dbus_free dbus_free_dylibloader_orig_dbus +#define dbus_free_string_array dbus_free_string_array_dylibloader_orig_dbus +#define dbus_shutdown dbus_shutdown_dylibloader_orig_dbus +#define dbus_message_new dbus_message_new_dylibloader_orig_dbus +#define dbus_message_new_method_call dbus_message_new_method_call_dylibloader_orig_dbus +#define dbus_message_new_method_return dbus_message_new_method_return_dylibloader_orig_dbus +#define dbus_message_new_signal dbus_message_new_signal_dylibloader_orig_dbus +#define dbus_message_new_error dbus_message_new_error_dylibloader_orig_dbus +#define dbus_message_new_error_printf dbus_message_new_error_printf_dylibloader_orig_dbus +#define dbus_message_copy dbus_message_copy_dylibloader_orig_dbus +#define dbus_message_ref dbus_message_ref_dylibloader_orig_dbus +#define dbus_message_unref dbus_message_unref_dylibloader_orig_dbus +#define dbus_message_get_type dbus_message_get_type_dylibloader_orig_dbus +#define dbus_message_set_path dbus_message_set_path_dylibloader_orig_dbus +#define dbus_message_get_path dbus_message_get_path_dylibloader_orig_dbus +#define dbus_message_has_path dbus_message_has_path_dylibloader_orig_dbus +#define dbus_message_set_interface dbus_message_set_interface_dylibloader_orig_dbus +#define dbus_message_get_interface dbus_message_get_interface_dylibloader_orig_dbus +#define dbus_message_has_interface dbus_message_has_interface_dylibloader_orig_dbus +#define dbus_message_set_member dbus_message_set_member_dylibloader_orig_dbus +#define dbus_message_get_member dbus_message_get_member_dylibloader_orig_dbus +#define dbus_message_has_member dbus_message_has_member_dylibloader_orig_dbus +#define dbus_message_set_error_name dbus_message_set_error_name_dylibloader_orig_dbus +#define dbus_message_get_error_name dbus_message_get_error_name_dylibloader_orig_dbus +#define dbus_message_set_destination dbus_message_set_destination_dylibloader_orig_dbus +#define dbus_message_get_destination dbus_message_get_destination_dylibloader_orig_dbus +#define dbus_message_set_sender dbus_message_set_sender_dylibloader_orig_dbus +#define dbus_message_get_sender dbus_message_get_sender_dylibloader_orig_dbus +#define dbus_message_get_signature dbus_message_get_signature_dylibloader_orig_dbus +#define dbus_message_set_no_reply dbus_message_set_no_reply_dylibloader_orig_dbus +#define dbus_message_get_no_reply dbus_message_get_no_reply_dylibloader_orig_dbus +#define dbus_message_is_method_call dbus_message_is_method_call_dylibloader_orig_dbus +#define dbus_message_is_signal dbus_message_is_signal_dylibloader_orig_dbus +#define dbus_message_is_error dbus_message_is_error_dylibloader_orig_dbus +#define dbus_message_has_destination dbus_message_has_destination_dylibloader_orig_dbus +#define dbus_message_has_sender dbus_message_has_sender_dylibloader_orig_dbus +#define dbus_message_has_signature dbus_message_has_signature_dylibloader_orig_dbus +#define dbus_message_get_serial dbus_message_get_serial_dylibloader_orig_dbus +#define dbus_message_set_serial dbus_message_set_serial_dylibloader_orig_dbus +#define dbus_message_set_reply_serial dbus_message_set_reply_serial_dylibloader_orig_dbus +#define dbus_message_get_reply_serial dbus_message_get_reply_serial_dylibloader_orig_dbus +#define dbus_message_set_auto_start dbus_message_set_auto_start_dylibloader_orig_dbus +#define dbus_message_get_auto_start dbus_message_get_auto_start_dylibloader_orig_dbus +#define dbus_message_get_path_decomposed dbus_message_get_path_decomposed_dylibloader_orig_dbus +#define dbus_message_append_args dbus_message_append_args_dylibloader_orig_dbus +#define dbus_message_append_args_valist dbus_message_append_args_valist_dylibloader_orig_dbus +#define dbus_message_get_args dbus_message_get_args_dylibloader_orig_dbus +#define dbus_message_get_args_valist dbus_message_get_args_valist_dylibloader_orig_dbus +#define dbus_message_contains_unix_fds dbus_message_contains_unix_fds_dylibloader_orig_dbus +#define dbus_message_iter_init_closed dbus_message_iter_init_closed_dylibloader_orig_dbus +#define dbus_message_iter_init dbus_message_iter_init_dylibloader_orig_dbus +#define dbus_message_iter_has_next dbus_message_iter_has_next_dylibloader_orig_dbus +#define dbus_message_iter_next dbus_message_iter_next_dylibloader_orig_dbus +#define dbus_message_iter_get_signature dbus_message_iter_get_signature_dylibloader_orig_dbus +#define dbus_message_iter_get_arg_type dbus_message_iter_get_arg_type_dylibloader_orig_dbus +#define dbus_message_iter_get_element_type dbus_message_iter_get_element_type_dylibloader_orig_dbus +#define dbus_message_iter_recurse dbus_message_iter_recurse_dylibloader_orig_dbus +#define dbus_message_iter_get_basic dbus_message_iter_get_basic_dylibloader_orig_dbus +#define dbus_message_iter_get_element_count dbus_message_iter_get_element_count_dylibloader_orig_dbus +#define dbus_message_iter_get_array_len dbus_message_iter_get_array_len_dylibloader_orig_dbus +#define dbus_message_iter_get_fixed_array dbus_message_iter_get_fixed_array_dylibloader_orig_dbus +#define dbus_message_iter_init_append dbus_message_iter_init_append_dylibloader_orig_dbus +#define dbus_message_iter_append_basic dbus_message_iter_append_basic_dylibloader_orig_dbus +#define dbus_message_iter_append_fixed_array dbus_message_iter_append_fixed_array_dylibloader_orig_dbus +#define dbus_message_iter_open_container dbus_message_iter_open_container_dylibloader_orig_dbus +#define dbus_message_iter_close_container dbus_message_iter_close_container_dylibloader_orig_dbus +#define dbus_message_iter_abandon_container dbus_message_iter_abandon_container_dylibloader_orig_dbus +#define dbus_message_iter_abandon_container_if_open dbus_message_iter_abandon_container_if_open_dylibloader_orig_dbus +#define dbus_message_lock dbus_message_lock_dylibloader_orig_dbus +#define dbus_set_error_from_message dbus_set_error_from_message_dylibloader_orig_dbus +#define dbus_message_allocate_data_slot dbus_message_allocate_data_slot_dylibloader_orig_dbus +#define dbus_message_free_data_slot dbus_message_free_data_slot_dylibloader_orig_dbus +#define dbus_message_set_data dbus_message_set_data_dylibloader_orig_dbus +#define dbus_message_get_data dbus_message_get_data_dylibloader_orig_dbus +#define dbus_message_type_from_string dbus_message_type_from_string_dylibloader_orig_dbus +#define dbus_message_type_to_string dbus_message_type_to_string_dylibloader_orig_dbus +#define dbus_message_marshal dbus_message_marshal_dylibloader_orig_dbus +#define dbus_message_demarshal dbus_message_demarshal_dylibloader_orig_dbus +#define dbus_message_demarshal_bytes_needed dbus_message_demarshal_bytes_needed_dylibloader_orig_dbus +#define dbus_message_set_allow_interactive_authorization dbus_message_set_allow_interactive_authorization_dylibloader_orig_dbus +#define dbus_message_get_allow_interactive_authorization dbus_message_get_allow_interactive_authorization_dylibloader_orig_dbus +#define dbus_connection_open dbus_connection_open_dylibloader_orig_dbus +#define dbus_connection_open_private dbus_connection_open_private_dylibloader_orig_dbus +#define dbus_connection_ref dbus_connection_ref_dylibloader_orig_dbus +#define dbus_connection_unref dbus_connection_unref_dylibloader_orig_dbus +#define dbus_connection_close dbus_connection_close_dylibloader_orig_dbus +#define dbus_connection_get_is_connected dbus_connection_get_is_connected_dylibloader_orig_dbus +#define dbus_connection_get_is_authenticated dbus_connection_get_is_authenticated_dylibloader_orig_dbus +#define dbus_connection_get_is_anonymous dbus_connection_get_is_anonymous_dylibloader_orig_dbus +#define dbus_connection_get_server_id dbus_connection_get_server_id_dylibloader_orig_dbus +#define dbus_connection_can_send_type dbus_connection_can_send_type_dylibloader_orig_dbus +#define dbus_connection_set_exit_on_disconnect dbus_connection_set_exit_on_disconnect_dylibloader_orig_dbus +#define dbus_connection_flush dbus_connection_flush_dylibloader_orig_dbus +#define dbus_connection_read_write_dispatch dbus_connection_read_write_dispatch_dylibloader_orig_dbus +#define dbus_connection_read_write dbus_connection_read_write_dylibloader_orig_dbus +#define dbus_connection_borrow_message dbus_connection_borrow_message_dylibloader_orig_dbus +#define dbus_connection_return_message dbus_connection_return_message_dylibloader_orig_dbus +#define dbus_connection_steal_borrowed_message dbus_connection_steal_borrowed_message_dylibloader_orig_dbus +#define dbus_connection_pop_message dbus_connection_pop_message_dylibloader_orig_dbus +#define dbus_connection_get_dispatch_status dbus_connection_get_dispatch_status_dylibloader_orig_dbus +#define dbus_connection_dispatch dbus_connection_dispatch_dylibloader_orig_dbus +#define dbus_connection_has_messages_to_send dbus_connection_has_messages_to_send_dylibloader_orig_dbus +#define dbus_connection_send dbus_connection_send_dylibloader_orig_dbus +#define dbus_connection_send_with_reply dbus_connection_send_with_reply_dylibloader_orig_dbus +#define dbus_connection_send_with_reply_and_block dbus_connection_send_with_reply_and_block_dylibloader_orig_dbus +#define dbus_connection_set_watch_functions dbus_connection_set_watch_functions_dylibloader_orig_dbus +#define dbus_connection_set_timeout_functions dbus_connection_set_timeout_functions_dylibloader_orig_dbus +#define dbus_connection_set_wakeup_main_function dbus_connection_set_wakeup_main_function_dylibloader_orig_dbus +#define dbus_connection_set_dispatch_status_function dbus_connection_set_dispatch_status_function_dylibloader_orig_dbus +#define dbus_connection_get_unix_user dbus_connection_get_unix_user_dylibloader_orig_dbus +#define dbus_connection_get_unix_process_id dbus_connection_get_unix_process_id_dylibloader_orig_dbus +#define dbus_connection_get_adt_audit_session_data dbus_connection_get_adt_audit_session_data_dylibloader_orig_dbus +#define dbus_connection_set_unix_user_function dbus_connection_set_unix_user_function_dylibloader_orig_dbus +#define dbus_connection_get_windows_user dbus_connection_get_windows_user_dylibloader_orig_dbus +#define dbus_connection_set_windows_user_function dbus_connection_set_windows_user_function_dylibloader_orig_dbus +#define dbus_connection_set_allow_anonymous dbus_connection_set_allow_anonymous_dylibloader_orig_dbus +#define dbus_connection_set_route_peer_messages dbus_connection_set_route_peer_messages_dylibloader_orig_dbus +#define dbus_connection_add_filter dbus_connection_add_filter_dylibloader_orig_dbus +#define dbus_connection_remove_filter dbus_connection_remove_filter_dylibloader_orig_dbus +#define dbus_connection_allocate_data_slot dbus_connection_allocate_data_slot_dylibloader_orig_dbus +#define dbus_connection_free_data_slot dbus_connection_free_data_slot_dylibloader_orig_dbus +#define dbus_connection_set_data dbus_connection_set_data_dylibloader_orig_dbus +#define dbus_connection_get_data dbus_connection_get_data_dylibloader_orig_dbus +#define dbus_connection_set_change_sigpipe dbus_connection_set_change_sigpipe_dylibloader_orig_dbus +#define dbus_connection_set_max_message_size dbus_connection_set_max_message_size_dylibloader_orig_dbus +#define dbus_connection_get_max_message_size dbus_connection_get_max_message_size_dylibloader_orig_dbus +#define dbus_connection_set_max_received_size dbus_connection_set_max_received_size_dylibloader_orig_dbus +#define dbus_connection_get_max_received_size dbus_connection_get_max_received_size_dylibloader_orig_dbus +#define dbus_connection_set_max_message_unix_fds dbus_connection_set_max_message_unix_fds_dylibloader_orig_dbus +#define dbus_connection_get_max_message_unix_fds dbus_connection_get_max_message_unix_fds_dylibloader_orig_dbus +#define dbus_connection_set_max_received_unix_fds dbus_connection_set_max_received_unix_fds_dylibloader_orig_dbus +#define dbus_connection_get_max_received_unix_fds dbus_connection_get_max_received_unix_fds_dylibloader_orig_dbus +#define dbus_connection_get_outgoing_size dbus_connection_get_outgoing_size_dylibloader_orig_dbus +#define dbus_connection_get_outgoing_unix_fds dbus_connection_get_outgoing_unix_fds_dylibloader_orig_dbus +#define dbus_connection_preallocate_send dbus_connection_preallocate_send_dylibloader_orig_dbus +#define dbus_connection_free_preallocated_send dbus_connection_free_preallocated_send_dylibloader_orig_dbus +#define dbus_connection_send_preallocated dbus_connection_send_preallocated_dylibloader_orig_dbus +#define dbus_connection_try_register_object_path dbus_connection_try_register_object_path_dylibloader_orig_dbus +#define dbus_connection_register_object_path dbus_connection_register_object_path_dylibloader_orig_dbus +#define dbus_connection_try_register_fallback dbus_connection_try_register_fallback_dylibloader_orig_dbus +#define dbus_connection_register_fallback dbus_connection_register_fallback_dylibloader_orig_dbus +#define dbus_connection_unregister_object_path dbus_connection_unregister_object_path_dylibloader_orig_dbus +#define dbus_connection_get_object_path_data dbus_connection_get_object_path_data_dylibloader_orig_dbus +#define dbus_connection_list_registered dbus_connection_list_registered_dylibloader_orig_dbus +#define dbus_connection_get_unix_fd dbus_connection_get_unix_fd_dylibloader_orig_dbus +#define dbus_connection_get_socket dbus_connection_get_socket_dylibloader_orig_dbus +#define dbus_watch_get_fd dbus_watch_get_fd_dylibloader_orig_dbus +#define dbus_watch_get_unix_fd dbus_watch_get_unix_fd_dylibloader_orig_dbus +#define dbus_watch_get_socket dbus_watch_get_socket_dylibloader_orig_dbus +#define dbus_watch_get_flags dbus_watch_get_flags_dylibloader_orig_dbus +#define dbus_watch_get_data dbus_watch_get_data_dylibloader_orig_dbus +#define dbus_watch_set_data dbus_watch_set_data_dylibloader_orig_dbus +#define dbus_watch_handle dbus_watch_handle_dylibloader_orig_dbus +#define dbus_watch_get_enabled dbus_watch_get_enabled_dylibloader_orig_dbus +#define dbus_timeout_get_interval dbus_timeout_get_interval_dylibloader_orig_dbus +#define dbus_timeout_get_data dbus_timeout_get_data_dylibloader_orig_dbus +#define dbus_timeout_set_data dbus_timeout_set_data_dylibloader_orig_dbus +#define dbus_timeout_handle dbus_timeout_handle_dylibloader_orig_dbus +#define dbus_timeout_get_enabled dbus_timeout_get_enabled_dylibloader_orig_dbus +#define dbus_bus_get dbus_bus_get_dylibloader_orig_dbus +#define dbus_bus_get_private dbus_bus_get_private_dylibloader_orig_dbus +#define dbus_bus_register dbus_bus_register_dylibloader_orig_dbus +#define dbus_bus_set_unique_name dbus_bus_set_unique_name_dylibloader_orig_dbus +#define dbus_bus_get_unique_name dbus_bus_get_unique_name_dylibloader_orig_dbus +#define dbus_bus_get_unix_user dbus_bus_get_unix_user_dylibloader_orig_dbus +#define dbus_bus_get_id dbus_bus_get_id_dylibloader_orig_dbus +#define dbus_bus_request_name dbus_bus_request_name_dylibloader_orig_dbus +#define dbus_bus_release_name dbus_bus_release_name_dylibloader_orig_dbus +#define dbus_bus_name_has_owner dbus_bus_name_has_owner_dylibloader_orig_dbus +#define dbus_bus_start_service_by_name dbus_bus_start_service_by_name_dylibloader_orig_dbus +#define dbus_bus_add_match dbus_bus_add_match_dylibloader_orig_dbus +#define dbus_bus_remove_match dbus_bus_remove_match_dylibloader_orig_dbus +#define dbus_get_local_machine_id dbus_get_local_machine_id_dylibloader_orig_dbus +#define dbus_get_version dbus_get_version_dylibloader_orig_dbus +#define dbus_setenv dbus_setenv_dylibloader_orig_dbus +#define dbus_try_get_local_machine_id dbus_try_get_local_machine_id_dylibloader_orig_dbus +#define dbus_pending_call_ref dbus_pending_call_ref_dylibloader_orig_dbus +#define dbus_pending_call_unref dbus_pending_call_unref_dylibloader_orig_dbus +#define dbus_pending_call_set_notify dbus_pending_call_set_notify_dylibloader_orig_dbus +#define dbus_pending_call_cancel dbus_pending_call_cancel_dylibloader_orig_dbus +#define dbus_pending_call_get_completed dbus_pending_call_get_completed_dylibloader_orig_dbus +#define dbus_pending_call_steal_reply dbus_pending_call_steal_reply_dylibloader_orig_dbus +#define dbus_pending_call_block dbus_pending_call_block_dylibloader_orig_dbus +#define dbus_pending_call_allocate_data_slot dbus_pending_call_allocate_data_slot_dylibloader_orig_dbus +#define dbus_pending_call_free_data_slot dbus_pending_call_free_data_slot_dylibloader_orig_dbus +#define dbus_pending_call_set_data dbus_pending_call_set_data_dylibloader_orig_dbus +#define dbus_pending_call_get_data dbus_pending_call_get_data_dylibloader_orig_dbus +#define dbus_server_listen dbus_server_listen_dylibloader_orig_dbus +#define dbus_server_ref dbus_server_ref_dylibloader_orig_dbus +#define dbus_server_unref dbus_server_unref_dylibloader_orig_dbus +#define dbus_server_disconnect dbus_server_disconnect_dylibloader_orig_dbus +#define dbus_server_get_is_connected dbus_server_get_is_connected_dylibloader_orig_dbus +#define dbus_server_get_address dbus_server_get_address_dylibloader_orig_dbus +#define dbus_server_get_id dbus_server_get_id_dylibloader_orig_dbus +#define dbus_server_set_new_connection_function dbus_server_set_new_connection_function_dylibloader_orig_dbus +#define dbus_server_set_watch_functions dbus_server_set_watch_functions_dylibloader_orig_dbus +#define dbus_server_set_timeout_functions dbus_server_set_timeout_functions_dylibloader_orig_dbus +#define dbus_server_set_auth_mechanisms dbus_server_set_auth_mechanisms_dylibloader_orig_dbus +#define dbus_server_allocate_data_slot dbus_server_allocate_data_slot_dylibloader_orig_dbus +#define dbus_server_free_data_slot dbus_server_free_data_slot_dylibloader_orig_dbus +#define dbus_server_set_data dbus_server_set_data_dylibloader_orig_dbus +#define dbus_server_get_data dbus_server_get_data_dylibloader_orig_dbus +#define dbus_signature_iter_init dbus_signature_iter_init_dylibloader_orig_dbus +#define dbus_signature_iter_get_current_type dbus_signature_iter_get_current_type_dylibloader_orig_dbus +#define dbus_signature_iter_get_signature dbus_signature_iter_get_signature_dylibloader_orig_dbus +#define dbus_signature_iter_get_element_type dbus_signature_iter_get_element_type_dylibloader_orig_dbus +#define dbus_signature_iter_next dbus_signature_iter_next_dylibloader_orig_dbus +#define dbus_signature_iter_recurse dbus_signature_iter_recurse_dylibloader_orig_dbus +#define dbus_signature_validate dbus_signature_validate_dylibloader_orig_dbus +#define dbus_signature_validate_single dbus_signature_validate_single_dylibloader_orig_dbus +#define dbus_type_is_valid dbus_type_is_valid_dylibloader_orig_dbus +#define dbus_type_is_basic dbus_type_is_basic_dylibloader_orig_dbus +#define dbus_type_is_container dbus_type_is_container_dylibloader_orig_dbus +#define dbus_type_is_fixed dbus_type_is_fixed_dylibloader_orig_dbus +#define dbus_validate_path dbus_validate_path_dylibloader_orig_dbus +#define dbus_validate_interface dbus_validate_interface_dylibloader_orig_dbus +#define dbus_validate_member dbus_validate_member_dylibloader_orig_dbus +#define dbus_validate_error_name dbus_validate_error_name_dylibloader_orig_dbus +#define dbus_validate_bus_name dbus_validate_bus_name_dylibloader_orig_dbus +#define dbus_validate_utf8 dbus_validate_utf8_dylibloader_orig_dbus +#define dbus_threads_init dbus_threads_init_dylibloader_orig_dbus +#define dbus_threads_init_default dbus_threads_init_default_dylibloader_orig_dbus +#include <dbus/dbus.h> +#undef dbus_error_init +#undef dbus_error_free +#undef dbus_set_error +#undef dbus_set_error_const +#undef dbus_move_error +#undef dbus_error_has_name +#undef dbus_error_is_set +#undef dbus_parse_address +#undef dbus_address_entry_get_value +#undef dbus_address_entry_get_method +#undef dbus_address_entries_free +#undef dbus_address_escape_value +#undef dbus_address_unescape_value +#undef dbus_malloc +#undef dbus_malloc0 +#undef dbus_realloc +#undef dbus_free +#undef dbus_free_string_array +#undef dbus_shutdown +#undef dbus_message_new +#undef dbus_message_new_method_call +#undef dbus_message_new_method_return +#undef dbus_message_new_signal +#undef dbus_message_new_error +#undef dbus_message_new_error_printf +#undef dbus_message_copy +#undef dbus_message_ref +#undef dbus_message_unref +#undef dbus_message_get_type +#undef dbus_message_set_path +#undef dbus_message_get_path +#undef dbus_message_has_path +#undef dbus_message_set_interface +#undef dbus_message_get_interface +#undef dbus_message_has_interface +#undef dbus_message_set_member +#undef dbus_message_get_member +#undef dbus_message_has_member +#undef dbus_message_set_error_name +#undef dbus_message_get_error_name +#undef dbus_message_set_destination +#undef dbus_message_get_destination +#undef dbus_message_set_sender +#undef dbus_message_get_sender +#undef dbus_message_get_signature +#undef dbus_message_set_no_reply +#undef dbus_message_get_no_reply +#undef dbus_message_is_method_call +#undef dbus_message_is_signal +#undef dbus_message_is_error +#undef dbus_message_has_destination +#undef dbus_message_has_sender +#undef dbus_message_has_signature +#undef dbus_message_get_serial +#undef dbus_message_set_serial +#undef dbus_message_set_reply_serial +#undef dbus_message_get_reply_serial +#undef dbus_message_set_auto_start +#undef dbus_message_get_auto_start +#undef dbus_message_get_path_decomposed +#undef dbus_message_append_args +#undef dbus_message_append_args_valist +#undef dbus_message_get_args +#undef dbus_message_get_args_valist +#undef dbus_message_contains_unix_fds +#undef dbus_message_iter_init_closed +#undef dbus_message_iter_init +#undef dbus_message_iter_has_next +#undef dbus_message_iter_next +#undef dbus_message_iter_get_signature +#undef dbus_message_iter_get_arg_type +#undef dbus_message_iter_get_element_type +#undef dbus_message_iter_recurse +#undef dbus_message_iter_get_basic +#undef dbus_message_iter_get_element_count +#undef dbus_message_iter_get_array_len +#undef dbus_message_iter_get_fixed_array +#undef dbus_message_iter_init_append +#undef dbus_message_iter_append_basic +#undef dbus_message_iter_append_fixed_array +#undef dbus_message_iter_open_container +#undef dbus_message_iter_close_container +#undef dbus_message_iter_abandon_container +#undef dbus_message_iter_abandon_container_if_open +#undef dbus_message_lock +#undef dbus_set_error_from_message +#undef dbus_message_allocate_data_slot +#undef dbus_message_free_data_slot +#undef dbus_message_set_data +#undef dbus_message_get_data +#undef dbus_message_type_from_string +#undef dbus_message_type_to_string +#undef dbus_message_marshal +#undef dbus_message_demarshal +#undef dbus_message_demarshal_bytes_needed +#undef dbus_message_set_allow_interactive_authorization +#undef dbus_message_get_allow_interactive_authorization +#undef dbus_connection_open +#undef dbus_connection_open_private +#undef dbus_connection_ref +#undef dbus_connection_unref +#undef dbus_connection_close +#undef dbus_connection_get_is_connected +#undef dbus_connection_get_is_authenticated +#undef dbus_connection_get_is_anonymous +#undef dbus_connection_get_server_id +#undef dbus_connection_can_send_type +#undef dbus_connection_set_exit_on_disconnect +#undef dbus_connection_flush +#undef dbus_connection_read_write_dispatch +#undef dbus_connection_read_write +#undef dbus_connection_borrow_message +#undef dbus_connection_return_message +#undef dbus_connection_steal_borrowed_message +#undef dbus_connection_pop_message +#undef dbus_connection_get_dispatch_status +#undef dbus_connection_dispatch +#undef dbus_connection_has_messages_to_send +#undef dbus_connection_send +#undef dbus_connection_send_with_reply +#undef dbus_connection_send_with_reply_and_block +#undef dbus_connection_set_watch_functions +#undef dbus_connection_set_timeout_functions +#undef dbus_connection_set_wakeup_main_function +#undef dbus_connection_set_dispatch_status_function +#undef dbus_connection_get_unix_user +#undef dbus_connection_get_unix_process_id +#undef dbus_connection_get_adt_audit_session_data +#undef dbus_connection_set_unix_user_function +#undef dbus_connection_get_windows_user +#undef dbus_connection_set_windows_user_function +#undef dbus_connection_set_allow_anonymous +#undef dbus_connection_set_route_peer_messages +#undef dbus_connection_add_filter +#undef dbus_connection_remove_filter +#undef dbus_connection_allocate_data_slot +#undef dbus_connection_free_data_slot +#undef dbus_connection_set_data +#undef dbus_connection_get_data +#undef dbus_connection_set_change_sigpipe +#undef dbus_connection_set_max_message_size +#undef dbus_connection_get_max_message_size +#undef dbus_connection_set_max_received_size +#undef dbus_connection_get_max_received_size +#undef dbus_connection_set_max_message_unix_fds +#undef dbus_connection_get_max_message_unix_fds +#undef dbus_connection_set_max_received_unix_fds +#undef dbus_connection_get_max_received_unix_fds +#undef dbus_connection_get_outgoing_size +#undef dbus_connection_get_outgoing_unix_fds +#undef dbus_connection_preallocate_send +#undef dbus_connection_free_preallocated_send +#undef dbus_connection_send_preallocated +#undef dbus_connection_try_register_object_path +#undef dbus_connection_register_object_path +#undef dbus_connection_try_register_fallback +#undef dbus_connection_register_fallback +#undef dbus_connection_unregister_object_path +#undef dbus_connection_get_object_path_data +#undef dbus_connection_list_registered +#undef dbus_connection_get_unix_fd +#undef dbus_connection_get_socket +#undef dbus_watch_get_fd +#undef dbus_watch_get_unix_fd +#undef dbus_watch_get_socket +#undef dbus_watch_get_flags +#undef dbus_watch_get_data +#undef dbus_watch_set_data +#undef dbus_watch_handle +#undef dbus_watch_get_enabled +#undef dbus_timeout_get_interval +#undef dbus_timeout_get_data +#undef dbus_timeout_set_data +#undef dbus_timeout_handle +#undef dbus_timeout_get_enabled +#undef dbus_bus_get +#undef dbus_bus_get_private +#undef dbus_bus_register +#undef dbus_bus_set_unique_name +#undef dbus_bus_get_unique_name +#undef dbus_bus_get_unix_user +#undef dbus_bus_get_id +#undef dbus_bus_request_name +#undef dbus_bus_release_name +#undef dbus_bus_name_has_owner +#undef dbus_bus_start_service_by_name +#undef dbus_bus_add_match +#undef dbus_bus_remove_match +#undef dbus_get_local_machine_id +#undef dbus_get_version +#undef dbus_setenv +#undef dbus_try_get_local_machine_id +#undef dbus_pending_call_ref +#undef dbus_pending_call_unref +#undef dbus_pending_call_set_notify +#undef dbus_pending_call_cancel +#undef dbus_pending_call_get_completed +#undef dbus_pending_call_steal_reply +#undef dbus_pending_call_block +#undef dbus_pending_call_allocate_data_slot +#undef dbus_pending_call_free_data_slot +#undef dbus_pending_call_set_data +#undef dbus_pending_call_get_data +#undef dbus_server_listen +#undef dbus_server_ref +#undef dbus_server_unref +#undef dbus_server_disconnect +#undef dbus_server_get_is_connected +#undef dbus_server_get_address +#undef dbus_server_get_id +#undef dbus_server_set_new_connection_function +#undef dbus_server_set_watch_functions +#undef dbus_server_set_timeout_functions +#undef dbus_server_set_auth_mechanisms +#undef dbus_server_allocate_data_slot +#undef dbus_server_free_data_slot +#undef dbus_server_set_data +#undef dbus_server_get_data +#undef dbus_signature_iter_init +#undef dbus_signature_iter_get_current_type +#undef dbus_signature_iter_get_signature +#undef dbus_signature_iter_get_element_type +#undef dbus_signature_iter_next +#undef dbus_signature_iter_recurse +#undef dbus_signature_validate +#undef dbus_signature_validate_single +#undef dbus_type_is_valid +#undef dbus_type_is_basic +#undef dbus_type_is_container +#undef dbus_type_is_fixed +#undef dbus_validate_path +#undef dbus_validate_interface +#undef dbus_validate_member +#undef dbus_validate_error_name +#undef dbus_validate_bus_name +#undef dbus_validate_utf8 +#undef dbus_threads_init +#undef dbus_threads_init_default +#include <dlfcn.h> +#include <stdio.h> +void (*dbus_error_init_dylibloader_wrapper_dbus)( DBusError*); +void (*dbus_error_free_dylibloader_wrapper_dbus)( DBusError*); +void (*dbus_set_error_dylibloader_wrapper_dbus)( DBusError*,const char*,const char*,...); +void (*dbus_set_error_const_dylibloader_wrapper_dbus)( DBusError*,const char*,const char*); +void (*dbus_move_error_dylibloader_wrapper_dbus)( DBusError*, DBusError*); +dbus_bool_t (*dbus_error_has_name_dylibloader_wrapper_dbus)(const DBusError*,const char*); +dbus_bool_t (*dbus_error_is_set_dylibloader_wrapper_dbus)(const DBusError*); +dbus_bool_t (*dbus_parse_address_dylibloader_wrapper_dbus)(const char*, DBusAddressEntry***, int*, DBusError*); +const char* (*dbus_address_entry_get_value_dylibloader_wrapper_dbus)( DBusAddressEntry*,const char*); +const char* (*dbus_address_entry_get_method_dylibloader_wrapper_dbus)( DBusAddressEntry*); +void (*dbus_address_entries_free_dylibloader_wrapper_dbus)( DBusAddressEntry**); +char* (*dbus_address_escape_value_dylibloader_wrapper_dbus)(const char*); +char* (*dbus_address_unescape_value_dylibloader_wrapper_dbus)(const char*, DBusError*); +void* (*dbus_malloc_dylibloader_wrapper_dbus)( size_t); +void* (*dbus_malloc0_dylibloader_wrapper_dbus)( size_t); +void* (*dbus_realloc_dylibloader_wrapper_dbus)( void*, size_t); +void (*dbus_free_dylibloader_wrapper_dbus)( void*); +void (*dbus_free_string_array_dylibloader_wrapper_dbus)( char**); +void (*dbus_shutdown_dylibloader_wrapper_dbus)( void); +DBusMessage* (*dbus_message_new_dylibloader_wrapper_dbus)( int); +DBusMessage* (*dbus_message_new_method_call_dylibloader_wrapper_dbus)(const char*,const char*,const char*,const char*); +DBusMessage* (*dbus_message_new_method_return_dylibloader_wrapper_dbus)( DBusMessage*); +DBusMessage* (*dbus_message_new_signal_dylibloader_wrapper_dbus)(const char*,const char*,const char*); +DBusMessage* (*dbus_message_new_error_dylibloader_wrapper_dbus)( DBusMessage*,const char*,const char*); +DBusMessage* (*dbus_message_new_error_printf_dylibloader_wrapper_dbus)( DBusMessage*,const char*,const char*,...); +DBusMessage* (*dbus_message_copy_dylibloader_wrapper_dbus)(const DBusMessage*); +DBusMessage* (*dbus_message_ref_dylibloader_wrapper_dbus)( DBusMessage*); +void (*dbus_message_unref_dylibloader_wrapper_dbus)( DBusMessage*); +int (*dbus_message_get_type_dylibloader_wrapper_dbus)( DBusMessage*); +dbus_bool_t (*dbus_message_set_path_dylibloader_wrapper_dbus)( DBusMessage*,const char*); +const char* (*dbus_message_get_path_dylibloader_wrapper_dbus)( DBusMessage*); +dbus_bool_t (*dbus_message_has_path_dylibloader_wrapper_dbus)( DBusMessage*,const char*); +dbus_bool_t (*dbus_message_set_interface_dylibloader_wrapper_dbus)( DBusMessage*,const char*); +const char* (*dbus_message_get_interface_dylibloader_wrapper_dbus)( DBusMessage*); +dbus_bool_t (*dbus_message_has_interface_dylibloader_wrapper_dbus)( DBusMessage*,const char*); +dbus_bool_t (*dbus_message_set_member_dylibloader_wrapper_dbus)( DBusMessage*,const char*); +const char* (*dbus_message_get_member_dylibloader_wrapper_dbus)( DBusMessage*); +dbus_bool_t (*dbus_message_has_member_dylibloader_wrapper_dbus)( DBusMessage*,const char*); +dbus_bool_t (*dbus_message_set_error_name_dylibloader_wrapper_dbus)( DBusMessage*,const char*); +const char* (*dbus_message_get_error_name_dylibloader_wrapper_dbus)( DBusMessage*); +dbus_bool_t (*dbus_message_set_destination_dylibloader_wrapper_dbus)( DBusMessage*,const char*); +const char* (*dbus_message_get_destination_dylibloader_wrapper_dbus)( DBusMessage*); +dbus_bool_t (*dbus_message_set_sender_dylibloader_wrapper_dbus)( DBusMessage*,const char*); +const char* (*dbus_message_get_sender_dylibloader_wrapper_dbus)( DBusMessage*); +const char* (*dbus_message_get_signature_dylibloader_wrapper_dbus)( DBusMessage*); +void (*dbus_message_set_no_reply_dylibloader_wrapper_dbus)( DBusMessage*, dbus_bool_t); +dbus_bool_t (*dbus_message_get_no_reply_dylibloader_wrapper_dbus)( DBusMessage*); +dbus_bool_t (*dbus_message_is_method_call_dylibloader_wrapper_dbus)( DBusMessage*,const char*,const char*); +dbus_bool_t (*dbus_message_is_signal_dylibloader_wrapper_dbus)( DBusMessage*,const char*,const char*); +dbus_bool_t (*dbus_message_is_error_dylibloader_wrapper_dbus)( DBusMessage*,const char*); +dbus_bool_t (*dbus_message_has_destination_dylibloader_wrapper_dbus)( DBusMessage*,const char*); +dbus_bool_t (*dbus_message_has_sender_dylibloader_wrapper_dbus)( DBusMessage*,const char*); +dbus_bool_t (*dbus_message_has_signature_dylibloader_wrapper_dbus)( DBusMessage*,const char*); +dbus_uint32_t (*dbus_message_get_serial_dylibloader_wrapper_dbus)( DBusMessage*); +void (*dbus_message_set_serial_dylibloader_wrapper_dbus)( DBusMessage*, dbus_uint32_t); +dbus_bool_t (*dbus_message_set_reply_serial_dylibloader_wrapper_dbus)( DBusMessage*, dbus_uint32_t); +dbus_uint32_t (*dbus_message_get_reply_serial_dylibloader_wrapper_dbus)( DBusMessage*); +void (*dbus_message_set_auto_start_dylibloader_wrapper_dbus)( DBusMessage*, dbus_bool_t); +dbus_bool_t (*dbus_message_get_auto_start_dylibloader_wrapper_dbus)( DBusMessage*); +dbus_bool_t (*dbus_message_get_path_decomposed_dylibloader_wrapper_dbus)( DBusMessage*, char***); +dbus_bool_t (*dbus_message_append_args_dylibloader_wrapper_dbus)( DBusMessage*, int,...); +dbus_bool_t (*dbus_message_append_args_valist_dylibloader_wrapper_dbus)( DBusMessage*, int, va_list); +dbus_bool_t (*dbus_message_get_args_dylibloader_wrapper_dbus)( DBusMessage*, DBusError*, int,...); +dbus_bool_t (*dbus_message_get_args_valist_dylibloader_wrapper_dbus)( DBusMessage*, DBusError*, int, va_list); +dbus_bool_t (*dbus_message_contains_unix_fds_dylibloader_wrapper_dbus)( DBusMessage*); +void (*dbus_message_iter_init_closed_dylibloader_wrapper_dbus)( DBusMessageIter*); +dbus_bool_t (*dbus_message_iter_init_dylibloader_wrapper_dbus)( DBusMessage*, DBusMessageIter*); +dbus_bool_t (*dbus_message_iter_has_next_dylibloader_wrapper_dbus)( DBusMessageIter*); +dbus_bool_t (*dbus_message_iter_next_dylibloader_wrapper_dbus)( DBusMessageIter*); +char* (*dbus_message_iter_get_signature_dylibloader_wrapper_dbus)( DBusMessageIter*); +int (*dbus_message_iter_get_arg_type_dylibloader_wrapper_dbus)( DBusMessageIter*); +int (*dbus_message_iter_get_element_type_dylibloader_wrapper_dbus)( DBusMessageIter*); +void (*dbus_message_iter_recurse_dylibloader_wrapper_dbus)( DBusMessageIter*, DBusMessageIter*); +void (*dbus_message_iter_get_basic_dylibloader_wrapper_dbus)( DBusMessageIter*, void*); +int (*dbus_message_iter_get_element_count_dylibloader_wrapper_dbus)( DBusMessageIter*); +int (*dbus_message_iter_get_array_len_dylibloader_wrapper_dbus)( DBusMessageIter*); +void (*dbus_message_iter_get_fixed_array_dylibloader_wrapper_dbus)( DBusMessageIter*, void*, int*); +void (*dbus_message_iter_init_append_dylibloader_wrapper_dbus)( DBusMessage*, DBusMessageIter*); +dbus_bool_t (*dbus_message_iter_append_basic_dylibloader_wrapper_dbus)( DBusMessageIter*, int,const void*); +dbus_bool_t (*dbus_message_iter_append_fixed_array_dylibloader_wrapper_dbus)( DBusMessageIter*, int,const void*, int); +dbus_bool_t (*dbus_message_iter_open_container_dylibloader_wrapper_dbus)( DBusMessageIter*, int,const char*, DBusMessageIter*); +dbus_bool_t (*dbus_message_iter_close_container_dylibloader_wrapper_dbus)( DBusMessageIter*, DBusMessageIter*); +void (*dbus_message_iter_abandon_container_dylibloader_wrapper_dbus)( DBusMessageIter*, DBusMessageIter*); +void (*dbus_message_iter_abandon_container_if_open_dylibloader_wrapper_dbus)( DBusMessageIter*, DBusMessageIter*); +void (*dbus_message_lock_dylibloader_wrapper_dbus)( DBusMessage*); +dbus_bool_t (*dbus_set_error_from_message_dylibloader_wrapper_dbus)( DBusError*, DBusMessage*); +dbus_bool_t (*dbus_message_allocate_data_slot_dylibloader_wrapper_dbus)( dbus_int32_t*); +void (*dbus_message_free_data_slot_dylibloader_wrapper_dbus)( dbus_int32_t*); +dbus_bool_t (*dbus_message_set_data_dylibloader_wrapper_dbus)( DBusMessage*, dbus_int32_t, void*, DBusFreeFunction); +void* (*dbus_message_get_data_dylibloader_wrapper_dbus)( DBusMessage*, dbus_int32_t); +int (*dbus_message_type_from_string_dylibloader_wrapper_dbus)(const char*); +const char* (*dbus_message_type_to_string_dylibloader_wrapper_dbus)( int); +dbus_bool_t (*dbus_message_marshal_dylibloader_wrapper_dbus)( DBusMessage*, char**, int*); +DBusMessage* (*dbus_message_demarshal_dylibloader_wrapper_dbus)(const char*, int, DBusError*); +int (*dbus_message_demarshal_bytes_needed_dylibloader_wrapper_dbus)(const char*, int); +void (*dbus_message_set_allow_interactive_authorization_dylibloader_wrapper_dbus)( DBusMessage*, dbus_bool_t); +dbus_bool_t (*dbus_message_get_allow_interactive_authorization_dylibloader_wrapper_dbus)( DBusMessage*); +DBusConnection* (*dbus_connection_open_dylibloader_wrapper_dbus)(const char*, DBusError*); +DBusConnection* (*dbus_connection_open_private_dylibloader_wrapper_dbus)(const char*, DBusError*); +DBusConnection* (*dbus_connection_ref_dylibloader_wrapper_dbus)( DBusConnection*); +void (*dbus_connection_unref_dylibloader_wrapper_dbus)( DBusConnection*); +void (*dbus_connection_close_dylibloader_wrapper_dbus)( DBusConnection*); +dbus_bool_t (*dbus_connection_get_is_connected_dylibloader_wrapper_dbus)( DBusConnection*); +dbus_bool_t (*dbus_connection_get_is_authenticated_dylibloader_wrapper_dbus)( DBusConnection*); +dbus_bool_t (*dbus_connection_get_is_anonymous_dylibloader_wrapper_dbus)( DBusConnection*); +char* (*dbus_connection_get_server_id_dylibloader_wrapper_dbus)( DBusConnection*); +dbus_bool_t (*dbus_connection_can_send_type_dylibloader_wrapper_dbus)( DBusConnection*, int); +void (*dbus_connection_set_exit_on_disconnect_dylibloader_wrapper_dbus)( DBusConnection*, dbus_bool_t); +void (*dbus_connection_flush_dylibloader_wrapper_dbus)( DBusConnection*); +dbus_bool_t (*dbus_connection_read_write_dispatch_dylibloader_wrapper_dbus)( DBusConnection*, int); +dbus_bool_t (*dbus_connection_read_write_dylibloader_wrapper_dbus)( DBusConnection*, int); +DBusMessage* (*dbus_connection_borrow_message_dylibloader_wrapper_dbus)( DBusConnection*); +void (*dbus_connection_return_message_dylibloader_wrapper_dbus)( DBusConnection*, DBusMessage*); +void (*dbus_connection_steal_borrowed_message_dylibloader_wrapper_dbus)( DBusConnection*, DBusMessage*); +DBusMessage* (*dbus_connection_pop_message_dylibloader_wrapper_dbus)( DBusConnection*); +DBusDispatchStatus (*dbus_connection_get_dispatch_status_dylibloader_wrapper_dbus)( DBusConnection*); +DBusDispatchStatus (*dbus_connection_dispatch_dylibloader_wrapper_dbus)( DBusConnection*); +dbus_bool_t (*dbus_connection_has_messages_to_send_dylibloader_wrapper_dbus)( DBusConnection*); +dbus_bool_t (*dbus_connection_send_dylibloader_wrapper_dbus)( DBusConnection*, DBusMessage*, dbus_uint32_t*); +dbus_bool_t (*dbus_connection_send_with_reply_dylibloader_wrapper_dbus)( DBusConnection*, DBusMessage*, DBusPendingCall**, int); +DBusMessage* (*dbus_connection_send_with_reply_and_block_dylibloader_wrapper_dbus)( DBusConnection*, DBusMessage*, int, DBusError*); +dbus_bool_t (*dbus_connection_set_watch_functions_dylibloader_wrapper_dbus)( DBusConnection*, DBusAddWatchFunction, DBusRemoveWatchFunction, DBusWatchToggledFunction, void*, DBusFreeFunction); +dbus_bool_t (*dbus_connection_set_timeout_functions_dylibloader_wrapper_dbus)( DBusConnection*, DBusAddTimeoutFunction, DBusRemoveTimeoutFunction, DBusTimeoutToggledFunction, void*, DBusFreeFunction); +void (*dbus_connection_set_wakeup_main_function_dylibloader_wrapper_dbus)( DBusConnection*, DBusWakeupMainFunction, void*, DBusFreeFunction); +void (*dbus_connection_set_dispatch_status_function_dylibloader_wrapper_dbus)( DBusConnection*, DBusDispatchStatusFunction, void*, DBusFreeFunction); +dbus_bool_t (*dbus_connection_get_unix_user_dylibloader_wrapper_dbus)( DBusConnection*, unsigned long*); +dbus_bool_t (*dbus_connection_get_unix_process_id_dylibloader_wrapper_dbus)( DBusConnection*, unsigned long*); +dbus_bool_t (*dbus_connection_get_adt_audit_session_data_dylibloader_wrapper_dbus)( DBusConnection*, void**, dbus_int32_t*); +void (*dbus_connection_set_unix_user_function_dylibloader_wrapper_dbus)( DBusConnection*, DBusAllowUnixUserFunction, void*, DBusFreeFunction); +dbus_bool_t (*dbus_connection_get_windows_user_dylibloader_wrapper_dbus)( DBusConnection*, char**); +void (*dbus_connection_set_windows_user_function_dylibloader_wrapper_dbus)( DBusConnection*, DBusAllowWindowsUserFunction, void*, DBusFreeFunction); +void (*dbus_connection_set_allow_anonymous_dylibloader_wrapper_dbus)( DBusConnection*, dbus_bool_t); +void (*dbus_connection_set_route_peer_messages_dylibloader_wrapper_dbus)( DBusConnection*, dbus_bool_t); +dbus_bool_t (*dbus_connection_add_filter_dylibloader_wrapper_dbus)( DBusConnection*, DBusHandleMessageFunction, void*, DBusFreeFunction); +void (*dbus_connection_remove_filter_dylibloader_wrapper_dbus)( DBusConnection*, DBusHandleMessageFunction, void*); +dbus_bool_t (*dbus_connection_allocate_data_slot_dylibloader_wrapper_dbus)( dbus_int32_t*); +void (*dbus_connection_free_data_slot_dylibloader_wrapper_dbus)( dbus_int32_t*); +dbus_bool_t (*dbus_connection_set_data_dylibloader_wrapper_dbus)( DBusConnection*, dbus_int32_t, void*, DBusFreeFunction); +void* (*dbus_connection_get_data_dylibloader_wrapper_dbus)( DBusConnection*, dbus_int32_t); +void (*dbus_connection_set_change_sigpipe_dylibloader_wrapper_dbus)( dbus_bool_t); +void (*dbus_connection_set_max_message_size_dylibloader_wrapper_dbus)( DBusConnection*, long); +long (*dbus_connection_get_max_message_size_dylibloader_wrapper_dbus)( DBusConnection*); +void (*dbus_connection_set_max_received_size_dylibloader_wrapper_dbus)( DBusConnection*, long); +long (*dbus_connection_get_max_received_size_dylibloader_wrapper_dbus)( DBusConnection*); +void (*dbus_connection_set_max_message_unix_fds_dylibloader_wrapper_dbus)( DBusConnection*, long); +long (*dbus_connection_get_max_message_unix_fds_dylibloader_wrapper_dbus)( DBusConnection*); +void (*dbus_connection_set_max_received_unix_fds_dylibloader_wrapper_dbus)( DBusConnection*, long); +long (*dbus_connection_get_max_received_unix_fds_dylibloader_wrapper_dbus)( DBusConnection*); +long (*dbus_connection_get_outgoing_size_dylibloader_wrapper_dbus)( DBusConnection*); +long (*dbus_connection_get_outgoing_unix_fds_dylibloader_wrapper_dbus)( DBusConnection*); +DBusPreallocatedSend* (*dbus_connection_preallocate_send_dylibloader_wrapper_dbus)( DBusConnection*); +void (*dbus_connection_free_preallocated_send_dylibloader_wrapper_dbus)( DBusConnection*, DBusPreallocatedSend*); +void (*dbus_connection_send_preallocated_dylibloader_wrapper_dbus)( DBusConnection*, DBusPreallocatedSend*, DBusMessage*, dbus_uint32_t*); +dbus_bool_t (*dbus_connection_try_register_object_path_dylibloader_wrapper_dbus)( DBusConnection*,const char*,const DBusObjectPathVTable*, void*, DBusError*); +dbus_bool_t (*dbus_connection_register_object_path_dylibloader_wrapper_dbus)( DBusConnection*,const char*,const DBusObjectPathVTable*, void*); +dbus_bool_t (*dbus_connection_try_register_fallback_dylibloader_wrapper_dbus)( DBusConnection*,const char*,const DBusObjectPathVTable*, void*, DBusError*); +dbus_bool_t (*dbus_connection_register_fallback_dylibloader_wrapper_dbus)( DBusConnection*,const char*,const DBusObjectPathVTable*, void*); +dbus_bool_t (*dbus_connection_unregister_object_path_dylibloader_wrapper_dbus)( DBusConnection*,const char*); +dbus_bool_t (*dbus_connection_get_object_path_data_dylibloader_wrapper_dbus)( DBusConnection*,const char*, void**); +dbus_bool_t (*dbus_connection_list_registered_dylibloader_wrapper_dbus)( DBusConnection*,const char*, char***); +dbus_bool_t (*dbus_connection_get_unix_fd_dylibloader_wrapper_dbus)( DBusConnection*, int*); +dbus_bool_t (*dbus_connection_get_socket_dylibloader_wrapper_dbus)( DBusConnection*, int*); +int (*dbus_watch_get_fd_dylibloader_wrapper_dbus)( DBusWatch*); +int (*dbus_watch_get_unix_fd_dylibloader_wrapper_dbus)( DBusWatch*); +int (*dbus_watch_get_socket_dylibloader_wrapper_dbus)( DBusWatch*); +unsigned int (*dbus_watch_get_flags_dylibloader_wrapper_dbus)( DBusWatch*); +void* (*dbus_watch_get_data_dylibloader_wrapper_dbus)( DBusWatch*); +void (*dbus_watch_set_data_dylibloader_wrapper_dbus)( DBusWatch*, void*, DBusFreeFunction); +dbus_bool_t (*dbus_watch_handle_dylibloader_wrapper_dbus)( DBusWatch*, unsigned int); +dbus_bool_t (*dbus_watch_get_enabled_dylibloader_wrapper_dbus)( DBusWatch*); +int (*dbus_timeout_get_interval_dylibloader_wrapper_dbus)( DBusTimeout*); +void* (*dbus_timeout_get_data_dylibloader_wrapper_dbus)( DBusTimeout*); +void (*dbus_timeout_set_data_dylibloader_wrapper_dbus)( DBusTimeout*, void*, DBusFreeFunction); +dbus_bool_t (*dbus_timeout_handle_dylibloader_wrapper_dbus)( DBusTimeout*); +dbus_bool_t (*dbus_timeout_get_enabled_dylibloader_wrapper_dbus)( DBusTimeout*); +DBusConnection* (*dbus_bus_get_dylibloader_wrapper_dbus)( DBusBusType, DBusError*); +DBusConnection* (*dbus_bus_get_private_dylibloader_wrapper_dbus)( DBusBusType, DBusError*); +dbus_bool_t (*dbus_bus_register_dylibloader_wrapper_dbus)( DBusConnection*, DBusError*); +dbus_bool_t (*dbus_bus_set_unique_name_dylibloader_wrapper_dbus)( DBusConnection*,const char*); +const char* (*dbus_bus_get_unique_name_dylibloader_wrapper_dbus)( DBusConnection*); +unsigned long (*dbus_bus_get_unix_user_dylibloader_wrapper_dbus)( DBusConnection*,const char*, DBusError*); +char* (*dbus_bus_get_id_dylibloader_wrapper_dbus)( DBusConnection*, DBusError*); +int (*dbus_bus_request_name_dylibloader_wrapper_dbus)( DBusConnection*,const char*, unsigned int, DBusError*); +int (*dbus_bus_release_name_dylibloader_wrapper_dbus)( DBusConnection*,const char*, DBusError*); +dbus_bool_t (*dbus_bus_name_has_owner_dylibloader_wrapper_dbus)( DBusConnection*,const char*, DBusError*); +dbus_bool_t (*dbus_bus_start_service_by_name_dylibloader_wrapper_dbus)( DBusConnection*,const char*, dbus_uint32_t, dbus_uint32_t*, DBusError*); +void (*dbus_bus_add_match_dylibloader_wrapper_dbus)( DBusConnection*,const char*, DBusError*); +void (*dbus_bus_remove_match_dylibloader_wrapper_dbus)( DBusConnection*,const char*, DBusError*); +char* (*dbus_get_local_machine_id_dylibloader_wrapper_dbus)( void); +void (*dbus_get_version_dylibloader_wrapper_dbus)( int*, int*, int*); +dbus_bool_t (*dbus_setenv_dylibloader_wrapper_dbus)(const char*,const char*); +char* (*dbus_try_get_local_machine_id_dylibloader_wrapper_dbus)( DBusError*); +DBusPendingCall* (*dbus_pending_call_ref_dylibloader_wrapper_dbus)( DBusPendingCall*); +void (*dbus_pending_call_unref_dylibloader_wrapper_dbus)( DBusPendingCall*); +dbus_bool_t (*dbus_pending_call_set_notify_dylibloader_wrapper_dbus)( DBusPendingCall*, DBusPendingCallNotifyFunction, void*, DBusFreeFunction); +void (*dbus_pending_call_cancel_dylibloader_wrapper_dbus)( DBusPendingCall*); +dbus_bool_t (*dbus_pending_call_get_completed_dylibloader_wrapper_dbus)( DBusPendingCall*); +DBusMessage* (*dbus_pending_call_steal_reply_dylibloader_wrapper_dbus)( DBusPendingCall*); +void (*dbus_pending_call_block_dylibloader_wrapper_dbus)( DBusPendingCall*); +dbus_bool_t (*dbus_pending_call_allocate_data_slot_dylibloader_wrapper_dbus)( dbus_int32_t*); +void (*dbus_pending_call_free_data_slot_dylibloader_wrapper_dbus)( dbus_int32_t*); +dbus_bool_t (*dbus_pending_call_set_data_dylibloader_wrapper_dbus)( DBusPendingCall*, dbus_int32_t, void*, DBusFreeFunction); +void* (*dbus_pending_call_get_data_dylibloader_wrapper_dbus)( DBusPendingCall*, dbus_int32_t); +DBusServer* (*dbus_server_listen_dylibloader_wrapper_dbus)(const char*, DBusError*); +DBusServer* (*dbus_server_ref_dylibloader_wrapper_dbus)( DBusServer*); +void (*dbus_server_unref_dylibloader_wrapper_dbus)( DBusServer*); +void (*dbus_server_disconnect_dylibloader_wrapper_dbus)( DBusServer*); +dbus_bool_t (*dbus_server_get_is_connected_dylibloader_wrapper_dbus)( DBusServer*); +char* (*dbus_server_get_address_dylibloader_wrapper_dbus)( DBusServer*); +char* (*dbus_server_get_id_dylibloader_wrapper_dbus)( DBusServer*); +void (*dbus_server_set_new_connection_function_dylibloader_wrapper_dbus)( DBusServer*, DBusNewConnectionFunction, void*, DBusFreeFunction); +dbus_bool_t (*dbus_server_set_watch_functions_dylibloader_wrapper_dbus)( DBusServer*, DBusAddWatchFunction, DBusRemoveWatchFunction, DBusWatchToggledFunction, void*, DBusFreeFunction); +dbus_bool_t (*dbus_server_set_timeout_functions_dylibloader_wrapper_dbus)( DBusServer*, DBusAddTimeoutFunction, DBusRemoveTimeoutFunction, DBusTimeoutToggledFunction, void*, DBusFreeFunction); +dbus_bool_t (*dbus_server_set_auth_mechanisms_dylibloader_wrapper_dbus)( DBusServer*,const char**); +dbus_bool_t (*dbus_server_allocate_data_slot_dylibloader_wrapper_dbus)( dbus_int32_t*); +void (*dbus_server_free_data_slot_dylibloader_wrapper_dbus)( dbus_int32_t*); +dbus_bool_t (*dbus_server_set_data_dylibloader_wrapper_dbus)( DBusServer*, int, void*, DBusFreeFunction); +void* (*dbus_server_get_data_dylibloader_wrapper_dbus)( DBusServer*, int); +void (*dbus_signature_iter_init_dylibloader_wrapper_dbus)( DBusSignatureIter*,const char*); +int (*dbus_signature_iter_get_current_type_dylibloader_wrapper_dbus)(const DBusSignatureIter*); +char* (*dbus_signature_iter_get_signature_dylibloader_wrapper_dbus)(const DBusSignatureIter*); +int (*dbus_signature_iter_get_element_type_dylibloader_wrapper_dbus)(const DBusSignatureIter*); +dbus_bool_t (*dbus_signature_iter_next_dylibloader_wrapper_dbus)( DBusSignatureIter*); +void (*dbus_signature_iter_recurse_dylibloader_wrapper_dbus)(const DBusSignatureIter*, DBusSignatureIter*); +dbus_bool_t (*dbus_signature_validate_dylibloader_wrapper_dbus)(const char*, DBusError*); +dbus_bool_t (*dbus_signature_validate_single_dylibloader_wrapper_dbus)(const char*, DBusError*); +dbus_bool_t (*dbus_type_is_valid_dylibloader_wrapper_dbus)( int); +dbus_bool_t (*dbus_type_is_basic_dylibloader_wrapper_dbus)( int); +dbus_bool_t (*dbus_type_is_container_dylibloader_wrapper_dbus)( int); +dbus_bool_t (*dbus_type_is_fixed_dylibloader_wrapper_dbus)( int); +dbus_bool_t (*dbus_validate_path_dylibloader_wrapper_dbus)(const char*, DBusError*); +dbus_bool_t (*dbus_validate_interface_dylibloader_wrapper_dbus)(const char*, DBusError*); +dbus_bool_t (*dbus_validate_member_dylibloader_wrapper_dbus)(const char*, DBusError*); +dbus_bool_t (*dbus_validate_error_name_dylibloader_wrapper_dbus)(const char*, DBusError*); +dbus_bool_t (*dbus_validate_bus_name_dylibloader_wrapper_dbus)(const char*, DBusError*); +dbus_bool_t (*dbus_validate_utf8_dylibloader_wrapper_dbus)(const char*, DBusError*); +dbus_bool_t (*dbus_threads_init_dylibloader_wrapper_dbus)(const DBusThreadFunctions*); +dbus_bool_t (*dbus_threads_init_default_dylibloader_wrapper_dbus)( void); +int initialize_dbus(int verbose) { + void *handle; + char *error; + handle = dlopen("libdbus-1.so", RTLD_LAZY); + if (!handle) { + if (verbose) { + fprintf(stderr, "%s\n", dlerror()); + } + return(1); + } + dlerror(); +// dbus_error_init + *(void **) (&dbus_error_init_dylibloader_wrapper_dbus) = dlsym(handle, "dbus_error_init"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// dbus_error_free + *(void **) (&dbus_error_free_dylibloader_wrapper_dbus) = dlsym(handle, "dbus_error_free"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// dbus_set_error + *(void **) (&dbus_set_error_dylibloader_wrapper_dbus) = dlsym(handle, "dbus_set_error"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// dbus_set_error_const + *(void **) (&dbus_set_error_const_dylibloader_wrapper_dbus) = dlsym(handle, "dbus_set_error_const"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// dbus_move_error + *(void **) (&dbus_move_error_dylibloader_wrapper_dbus) = dlsym(handle, "dbus_move_error"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// dbus_error_has_name + *(void **) (&dbus_error_has_name_dylibloader_wrapper_dbus) = dlsym(handle, "dbus_error_has_name"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// dbus_error_is_set + *(void **) (&dbus_error_is_set_dylibloader_wrapper_dbus) = dlsym(handle, "dbus_error_is_set"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// dbus_parse_address + *(void **) (&dbus_parse_address_dylibloader_wrapper_dbus) = dlsym(handle, "dbus_parse_address"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// dbus_address_entry_get_value + *(void **) (&dbus_address_entry_get_value_dylibloader_wrapper_dbus) = dlsym(handle, "dbus_address_entry_get_value"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// dbus_address_entry_get_method + *(void **) (&dbus_address_entry_get_method_dylibloader_wrapper_dbus) = dlsym(handle, "dbus_address_entry_get_method"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// dbus_address_entries_free + *(void **) (&dbus_address_entries_free_dylibloader_wrapper_dbus) = dlsym(handle, "dbus_address_entries_free"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// dbus_address_escape_value + *(void **) (&dbus_address_escape_value_dylibloader_wrapper_dbus) = dlsym(handle, "dbus_address_escape_value"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// dbus_address_unescape_value + *(void **) (&dbus_address_unescape_value_dylibloader_wrapper_dbus) = dlsym(handle, "dbus_address_unescape_value"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// dbus_malloc + *(void **) (&dbus_malloc_dylibloader_wrapper_dbus) = dlsym(handle, "dbus_malloc"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// dbus_malloc0 + *(void **) (&dbus_malloc0_dylibloader_wrapper_dbus) = dlsym(handle, "dbus_malloc0"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// dbus_realloc + *(void **) (&dbus_realloc_dylibloader_wrapper_dbus) = dlsym(handle, "dbus_realloc"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// dbus_free + *(void **) (&dbus_free_dylibloader_wrapper_dbus) = dlsym(handle, "dbus_free"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// dbus_free_string_array + *(void **) (&dbus_free_string_array_dylibloader_wrapper_dbus) = dlsym(handle, "dbus_free_string_array"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// dbus_shutdown + *(void **) (&dbus_shutdown_dylibloader_wrapper_dbus) = dlsym(handle, "dbus_shutdown"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// dbus_message_new + *(void **) (&dbus_message_new_dylibloader_wrapper_dbus) = dlsym(handle, "dbus_message_new"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// dbus_message_new_method_call + *(void **) (&dbus_message_new_method_call_dylibloader_wrapper_dbus) = dlsym(handle, "dbus_message_new_method_call"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// dbus_message_new_method_return + *(void **) (&dbus_message_new_method_return_dylibloader_wrapper_dbus) = dlsym(handle, "dbus_message_new_method_return"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// dbus_message_new_signal + *(void **) (&dbus_message_new_signal_dylibloader_wrapper_dbus) = dlsym(handle, "dbus_message_new_signal"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// dbus_message_new_error + *(void **) (&dbus_message_new_error_dylibloader_wrapper_dbus) = dlsym(handle, "dbus_message_new_error"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// dbus_message_new_error_printf + *(void **) (&dbus_message_new_error_printf_dylibloader_wrapper_dbus) = dlsym(handle, "dbus_message_new_error_printf"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// dbus_message_copy + *(void **) (&dbus_message_copy_dylibloader_wrapper_dbus) = dlsym(handle, "dbus_message_copy"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// dbus_message_ref + *(void **) (&dbus_message_ref_dylibloader_wrapper_dbus) = dlsym(handle, "dbus_message_ref"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// dbus_message_unref + *(void **) (&dbus_message_unref_dylibloader_wrapper_dbus) = dlsym(handle, "dbus_message_unref"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// dbus_message_get_type + *(void **) (&dbus_message_get_type_dylibloader_wrapper_dbus) = dlsym(handle, "dbus_message_get_type"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// dbus_message_set_path + *(void **) (&dbus_message_set_path_dylibloader_wrapper_dbus) = dlsym(handle, "dbus_message_set_path"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// dbus_message_get_path + *(void **) (&dbus_message_get_path_dylibloader_wrapper_dbus) = dlsym(handle, "dbus_message_get_path"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// dbus_message_has_path + *(void **) (&dbus_message_has_path_dylibloader_wrapper_dbus) = dlsym(handle, "dbus_message_has_path"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// dbus_message_set_interface + *(void **) (&dbus_message_set_interface_dylibloader_wrapper_dbus) = dlsym(handle, "dbus_message_set_interface"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// dbus_message_get_interface + *(void **) (&dbus_message_get_interface_dylibloader_wrapper_dbus) = dlsym(handle, "dbus_message_get_interface"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// dbus_message_has_interface + *(void **) (&dbus_message_has_interface_dylibloader_wrapper_dbus) = dlsym(handle, "dbus_message_has_interface"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// dbus_message_set_member + *(void **) (&dbus_message_set_member_dylibloader_wrapper_dbus) = dlsym(handle, "dbus_message_set_member"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// dbus_message_get_member + *(void **) (&dbus_message_get_member_dylibloader_wrapper_dbus) = dlsym(handle, "dbus_message_get_member"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// dbus_message_has_member + *(void **) (&dbus_message_has_member_dylibloader_wrapper_dbus) = dlsym(handle, "dbus_message_has_member"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// dbus_message_set_error_name + *(void **) (&dbus_message_set_error_name_dylibloader_wrapper_dbus) = dlsym(handle, "dbus_message_set_error_name"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// dbus_message_get_error_name + *(void **) (&dbus_message_get_error_name_dylibloader_wrapper_dbus) = dlsym(handle, "dbus_message_get_error_name"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// dbus_message_set_destination + *(void **) (&dbus_message_set_destination_dylibloader_wrapper_dbus) = dlsym(handle, "dbus_message_set_destination"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// dbus_message_get_destination + *(void **) (&dbus_message_get_destination_dylibloader_wrapper_dbus) = dlsym(handle, "dbus_message_get_destination"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// dbus_message_set_sender + *(void **) (&dbus_message_set_sender_dylibloader_wrapper_dbus) = dlsym(handle, "dbus_message_set_sender"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// dbus_message_get_sender + *(void **) (&dbus_message_get_sender_dylibloader_wrapper_dbus) = dlsym(handle, "dbus_message_get_sender"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// dbus_message_get_signature + *(void **) (&dbus_message_get_signature_dylibloader_wrapper_dbus) = dlsym(handle, "dbus_message_get_signature"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// dbus_message_set_no_reply + *(void **) (&dbus_message_set_no_reply_dylibloader_wrapper_dbus) = dlsym(handle, "dbus_message_set_no_reply"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// dbus_message_get_no_reply + *(void **) (&dbus_message_get_no_reply_dylibloader_wrapper_dbus) = dlsym(handle, "dbus_message_get_no_reply"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// dbus_message_is_method_call + *(void **) (&dbus_message_is_method_call_dylibloader_wrapper_dbus) = dlsym(handle, "dbus_message_is_method_call"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// dbus_message_is_signal + *(void **) (&dbus_message_is_signal_dylibloader_wrapper_dbus) = dlsym(handle, "dbus_message_is_signal"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// dbus_message_is_error + *(void **) (&dbus_message_is_error_dylibloader_wrapper_dbus) = dlsym(handle, "dbus_message_is_error"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// dbus_message_has_destination + *(void **) (&dbus_message_has_destination_dylibloader_wrapper_dbus) = dlsym(handle, "dbus_message_has_destination"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// dbus_message_has_sender + *(void **) (&dbus_message_has_sender_dylibloader_wrapper_dbus) = dlsym(handle, "dbus_message_has_sender"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// dbus_message_has_signature + *(void **) (&dbus_message_has_signature_dylibloader_wrapper_dbus) = dlsym(handle, "dbus_message_has_signature"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// dbus_message_get_serial + *(void **) (&dbus_message_get_serial_dylibloader_wrapper_dbus) = dlsym(handle, "dbus_message_get_serial"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// dbus_message_set_serial + *(void **) (&dbus_message_set_serial_dylibloader_wrapper_dbus) = dlsym(handle, "dbus_message_set_serial"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// dbus_message_set_reply_serial + *(void **) (&dbus_message_set_reply_serial_dylibloader_wrapper_dbus) = dlsym(handle, "dbus_message_set_reply_serial"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// dbus_message_get_reply_serial + *(void **) (&dbus_message_get_reply_serial_dylibloader_wrapper_dbus) = dlsym(handle, "dbus_message_get_reply_serial"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// dbus_message_set_auto_start + *(void **) (&dbus_message_set_auto_start_dylibloader_wrapper_dbus) = dlsym(handle, "dbus_message_set_auto_start"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// dbus_message_get_auto_start + *(void **) (&dbus_message_get_auto_start_dylibloader_wrapper_dbus) = dlsym(handle, "dbus_message_get_auto_start"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// dbus_message_get_path_decomposed + *(void **) (&dbus_message_get_path_decomposed_dylibloader_wrapper_dbus) = dlsym(handle, "dbus_message_get_path_decomposed"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// dbus_message_append_args + *(void **) (&dbus_message_append_args_dylibloader_wrapper_dbus) = dlsym(handle, "dbus_message_append_args"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// dbus_message_append_args_valist + *(void **) (&dbus_message_append_args_valist_dylibloader_wrapper_dbus) = dlsym(handle, "dbus_message_append_args_valist"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// dbus_message_get_args + *(void **) (&dbus_message_get_args_dylibloader_wrapper_dbus) = dlsym(handle, "dbus_message_get_args"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// dbus_message_get_args_valist + *(void **) (&dbus_message_get_args_valist_dylibloader_wrapper_dbus) = dlsym(handle, "dbus_message_get_args_valist"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// dbus_message_contains_unix_fds + *(void **) (&dbus_message_contains_unix_fds_dylibloader_wrapper_dbus) = dlsym(handle, "dbus_message_contains_unix_fds"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// dbus_message_iter_init_closed + *(void **) (&dbus_message_iter_init_closed_dylibloader_wrapper_dbus) = dlsym(handle, "dbus_message_iter_init_closed"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// dbus_message_iter_init + *(void **) (&dbus_message_iter_init_dylibloader_wrapper_dbus) = dlsym(handle, "dbus_message_iter_init"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// dbus_message_iter_has_next + *(void **) (&dbus_message_iter_has_next_dylibloader_wrapper_dbus) = dlsym(handle, "dbus_message_iter_has_next"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// dbus_message_iter_next + *(void **) (&dbus_message_iter_next_dylibloader_wrapper_dbus) = dlsym(handle, "dbus_message_iter_next"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// dbus_message_iter_get_signature + *(void **) (&dbus_message_iter_get_signature_dylibloader_wrapper_dbus) = dlsym(handle, "dbus_message_iter_get_signature"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// dbus_message_iter_get_arg_type + *(void **) (&dbus_message_iter_get_arg_type_dylibloader_wrapper_dbus) = dlsym(handle, "dbus_message_iter_get_arg_type"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// dbus_message_iter_get_element_type + *(void **) (&dbus_message_iter_get_element_type_dylibloader_wrapper_dbus) = dlsym(handle, "dbus_message_iter_get_element_type"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// dbus_message_iter_recurse + *(void **) (&dbus_message_iter_recurse_dylibloader_wrapper_dbus) = dlsym(handle, "dbus_message_iter_recurse"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// dbus_message_iter_get_basic + *(void **) (&dbus_message_iter_get_basic_dylibloader_wrapper_dbus) = dlsym(handle, "dbus_message_iter_get_basic"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// dbus_message_iter_get_element_count + *(void **) (&dbus_message_iter_get_element_count_dylibloader_wrapper_dbus) = dlsym(handle, "dbus_message_iter_get_element_count"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// dbus_message_iter_get_array_len + *(void **) (&dbus_message_iter_get_array_len_dylibloader_wrapper_dbus) = dlsym(handle, "dbus_message_iter_get_array_len"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// dbus_message_iter_get_fixed_array + *(void **) (&dbus_message_iter_get_fixed_array_dylibloader_wrapper_dbus) = dlsym(handle, "dbus_message_iter_get_fixed_array"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// dbus_message_iter_init_append + *(void **) (&dbus_message_iter_init_append_dylibloader_wrapper_dbus) = dlsym(handle, "dbus_message_iter_init_append"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// dbus_message_iter_append_basic + *(void **) (&dbus_message_iter_append_basic_dylibloader_wrapper_dbus) = dlsym(handle, "dbus_message_iter_append_basic"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// dbus_message_iter_append_fixed_array + *(void **) (&dbus_message_iter_append_fixed_array_dylibloader_wrapper_dbus) = dlsym(handle, "dbus_message_iter_append_fixed_array"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// dbus_message_iter_open_container + *(void **) (&dbus_message_iter_open_container_dylibloader_wrapper_dbus) = dlsym(handle, "dbus_message_iter_open_container"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// dbus_message_iter_close_container + *(void **) (&dbus_message_iter_close_container_dylibloader_wrapper_dbus) = dlsym(handle, "dbus_message_iter_close_container"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// dbus_message_iter_abandon_container + *(void **) (&dbus_message_iter_abandon_container_dylibloader_wrapper_dbus) = dlsym(handle, "dbus_message_iter_abandon_container"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// dbus_message_iter_abandon_container_if_open + *(void **) (&dbus_message_iter_abandon_container_if_open_dylibloader_wrapper_dbus) = dlsym(handle, "dbus_message_iter_abandon_container_if_open"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// dbus_message_lock + *(void **) (&dbus_message_lock_dylibloader_wrapper_dbus) = dlsym(handle, "dbus_message_lock"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// dbus_set_error_from_message + *(void **) (&dbus_set_error_from_message_dylibloader_wrapper_dbus) = dlsym(handle, "dbus_set_error_from_message"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// dbus_message_allocate_data_slot + *(void **) (&dbus_message_allocate_data_slot_dylibloader_wrapper_dbus) = dlsym(handle, "dbus_message_allocate_data_slot"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// dbus_message_free_data_slot + *(void **) (&dbus_message_free_data_slot_dylibloader_wrapper_dbus) = dlsym(handle, "dbus_message_free_data_slot"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// dbus_message_set_data + *(void **) (&dbus_message_set_data_dylibloader_wrapper_dbus) = dlsym(handle, "dbus_message_set_data"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// dbus_message_get_data + *(void **) (&dbus_message_get_data_dylibloader_wrapper_dbus) = dlsym(handle, "dbus_message_get_data"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// dbus_message_type_from_string + *(void **) (&dbus_message_type_from_string_dylibloader_wrapper_dbus) = dlsym(handle, "dbus_message_type_from_string"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// dbus_message_type_to_string + *(void **) (&dbus_message_type_to_string_dylibloader_wrapper_dbus) = dlsym(handle, "dbus_message_type_to_string"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// dbus_message_marshal + *(void **) (&dbus_message_marshal_dylibloader_wrapper_dbus) = dlsym(handle, "dbus_message_marshal"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// dbus_message_demarshal + *(void **) (&dbus_message_demarshal_dylibloader_wrapper_dbus) = dlsym(handle, "dbus_message_demarshal"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// dbus_message_demarshal_bytes_needed + *(void **) (&dbus_message_demarshal_bytes_needed_dylibloader_wrapper_dbus) = dlsym(handle, "dbus_message_demarshal_bytes_needed"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// dbus_message_set_allow_interactive_authorization + *(void **) (&dbus_message_set_allow_interactive_authorization_dylibloader_wrapper_dbus) = dlsym(handle, "dbus_message_set_allow_interactive_authorization"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// dbus_message_get_allow_interactive_authorization + *(void **) (&dbus_message_get_allow_interactive_authorization_dylibloader_wrapper_dbus) = dlsym(handle, "dbus_message_get_allow_interactive_authorization"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// dbus_connection_open + *(void **) (&dbus_connection_open_dylibloader_wrapper_dbus) = dlsym(handle, "dbus_connection_open"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// dbus_connection_open_private + *(void **) (&dbus_connection_open_private_dylibloader_wrapper_dbus) = dlsym(handle, "dbus_connection_open_private"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// dbus_connection_ref + *(void **) (&dbus_connection_ref_dylibloader_wrapper_dbus) = dlsym(handle, "dbus_connection_ref"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// dbus_connection_unref + *(void **) (&dbus_connection_unref_dylibloader_wrapper_dbus) = dlsym(handle, "dbus_connection_unref"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// dbus_connection_close + *(void **) (&dbus_connection_close_dylibloader_wrapper_dbus) = dlsym(handle, "dbus_connection_close"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// dbus_connection_get_is_connected + *(void **) (&dbus_connection_get_is_connected_dylibloader_wrapper_dbus) = dlsym(handle, "dbus_connection_get_is_connected"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// dbus_connection_get_is_authenticated + *(void **) (&dbus_connection_get_is_authenticated_dylibloader_wrapper_dbus) = dlsym(handle, "dbus_connection_get_is_authenticated"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// dbus_connection_get_is_anonymous + *(void **) (&dbus_connection_get_is_anonymous_dylibloader_wrapper_dbus) = dlsym(handle, "dbus_connection_get_is_anonymous"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// dbus_connection_get_server_id + *(void **) (&dbus_connection_get_server_id_dylibloader_wrapper_dbus) = dlsym(handle, "dbus_connection_get_server_id"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// dbus_connection_can_send_type + *(void **) (&dbus_connection_can_send_type_dylibloader_wrapper_dbus) = dlsym(handle, "dbus_connection_can_send_type"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// dbus_connection_set_exit_on_disconnect + *(void **) (&dbus_connection_set_exit_on_disconnect_dylibloader_wrapper_dbus) = dlsym(handle, "dbus_connection_set_exit_on_disconnect"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// dbus_connection_flush + *(void **) (&dbus_connection_flush_dylibloader_wrapper_dbus) = dlsym(handle, "dbus_connection_flush"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// dbus_connection_read_write_dispatch + *(void **) (&dbus_connection_read_write_dispatch_dylibloader_wrapper_dbus) = dlsym(handle, "dbus_connection_read_write_dispatch"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// dbus_connection_read_write + *(void **) (&dbus_connection_read_write_dylibloader_wrapper_dbus) = dlsym(handle, "dbus_connection_read_write"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// dbus_connection_borrow_message + *(void **) (&dbus_connection_borrow_message_dylibloader_wrapper_dbus) = dlsym(handle, "dbus_connection_borrow_message"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// dbus_connection_return_message + *(void **) (&dbus_connection_return_message_dylibloader_wrapper_dbus) = dlsym(handle, "dbus_connection_return_message"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// dbus_connection_steal_borrowed_message + *(void **) (&dbus_connection_steal_borrowed_message_dylibloader_wrapper_dbus) = dlsym(handle, "dbus_connection_steal_borrowed_message"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// dbus_connection_pop_message + *(void **) (&dbus_connection_pop_message_dylibloader_wrapper_dbus) = dlsym(handle, "dbus_connection_pop_message"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// dbus_connection_get_dispatch_status + *(void **) (&dbus_connection_get_dispatch_status_dylibloader_wrapper_dbus) = dlsym(handle, "dbus_connection_get_dispatch_status"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// dbus_connection_dispatch + *(void **) (&dbus_connection_dispatch_dylibloader_wrapper_dbus) = dlsym(handle, "dbus_connection_dispatch"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// dbus_connection_has_messages_to_send + *(void **) (&dbus_connection_has_messages_to_send_dylibloader_wrapper_dbus) = dlsym(handle, "dbus_connection_has_messages_to_send"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// dbus_connection_send + *(void **) (&dbus_connection_send_dylibloader_wrapper_dbus) = dlsym(handle, "dbus_connection_send"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// dbus_connection_send_with_reply + *(void **) (&dbus_connection_send_with_reply_dylibloader_wrapper_dbus) = dlsym(handle, "dbus_connection_send_with_reply"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// dbus_connection_send_with_reply_and_block + *(void **) (&dbus_connection_send_with_reply_and_block_dylibloader_wrapper_dbus) = dlsym(handle, "dbus_connection_send_with_reply_and_block"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// dbus_connection_set_watch_functions + *(void **) (&dbus_connection_set_watch_functions_dylibloader_wrapper_dbus) = dlsym(handle, "dbus_connection_set_watch_functions"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// dbus_connection_set_timeout_functions + *(void **) (&dbus_connection_set_timeout_functions_dylibloader_wrapper_dbus) = dlsym(handle, "dbus_connection_set_timeout_functions"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// dbus_connection_set_wakeup_main_function + *(void **) (&dbus_connection_set_wakeup_main_function_dylibloader_wrapper_dbus) = dlsym(handle, "dbus_connection_set_wakeup_main_function"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// dbus_connection_set_dispatch_status_function + *(void **) (&dbus_connection_set_dispatch_status_function_dylibloader_wrapper_dbus) = dlsym(handle, "dbus_connection_set_dispatch_status_function"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// dbus_connection_get_unix_user + *(void **) (&dbus_connection_get_unix_user_dylibloader_wrapper_dbus) = dlsym(handle, "dbus_connection_get_unix_user"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// dbus_connection_get_unix_process_id + *(void **) (&dbus_connection_get_unix_process_id_dylibloader_wrapper_dbus) = dlsym(handle, "dbus_connection_get_unix_process_id"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// dbus_connection_get_adt_audit_session_data + *(void **) (&dbus_connection_get_adt_audit_session_data_dylibloader_wrapper_dbus) = dlsym(handle, "dbus_connection_get_adt_audit_session_data"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// dbus_connection_set_unix_user_function + *(void **) (&dbus_connection_set_unix_user_function_dylibloader_wrapper_dbus) = dlsym(handle, "dbus_connection_set_unix_user_function"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// dbus_connection_get_windows_user + *(void **) (&dbus_connection_get_windows_user_dylibloader_wrapper_dbus) = dlsym(handle, "dbus_connection_get_windows_user"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// dbus_connection_set_windows_user_function + *(void **) (&dbus_connection_set_windows_user_function_dylibloader_wrapper_dbus) = dlsym(handle, "dbus_connection_set_windows_user_function"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// dbus_connection_set_allow_anonymous + *(void **) (&dbus_connection_set_allow_anonymous_dylibloader_wrapper_dbus) = dlsym(handle, "dbus_connection_set_allow_anonymous"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// dbus_connection_set_route_peer_messages + *(void **) (&dbus_connection_set_route_peer_messages_dylibloader_wrapper_dbus) = dlsym(handle, "dbus_connection_set_route_peer_messages"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// dbus_connection_add_filter + *(void **) (&dbus_connection_add_filter_dylibloader_wrapper_dbus) = dlsym(handle, "dbus_connection_add_filter"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// dbus_connection_remove_filter + *(void **) (&dbus_connection_remove_filter_dylibloader_wrapper_dbus) = dlsym(handle, "dbus_connection_remove_filter"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// dbus_connection_allocate_data_slot + *(void **) (&dbus_connection_allocate_data_slot_dylibloader_wrapper_dbus) = dlsym(handle, "dbus_connection_allocate_data_slot"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// dbus_connection_free_data_slot + *(void **) (&dbus_connection_free_data_slot_dylibloader_wrapper_dbus) = dlsym(handle, "dbus_connection_free_data_slot"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// dbus_connection_set_data + *(void **) (&dbus_connection_set_data_dylibloader_wrapper_dbus) = dlsym(handle, "dbus_connection_set_data"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// dbus_connection_get_data + *(void **) (&dbus_connection_get_data_dylibloader_wrapper_dbus) = dlsym(handle, "dbus_connection_get_data"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// dbus_connection_set_change_sigpipe + *(void **) (&dbus_connection_set_change_sigpipe_dylibloader_wrapper_dbus) = dlsym(handle, "dbus_connection_set_change_sigpipe"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// dbus_connection_set_max_message_size + *(void **) (&dbus_connection_set_max_message_size_dylibloader_wrapper_dbus) = dlsym(handle, "dbus_connection_set_max_message_size"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// dbus_connection_get_max_message_size + *(void **) (&dbus_connection_get_max_message_size_dylibloader_wrapper_dbus) = dlsym(handle, "dbus_connection_get_max_message_size"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// dbus_connection_set_max_received_size + *(void **) (&dbus_connection_set_max_received_size_dylibloader_wrapper_dbus) = dlsym(handle, "dbus_connection_set_max_received_size"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// dbus_connection_get_max_received_size + *(void **) (&dbus_connection_get_max_received_size_dylibloader_wrapper_dbus) = dlsym(handle, "dbus_connection_get_max_received_size"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// dbus_connection_set_max_message_unix_fds + *(void **) (&dbus_connection_set_max_message_unix_fds_dylibloader_wrapper_dbus) = dlsym(handle, "dbus_connection_set_max_message_unix_fds"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// dbus_connection_get_max_message_unix_fds + *(void **) (&dbus_connection_get_max_message_unix_fds_dylibloader_wrapper_dbus) = dlsym(handle, "dbus_connection_get_max_message_unix_fds"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// dbus_connection_set_max_received_unix_fds + *(void **) (&dbus_connection_set_max_received_unix_fds_dylibloader_wrapper_dbus) = dlsym(handle, "dbus_connection_set_max_received_unix_fds"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// dbus_connection_get_max_received_unix_fds + *(void **) (&dbus_connection_get_max_received_unix_fds_dylibloader_wrapper_dbus) = dlsym(handle, "dbus_connection_get_max_received_unix_fds"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// dbus_connection_get_outgoing_size + *(void **) (&dbus_connection_get_outgoing_size_dylibloader_wrapper_dbus) = dlsym(handle, "dbus_connection_get_outgoing_size"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// dbus_connection_get_outgoing_unix_fds + *(void **) (&dbus_connection_get_outgoing_unix_fds_dylibloader_wrapper_dbus) = dlsym(handle, "dbus_connection_get_outgoing_unix_fds"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// dbus_connection_preallocate_send + *(void **) (&dbus_connection_preallocate_send_dylibloader_wrapper_dbus) = dlsym(handle, "dbus_connection_preallocate_send"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// dbus_connection_free_preallocated_send + *(void **) (&dbus_connection_free_preallocated_send_dylibloader_wrapper_dbus) = dlsym(handle, "dbus_connection_free_preallocated_send"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// dbus_connection_send_preallocated + *(void **) (&dbus_connection_send_preallocated_dylibloader_wrapper_dbus) = dlsym(handle, "dbus_connection_send_preallocated"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// dbus_connection_try_register_object_path + *(void **) (&dbus_connection_try_register_object_path_dylibloader_wrapper_dbus) = dlsym(handle, "dbus_connection_try_register_object_path"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// dbus_connection_register_object_path + *(void **) (&dbus_connection_register_object_path_dylibloader_wrapper_dbus) = dlsym(handle, "dbus_connection_register_object_path"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// dbus_connection_try_register_fallback + *(void **) (&dbus_connection_try_register_fallback_dylibloader_wrapper_dbus) = dlsym(handle, "dbus_connection_try_register_fallback"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// dbus_connection_register_fallback + *(void **) (&dbus_connection_register_fallback_dylibloader_wrapper_dbus) = dlsym(handle, "dbus_connection_register_fallback"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// dbus_connection_unregister_object_path + *(void **) (&dbus_connection_unregister_object_path_dylibloader_wrapper_dbus) = dlsym(handle, "dbus_connection_unregister_object_path"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// dbus_connection_get_object_path_data + *(void **) (&dbus_connection_get_object_path_data_dylibloader_wrapper_dbus) = dlsym(handle, "dbus_connection_get_object_path_data"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// dbus_connection_list_registered + *(void **) (&dbus_connection_list_registered_dylibloader_wrapper_dbus) = dlsym(handle, "dbus_connection_list_registered"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// dbus_connection_get_unix_fd + *(void **) (&dbus_connection_get_unix_fd_dylibloader_wrapper_dbus) = dlsym(handle, "dbus_connection_get_unix_fd"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// dbus_connection_get_socket + *(void **) (&dbus_connection_get_socket_dylibloader_wrapper_dbus) = dlsym(handle, "dbus_connection_get_socket"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// dbus_watch_get_fd + *(void **) (&dbus_watch_get_fd_dylibloader_wrapper_dbus) = dlsym(handle, "dbus_watch_get_fd"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// dbus_watch_get_unix_fd + *(void **) (&dbus_watch_get_unix_fd_dylibloader_wrapper_dbus) = dlsym(handle, "dbus_watch_get_unix_fd"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// dbus_watch_get_socket + *(void **) (&dbus_watch_get_socket_dylibloader_wrapper_dbus) = dlsym(handle, "dbus_watch_get_socket"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// dbus_watch_get_flags + *(void **) (&dbus_watch_get_flags_dylibloader_wrapper_dbus) = dlsym(handle, "dbus_watch_get_flags"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// dbus_watch_get_data + *(void **) (&dbus_watch_get_data_dylibloader_wrapper_dbus) = dlsym(handle, "dbus_watch_get_data"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// dbus_watch_set_data + *(void **) (&dbus_watch_set_data_dylibloader_wrapper_dbus) = dlsym(handle, "dbus_watch_set_data"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// dbus_watch_handle + *(void **) (&dbus_watch_handle_dylibloader_wrapper_dbus) = dlsym(handle, "dbus_watch_handle"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// dbus_watch_get_enabled + *(void **) (&dbus_watch_get_enabled_dylibloader_wrapper_dbus) = dlsym(handle, "dbus_watch_get_enabled"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// dbus_timeout_get_interval + *(void **) (&dbus_timeout_get_interval_dylibloader_wrapper_dbus) = dlsym(handle, "dbus_timeout_get_interval"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// dbus_timeout_get_data + *(void **) (&dbus_timeout_get_data_dylibloader_wrapper_dbus) = dlsym(handle, "dbus_timeout_get_data"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// dbus_timeout_set_data + *(void **) (&dbus_timeout_set_data_dylibloader_wrapper_dbus) = dlsym(handle, "dbus_timeout_set_data"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// dbus_timeout_handle + *(void **) (&dbus_timeout_handle_dylibloader_wrapper_dbus) = dlsym(handle, "dbus_timeout_handle"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// dbus_timeout_get_enabled + *(void **) (&dbus_timeout_get_enabled_dylibloader_wrapper_dbus) = dlsym(handle, "dbus_timeout_get_enabled"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// dbus_bus_get + *(void **) (&dbus_bus_get_dylibloader_wrapper_dbus) = dlsym(handle, "dbus_bus_get"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// dbus_bus_get_private + *(void **) (&dbus_bus_get_private_dylibloader_wrapper_dbus) = dlsym(handle, "dbus_bus_get_private"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// dbus_bus_register + *(void **) (&dbus_bus_register_dylibloader_wrapper_dbus) = dlsym(handle, "dbus_bus_register"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// dbus_bus_set_unique_name + *(void **) (&dbus_bus_set_unique_name_dylibloader_wrapper_dbus) = dlsym(handle, "dbus_bus_set_unique_name"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// dbus_bus_get_unique_name + *(void **) (&dbus_bus_get_unique_name_dylibloader_wrapper_dbus) = dlsym(handle, "dbus_bus_get_unique_name"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// dbus_bus_get_unix_user + *(void **) (&dbus_bus_get_unix_user_dylibloader_wrapper_dbus) = dlsym(handle, "dbus_bus_get_unix_user"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// dbus_bus_get_id + *(void **) (&dbus_bus_get_id_dylibloader_wrapper_dbus) = dlsym(handle, "dbus_bus_get_id"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// dbus_bus_request_name + *(void **) (&dbus_bus_request_name_dylibloader_wrapper_dbus) = dlsym(handle, "dbus_bus_request_name"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// dbus_bus_release_name + *(void **) (&dbus_bus_release_name_dylibloader_wrapper_dbus) = dlsym(handle, "dbus_bus_release_name"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// dbus_bus_name_has_owner + *(void **) (&dbus_bus_name_has_owner_dylibloader_wrapper_dbus) = dlsym(handle, "dbus_bus_name_has_owner"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// dbus_bus_start_service_by_name + *(void **) (&dbus_bus_start_service_by_name_dylibloader_wrapper_dbus) = dlsym(handle, "dbus_bus_start_service_by_name"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// dbus_bus_add_match + *(void **) (&dbus_bus_add_match_dylibloader_wrapper_dbus) = dlsym(handle, "dbus_bus_add_match"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// dbus_bus_remove_match + *(void **) (&dbus_bus_remove_match_dylibloader_wrapper_dbus) = dlsym(handle, "dbus_bus_remove_match"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// dbus_get_local_machine_id + *(void **) (&dbus_get_local_machine_id_dylibloader_wrapper_dbus) = dlsym(handle, "dbus_get_local_machine_id"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// dbus_get_version + *(void **) (&dbus_get_version_dylibloader_wrapper_dbus) = dlsym(handle, "dbus_get_version"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// dbus_setenv + *(void **) (&dbus_setenv_dylibloader_wrapper_dbus) = dlsym(handle, "dbus_setenv"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// dbus_try_get_local_machine_id + *(void **) (&dbus_try_get_local_machine_id_dylibloader_wrapper_dbus) = dlsym(handle, "dbus_try_get_local_machine_id"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// dbus_pending_call_ref + *(void **) (&dbus_pending_call_ref_dylibloader_wrapper_dbus) = dlsym(handle, "dbus_pending_call_ref"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// dbus_pending_call_unref + *(void **) (&dbus_pending_call_unref_dylibloader_wrapper_dbus) = dlsym(handle, "dbus_pending_call_unref"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// dbus_pending_call_set_notify + *(void **) (&dbus_pending_call_set_notify_dylibloader_wrapper_dbus) = dlsym(handle, "dbus_pending_call_set_notify"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// dbus_pending_call_cancel + *(void **) (&dbus_pending_call_cancel_dylibloader_wrapper_dbus) = dlsym(handle, "dbus_pending_call_cancel"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// dbus_pending_call_get_completed + *(void **) (&dbus_pending_call_get_completed_dylibloader_wrapper_dbus) = dlsym(handle, "dbus_pending_call_get_completed"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// dbus_pending_call_steal_reply + *(void **) (&dbus_pending_call_steal_reply_dylibloader_wrapper_dbus) = dlsym(handle, "dbus_pending_call_steal_reply"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// dbus_pending_call_block + *(void **) (&dbus_pending_call_block_dylibloader_wrapper_dbus) = dlsym(handle, "dbus_pending_call_block"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// dbus_pending_call_allocate_data_slot + *(void **) (&dbus_pending_call_allocate_data_slot_dylibloader_wrapper_dbus) = dlsym(handle, "dbus_pending_call_allocate_data_slot"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// dbus_pending_call_free_data_slot + *(void **) (&dbus_pending_call_free_data_slot_dylibloader_wrapper_dbus) = dlsym(handle, "dbus_pending_call_free_data_slot"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// dbus_pending_call_set_data + *(void **) (&dbus_pending_call_set_data_dylibloader_wrapper_dbus) = dlsym(handle, "dbus_pending_call_set_data"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// dbus_pending_call_get_data + *(void **) (&dbus_pending_call_get_data_dylibloader_wrapper_dbus) = dlsym(handle, "dbus_pending_call_get_data"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// dbus_server_listen + *(void **) (&dbus_server_listen_dylibloader_wrapper_dbus) = dlsym(handle, "dbus_server_listen"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// dbus_server_ref + *(void **) (&dbus_server_ref_dylibloader_wrapper_dbus) = dlsym(handle, "dbus_server_ref"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// dbus_server_unref + *(void **) (&dbus_server_unref_dylibloader_wrapper_dbus) = dlsym(handle, "dbus_server_unref"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// dbus_server_disconnect + *(void **) (&dbus_server_disconnect_dylibloader_wrapper_dbus) = dlsym(handle, "dbus_server_disconnect"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// dbus_server_get_is_connected + *(void **) (&dbus_server_get_is_connected_dylibloader_wrapper_dbus) = dlsym(handle, "dbus_server_get_is_connected"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// dbus_server_get_address + *(void **) (&dbus_server_get_address_dylibloader_wrapper_dbus) = dlsym(handle, "dbus_server_get_address"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// dbus_server_get_id + *(void **) (&dbus_server_get_id_dylibloader_wrapper_dbus) = dlsym(handle, "dbus_server_get_id"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// dbus_server_set_new_connection_function + *(void **) (&dbus_server_set_new_connection_function_dylibloader_wrapper_dbus) = dlsym(handle, "dbus_server_set_new_connection_function"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// dbus_server_set_watch_functions + *(void **) (&dbus_server_set_watch_functions_dylibloader_wrapper_dbus) = dlsym(handle, "dbus_server_set_watch_functions"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// dbus_server_set_timeout_functions + *(void **) (&dbus_server_set_timeout_functions_dylibloader_wrapper_dbus) = dlsym(handle, "dbus_server_set_timeout_functions"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// dbus_server_set_auth_mechanisms + *(void **) (&dbus_server_set_auth_mechanisms_dylibloader_wrapper_dbus) = dlsym(handle, "dbus_server_set_auth_mechanisms"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// dbus_server_allocate_data_slot + *(void **) (&dbus_server_allocate_data_slot_dylibloader_wrapper_dbus) = dlsym(handle, "dbus_server_allocate_data_slot"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// dbus_server_free_data_slot + *(void **) (&dbus_server_free_data_slot_dylibloader_wrapper_dbus) = dlsym(handle, "dbus_server_free_data_slot"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// dbus_server_set_data + *(void **) (&dbus_server_set_data_dylibloader_wrapper_dbus) = dlsym(handle, "dbus_server_set_data"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// dbus_server_get_data + *(void **) (&dbus_server_get_data_dylibloader_wrapper_dbus) = dlsym(handle, "dbus_server_get_data"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// dbus_signature_iter_init + *(void **) (&dbus_signature_iter_init_dylibloader_wrapper_dbus) = dlsym(handle, "dbus_signature_iter_init"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// dbus_signature_iter_get_current_type + *(void **) (&dbus_signature_iter_get_current_type_dylibloader_wrapper_dbus) = dlsym(handle, "dbus_signature_iter_get_current_type"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// dbus_signature_iter_get_signature + *(void **) (&dbus_signature_iter_get_signature_dylibloader_wrapper_dbus) = dlsym(handle, "dbus_signature_iter_get_signature"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// dbus_signature_iter_get_element_type + *(void **) (&dbus_signature_iter_get_element_type_dylibloader_wrapper_dbus) = dlsym(handle, "dbus_signature_iter_get_element_type"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// dbus_signature_iter_next + *(void **) (&dbus_signature_iter_next_dylibloader_wrapper_dbus) = dlsym(handle, "dbus_signature_iter_next"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// dbus_signature_iter_recurse + *(void **) (&dbus_signature_iter_recurse_dylibloader_wrapper_dbus) = dlsym(handle, "dbus_signature_iter_recurse"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// dbus_signature_validate + *(void **) (&dbus_signature_validate_dylibloader_wrapper_dbus) = dlsym(handle, "dbus_signature_validate"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// dbus_signature_validate_single + *(void **) (&dbus_signature_validate_single_dylibloader_wrapper_dbus) = dlsym(handle, "dbus_signature_validate_single"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// dbus_type_is_valid + *(void **) (&dbus_type_is_valid_dylibloader_wrapper_dbus) = dlsym(handle, "dbus_type_is_valid"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// dbus_type_is_basic + *(void **) (&dbus_type_is_basic_dylibloader_wrapper_dbus) = dlsym(handle, "dbus_type_is_basic"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// dbus_type_is_container + *(void **) (&dbus_type_is_container_dylibloader_wrapper_dbus) = dlsym(handle, "dbus_type_is_container"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// dbus_type_is_fixed + *(void **) (&dbus_type_is_fixed_dylibloader_wrapper_dbus) = dlsym(handle, "dbus_type_is_fixed"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// dbus_validate_path + *(void **) (&dbus_validate_path_dylibloader_wrapper_dbus) = dlsym(handle, "dbus_validate_path"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// dbus_validate_interface + *(void **) (&dbus_validate_interface_dylibloader_wrapper_dbus) = dlsym(handle, "dbus_validate_interface"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// dbus_validate_member + *(void **) (&dbus_validate_member_dylibloader_wrapper_dbus) = dlsym(handle, "dbus_validate_member"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// dbus_validate_error_name + *(void **) (&dbus_validate_error_name_dylibloader_wrapper_dbus) = dlsym(handle, "dbus_validate_error_name"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// dbus_validate_bus_name + *(void **) (&dbus_validate_bus_name_dylibloader_wrapper_dbus) = dlsym(handle, "dbus_validate_bus_name"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// dbus_validate_utf8 + *(void **) (&dbus_validate_utf8_dylibloader_wrapper_dbus) = dlsym(handle, "dbus_validate_utf8"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// dbus_threads_init + *(void **) (&dbus_threads_init_dylibloader_wrapper_dbus) = dlsym(handle, "dbus_threads_init"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// dbus_threads_init_default + *(void **) (&dbus_threads_init_default_dylibloader_wrapper_dbus) = dlsym(handle, "dbus_threads_init_default"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +return 0; +} diff --git a/platform/linuxbsd/dbus-so_wrap.h b/platform/linuxbsd/dbus-so_wrap.h new file mode 100644 index 0000000000..52e1dd300c --- /dev/null +++ b/platform/linuxbsd/dbus-so_wrap.h @@ -0,0 +1,970 @@ +#ifndef DYLIBLOAD_WRAPPER_DBUS +#define DYLIBLOAD_WRAPPER_DBUS +// This file is generated. Do not edit! +// see https://github.com/hpvb/dynload-wrapper for details +// generated by ./generate-wrapper.py 0.3 on 2022-07-29 07:23:21 +// flags: ./generate-wrapper.py --include /usr/include/dbus-1.0/dbus/dbus.h --sys-include <dbus/dbus.h> --soname libdbus-1.so --init-name dbus --output-header dbus-so_wrap.h --output-implementation dbus-so_wrap.c +// +#include <stdint.h> + +#define dbus_error_init dbus_error_init_dylibloader_orig_dbus +#define dbus_error_free dbus_error_free_dylibloader_orig_dbus +#define dbus_set_error dbus_set_error_dylibloader_orig_dbus +#define dbus_set_error_const dbus_set_error_const_dylibloader_orig_dbus +#define dbus_move_error dbus_move_error_dylibloader_orig_dbus +#define dbus_error_has_name dbus_error_has_name_dylibloader_orig_dbus +#define dbus_error_is_set dbus_error_is_set_dylibloader_orig_dbus +#define dbus_parse_address dbus_parse_address_dylibloader_orig_dbus +#define dbus_address_entry_get_value dbus_address_entry_get_value_dylibloader_orig_dbus +#define dbus_address_entry_get_method dbus_address_entry_get_method_dylibloader_orig_dbus +#define dbus_address_entries_free dbus_address_entries_free_dylibloader_orig_dbus +#define dbus_address_escape_value dbus_address_escape_value_dylibloader_orig_dbus +#define dbus_address_unescape_value dbus_address_unescape_value_dylibloader_orig_dbus +#define dbus_malloc dbus_malloc_dylibloader_orig_dbus +#define dbus_malloc0 dbus_malloc0_dylibloader_orig_dbus +#define dbus_realloc dbus_realloc_dylibloader_orig_dbus +#define dbus_free dbus_free_dylibloader_orig_dbus +#define dbus_free_string_array dbus_free_string_array_dylibloader_orig_dbus +#define dbus_shutdown dbus_shutdown_dylibloader_orig_dbus +#define dbus_message_new dbus_message_new_dylibloader_orig_dbus +#define dbus_message_new_method_call dbus_message_new_method_call_dylibloader_orig_dbus +#define dbus_message_new_method_return dbus_message_new_method_return_dylibloader_orig_dbus +#define dbus_message_new_signal dbus_message_new_signal_dylibloader_orig_dbus +#define dbus_message_new_error dbus_message_new_error_dylibloader_orig_dbus +#define dbus_message_new_error_printf dbus_message_new_error_printf_dylibloader_orig_dbus +#define dbus_message_copy dbus_message_copy_dylibloader_orig_dbus +#define dbus_message_ref dbus_message_ref_dylibloader_orig_dbus +#define dbus_message_unref dbus_message_unref_dylibloader_orig_dbus +#define dbus_message_get_type dbus_message_get_type_dylibloader_orig_dbus +#define dbus_message_set_path dbus_message_set_path_dylibloader_orig_dbus +#define dbus_message_get_path dbus_message_get_path_dylibloader_orig_dbus +#define dbus_message_has_path dbus_message_has_path_dylibloader_orig_dbus +#define dbus_message_set_interface dbus_message_set_interface_dylibloader_orig_dbus +#define dbus_message_get_interface dbus_message_get_interface_dylibloader_orig_dbus +#define dbus_message_has_interface dbus_message_has_interface_dylibloader_orig_dbus +#define dbus_message_set_member dbus_message_set_member_dylibloader_orig_dbus +#define dbus_message_get_member dbus_message_get_member_dylibloader_orig_dbus +#define dbus_message_has_member dbus_message_has_member_dylibloader_orig_dbus +#define dbus_message_set_error_name dbus_message_set_error_name_dylibloader_orig_dbus +#define dbus_message_get_error_name dbus_message_get_error_name_dylibloader_orig_dbus +#define dbus_message_set_destination dbus_message_set_destination_dylibloader_orig_dbus +#define dbus_message_get_destination dbus_message_get_destination_dylibloader_orig_dbus +#define dbus_message_set_sender dbus_message_set_sender_dylibloader_orig_dbus +#define dbus_message_get_sender dbus_message_get_sender_dylibloader_orig_dbus +#define dbus_message_get_signature dbus_message_get_signature_dylibloader_orig_dbus +#define dbus_message_set_no_reply dbus_message_set_no_reply_dylibloader_orig_dbus +#define dbus_message_get_no_reply dbus_message_get_no_reply_dylibloader_orig_dbus +#define dbus_message_is_method_call dbus_message_is_method_call_dylibloader_orig_dbus +#define dbus_message_is_signal dbus_message_is_signal_dylibloader_orig_dbus +#define dbus_message_is_error dbus_message_is_error_dylibloader_orig_dbus +#define dbus_message_has_destination dbus_message_has_destination_dylibloader_orig_dbus +#define dbus_message_has_sender dbus_message_has_sender_dylibloader_orig_dbus +#define dbus_message_has_signature dbus_message_has_signature_dylibloader_orig_dbus +#define dbus_message_get_serial dbus_message_get_serial_dylibloader_orig_dbus +#define dbus_message_set_serial dbus_message_set_serial_dylibloader_orig_dbus +#define dbus_message_set_reply_serial dbus_message_set_reply_serial_dylibloader_orig_dbus +#define dbus_message_get_reply_serial dbus_message_get_reply_serial_dylibloader_orig_dbus +#define dbus_message_set_auto_start dbus_message_set_auto_start_dylibloader_orig_dbus +#define dbus_message_get_auto_start dbus_message_get_auto_start_dylibloader_orig_dbus +#define dbus_message_get_path_decomposed dbus_message_get_path_decomposed_dylibloader_orig_dbus +#define dbus_message_append_args dbus_message_append_args_dylibloader_orig_dbus +#define dbus_message_append_args_valist dbus_message_append_args_valist_dylibloader_orig_dbus +#define dbus_message_get_args dbus_message_get_args_dylibloader_orig_dbus +#define dbus_message_get_args_valist dbus_message_get_args_valist_dylibloader_orig_dbus +#define dbus_message_contains_unix_fds dbus_message_contains_unix_fds_dylibloader_orig_dbus +#define dbus_message_iter_init_closed dbus_message_iter_init_closed_dylibloader_orig_dbus +#define dbus_message_iter_init dbus_message_iter_init_dylibloader_orig_dbus +#define dbus_message_iter_has_next dbus_message_iter_has_next_dylibloader_orig_dbus +#define dbus_message_iter_next dbus_message_iter_next_dylibloader_orig_dbus +#define dbus_message_iter_get_signature dbus_message_iter_get_signature_dylibloader_orig_dbus +#define dbus_message_iter_get_arg_type dbus_message_iter_get_arg_type_dylibloader_orig_dbus +#define dbus_message_iter_get_element_type dbus_message_iter_get_element_type_dylibloader_orig_dbus +#define dbus_message_iter_recurse dbus_message_iter_recurse_dylibloader_orig_dbus +#define dbus_message_iter_get_basic dbus_message_iter_get_basic_dylibloader_orig_dbus +#define dbus_message_iter_get_element_count dbus_message_iter_get_element_count_dylibloader_orig_dbus +#define dbus_message_iter_get_array_len dbus_message_iter_get_array_len_dylibloader_orig_dbus +#define dbus_message_iter_get_fixed_array dbus_message_iter_get_fixed_array_dylibloader_orig_dbus +#define dbus_message_iter_init_append dbus_message_iter_init_append_dylibloader_orig_dbus +#define dbus_message_iter_append_basic dbus_message_iter_append_basic_dylibloader_orig_dbus +#define dbus_message_iter_append_fixed_array dbus_message_iter_append_fixed_array_dylibloader_orig_dbus +#define dbus_message_iter_open_container dbus_message_iter_open_container_dylibloader_orig_dbus +#define dbus_message_iter_close_container dbus_message_iter_close_container_dylibloader_orig_dbus +#define dbus_message_iter_abandon_container dbus_message_iter_abandon_container_dylibloader_orig_dbus +#define dbus_message_iter_abandon_container_if_open dbus_message_iter_abandon_container_if_open_dylibloader_orig_dbus +#define dbus_message_lock dbus_message_lock_dylibloader_orig_dbus +#define dbus_set_error_from_message dbus_set_error_from_message_dylibloader_orig_dbus +#define dbus_message_allocate_data_slot dbus_message_allocate_data_slot_dylibloader_orig_dbus +#define dbus_message_free_data_slot dbus_message_free_data_slot_dylibloader_orig_dbus +#define dbus_message_set_data dbus_message_set_data_dylibloader_orig_dbus +#define dbus_message_get_data dbus_message_get_data_dylibloader_orig_dbus +#define dbus_message_type_from_string dbus_message_type_from_string_dylibloader_orig_dbus +#define dbus_message_type_to_string dbus_message_type_to_string_dylibloader_orig_dbus +#define dbus_message_marshal dbus_message_marshal_dylibloader_orig_dbus +#define dbus_message_demarshal dbus_message_demarshal_dylibloader_orig_dbus +#define dbus_message_demarshal_bytes_needed dbus_message_demarshal_bytes_needed_dylibloader_orig_dbus +#define dbus_message_set_allow_interactive_authorization dbus_message_set_allow_interactive_authorization_dylibloader_orig_dbus +#define dbus_message_get_allow_interactive_authorization dbus_message_get_allow_interactive_authorization_dylibloader_orig_dbus +#define dbus_connection_open dbus_connection_open_dylibloader_orig_dbus +#define dbus_connection_open_private dbus_connection_open_private_dylibloader_orig_dbus +#define dbus_connection_ref dbus_connection_ref_dylibloader_orig_dbus +#define dbus_connection_unref dbus_connection_unref_dylibloader_orig_dbus +#define dbus_connection_close dbus_connection_close_dylibloader_orig_dbus +#define dbus_connection_get_is_connected dbus_connection_get_is_connected_dylibloader_orig_dbus +#define dbus_connection_get_is_authenticated dbus_connection_get_is_authenticated_dylibloader_orig_dbus +#define dbus_connection_get_is_anonymous dbus_connection_get_is_anonymous_dylibloader_orig_dbus +#define dbus_connection_get_server_id dbus_connection_get_server_id_dylibloader_orig_dbus +#define dbus_connection_can_send_type dbus_connection_can_send_type_dylibloader_orig_dbus +#define dbus_connection_set_exit_on_disconnect dbus_connection_set_exit_on_disconnect_dylibloader_orig_dbus +#define dbus_connection_flush dbus_connection_flush_dylibloader_orig_dbus +#define dbus_connection_read_write_dispatch dbus_connection_read_write_dispatch_dylibloader_orig_dbus +#define dbus_connection_read_write dbus_connection_read_write_dylibloader_orig_dbus +#define dbus_connection_borrow_message dbus_connection_borrow_message_dylibloader_orig_dbus +#define dbus_connection_return_message dbus_connection_return_message_dylibloader_orig_dbus +#define dbus_connection_steal_borrowed_message dbus_connection_steal_borrowed_message_dylibloader_orig_dbus +#define dbus_connection_pop_message dbus_connection_pop_message_dylibloader_orig_dbus +#define dbus_connection_get_dispatch_status dbus_connection_get_dispatch_status_dylibloader_orig_dbus +#define dbus_connection_dispatch dbus_connection_dispatch_dylibloader_orig_dbus +#define dbus_connection_has_messages_to_send dbus_connection_has_messages_to_send_dylibloader_orig_dbus +#define dbus_connection_send dbus_connection_send_dylibloader_orig_dbus +#define dbus_connection_send_with_reply dbus_connection_send_with_reply_dylibloader_orig_dbus +#define dbus_connection_send_with_reply_and_block dbus_connection_send_with_reply_and_block_dylibloader_orig_dbus +#define dbus_connection_set_watch_functions dbus_connection_set_watch_functions_dylibloader_orig_dbus +#define dbus_connection_set_timeout_functions dbus_connection_set_timeout_functions_dylibloader_orig_dbus +#define dbus_connection_set_wakeup_main_function dbus_connection_set_wakeup_main_function_dylibloader_orig_dbus +#define dbus_connection_set_dispatch_status_function dbus_connection_set_dispatch_status_function_dylibloader_orig_dbus +#define dbus_connection_get_unix_user dbus_connection_get_unix_user_dylibloader_orig_dbus +#define dbus_connection_get_unix_process_id dbus_connection_get_unix_process_id_dylibloader_orig_dbus +#define dbus_connection_get_adt_audit_session_data dbus_connection_get_adt_audit_session_data_dylibloader_orig_dbus +#define dbus_connection_set_unix_user_function dbus_connection_set_unix_user_function_dylibloader_orig_dbus +#define dbus_connection_get_windows_user dbus_connection_get_windows_user_dylibloader_orig_dbus +#define dbus_connection_set_windows_user_function dbus_connection_set_windows_user_function_dylibloader_orig_dbus +#define dbus_connection_set_allow_anonymous dbus_connection_set_allow_anonymous_dylibloader_orig_dbus +#define dbus_connection_set_route_peer_messages dbus_connection_set_route_peer_messages_dylibloader_orig_dbus +#define dbus_connection_add_filter dbus_connection_add_filter_dylibloader_orig_dbus +#define dbus_connection_remove_filter dbus_connection_remove_filter_dylibloader_orig_dbus +#define dbus_connection_allocate_data_slot dbus_connection_allocate_data_slot_dylibloader_orig_dbus +#define dbus_connection_free_data_slot dbus_connection_free_data_slot_dylibloader_orig_dbus +#define dbus_connection_set_data dbus_connection_set_data_dylibloader_orig_dbus +#define dbus_connection_get_data dbus_connection_get_data_dylibloader_orig_dbus +#define dbus_connection_set_change_sigpipe dbus_connection_set_change_sigpipe_dylibloader_orig_dbus +#define dbus_connection_set_max_message_size dbus_connection_set_max_message_size_dylibloader_orig_dbus +#define dbus_connection_get_max_message_size dbus_connection_get_max_message_size_dylibloader_orig_dbus +#define dbus_connection_set_max_received_size dbus_connection_set_max_received_size_dylibloader_orig_dbus +#define dbus_connection_get_max_received_size dbus_connection_get_max_received_size_dylibloader_orig_dbus +#define dbus_connection_set_max_message_unix_fds dbus_connection_set_max_message_unix_fds_dylibloader_orig_dbus +#define dbus_connection_get_max_message_unix_fds dbus_connection_get_max_message_unix_fds_dylibloader_orig_dbus +#define dbus_connection_set_max_received_unix_fds dbus_connection_set_max_received_unix_fds_dylibloader_orig_dbus +#define dbus_connection_get_max_received_unix_fds dbus_connection_get_max_received_unix_fds_dylibloader_orig_dbus +#define dbus_connection_get_outgoing_size dbus_connection_get_outgoing_size_dylibloader_orig_dbus +#define dbus_connection_get_outgoing_unix_fds dbus_connection_get_outgoing_unix_fds_dylibloader_orig_dbus +#define dbus_connection_preallocate_send dbus_connection_preallocate_send_dylibloader_orig_dbus +#define dbus_connection_free_preallocated_send dbus_connection_free_preallocated_send_dylibloader_orig_dbus +#define dbus_connection_send_preallocated dbus_connection_send_preallocated_dylibloader_orig_dbus +#define dbus_connection_try_register_object_path dbus_connection_try_register_object_path_dylibloader_orig_dbus +#define dbus_connection_register_object_path dbus_connection_register_object_path_dylibloader_orig_dbus +#define dbus_connection_try_register_fallback dbus_connection_try_register_fallback_dylibloader_orig_dbus +#define dbus_connection_register_fallback dbus_connection_register_fallback_dylibloader_orig_dbus +#define dbus_connection_unregister_object_path dbus_connection_unregister_object_path_dylibloader_orig_dbus +#define dbus_connection_get_object_path_data dbus_connection_get_object_path_data_dylibloader_orig_dbus +#define dbus_connection_list_registered dbus_connection_list_registered_dylibloader_orig_dbus +#define dbus_connection_get_unix_fd dbus_connection_get_unix_fd_dylibloader_orig_dbus +#define dbus_connection_get_socket dbus_connection_get_socket_dylibloader_orig_dbus +#define dbus_watch_get_fd dbus_watch_get_fd_dylibloader_orig_dbus +#define dbus_watch_get_unix_fd dbus_watch_get_unix_fd_dylibloader_orig_dbus +#define dbus_watch_get_socket dbus_watch_get_socket_dylibloader_orig_dbus +#define dbus_watch_get_flags dbus_watch_get_flags_dylibloader_orig_dbus +#define dbus_watch_get_data dbus_watch_get_data_dylibloader_orig_dbus +#define dbus_watch_set_data dbus_watch_set_data_dylibloader_orig_dbus +#define dbus_watch_handle dbus_watch_handle_dylibloader_orig_dbus +#define dbus_watch_get_enabled dbus_watch_get_enabled_dylibloader_orig_dbus +#define dbus_timeout_get_interval dbus_timeout_get_interval_dylibloader_orig_dbus +#define dbus_timeout_get_data dbus_timeout_get_data_dylibloader_orig_dbus +#define dbus_timeout_set_data dbus_timeout_set_data_dylibloader_orig_dbus +#define dbus_timeout_handle dbus_timeout_handle_dylibloader_orig_dbus +#define dbus_timeout_get_enabled dbus_timeout_get_enabled_dylibloader_orig_dbus +#define dbus_bus_get dbus_bus_get_dylibloader_orig_dbus +#define dbus_bus_get_private dbus_bus_get_private_dylibloader_orig_dbus +#define dbus_bus_register dbus_bus_register_dylibloader_orig_dbus +#define dbus_bus_set_unique_name dbus_bus_set_unique_name_dylibloader_orig_dbus +#define dbus_bus_get_unique_name dbus_bus_get_unique_name_dylibloader_orig_dbus +#define dbus_bus_get_unix_user dbus_bus_get_unix_user_dylibloader_orig_dbus +#define dbus_bus_get_id dbus_bus_get_id_dylibloader_orig_dbus +#define dbus_bus_request_name dbus_bus_request_name_dylibloader_orig_dbus +#define dbus_bus_release_name dbus_bus_release_name_dylibloader_orig_dbus +#define dbus_bus_name_has_owner dbus_bus_name_has_owner_dylibloader_orig_dbus +#define dbus_bus_start_service_by_name dbus_bus_start_service_by_name_dylibloader_orig_dbus +#define dbus_bus_add_match dbus_bus_add_match_dylibloader_orig_dbus +#define dbus_bus_remove_match dbus_bus_remove_match_dylibloader_orig_dbus +#define dbus_get_local_machine_id dbus_get_local_machine_id_dylibloader_orig_dbus +#define dbus_get_version dbus_get_version_dylibloader_orig_dbus +#define dbus_setenv dbus_setenv_dylibloader_orig_dbus +#define dbus_try_get_local_machine_id dbus_try_get_local_machine_id_dylibloader_orig_dbus +#define dbus_pending_call_ref dbus_pending_call_ref_dylibloader_orig_dbus +#define dbus_pending_call_unref dbus_pending_call_unref_dylibloader_orig_dbus +#define dbus_pending_call_set_notify dbus_pending_call_set_notify_dylibloader_orig_dbus +#define dbus_pending_call_cancel dbus_pending_call_cancel_dylibloader_orig_dbus +#define dbus_pending_call_get_completed dbus_pending_call_get_completed_dylibloader_orig_dbus +#define dbus_pending_call_steal_reply dbus_pending_call_steal_reply_dylibloader_orig_dbus +#define dbus_pending_call_block dbus_pending_call_block_dylibloader_orig_dbus +#define dbus_pending_call_allocate_data_slot dbus_pending_call_allocate_data_slot_dylibloader_orig_dbus +#define dbus_pending_call_free_data_slot dbus_pending_call_free_data_slot_dylibloader_orig_dbus +#define dbus_pending_call_set_data dbus_pending_call_set_data_dylibloader_orig_dbus +#define dbus_pending_call_get_data dbus_pending_call_get_data_dylibloader_orig_dbus +#define dbus_server_listen dbus_server_listen_dylibloader_orig_dbus +#define dbus_server_ref dbus_server_ref_dylibloader_orig_dbus +#define dbus_server_unref dbus_server_unref_dylibloader_orig_dbus +#define dbus_server_disconnect dbus_server_disconnect_dylibloader_orig_dbus +#define dbus_server_get_is_connected dbus_server_get_is_connected_dylibloader_orig_dbus +#define dbus_server_get_address dbus_server_get_address_dylibloader_orig_dbus +#define dbus_server_get_id dbus_server_get_id_dylibloader_orig_dbus +#define dbus_server_set_new_connection_function dbus_server_set_new_connection_function_dylibloader_orig_dbus +#define dbus_server_set_watch_functions dbus_server_set_watch_functions_dylibloader_orig_dbus +#define dbus_server_set_timeout_functions dbus_server_set_timeout_functions_dylibloader_orig_dbus +#define dbus_server_set_auth_mechanisms dbus_server_set_auth_mechanisms_dylibloader_orig_dbus +#define dbus_server_allocate_data_slot dbus_server_allocate_data_slot_dylibloader_orig_dbus +#define dbus_server_free_data_slot dbus_server_free_data_slot_dylibloader_orig_dbus +#define dbus_server_set_data dbus_server_set_data_dylibloader_orig_dbus +#define dbus_server_get_data dbus_server_get_data_dylibloader_orig_dbus +#define dbus_signature_iter_init dbus_signature_iter_init_dylibloader_orig_dbus +#define dbus_signature_iter_get_current_type dbus_signature_iter_get_current_type_dylibloader_orig_dbus +#define dbus_signature_iter_get_signature dbus_signature_iter_get_signature_dylibloader_orig_dbus +#define dbus_signature_iter_get_element_type dbus_signature_iter_get_element_type_dylibloader_orig_dbus +#define dbus_signature_iter_next dbus_signature_iter_next_dylibloader_orig_dbus +#define dbus_signature_iter_recurse dbus_signature_iter_recurse_dylibloader_orig_dbus +#define dbus_signature_validate dbus_signature_validate_dylibloader_orig_dbus +#define dbus_signature_validate_single dbus_signature_validate_single_dylibloader_orig_dbus +#define dbus_type_is_valid dbus_type_is_valid_dylibloader_orig_dbus +#define dbus_type_is_basic dbus_type_is_basic_dylibloader_orig_dbus +#define dbus_type_is_container dbus_type_is_container_dylibloader_orig_dbus +#define dbus_type_is_fixed dbus_type_is_fixed_dylibloader_orig_dbus +#define dbus_validate_path dbus_validate_path_dylibloader_orig_dbus +#define dbus_validate_interface dbus_validate_interface_dylibloader_orig_dbus +#define dbus_validate_member dbus_validate_member_dylibloader_orig_dbus +#define dbus_validate_error_name dbus_validate_error_name_dylibloader_orig_dbus +#define dbus_validate_bus_name dbus_validate_bus_name_dylibloader_orig_dbus +#define dbus_validate_utf8 dbus_validate_utf8_dylibloader_orig_dbus +#define dbus_threads_init dbus_threads_init_dylibloader_orig_dbus +#define dbus_threads_init_default dbus_threads_init_default_dylibloader_orig_dbus +#include <dbus/dbus.h> +#undef dbus_error_init +#undef dbus_error_free +#undef dbus_set_error +#undef dbus_set_error_const +#undef dbus_move_error +#undef dbus_error_has_name +#undef dbus_error_is_set +#undef dbus_parse_address +#undef dbus_address_entry_get_value +#undef dbus_address_entry_get_method +#undef dbus_address_entries_free +#undef dbus_address_escape_value +#undef dbus_address_unescape_value +#undef dbus_malloc +#undef dbus_malloc0 +#undef dbus_realloc +#undef dbus_free +#undef dbus_free_string_array +#undef dbus_shutdown +#undef dbus_message_new +#undef dbus_message_new_method_call +#undef dbus_message_new_method_return +#undef dbus_message_new_signal +#undef dbus_message_new_error +#undef dbus_message_new_error_printf +#undef dbus_message_copy +#undef dbus_message_ref +#undef dbus_message_unref +#undef dbus_message_get_type +#undef dbus_message_set_path +#undef dbus_message_get_path +#undef dbus_message_has_path +#undef dbus_message_set_interface +#undef dbus_message_get_interface +#undef dbus_message_has_interface +#undef dbus_message_set_member +#undef dbus_message_get_member +#undef dbus_message_has_member +#undef dbus_message_set_error_name +#undef dbus_message_get_error_name +#undef dbus_message_set_destination +#undef dbus_message_get_destination +#undef dbus_message_set_sender +#undef dbus_message_get_sender +#undef dbus_message_get_signature +#undef dbus_message_set_no_reply +#undef dbus_message_get_no_reply +#undef dbus_message_is_method_call +#undef dbus_message_is_signal +#undef dbus_message_is_error +#undef dbus_message_has_destination +#undef dbus_message_has_sender +#undef dbus_message_has_signature +#undef dbus_message_get_serial +#undef dbus_message_set_serial +#undef dbus_message_set_reply_serial +#undef dbus_message_get_reply_serial +#undef dbus_message_set_auto_start +#undef dbus_message_get_auto_start +#undef dbus_message_get_path_decomposed +#undef dbus_message_append_args +#undef dbus_message_append_args_valist +#undef dbus_message_get_args +#undef dbus_message_get_args_valist +#undef dbus_message_contains_unix_fds +#undef dbus_message_iter_init_closed +#undef dbus_message_iter_init +#undef dbus_message_iter_has_next +#undef dbus_message_iter_next +#undef dbus_message_iter_get_signature +#undef dbus_message_iter_get_arg_type +#undef dbus_message_iter_get_element_type +#undef dbus_message_iter_recurse +#undef dbus_message_iter_get_basic +#undef dbus_message_iter_get_element_count +#undef dbus_message_iter_get_array_len +#undef dbus_message_iter_get_fixed_array +#undef dbus_message_iter_init_append +#undef dbus_message_iter_append_basic +#undef dbus_message_iter_append_fixed_array +#undef dbus_message_iter_open_container +#undef dbus_message_iter_close_container +#undef dbus_message_iter_abandon_container +#undef dbus_message_iter_abandon_container_if_open +#undef dbus_message_lock +#undef dbus_set_error_from_message +#undef dbus_message_allocate_data_slot +#undef dbus_message_free_data_slot +#undef dbus_message_set_data +#undef dbus_message_get_data +#undef dbus_message_type_from_string +#undef dbus_message_type_to_string +#undef dbus_message_marshal +#undef dbus_message_demarshal +#undef dbus_message_demarshal_bytes_needed +#undef dbus_message_set_allow_interactive_authorization +#undef dbus_message_get_allow_interactive_authorization +#undef dbus_connection_open +#undef dbus_connection_open_private +#undef dbus_connection_ref +#undef dbus_connection_unref +#undef dbus_connection_close +#undef dbus_connection_get_is_connected +#undef dbus_connection_get_is_authenticated +#undef dbus_connection_get_is_anonymous +#undef dbus_connection_get_server_id +#undef dbus_connection_can_send_type +#undef dbus_connection_set_exit_on_disconnect +#undef dbus_connection_flush +#undef dbus_connection_read_write_dispatch +#undef dbus_connection_read_write +#undef dbus_connection_borrow_message +#undef dbus_connection_return_message +#undef dbus_connection_steal_borrowed_message +#undef dbus_connection_pop_message +#undef dbus_connection_get_dispatch_status +#undef dbus_connection_dispatch +#undef dbus_connection_has_messages_to_send +#undef dbus_connection_send +#undef dbus_connection_send_with_reply +#undef dbus_connection_send_with_reply_and_block +#undef dbus_connection_set_watch_functions +#undef dbus_connection_set_timeout_functions +#undef dbus_connection_set_wakeup_main_function +#undef dbus_connection_set_dispatch_status_function +#undef dbus_connection_get_unix_user +#undef dbus_connection_get_unix_process_id +#undef dbus_connection_get_adt_audit_session_data +#undef dbus_connection_set_unix_user_function +#undef dbus_connection_get_windows_user +#undef dbus_connection_set_windows_user_function +#undef dbus_connection_set_allow_anonymous +#undef dbus_connection_set_route_peer_messages +#undef dbus_connection_add_filter +#undef dbus_connection_remove_filter +#undef dbus_connection_allocate_data_slot +#undef dbus_connection_free_data_slot +#undef dbus_connection_set_data +#undef dbus_connection_get_data +#undef dbus_connection_set_change_sigpipe +#undef dbus_connection_set_max_message_size +#undef dbus_connection_get_max_message_size +#undef dbus_connection_set_max_received_size +#undef dbus_connection_get_max_received_size +#undef dbus_connection_set_max_message_unix_fds +#undef dbus_connection_get_max_message_unix_fds +#undef dbus_connection_set_max_received_unix_fds +#undef dbus_connection_get_max_received_unix_fds +#undef dbus_connection_get_outgoing_size +#undef dbus_connection_get_outgoing_unix_fds +#undef dbus_connection_preallocate_send +#undef dbus_connection_free_preallocated_send +#undef dbus_connection_send_preallocated +#undef dbus_connection_try_register_object_path +#undef dbus_connection_register_object_path +#undef dbus_connection_try_register_fallback +#undef dbus_connection_register_fallback +#undef dbus_connection_unregister_object_path +#undef dbus_connection_get_object_path_data +#undef dbus_connection_list_registered +#undef dbus_connection_get_unix_fd +#undef dbus_connection_get_socket +#undef dbus_watch_get_fd +#undef dbus_watch_get_unix_fd +#undef dbus_watch_get_socket +#undef dbus_watch_get_flags +#undef dbus_watch_get_data +#undef dbus_watch_set_data +#undef dbus_watch_handle +#undef dbus_watch_get_enabled +#undef dbus_timeout_get_interval +#undef dbus_timeout_get_data +#undef dbus_timeout_set_data +#undef dbus_timeout_handle +#undef dbus_timeout_get_enabled +#undef dbus_bus_get +#undef dbus_bus_get_private +#undef dbus_bus_register +#undef dbus_bus_set_unique_name +#undef dbus_bus_get_unique_name +#undef dbus_bus_get_unix_user +#undef dbus_bus_get_id +#undef dbus_bus_request_name +#undef dbus_bus_release_name +#undef dbus_bus_name_has_owner +#undef dbus_bus_start_service_by_name +#undef dbus_bus_add_match +#undef dbus_bus_remove_match +#undef dbus_get_local_machine_id +#undef dbus_get_version +#undef dbus_setenv +#undef dbus_try_get_local_machine_id +#undef dbus_pending_call_ref +#undef dbus_pending_call_unref +#undef dbus_pending_call_set_notify +#undef dbus_pending_call_cancel +#undef dbus_pending_call_get_completed +#undef dbus_pending_call_steal_reply +#undef dbus_pending_call_block +#undef dbus_pending_call_allocate_data_slot +#undef dbus_pending_call_free_data_slot +#undef dbus_pending_call_set_data +#undef dbus_pending_call_get_data +#undef dbus_server_listen +#undef dbus_server_ref +#undef dbus_server_unref +#undef dbus_server_disconnect +#undef dbus_server_get_is_connected +#undef dbus_server_get_address +#undef dbus_server_get_id +#undef dbus_server_set_new_connection_function +#undef dbus_server_set_watch_functions +#undef dbus_server_set_timeout_functions +#undef dbus_server_set_auth_mechanisms +#undef dbus_server_allocate_data_slot +#undef dbus_server_free_data_slot +#undef dbus_server_set_data +#undef dbus_server_get_data +#undef dbus_signature_iter_init +#undef dbus_signature_iter_get_current_type +#undef dbus_signature_iter_get_signature +#undef dbus_signature_iter_get_element_type +#undef dbus_signature_iter_next +#undef dbus_signature_iter_recurse +#undef dbus_signature_validate +#undef dbus_signature_validate_single +#undef dbus_type_is_valid +#undef dbus_type_is_basic +#undef dbus_type_is_container +#undef dbus_type_is_fixed +#undef dbus_validate_path +#undef dbus_validate_interface +#undef dbus_validate_member +#undef dbus_validate_error_name +#undef dbus_validate_bus_name +#undef dbus_validate_utf8 +#undef dbus_threads_init +#undef dbus_threads_init_default +#ifdef __cplusplus +extern "C" { +#endif +#define dbus_error_init dbus_error_init_dylibloader_wrapper_dbus +#define dbus_error_free dbus_error_free_dylibloader_wrapper_dbus +#define dbus_set_error dbus_set_error_dylibloader_wrapper_dbus +#define dbus_set_error_const dbus_set_error_const_dylibloader_wrapper_dbus +#define dbus_move_error dbus_move_error_dylibloader_wrapper_dbus +#define dbus_error_has_name dbus_error_has_name_dylibloader_wrapper_dbus +#define dbus_error_is_set dbus_error_is_set_dylibloader_wrapper_dbus +#define dbus_parse_address dbus_parse_address_dylibloader_wrapper_dbus +#define dbus_address_entry_get_value dbus_address_entry_get_value_dylibloader_wrapper_dbus +#define dbus_address_entry_get_method dbus_address_entry_get_method_dylibloader_wrapper_dbus +#define dbus_address_entries_free dbus_address_entries_free_dylibloader_wrapper_dbus +#define dbus_address_escape_value dbus_address_escape_value_dylibloader_wrapper_dbus +#define dbus_address_unescape_value dbus_address_unescape_value_dylibloader_wrapper_dbus +#define dbus_malloc dbus_malloc_dylibloader_wrapper_dbus +#define dbus_malloc0 dbus_malloc0_dylibloader_wrapper_dbus +#define dbus_realloc dbus_realloc_dylibloader_wrapper_dbus +#define dbus_free dbus_free_dylibloader_wrapper_dbus +#define dbus_free_string_array dbus_free_string_array_dylibloader_wrapper_dbus +#define dbus_shutdown dbus_shutdown_dylibloader_wrapper_dbus +#define dbus_message_new dbus_message_new_dylibloader_wrapper_dbus +#define dbus_message_new_method_call dbus_message_new_method_call_dylibloader_wrapper_dbus +#define dbus_message_new_method_return dbus_message_new_method_return_dylibloader_wrapper_dbus +#define dbus_message_new_signal dbus_message_new_signal_dylibloader_wrapper_dbus +#define dbus_message_new_error dbus_message_new_error_dylibloader_wrapper_dbus +#define dbus_message_new_error_printf dbus_message_new_error_printf_dylibloader_wrapper_dbus +#define dbus_message_copy dbus_message_copy_dylibloader_wrapper_dbus +#define dbus_message_ref dbus_message_ref_dylibloader_wrapper_dbus +#define dbus_message_unref dbus_message_unref_dylibloader_wrapper_dbus +#define dbus_message_get_type dbus_message_get_type_dylibloader_wrapper_dbus +#define dbus_message_set_path dbus_message_set_path_dylibloader_wrapper_dbus +#define dbus_message_get_path dbus_message_get_path_dylibloader_wrapper_dbus +#define dbus_message_has_path dbus_message_has_path_dylibloader_wrapper_dbus +#define dbus_message_set_interface dbus_message_set_interface_dylibloader_wrapper_dbus +#define dbus_message_get_interface dbus_message_get_interface_dylibloader_wrapper_dbus +#define dbus_message_has_interface dbus_message_has_interface_dylibloader_wrapper_dbus +#define dbus_message_set_member dbus_message_set_member_dylibloader_wrapper_dbus +#define dbus_message_get_member dbus_message_get_member_dylibloader_wrapper_dbus +#define dbus_message_has_member dbus_message_has_member_dylibloader_wrapper_dbus +#define dbus_message_set_error_name dbus_message_set_error_name_dylibloader_wrapper_dbus +#define dbus_message_get_error_name dbus_message_get_error_name_dylibloader_wrapper_dbus +#define dbus_message_set_destination dbus_message_set_destination_dylibloader_wrapper_dbus +#define dbus_message_get_destination dbus_message_get_destination_dylibloader_wrapper_dbus +#define dbus_message_set_sender dbus_message_set_sender_dylibloader_wrapper_dbus +#define dbus_message_get_sender dbus_message_get_sender_dylibloader_wrapper_dbus +#define dbus_message_get_signature dbus_message_get_signature_dylibloader_wrapper_dbus +#define dbus_message_set_no_reply dbus_message_set_no_reply_dylibloader_wrapper_dbus +#define dbus_message_get_no_reply dbus_message_get_no_reply_dylibloader_wrapper_dbus +#define dbus_message_is_method_call dbus_message_is_method_call_dylibloader_wrapper_dbus +#define dbus_message_is_signal dbus_message_is_signal_dylibloader_wrapper_dbus +#define dbus_message_is_error dbus_message_is_error_dylibloader_wrapper_dbus +#define dbus_message_has_destination dbus_message_has_destination_dylibloader_wrapper_dbus +#define dbus_message_has_sender dbus_message_has_sender_dylibloader_wrapper_dbus +#define dbus_message_has_signature dbus_message_has_signature_dylibloader_wrapper_dbus +#define dbus_message_get_serial dbus_message_get_serial_dylibloader_wrapper_dbus +#define dbus_message_set_serial dbus_message_set_serial_dylibloader_wrapper_dbus +#define dbus_message_set_reply_serial dbus_message_set_reply_serial_dylibloader_wrapper_dbus +#define dbus_message_get_reply_serial dbus_message_get_reply_serial_dylibloader_wrapper_dbus +#define dbus_message_set_auto_start dbus_message_set_auto_start_dylibloader_wrapper_dbus +#define dbus_message_get_auto_start dbus_message_get_auto_start_dylibloader_wrapper_dbus +#define dbus_message_get_path_decomposed dbus_message_get_path_decomposed_dylibloader_wrapper_dbus +#define dbus_message_append_args dbus_message_append_args_dylibloader_wrapper_dbus +#define dbus_message_append_args_valist dbus_message_append_args_valist_dylibloader_wrapper_dbus +#define dbus_message_get_args dbus_message_get_args_dylibloader_wrapper_dbus +#define dbus_message_get_args_valist dbus_message_get_args_valist_dylibloader_wrapper_dbus +#define dbus_message_contains_unix_fds dbus_message_contains_unix_fds_dylibloader_wrapper_dbus +#define dbus_message_iter_init_closed dbus_message_iter_init_closed_dylibloader_wrapper_dbus +#define dbus_message_iter_init dbus_message_iter_init_dylibloader_wrapper_dbus +#define dbus_message_iter_has_next dbus_message_iter_has_next_dylibloader_wrapper_dbus +#define dbus_message_iter_next dbus_message_iter_next_dylibloader_wrapper_dbus +#define dbus_message_iter_get_signature dbus_message_iter_get_signature_dylibloader_wrapper_dbus +#define dbus_message_iter_get_arg_type dbus_message_iter_get_arg_type_dylibloader_wrapper_dbus +#define dbus_message_iter_get_element_type dbus_message_iter_get_element_type_dylibloader_wrapper_dbus +#define dbus_message_iter_recurse dbus_message_iter_recurse_dylibloader_wrapper_dbus +#define dbus_message_iter_get_basic dbus_message_iter_get_basic_dylibloader_wrapper_dbus +#define dbus_message_iter_get_element_count dbus_message_iter_get_element_count_dylibloader_wrapper_dbus +#define dbus_message_iter_get_array_len dbus_message_iter_get_array_len_dylibloader_wrapper_dbus +#define dbus_message_iter_get_fixed_array dbus_message_iter_get_fixed_array_dylibloader_wrapper_dbus +#define dbus_message_iter_init_append dbus_message_iter_init_append_dylibloader_wrapper_dbus +#define dbus_message_iter_append_basic dbus_message_iter_append_basic_dylibloader_wrapper_dbus +#define dbus_message_iter_append_fixed_array dbus_message_iter_append_fixed_array_dylibloader_wrapper_dbus +#define dbus_message_iter_open_container dbus_message_iter_open_container_dylibloader_wrapper_dbus +#define dbus_message_iter_close_container dbus_message_iter_close_container_dylibloader_wrapper_dbus +#define dbus_message_iter_abandon_container dbus_message_iter_abandon_container_dylibloader_wrapper_dbus +#define dbus_message_iter_abandon_container_if_open dbus_message_iter_abandon_container_if_open_dylibloader_wrapper_dbus +#define dbus_message_lock dbus_message_lock_dylibloader_wrapper_dbus +#define dbus_set_error_from_message dbus_set_error_from_message_dylibloader_wrapper_dbus +#define dbus_message_allocate_data_slot dbus_message_allocate_data_slot_dylibloader_wrapper_dbus +#define dbus_message_free_data_slot dbus_message_free_data_slot_dylibloader_wrapper_dbus +#define dbus_message_set_data dbus_message_set_data_dylibloader_wrapper_dbus +#define dbus_message_get_data dbus_message_get_data_dylibloader_wrapper_dbus +#define dbus_message_type_from_string dbus_message_type_from_string_dylibloader_wrapper_dbus +#define dbus_message_type_to_string dbus_message_type_to_string_dylibloader_wrapper_dbus +#define dbus_message_marshal dbus_message_marshal_dylibloader_wrapper_dbus +#define dbus_message_demarshal dbus_message_demarshal_dylibloader_wrapper_dbus +#define dbus_message_demarshal_bytes_needed dbus_message_demarshal_bytes_needed_dylibloader_wrapper_dbus +#define dbus_message_set_allow_interactive_authorization dbus_message_set_allow_interactive_authorization_dylibloader_wrapper_dbus +#define dbus_message_get_allow_interactive_authorization dbus_message_get_allow_interactive_authorization_dylibloader_wrapper_dbus +#define dbus_connection_open dbus_connection_open_dylibloader_wrapper_dbus +#define dbus_connection_open_private dbus_connection_open_private_dylibloader_wrapper_dbus +#define dbus_connection_ref dbus_connection_ref_dylibloader_wrapper_dbus +#define dbus_connection_unref dbus_connection_unref_dylibloader_wrapper_dbus +#define dbus_connection_close dbus_connection_close_dylibloader_wrapper_dbus +#define dbus_connection_get_is_connected dbus_connection_get_is_connected_dylibloader_wrapper_dbus +#define dbus_connection_get_is_authenticated dbus_connection_get_is_authenticated_dylibloader_wrapper_dbus +#define dbus_connection_get_is_anonymous dbus_connection_get_is_anonymous_dylibloader_wrapper_dbus +#define dbus_connection_get_server_id dbus_connection_get_server_id_dylibloader_wrapper_dbus +#define dbus_connection_can_send_type dbus_connection_can_send_type_dylibloader_wrapper_dbus +#define dbus_connection_set_exit_on_disconnect dbus_connection_set_exit_on_disconnect_dylibloader_wrapper_dbus +#define dbus_connection_flush dbus_connection_flush_dylibloader_wrapper_dbus +#define dbus_connection_read_write_dispatch dbus_connection_read_write_dispatch_dylibloader_wrapper_dbus +#define dbus_connection_read_write dbus_connection_read_write_dylibloader_wrapper_dbus +#define dbus_connection_borrow_message dbus_connection_borrow_message_dylibloader_wrapper_dbus +#define dbus_connection_return_message dbus_connection_return_message_dylibloader_wrapper_dbus +#define dbus_connection_steal_borrowed_message dbus_connection_steal_borrowed_message_dylibloader_wrapper_dbus +#define dbus_connection_pop_message dbus_connection_pop_message_dylibloader_wrapper_dbus +#define dbus_connection_get_dispatch_status dbus_connection_get_dispatch_status_dylibloader_wrapper_dbus +#define dbus_connection_dispatch dbus_connection_dispatch_dylibloader_wrapper_dbus +#define dbus_connection_has_messages_to_send dbus_connection_has_messages_to_send_dylibloader_wrapper_dbus +#define dbus_connection_send dbus_connection_send_dylibloader_wrapper_dbus +#define dbus_connection_send_with_reply dbus_connection_send_with_reply_dylibloader_wrapper_dbus +#define dbus_connection_send_with_reply_and_block dbus_connection_send_with_reply_and_block_dylibloader_wrapper_dbus +#define dbus_connection_set_watch_functions dbus_connection_set_watch_functions_dylibloader_wrapper_dbus +#define dbus_connection_set_timeout_functions dbus_connection_set_timeout_functions_dylibloader_wrapper_dbus +#define dbus_connection_set_wakeup_main_function dbus_connection_set_wakeup_main_function_dylibloader_wrapper_dbus +#define dbus_connection_set_dispatch_status_function dbus_connection_set_dispatch_status_function_dylibloader_wrapper_dbus +#define dbus_connection_get_unix_user dbus_connection_get_unix_user_dylibloader_wrapper_dbus +#define dbus_connection_get_unix_process_id dbus_connection_get_unix_process_id_dylibloader_wrapper_dbus +#define dbus_connection_get_adt_audit_session_data dbus_connection_get_adt_audit_session_data_dylibloader_wrapper_dbus +#define dbus_connection_set_unix_user_function dbus_connection_set_unix_user_function_dylibloader_wrapper_dbus +#define dbus_connection_get_windows_user dbus_connection_get_windows_user_dylibloader_wrapper_dbus +#define dbus_connection_set_windows_user_function dbus_connection_set_windows_user_function_dylibloader_wrapper_dbus +#define dbus_connection_set_allow_anonymous dbus_connection_set_allow_anonymous_dylibloader_wrapper_dbus +#define dbus_connection_set_route_peer_messages dbus_connection_set_route_peer_messages_dylibloader_wrapper_dbus +#define dbus_connection_add_filter dbus_connection_add_filter_dylibloader_wrapper_dbus +#define dbus_connection_remove_filter dbus_connection_remove_filter_dylibloader_wrapper_dbus +#define dbus_connection_allocate_data_slot dbus_connection_allocate_data_slot_dylibloader_wrapper_dbus +#define dbus_connection_free_data_slot dbus_connection_free_data_slot_dylibloader_wrapper_dbus +#define dbus_connection_set_data dbus_connection_set_data_dylibloader_wrapper_dbus +#define dbus_connection_get_data dbus_connection_get_data_dylibloader_wrapper_dbus +#define dbus_connection_set_change_sigpipe dbus_connection_set_change_sigpipe_dylibloader_wrapper_dbus +#define dbus_connection_set_max_message_size dbus_connection_set_max_message_size_dylibloader_wrapper_dbus +#define dbus_connection_get_max_message_size dbus_connection_get_max_message_size_dylibloader_wrapper_dbus +#define dbus_connection_set_max_received_size dbus_connection_set_max_received_size_dylibloader_wrapper_dbus +#define dbus_connection_get_max_received_size dbus_connection_get_max_received_size_dylibloader_wrapper_dbus +#define dbus_connection_set_max_message_unix_fds dbus_connection_set_max_message_unix_fds_dylibloader_wrapper_dbus +#define dbus_connection_get_max_message_unix_fds dbus_connection_get_max_message_unix_fds_dylibloader_wrapper_dbus +#define dbus_connection_set_max_received_unix_fds dbus_connection_set_max_received_unix_fds_dylibloader_wrapper_dbus +#define dbus_connection_get_max_received_unix_fds dbus_connection_get_max_received_unix_fds_dylibloader_wrapper_dbus +#define dbus_connection_get_outgoing_size dbus_connection_get_outgoing_size_dylibloader_wrapper_dbus +#define dbus_connection_get_outgoing_unix_fds dbus_connection_get_outgoing_unix_fds_dylibloader_wrapper_dbus +#define dbus_connection_preallocate_send dbus_connection_preallocate_send_dylibloader_wrapper_dbus +#define dbus_connection_free_preallocated_send dbus_connection_free_preallocated_send_dylibloader_wrapper_dbus +#define dbus_connection_send_preallocated dbus_connection_send_preallocated_dylibloader_wrapper_dbus +#define dbus_connection_try_register_object_path dbus_connection_try_register_object_path_dylibloader_wrapper_dbus +#define dbus_connection_register_object_path dbus_connection_register_object_path_dylibloader_wrapper_dbus +#define dbus_connection_try_register_fallback dbus_connection_try_register_fallback_dylibloader_wrapper_dbus +#define dbus_connection_register_fallback dbus_connection_register_fallback_dylibloader_wrapper_dbus +#define dbus_connection_unregister_object_path dbus_connection_unregister_object_path_dylibloader_wrapper_dbus +#define dbus_connection_get_object_path_data dbus_connection_get_object_path_data_dylibloader_wrapper_dbus +#define dbus_connection_list_registered dbus_connection_list_registered_dylibloader_wrapper_dbus +#define dbus_connection_get_unix_fd dbus_connection_get_unix_fd_dylibloader_wrapper_dbus +#define dbus_connection_get_socket dbus_connection_get_socket_dylibloader_wrapper_dbus +#define dbus_watch_get_fd dbus_watch_get_fd_dylibloader_wrapper_dbus +#define dbus_watch_get_unix_fd dbus_watch_get_unix_fd_dylibloader_wrapper_dbus +#define dbus_watch_get_socket dbus_watch_get_socket_dylibloader_wrapper_dbus +#define dbus_watch_get_flags dbus_watch_get_flags_dylibloader_wrapper_dbus +#define dbus_watch_get_data dbus_watch_get_data_dylibloader_wrapper_dbus +#define dbus_watch_set_data dbus_watch_set_data_dylibloader_wrapper_dbus +#define dbus_watch_handle dbus_watch_handle_dylibloader_wrapper_dbus +#define dbus_watch_get_enabled dbus_watch_get_enabled_dylibloader_wrapper_dbus +#define dbus_timeout_get_interval dbus_timeout_get_interval_dylibloader_wrapper_dbus +#define dbus_timeout_get_data dbus_timeout_get_data_dylibloader_wrapper_dbus +#define dbus_timeout_set_data dbus_timeout_set_data_dylibloader_wrapper_dbus +#define dbus_timeout_handle dbus_timeout_handle_dylibloader_wrapper_dbus +#define dbus_timeout_get_enabled dbus_timeout_get_enabled_dylibloader_wrapper_dbus +#define dbus_bus_get dbus_bus_get_dylibloader_wrapper_dbus +#define dbus_bus_get_private dbus_bus_get_private_dylibloader_wrapper_dbus +#define dbus_bus_register dbus_bus_register_dylibloader_wrapper_dbus +#define dbus_bus_set_unique_name dbus_bus_set_unique_name_dylibloader_wrapper_dbus +#define dbus_bus_get_unique_name dbus_bus_get_unique_name_dylibloader_wrapper_dbus +#define dbus_bus_get_unix_user dbus_bus_get_unix_user_dylibloader_wrapper_dbus +#define dbus_bus_get_id dbus_bus_get_id_dylibloader_wrapper_dbus +#define dbus_bus_request_name dbus_bus_request_name_dylibloader_wrapper_dbus +#define dbus_bus_release_name dbus_bus_release_name_dylibloader_wrapper_dbus +#define dbus_bus_name_has_owner dbus_bus_name_has_owner_dylibloader_wrapper_dbus +#define dbus_bus_start_service_by_name dbus_bus_start_service_by_name_dylibloader_wrapper_dbus +#define dbus_bus_add_match dbus_bus_add_match_dylibloader_wrapper_dbus +#define dbus_bus_remove_match dbus_bus_remove_match_dylibloader_wrapper_dbus +#define dbus_get_local_machine_id dbus_get_local_machine_id_dylibloader_wrapper_dbus +#define dbus_get_version dbus_get_version_dylibloader_wrapper_dbus +#define dbus_setenv dbus_setenv_dylibloader_wrapper_dbus +#define dbus_try_get_local_machine_id dbus_try_get_local_machine_id_dylibloader_wrapper_dbus +#define dbus_pending_call_ref dbus_pending_call_ref_dylibloader_wrapper_dbus +#define dbus_pending_call_unref dbus_pending_call_unref_dylibloader_wrapper_dbus +#define dbus_pending_call_set_notify dbus_pending_call_set_notify_dylibloader_wrapper_dbus +#define dbus_pending_call_cancel dbus_pending_call_cancel_dylibloader_wrapper_dbus +#define dbus_pending_call_get_completed dbus_pending_call_get_completed_dylibloader_wrapper_dbus +#define dbus_pending_call_steal_reply dbus_pending_call_steal_reply_dylibloader_wrapper_dbus +#define dbus_pending_call_block dbus_pending_call_block_dylibloader_wrapper_dbus +#define dbus_pending_call_allocate_data_slot dbus_pending_call_allocate_data_slot_dylibloader_wrapper_dbus +#define dbus_pending_call_free_data_slot dbus_pending_call_free_data_slot_dylibloader_wrapper_dbus +#define dbus_pending_call_set_data dbus_pending_call_set_data_dylibloader_wrapper_dbus +#define dbus_pending_call_get_data dbus_pending_call_get_data_dylibloader_wrapper_dbus +#define dbus_server_listen dbus_server_listen_dylibloader_wrapper_dbus +#define dbus_server_ref dbus_server_ref_dylibloader_wrapper_dbus +#define dbus_server_unref dbus_server_unref_dylibloader_wrapper_dbus +#define dbus_server_disconnect dbus_server_disconnect_dylibloader_wrapper_dbus +#define dbus_server_get_is_connected dbus_server_get_is_connected_dylibloader_wrapper_dbus +#define dbus_server_get_address dbus_server_get_address_dylibloader_wrapper_dbus +#define dbus_server_get_id dbus_server_get_id_dylibloader_wrapper_dbus +#define dbus_server_set_new_connection_function dbus_server_set_new_connection_function_dylibloader_wrapper_dbus +#define dbus_server_set_watch_functions dbus_server_set_watch_functions_dylibloader_wrapper_dbus +#define dbus_server_set_timeout_functions dbus_server_set_timeout_functions_dylibloader_wrapper_dbus +#define dbus_server_set_auth_mechanisms dbus_server_set_auth_mechanisms_dylibloader_wrapper_dbus +#define dbus_server_allocate_data_slot dbus_server_allocate_data_slot_dylibloader_wrapper_dbus +#define dbus_server_free_data_slot dbus_server_free_data_slot_dylibloader_wrapper_dbus +#define dbus_server_set_data dbus_server_set_data_dylibloader_wrapper_dbus +#define dbus_server_get_data dbus_server_get_data_dylibloader_wrapper_dbus +#define dbus_signature_iter_init dbus_signature_iter_init_dylibloader_wrapper_dbus +#define dbus_signature_iter_get_current_type dbus_signature_iter_get_current_type_dylibloader_wrapper_dbus +#define dbus_signature_iter_get_signature dbus_signature_iter_get_signature_dylibloader_wrapper_dbus +#define dbus_signature_iter_get_element_type dbus_signature_iter_get_element_type_dylibloader_wrapper_dbus +#define dbus_signature_iter_next dbus_signature_iter_next_dylibloader_wrapper_dbus +#define dbus_signature_iter_recurse dbus_signature_iter_recurse_dylibloader_wrapper_dbus +#define dbus_signature_validate dbus_signature_validate_dylibloader_wrapper_dbus +#define dbus_signature_validate_single dbus_signature_validate_single_dylibloader_wrapper_dbus +#define dbus_type_is_valid dbus_type_is_valid_dylibloader_wrapper_dbus +#define dbus_type_is_basic dbus_type_is_basic_dylibloader_wrapper_dbus +#define dbus_type_is_container dbus_type_is_container_dylibloader_wrapper_dbus +#define dbus_type_is_fixed dbus_type_is_fixed_dylibloader_wrapper_dbus +#define dbus_validate_path dbus_validate_path_dylibloader_wrapper_dbus +#define dbus_validate_interface dbus_validate_interface_dylibloader_wrapper_dbus +#define dbus_validate_member dbus_validate_member_dylibloader_wrapper_dbus +#define dbus_validate_error_name dbus_validate_error_name_dylibloader_wrapper_dbus +#define dbus_validate_bus_name dbus_validate_bus_name_dylibloader_wrapper_dbus +#define dbus_validate_utf8 dbus_validate_utf8_dylibloader_wrapper_dbus +#define dbus_threads_init dbus_threads_init_dylibloader_wrapper_dbus +#define dbus_threads_init_default dbus_threads_init_default_dylibloader_wrapper_dbus +extern void (*dbus_error_init_dylibloader_wrapper_dbus)( DBusError*); +extern void (*dbus_error_free_dylibloader_wrapper_dbus)( DBusError*); +extern void (*dbus_set_error_dylibloader_wrapper_dbus)( DBusError*,const char*,const char*,...); +extern void (*dbus_set_error_const_dylibloader_wrapper_dbus)( DBusError*,const char*,const char*); +extern void (*dbus_move_error_dylibloader_wrapper_dbus)( DBusError*, DBusError*); +extern dbus_bool_t (*dbus_error_has_name_dylibloader_wrapper_dbus)(const DBusError*,const char*); +extern dbus_bool_t (*dbus_error_is_set_dylibloader_wrapper_dbus)(const DBusError*); +extern dbus_bool_t (*dbus_parse_address_dylibloader_wrapper_dbus)(const char*, DBusAddressEntry***, int*, DBusError*); +extern const char* (*dbus_address_entry_get_value_dylibloader_wrapper_dbus)( DBusAddressEntry*,const char*); +extern const char* (*dbus_address_entry_get_method_dylibloader_wrapper_dbus)( DBusAddressEntry*); +extern void (*dbus_address_entries_free_dylibloader_wrapper_dbus)( DBusAddressEntry**); +extern char* (*dbus_address_escape_value_dylibloader_wrapper_dbus)(const char*); +extern char* (*dbus_address_unescape_value_dylibloader_wrapper_dbus)(const char*, DBusError*); +extern void* (*dbus_malloc_dylibloader_wrapper_dbus)( size_t); +extern void* (*dbus_malloc0_dylibloader_wrapper_dbus)( size_t); +extern void* (*dbus_realloc_dylibloader_wrapper_dbus)( void*, size_t); +extern void (*dbus_free_dylibloader_wrapper_dbus)( void*); +extern void (*dbus_free_string_array_dylibloader_wrapper_dbus)( char**); +extern void (*dbus_shutdown_dylibloader_wrapper_dbus)( void); +extern DBusMessage* (*dbus_message_new_dylibloader_wrapper_dbus)( int); +extern DBusMessage* (*dbus_message_new_method_call_dylibloader_wrapper_dbus)(const char*,const char*,const char*,const char*); +extern DBusMessage* (*dbus_message_new_method_return_dylibloader_wrapper_dbus)( DBusMessage*); +extern DBusMessage* (*dbus_message_new_signal_dylibloader_wrapper_dbus)(const char*,const char*,const char*); +extern DBusMessage* (*dbus_message_new_error_dylibloader_wrapper_dbus)( DBusMessage*,const char*,const char*); +extern DBusMessage* (*dbus_message_new_error_printf_dylibloader_wrapper_dbus)( DBusMessage*,const char*,const char*,...); +extern DBusMessage* (*dbus_message_copy_dylibloader_wrapper_dbus)(const DBusMessage*); +extern DBusMessage* (*dbus_message_ref_dylibloader_wrapper_dbus)( DBusMessage*); +extern void (*dbus_message_unref_dylibloader_wrapper_dbus)( DBusMessage*); +extern int (*dbus_message_get_type_dylibloader_wrapper_dbus)( DBusMessage*); +extern dbus_bool_t (*dbus_message_set_path_dylibloader_wrapper_dbus)( DBusMessage*,const char*); +extern const char* (*dbus_message_get_path_dylibloader_wrapper_dbus)( DBusMessage*); +extern dbus_bool_t (*dbus_message_has_path_dylibloader_wrapper_dbus)( DBusMessage*,const char*); +extern dbus_bool_t (*dbus_message_set_interface_dylibloader_wrapper_dbus)( DBusMessage*,const char*); +extern const char* (*dbus_message_get_interface_dylibloader_wrapper_dbus)( DBusMessage*); +extern dbus_bool_t (*dbus_message_has_interface_dylibloader_wrapper_dbus)( DBusMessage*,const char*); +extern dbus_bool_t (*dbus_message_set_member_dylibloader_wrapper_dbus)( DBusMessage*,const char*); +extern const char* (*dbus_message_get_member_dylibloader_wrapper_dbus)( DBusMessage*); +extern dbus_bool_t (*dbus_message_has_member_dylibloader_wrapper_dbus)( DBusMessage*,const char*); +extern dbus_bool_t (*dbus_message_set_error_name_dylibloader_wrapper_dbus)( DBusMessage*,const char*); +extern const char* (*dbus_message_get_error_name_dylibloader_wrapper_dbus)( DBusMessage*); +extern dbus_bool_t (*dbus_message_set_destination_dylibloader_wrapper_dbus)( DBusMessage*,const char*); +extern const char* (*dbus_message_get_destination_dylibloader_wrapper_dbus)( DBusMessage*); +extern dbus_bool_t (*dbus_message_set_sender_dylibloader_wrapper_dbus)( DBusMessage*,const char*); +extern const char* (*dbus_message_get_sender_dylibloader_wrapper_dbus)( DBusMessage*); +extern const char* (*dbus_message_get_signature_dylibloader_wrapper_dbus)( DBusMessage*); +extern void (*dbus_message_set_no_reply_dylibloader_wrapper_dbus)( DBusMessage*, dbus_bool_t); +extern dbus_bool_t (*dbus_message_get_no_reply_dylibloader_wrapper_dbus)( DBusMessage*); +extern dbus_bool_t (*dbus_message_is_method_call_dylibloader_wrapper_dbus)( DBusMessage*,const char*,const char*); +extern dbus_bool_t (*dbus_message_is_signal_dylibloader_wrapper_dbus)( DBusMessage*,const char*,const char*); +extern dbus_bool_t (*dbus_message_is_error_dylibloader_wrapper_dbus)( DBusMessage*,const char*); +extern dbus_bool_t (*dbus_message_has_destination_dylibloader_wrapper_dbus)( DBusMessage*,const char*); +extern dbus_bool_t (*dbus_message_has_sender_dylibloader_wrapper_dbus)( DBusMessage*,const char*); +extern dbus_bool_t (*dbus_message_has_signature_dylibloader_wrapper_dbus)( DBusMessage*,const char*); +extern dbus_uint32_t (*dbus_message_get_serial_dylibloader_wrapper_dbus)( DBusMessage*); +extern void (*dbus_message_set_serial_dylibloader_wrapper_dbus)( DBusMessage*, dbus_uint32_t); +extern dbus_bool_t (*dbus_message_set_reply_serial_dylibloader_wrapper_dbus)( DBusMessage*, dbus_uint32_t); +extern dbus_uint32_t (*dbus_message_get_reply_serial_dylibloader_wrapper_dbus)( DBusMessage*); +extern void (*dbus_message_set_auto_start_dylibloader_wrapper_dbus)( DBusMessage*, dbus_bool_t); +extern dbus_bool_t (*dbus_message_get_auto_start_dylibloader_wrapper_dbus)( DBusMessage*); +extern dbus_bool_t (*dbus_message_get_path_decomposed_dylibloader_wrapper_dbus)( DBusMessage*, char***); +extern dbus_bool_t (*dbus_message_append_args_dylibloader_wrapper_dbus)( DBusMessage*, int,...); +extern dbus_bool_t (*dbus_message_append_args_valist_dylibloader_wrapper_dbus)( DBusMessage*, int, va_list); +extern dbus_bool_t (*dbus_message_get_args_dylibloader_wrapper_dbus)( DBusMessage*, DBusError*, int,...); +extern dbus_bool_t (*dbus_message_get_args_valist_dylibloader_wrapper_dbus)( DBusMessage*, DBusError*, int, va_list); +extern dbus_bool_t (*dbus_message_contains_unix_fds_dylibloader_wrapper_dbus)( DBusMessage*); +extern void (*dbus_message_iter_init_closed_dylibloader_wrapper_dbus)( DBusMessageIter*); +extern dbus_bool_t (*dbus_message_iter_init_dylibloader_wrapper_dbus)( DBusMessage*, DBusMessageIter*); +extern dbus_bool_t (*dbus_message_iter_has_next_dylibloader_wrapper_dbus)( DBusMessageIter*); +extern dbus_bool_t (*dbus_message_iter_next_dylibloader_wrapper_dbus)( DBusMessageIter*); +extern char* (*dbus_message_iter_get_signature_dylibloader_wrapper_dbus)( DBusMessageIter*); +extern int (*dbus_message_iter_get_arg_type_dylibloader_wrapper_dbus)( DBusMessageIter*); +extern int (*dbus_message_iter_get_element_type_dylibloader_wrapper_dbus)( DBusMessageIter*); +extern void (*dbus_message_iter_recurse_dylibloader_wrapper_dbus)( DBusMessageIter*, DBusMessageIter*); +extern void (*dbus_message_iter_get_basic_dylibloader_wrapper_dbus)( DBusMessageIter*, void*); +extern int (*dbus_message_iter_get_element_count_dylibloader_wrapper_dbus)( DBusMessageIter*); +extern int (*dbus_message_iter_get_array_len_dylibloader_wrapper_dbus)( DBusMessageIter*); +extern void (*dbus_message_iter_get_fixed_array_dylibloader_wrapper_dbus)( DBusMessageIter*, void*, int*); +extern void (*dbus_message_iter_init_append_dylibloader_wrapper_dbus)( DBusMessage*, DBusMessageIter*); +extern dbus_bool_t (*dbus_message_iter_append_basic_dylibloader_wrapper_dbus)( DBusMessageIter*, int,const void*); +extern dbus_bool_t (*dbus_message_iter_append_fixed_array_dylibloader_wrapper_dbus)( DBusMessageIter*, int,const void*, int); +extern dbus_bool_t (*dbus_message_iter_open_container_dylibloader_wrapper_dbus)( DBusMessageIter*, int,const char*, DBusMessageIter*); +extern dbus_bool_t (*dbus_message_iter_close_container_dylibloader_wrapper_dbus)( DBusMessageIter*, DBusMessageIter*); +extern void (*dbus_message_iter_abandon_container_dylibloader_wrapper_dbus)( DBusMessageIter*, DBusMessageIter*); +extern void (*dbus_message_iter_abandon_container_if_open_dylibloader_wrapper_dbus)( DBusMessageIter*, DBusMessageIter*); +extern void (*dbus_message_lock_dylibloader_wrapper_dbus)( DBusMessage*); +extern dbus_bool_t (*dbus_set_error_from_message_dylibloader_wrapper_dbus)( DBusError*, DBusMessage*); +extern dbus_bool_t (*dbus_message_allocate_data_slot_dylibloader_wrapper_dbus)( dbus_int32_t*); +extern void (*dbus_message_free_data_slot_dylibloader_wrapper_dbus)( dbus_int32_t*); +extern dbus_bool_t (*dbus_message_set_data_dylibloader_wrapper_dbus)( DBusMessage*, dbus_int32_t, void*, DBusFreeFunction); +extern void* (*dbus_message_get_data_dylibloader_wrapper_dbus)( DBusMessage*, dbus_int32_t); +extern int (*dbus_message_type_from_string_dylibloader_wrapper_dbus)(const char*); +extern const char* (*dbus_message_type_to_string_dylibloader_wrapper_dbus)( int); +extern dbus_bool_t (*dbus_message_marshal_dylibloader_wrapper_dbus)( DBusMessage*, char**, int*); +extern DBusMessage* (*dbus_message_demarshal_dylibloader_wrapper_dbus)(const char*, int, DBusError*); +extern int (*dbus_message_demarshal_bytes_needed_dylibloader_wrapper_dbus)(const char*, int); +extern void (*dbus_message_set_allow_interactive_authorization_dylibloader_wrapper_dbus)( DBusMessage*, dbus_bool_t); +extern dbus_bool_t (*dbus_message_get_allow_interactive_authorization_dylibloader_wrapper_dbus)( DBusMessage*); +extern DBusConnection* (*dbus_connection_open_dylibloader_wrapper_dbus)(const char*, DBusError*); +extern DBusConnection* (*dbus_connection_open_private_dylibloader_wrapper_dbus)(const char*, DBusError*); +extern DBusConnection* (*dbus_connection_ref_dylibloader_wrapper_dbus)( DBusConnection*); +extern void (*dbus_connection_unref_dylibloader_wrapper_dbus)( DBusConnection*); +extern void (*dbus_connection_close_dylibloader_wrapper_dbus)( DBusConnection*); +extern dbus_bool_t (*dbus_connection_get_is_connected_dylibloader_wrapper_dbus)( DBusConnection*); +extern dbus_bool_t (*dbus_connection_get_is_authenticated_dylibloader_wrapper_dbus)( DBusConnection*); +extern dbus_bool_t (*dbus_connection_get_is_anonymous_dylibloader_wrapper_dbus)( DBusConnection*); +extern char* (*dbus_connection_get_server_id_dylibloader_wrapper_dbus)( DBusConnection*); +extern dbus_bool_t (*dbus_connection_can_send_type_dylibloader_wrapper_dbus)( DBusConnection*, int); +extern void (*dbus_connection_set_exit_on_disconnect_dylibloader_wrapper_dbus)( DBusConnection*, dbus_bool_t); +extern void (*dbus_connection_flush_dylibloader_wrapper_dbus)( DBusConnection*); +extern dbus_bool_t (*dbus_connection_read_write_dispatch_dylibloader_wrapper_dbus)( DBusConnection*, int); +extern dbus_bool_t (*dbus_connection_read_write_dylibloader_wrapper_dbus)( DBusConnection*, int); +extern DBusMessage* (*dbus_connection_borrow_message_dylibloader_wrapper_dbus)( DBusConnection*); +extern void (*dbus_connection_return_message_dylibloader_wrapper_dbus)( DBusConnection*, DBusMessage*); +extern void (*dbus_connection_steal_borrowed_message_dylibloader_wrapper_dbus)( DBusConnection*, DBusMessage*); +extern DBusMessage* (*dbus_connection_pop_message_dylibloader_wrapper_dbus)( DBusConnection*); +extern DBusDispatchStatus (*dbus_connection_get_dispatch_status_dylibloader_wrapper_dbus)( DBusConnection*); +extern DBusDispatchStatus (*dbus_connection_dispatch_dylibloader_wrapper_dbus)( DBusConnection*); +extern dbus_bool_t (*dbus_connection_has_messages_to_send_dylibloader_wrapper_dbus)( DBusConnection*); +extern dbus_bool_t (*dbus_connection_send_dylibloader_wrapper_dbus)( DBusConnection*, DBusMessage*, dbus_uint32_t*); +extern dbus_bool_t (*dbus_connection_send_with_reply_dylibloader_wrapper_dbus)( DBusConnection*, DBusMessage*, DBusPendingCall**, int); +extern DBusMessage* (*dbus_connection_send_with_reply_and_block_dylibloader_wrapper_dbus)( DBusConnection*, DBusMessage*, int, DBusError*); +extern dbus_bool_t (*dbus_connection_set_watch_functions_dylibloader_wrapper_dbus)( DBusConnection*, DBusAddWatchFunction, DBusRemoveWatchFunction, DBusWatchToggledFunction, void*, DBusFreeFunction); +extern dbus_bool_t (*dbus_connection_set_timeout_functions_dylibloader_wrapper_dbus)( DBusConnection*, DBusAddTimeoutFunction, DBusRemoveTimeoutFunction, DBusTimeoutToggledFunction, void*, DBusFreeFunction); +extern void (*dbus_connection_set_wakeup_main_function_dylibloader_wrapper_dbus)( DBusConnection*, DBusWakeupMainFunction, void*, DBusFreeFunction); +extern void (*dbus_connection_set_dispatch_status_function_dylibloader_wrapper_dbus)( DBusConnection*, DBusDispatchStatusFunction, void*, DBusFreeFunction); +extern dbus_bool_t (*dbus_connection_get_unix_user_dylibloader_wrapper_dbus)( DBusConnection*, unsigned long*); +extern dbus_bool_t (*dbus_connection_get_unix_process_id_dylibloader_wrapper_dbus)( DBusConnection*, unsigned long*); +extern dbus_bool_t (*dbus_connection_get_adt_audit_session_data_dylibloader_wrapper_dbus)( DBusConnection*, void**, dbus_int32_t*); +extern void (*dbus_connection_set_unix_user_function_dylibloader_wrapper_dbus)( DBusConnection*, DBusAllowUnixUserFunction, void*, DBusFreeFunction); +extern dbus_bool_t (*dbus_connection_get_windows_user_dylibloader_wrapper_dbus)( DBusConnection*, char**); +extern void (*dbus_connection_set_windows_user_function_dylibloader_wrapper_dbus)( DBusConnection*, DBusAllowWindowsUserFunction, void*, DBusFreeFunction); +extern void (*dbus_connection_set_allow_anonymous_dylibloader_wrapper_dbus)( DBusConnection*, dbus_bool_t); +extern void (*dbus_connection_set_route_peer_messages_dylibloader_wrapper_dbus)( DBusConnection*, dbus_bool_t); +extern dbus_bool_t (*dbus_connection_add_filter_dylibloader_wrapper_dbus)( DBusConnection*, DBusHandleMessageFunction, void*, DBusFreeFunction); +extern void (*dbus_connection_remove_filter_dylibloader_wrapper_dbus)( DBusConnection*, DBusHandleMessageFunction, void*); +extern dbus_bool_t (*dbus_connection_allocate_data_slot_dylibloader_wrapper_dbus)( dbus_int32_t*); +extern void (*dbus_connection_free_data_slot_dylibloader_wrapper_dbus)( dbus_int32_t*); +extern dbus_bool_t (*dbus_connection_set_data_dylibloader_wrapper_dbus)( DBusConnection*, dbus_int32_t, void*, DBusFreeFunction); +extern void* (*dbus_connection_get_data_dylibloader_wrapper_dbus)( DBusConnection*, dbus_int32_t); +extern void (*dbus_connection_set_change_sigpipe_dylibloader_wrapper_dbus)( dbus_bool_t); +extern void (*dbus_connection_set_max_message_size_dylibloader_wrapper_dbus)( DBusConnection*, long); +extern long (*dbus_connection_get_max_message_size_dylibloader_wrapper_dbus)( DBusConnection*); +extern void (*dbus_connection_set_max_received_size_dylibloader_wrapper_dbus)( DBusConnection*, long); +extern long (*dbus_connection_get_max_received_size_dylibloader_wrapper_dbus)( DBusConnection*); +extern void (*dbus_connection_set_max_message_unix_fds_dylibloader_wrapper_dbus)( DBusConnection*, long); +extern long (*dbus_connection_get_max_message_unix_fds_dylibloader_wrapper_dbus)( DBusConnection*); +extern void (*dbus_connection_set_max_received_unix_fds_dylibloader_wrapper_dbus)( DBusConnection*, long); +extern long (*dbus_connection_get_max_received_unix_fds_dylibloader_wrapper_dbus)( DBusConnection*); +extern long (*dbus_connection_get_outgoing_size_dylibloader_wrapper_dbus)( DBusConnection*); +extern long (*dbus_connection_get_outgoing_unix_fds_dylibloader_wrapper_dbus)( DBusConnection*); +extern DBusPreallocatedSend* (*dbus_connection_preallocate_send_dylibloader_wrapper_dbus)( DBusConnection*); +extern void (*dbus_connection_free_preallocated_send_dylibloader_wrapper_dbus)( DBusConnection*, DBusPreallocatedSend*); +extern void (*dbus_connection_send_preallocated_dylibloader_wrapper_dbus)( DBusConnection*, DBusPreallocatedSend*, DBusMessage*, dbus_uint32_t*); +extern dbus_bool_t (*dbus_connection_try_register_object_path_dylibloader_wrapper_dbus)( DBusConnection*,const char*,const DBusObjectPathVTable*, void*, DBusError*); +extern dbus_bool_t (*dbus_connection_register_object_path_dylibloader_wrapper_dbus)( DBusConnection*,const char*,const DBusObjectPathVTable*, void*); +extern dbus_bool_t (*dbus_connection_try_register_fallback_dylibloader_wrapper_dbus)( DBusConnection*,const char*,const DBusObjectPathVTable*, void*, DBusError*); +extern dbus_bool_t (*dbus_connection_register_fallback_dylibloader_wrapper_dbus)( DBusConnection*,const char*,const DBusObjectPathVTable*, void*); +extern dbus_bool_t (*dbus_connection_unregister_object_path_dylibloader_wrapper_dbus)( DBusConnection*,const char*); +extern dbus_bool_t (*dbus_connection_get_object_path_data_dylibloader_wrapper_dbus)( DBusConnection*,const char*, void**); +extern dbus_bool_t (*dbus_connection_list_registered_dylibloader_wrapper_dbus)( DBusConnection*,const char*, char***); +extern dbus_bool_t (*dbus_connection_get_unix_fd_dylibloader_wrapper_dbus)( DBusConnection*, int*); +extern dbus_bool_t (*dbus_connection_get_socket_dylibloader_wrapper_dbus)( DBusConnection*, int*); +extern int (*dbus_watch_get_fd_dylibloader_wrapper_dbus)( DBusWatch*); +extern int (*dbus_watch_get_unix_fd_dylibloader_wrapper_dbus)( DBusWatch*); +extern int (*dbus_watch_get_socket_dylibloader_wrapper_dbus)( DBusWatch*); +extern unsigned int (*dbus_watch_get_flags_dylibloader_wrapper_dbus)( DBusWatch*); +extern void* (*dbus_watch_get_data_dylibloader_wrapper_dbus)( DBusWatch*); +extern void (*dbus_watch_set_data_dylibloader_wrapper_dbus)( DBusWatch*, void*, DBusFreeFunction); +extern dbus_bool_t (*dbus_watch_handle_dylibloader_wrapper_dbus)( DBusWatch*, unsigned int); +extern dbus_bool_t (*dbus_watch_get_enabled_dylibloader_wrapper_dbus)( DBusWatch*); +extern int (*dbus_timeout_get_interval_dylibloader_wrapper_dbus)( DBusTimeout*); +extern void* (*dbus_timeout_get_data_dylibloader_wrapper_dbus)( DBusTimeout*); +extern void (*dbus_timeout_set_data_dylibloader_wrapper_dbus)( DBusTimeout*, void*, DBusFreeFunction); +extern dbus_bool_t (*dbus_timeout_handle_dylibloader_wrapper_dbus)( DBusTimeout*); +extern dbus_bool_t (*dbus_timeout_get_enabled_dylibloader_wrapper_dbus)( DBusTimeout*); +extern DBusConnection* (*dbus_bus_get_dylibloader_wrapper_dbus)( DBusBusType, DBusError*); +extern DBusConnection* (*dbus_bus_get_private_dylibloader_wrapper_dbus)( DBusBusType, DBusError*); +extern dbus_bool_t (*dbus_bus_register_dylibloader_wrapper_dbus)( DBusConnection*, DBusError*); +extern dbus_bool_t (*dbus_bus_set_unique_name_dylibloader_wrapper_dbus)( DBusConnection*,const char*); +extern const char* (*dbus_bus_get_unique_name_dylibloader_wrapper_dbus)( DBusConnection*); +extern unsigned long (*dbus_bus_get_unix_user_dylibloader_wrapper_dbus)( DBusConnection*,const char*, DBusError*); +extern char* (*dbus_bus_get_id_dylibloader_wrapper_dbus)( DBusConnection*, DBusError*); +extern int (*dbus_bus_request_name_dylibloader_wrapper_dbus)( DBusConnection*,const char*, unsigned int, DBusError*); +extern int (*dbus_bus_release_name_dylibloader_wrapper_dbus)( DBusConnection*,const char*, DBusError*); +extern dbus_bool_t (*dbus_bus_name_has_owner_dylibloader_wrapper_dbus)( DBusConnection*,const char*, DBusError*); +extern dbus_bool_t (*dbus_bus_start_service_by_name_dylibloader_wrapper_dbus)( DBusConnection*,const char*, dbus_uint32_t, dbus_uint32_t*, DBusError*); +extern void (*dbus_bus_add_match_dylibloader_wrapper_dbus)( DBusConnection*,const char*, DBusError*); +extern void (*dbus_bus_remove_match_dylibloader_wrapper_dbus)( DBusConnection*,const char*, DBusError*); +extern char* (*dbus_get_local_machine_id_dylibloader_wrapper_dbus)( void); +extern void (*dbus_get_version_dylibloader_wrapper_dbus)( int*, int*, int*); +extern dbus_bool_t (*dbus_setenv_dylibloader_wrapper_dbus)(const char*,const char*); +extern char* (*dbus_try_get_local_machine_id_dylibloader_wrapper_dbus)( DBusError*); +extern DBusPendingCall* (*dbus_pending_call_ref_dylibloader_wrapper_dbus)( DBusPendingCall*); +extern void (*dbus_pending_call_unref_dylibloader_wrapper_dbus)( DBusPendingCall*); +extern dbus_bool_t (*dbus_pending_call_set_notify_dylibloader_wrapper_dbus)( DBusPendingCall*, DBusPendingCallNotifyFunction, void*, DBusFreeFunction); +extern void (*dbus_pending_call_cancel_dylibloader_wrapper_dbus)( DBusPendingCall*); +extern dbus_bool_t (*dbus_pending_call_get_completed_dylibloader_wrapper_dbus)( DBusPendingCall*); +extern DBusMessage* (*dbus_pending_call_steal_reply_dylibloader_wrapper_dbus)( DBusPendingCall*); +extern void (*dbus_pending_call_block_dylibloader_wrapper_dbus)( DBusPendingCall*); +extern dbus_bool_t (*dbus_pending_call_allocate_data_slot_dylibloader_wrapper_dbus)( dbus_int32_t*); +extern void (*dbus_pending_call_free_data_slot_dylibloader_wrapper_dbus)( dbus_int32_t*); +extern dbus_bool_t (*dbus_pending_call_set_data_dylibloader_wrapper_dbus)( DBusPendingCall*, dbus_int32_t, void*, DBusFreeFunction); +extern void* (*dbus_pending_call_get_data_dylibloader_wrapper_dbus)( DBusPendingCall*, dbus_int32_t); +extern DBusServer* (*dbus_server_listen_dylibloader_wrapper_dbus)(const char*, DBusError*); +extern DBusServer* (*dbus_server_ref_dylibloader_wrapper_dbus)( DBusServer*); +extern void (*dbus_server_unref_dylibloader_wrapper_dbus)( DBusServer*); +extern void (*dbus_server_disconnect_dylibloader_wrapper_dbus)( DBusServer*); +extern dbus_bool_t (*dbus_server_get_is_connected_dylibloader_wrapper_dbus)( DBusServer*); +extern char* (*dbus_server_get_address_dylibloader_wrapper_dbus)( DBusServer*); +extern char* (*dbus_server_get_id_dylibloader_wrapper_dbus)( DBusServer*); +extern void (*dbus_server_set_new_connection_function_dylibloader_wrapper_dbus)( DBusServer*, DBusNewConnectionFunction, void*, DBusFreeFunction); +extern dbus_bool_t (*dbus_server_set_watch_functions_dylibloader_wrapper_dbus)( DBusServer*, DBusAddWatchFunction, DBusRemoveWatchFunction, DBusWatchToggledFunction, void*, DBusFreeFunction); +extern dbus_bool_t (*dbus_server_set_timeout_functions_dylibloader_wrapper_dbus)( DBusServer*, DBusAddTimeoutFunction, DBusRemoveTimeoutFunction, DBusTimeoutToggledFunction, void*, DBusFreeFunction); +extern dbus_bool_t (*dbus_server_set_auth_mechanisms_dylibloader_wrapper_dbus)( DBusServer*,const char**); +extern dbus_bool_t (*dbus_server_allocate_data_slot_dylibloader_wrapper_dbus)( dbus_int32_t*); +extern void (*dbus_server_free_data_slot_dylibloader_wrapper_dbus)( dbus_int32_t*); +extern dbus_bool_t (*dbus_server_set_data_dylibloader_wrapper_dbus)( DBusServer*, int, void*, DBusFreeFunction); +extern void* (*dbus_server_get_data_dylibloader_wrapper_dbus)( DBusServer*, int); +extern void (*dbus_signature_iter_init_dylibloader_wrapper_dbus)( DBusSignatureIter*,const char*); +extern int (*dbus_signature_iter_get_current_type_dylibloader_wrapper_dbus)(const DBusSignatureIter*); +extern char* (*dbus_signature_iter_get_signature_dylibloader_wrapper_dbus)(const DBusSignatureIter*); +extern int (*dbus_signature_iter_get_element_type_dylibloader_wrapper_dbus)(const DBusSignatureIter*); +extern dbus_bool_t (*dbus_signature_iter_next_dylibloader_wrapper_dbus)( DBusSignatureIter*); +extern void (*dbus_signature_iter_recurse_dylibloader_wrapper_dbus)(const DBusSignatureIter*, DBusSignatureIter*); +extern dbus_bool_t (*dbus_signature_validate_dylibloader_wrapper_dbus)(const char*, DBusError*); +extern dbus_bool_t (*dbus_signature_validate_single_dylibloader_wrapper_dbus)(const char*, DBusError*); +extern dbus_bool_t (*dbus_type_is_valid_dylibloader_wrapper_dbus)( int); +extern dbus_bool_t (*dbus_type_is_basic_dylibloader_wrapper_dbus)( int); +extern dbus_bool_t (*dbus_type_is_container_dylibloader_wrapper_dbus)( int); +extern dbus_bool_t (*dbus_type_is_fixed_dylibloader_wrapper_dbus)( int); +extern dbus_bool_t (*dbus_validate_path_dylibloader_wrapper_dbus)(const char*, DBusError*); +extern dbus_bool_t (*dbus_validate_interface_dylibloader_wrapper_dbus)(const char*, DBusError*); +extern dbus_bool_t (*dbus_validate_member_dylibloader_wrapper_dbus)(const char*, DBusError*); +extern dbus_bool_t (*dbus_validate_error_name_dylibloader_wrapper_dbus)(const char*, DBusError*); +extern dbus_bool_t (*dbus_validate_bus_name_dylibloader_wrapper_dbus)(const char*, DBusError*); +extern dbus_bool_t (*dbus_validate_utf8_dylibloader_wrapper_dbus)(const char*, DBusError*); +extern dbus_bool_t (*dbus_threads_init_dylibloader_wrapper_dbus)(const DBusThreadFunctions*); +extern dbus_bool_t (*dbus_threads_init_default_dylibloader_wrapper_dbus)( void); +int initialize_dbus(int verbose); +#ifdef __cplusplus +} +#endif +#endif diff --git a/platform/linuxbsd/detect.py b/platform/linuxbsd/detect.py index 19cf341c85..36644d5f29 100644 --- a/platform/linuxbsd/detect.py +++ b/platform/linuxbsd/detect.py @@ -1,6 +1,8 @@ import os import platform import sys +from methods import get_compiler_version, using_gcc +from platform_methods import detect_arch def is_active(): @@ -15,47 +17,11 @@ def can_build(): if os.name != "posix" or sys.platform == "darwin": return False - # Check the minimal dependencies - x11_error = os.system("pkg-config --version > /dev/null") - if x11_error: + pkgconf_error = os.system("pkg-config --version > /dev/null") + if pkgconf_error: print("Error: pkg-config not found. Aborting.") return False - x11_error = os.system("pkg-config x11 --modversion > /dev/null") - if x11_error: - print("Error: X11 libraries not found. Aborting.") - return False - - x11_error = os.system("pkg-config xcursor --modversion > /dev/null") - if x11_error: - print("Error: Xcursor library not found. Aborting.") - return False - - x11_error = os.system("pkg-config xinerama --modversion > /dev/null") - if x11_error: - print("Error: Xinerama library not found. Aborting.") - return False - - x11_error = os.system("pkg-config xext --modversion > /dev/null") - if x11_error: - print("Error: Xext library not found. Aborting.") - return False - - x11_error = os.system("pkg-config xrandr --modversion > /dev/null") - if x11_error: - print("Error: XrandR library not found. Aborting.") - return False - - x11_error = os.system("pkg-config xrender --modversion > /dev/null") - if x11_error: - print("Error: XRender library not found. Aborting.") - return False - - x11_error = os.system("pkg-config xi --modversion > /dev/null") - if x11_error: - print("Error: Xi library not found. Aborting.") - return False - return True @@ -63,9 +29,8 @@ def get_opts(): from SCons.Variables import BoolVariable, EnumVariable return [ + EnumVariable("linker", "Linker program", "default", ("default", "bfd", "gold", "lld", "mold")), BoolVariable("use_llvm", "Use the LLVM compiler", False), - BoolVariable("use_lld", "Use the LLD linker", False), - BoolVariable("use_thinlto", "Use ThinLTO", False), BoolVariable("use_static_cpp", "Link libgcc and libstdc++ statically for better portability", True), BoolVariable("use_coverage", "Test Godot coverage", False), BoolVariable("use_ubsan", "Use LLVM/GCC compiler undefined behavior sanitizer (UBSAN)", False), @@ -74,8 +39,9 @@ def get_opts(): BoolVariable("use_tsan", "Use LLVM/GCC compiler thread sanitizer (TSAN)", False), BoolVariable("use_msan", "Use LLVM compiler memory sanitizer (MSAN)", False), BoolVariable("pulseaudio", "Detect and use PulseAudio", True), - BoolVariable("dbus", "Detect and use D-Bus to handle screensaver", True), + BoolVariable("dbus", "Detect and use D-Bus to handle screensaver and portal desktop settings", True), BoolVariable("speechd", "Detect and use Speech Dispatcher for Text-to-Speech support", True), + BoolVariable("fontconfig", "Detect and use fontconfig for system fonts support", True), BoolVariable("udev", "Use udev for gamepad connection callbacks", True), BoolVariable("x11", "Enable X11 display", True), BoolVariable("debug_symbols", "Add debugging symbols to release/release_debug builds", True), @@ -86,10 +52,21 @@ def get_opts(): def get_flags(): - return [] + return [ + ("arch", detect_arch()), + ] def configure(env): + # Validate arch. + supported_arches = ["x86_32", "x86_64", "arm32", "arm64", "rv64", "ppc32", "ppc64"] + if env["arch"] not in supported_arches: + print( + 'Unsupported CPU architecture "%s" for Linux / *BSD. Supported architectures are: %s.' + % (env["arch"], ", ".join(supported_arches)) + ) + sys.exit() + ## Build type if env["target"] == "release": @@ -114,23 +91,7 @@ def configure(env): env.Prepend(CCFLAGS=["-g3"]) env.Append(LINKFLAGS=["-rdynamic"]) - ## Architecture - - is64 = sys.maxsize > 2**32 - if env["bits"] == "default": - env["bits"] = "64" if is64 else "32" - - machines = { - "riscv64": "rv64", - "ppc64le": "ppc64", - "ppc64": "ppc64", - "ppcle": "ppc", - "ppc": "ppc", - } - - if env["arch"] == "" and platform.machine() in machines: - env["arch"] = machines[platform.machine()] - + # CPU architecture flags. if env["arch"] == "rv64": # G = General-purpose extensions, C = Compression extension (very common). env.Append(CCFLAGS=["-march=rv64gc"]) @@ -147,15 +108,25 @@ def configure(env): env["CXX"] = "clang++" env.extra_suffix = ".llvm" + env.extra_suffix - if env["use_lld"]: - if env["use_llvm"]: - env.Append(LINKFLAGS=["-fuse-ld=lld"]) - if env["use_thinlto"]: - # A convenience so you don't need to write use_lto too when using SCons - env["use_lto"] = True + if env["linker"] != "default": + print("Using linker program: " + env["linker"]) + if env["linker"] == "mold" and using_gcc(env): # GCC < 12.1 doesn't support -fuse-ld=mold. + cc_version = get_compiler_version(env) + cc_semver = (int(cc_version["major"]), int(cc_version["minor"])) + if cc_semver < (12, 1): + found_wrapper = False + for path in ["/usr/libexec", "/usr/local/libexec", "/usr/lib", "/usr/local/lib"]: + if os.path.isfile(path + "/mold/ld"): + env.Append(LINKFLAGS=["-B" + path + "/mold"]) + 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.") + sys.exit(255) + else: + env.Append(LINKFLAGS=["-fuse-ld=mold"]) else: - print("Using LLD with GCC is not supported yet. Try compiling with 'use_llvm=yes'.") - sys.exit(255) + env.Append(LINKFLAGS=["-fuse-ld=%s" % env["linker"]]) if env["use_coverage"]: env.Append(CCFLAGS=["-ftest-coverage", "-fprofile-arcs"]) @@ -199,34 +170,37 @@ def configure(env): env.Append(CCFLAGS=["-fsanitize-recover=memory"]) env.Append(LINKFLAGS=["-fsanitize=memory"]) - if env["use_lto"]: - if not env["use_llvm"] and env.GetOption("num_jobs") > 1: + # LTO + 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`.") + sys.exit(255) + env.Append(CCFLAGS=["-flto=thin"]) + env.Append(LINKFLAGS=["-flto=thin"]) + elif not env["use_llvm"] and env.GetOption("num_jobs") > 1: env.Append(CCFLAGS=["-flto"]) env.Append(LINKFLAGS=["-flto=" + str(env.GetOption("num_jobs"))]) else: - if env["use_lld"] and env["use_thinlto"]: - env.Append(CCFLAGS=["-flto=thin"]) - env.Append(LINKFLAGS=["-flto=thin"]) - else: - env.Append(CCFLAGS=["-flto"]) - env.Append(LINKFLAGS=["-flto"]) + env.Append(CCFLAGS=["-flto"]) + env.Append(LINKFLAGS=["-flto"]) if not env["use_llvm"]: env["RANLIB"] = "gcc-ranlib" env["AR"] = "gcc-ar" env.Append(CCFLAGS=["-pipe"]) - env.Append(LINKFLAGS=["-pipe"]) ## Dependencies - env.ParseConfig("pkg-config x11 --cflags --libs") - env.ParseConfig("pkg-config xcursor --cflags --libs") - env.ParseConfig("pkg-config xinerama --cflags --libs") - env.ParseConfig("pkg-config xext --cflags --libs") - env.ParseConfig("pkg-config xrandr --cflags --libs") - env.ParseConfig("pkg-config xrender --cflags --libs") - env.ParseConfig("pkg-config xi --cflags --libs") + if env["x11"]: + env.ParseConfig("pkg-config x11 --cflags --libs") + env.ParseConfig("pkg-config xcursor --cflags --libs") + env.ParseConfig("pkg-config xinerama --cflags --libs") + env.ParseConfig("pkg-config xext --cflags --libs") + env.ParseConfig("pkg-config xrandr --cflags --libs") + env.ParseConfig("pkg-config xrender --cflags --libs") + env.ParseConfig("pkg-config xi --cflags --libs") if env["touch"]: env.Append(CPPDEFINES=["TOUCH_ENABLED"]) @@ -280,8 +254,7 @@ def configure(env): env["builtin_libvorbis"] = False # Needed to link against system libtheora env.ParseConfig("pkg-config theora theoradec --cflags --libs") else: - list_of_x86 = ["x86_64", "x86", "i386", "i586"] - if any(platform.machine() in s for s in list_of_x86): + if env["arch"] in ["x86_64", "x86_32"]: env["x86_libtheora_opt_gcc"] = True if not env["builtin_libvorbis"]: @@ -317,6 +290,14 @@ def configure(env): ## Flags + if env["fontconfig"]: + if os.system("pkg-config --exists fontconfig") == 0: # 0 means found + env.Append(CPPDEFINES=["FONTCONFIG_ENABLED"]) + env.ParseConfig("pkg-config fontconfig --cflags") # Only cflags, we dlopen the library. + else: + env["fontconfig"] = False + print("Warning: fontconfig libraries not found. Disabling the system fonts support.") + if os.system("pkg-config --exists alsa") == 0: # 0 means found env["alsa"] = True env.Append(CPPDEFINES=["ALSA_ENABLED", "ALSAMIDI_ENABLED"]) @@ -335,8 +316,9 @@ def configure(env): if env["dbus"]: if os.system("pkg-config --exists dbus-1") == 0: # 0 means found env.Append(CPPDEFINES=["DBUS_ENABLED"]) - env.ParseConfig("pkg-config dbus-1 --cflags --libs") + env.ParseConfig("pkg-config dbus-1 --cflags") # Only cflags, we dlopen the library. else: + env["dbus"] = False print("Warning: D-Bus development libraries not found. Disabling screensaver prevention.") if env["speechd"]: @@ -382,8 +364,9 @@ def configure(env): # No pkgconfig file so far, hardcode expected lib name. env.Append(LIBS=["glslang", "SPIRV"]) - env.Append(CPPDEFINES=["GLES3_ENABLED"]) - env.ParseConfig("pkg-config gl --cflags --libs") + if env["opengl3"]: + env.Append(CPPDEFINES=["GLES3_ENABLED"]) + env.ParseConfig("pkg-config gl --cflags --libs") env.Append(LIBS=["pthread"]) @@ -400,7 +383,9 @@ def configure(env): import subprocess import re - linker_version_str = subprocess.check_output([env.subst(env["LINK"]), "-Wl,--version"]).decode("utf-8") + linker_version_str = subprocess.check_output( + [env.subst(env["LINK"]), "-Wl,--version"] + env.subst(env["LINKFLAGS"]) + ).decode("utf-8") gnu_ld_version = re.search("^GNU ld [^$]*(\d+\.\d+)$", linker_version_str, re.MULTILINE) if not gnu_ld_version: print( @@ -413,11 +398,12 @@ def configure(env): env.Append(LINKFLAGS=["-T", "platform/linuxbsd/pck_embed.legacy.ld"]) ## Cross-compilation - - if is64 and env["bits"] == "32": + # TODO: Support cross-compilation on architectures other than x86. + host_is_64_bit = sys.maxsize > 2**32 + if host_is_64_bit and env["arch"] == "x86_32": env.Append(CCFLAGS=["-m32"]) env.Append(LINKFLAGS=["-m32", "-L/usr/lib/i386-linux-gnu"]) - elif not is64 and env["bits"] == "64": + elif not host_is_64_bit and env["arch"] == "x86_64": env.Append(CCFLAGS=["-m64"]) env.Append(LINKFLAGS=["-m64", "-L/usr/lib/i686-linux-gnu"]) diff --git a/platform/linuxbsd/detect_prime_x11.cpp b/platform/linuxbsd/detect_prime_x11.cpp index 42b7f68a5e..fb833ab5e6 100644 --- a/platform/linuxbsd/detect_prime_x11.cpp +++ b/platform/linuxbsd/detect_prime_x11.cpp @@ -177,6 +177,11 @@ int detect_prime() { } else { // In child, exit() here will not quit the engine. + // Prevent false leak reports as we will not be properly + // cleaning up these processes, and fork() makes a copy + // of all globals. + CoreGlobals::leak_reporting_enabled = false; + char string[201]; close(fdset[0]); diff --git a/platform/linuxbsd/detect_prime_x11.h b/platform/linuxbsd/detect_prime_x11.h index e60f9ebfdf..21ebaead32 100644 --- a/platform/linuxbsd/detect_prime_x11.h +++ b/platform/linuxbsd/detect_prime_x11.h @@ -34,4 +34,5 @@ int detect_prime(); #endif -#endif + +#endif // DETECT_PRIME_X11_H diff --git a/platform/linuxbsd/display_server_x11.cpp b/platform/linuxbsd/display_server_x11.cpp index b0f87484b9..0236e134fb 100644 --- a/platform/linuxbsd/display_server_x11.cpp +++ b/platform/linuxbsd/display_server_x11.cpp @@ -275,7 +275,7 @@ bool DisplayServerX11::_refresh_device_info() { xi.pen_pressure_range[dev->deviceid] = Vector2(pressure_min, pressure_max); xi.pen_tilt_x_range[dev->deviceid] = Vector2(tilt_x_min, tilt_x_max); xi.pen_tilt_y_range[dev->deviceid] = Vector2(tilt_y_min, tilt_y_max); - xi.pen_inverted_devices[dev->deviceid] = (bool)strstr(dev->name, "eraser"); + xi.pen_inverted_devices[dev->deviceid] = String(dev->name).findn("eraser") > 0; } XIFreeDeviceInfo(info); @@ -322,8 +322,8 @@ bool DisplayServerX11::tts_is_paused() const { return tts->is_paused(); } -Array DisplayServerX11::tts_get_voices() const { - ERR_FAIL_COND_V(!tts, Array()); +TypedArray<Dictionary> DisplayServerX11::tts_get_voices() const { + ERR_FAIL_COND_V(!tts, TypedArray<Dictionary>()); return tts->get_voices(); } @@ -349,6 +349,28 @@ void DisplayServerX11::tts_stop() { #endif +#ifdef DBUS_ENABLED + +bool DisplayServerX11::is_dark_mode_supported() const { + return portal_desktop->is_supported(); +} + +bool DisplayServerX11::is_dark_mode() const { + switch (portal_desktop->get_appearance_color_scheme()) { + case 1: + // Prefers dark theme. + return true; + case 2: + // Prefers light theme. + return false; + default: + // Preference unknown. + return false; + } +} + +#endif + void DisplayServerX11::mouse_set_mode(MouseMode p_mode) { _THREAD_SAFE_METHOD_ @@ -993,7 +1015,7 @@ Rect2i DisplayServerX11::screen_get_usable_rect(int p_screen) const { Rect2i left_rect(pos.x, pos.y + left_start_y, left, left_end_y - left_start_y); if (left_rect.size.x > 0) { Rect2i intersection = rect.intersection(left_rect); - if (!intersection.has_no_area() && intersection.size.x < rect.size.x) { + if (intersection.has_area() && intersection.size.x < rect.size.x) { rect.position.x = left_rect.size.x; rect.size.x = rect.size.x - intersection.size.x; } @@ -1002,7 +1024,7 @@ Rect2i DisplayServerX11::screen_get_usable_rect(int p_screen) const { Rect2i right_rect(pos.x + size.x - right, pos.y + right_start_y, right, right_end_y - right_start_y); if (right_rect.size.x > 0) { Rect2i intersection = rect.intersection(right_rect); - if (!intersection.has_no_area() && right_rect.size.x < rect.size.x) { + if (intersection.has_area() && right_rect.size.x < rect.size.x) { rect.size.x = intersection.position.x - rect.position.x; } } @@ -1010,7 +1032,7 @@ Rect2i DisplayServerX11::screen_get_usable_rect(int p_screen) const { Rect2i top_rect(pos.x + top_start_x, pos.y, top_end_x - top_start_x, top); if (top_rect.size.y > 0) { Rect2i intersection = rect.intersection(top_rect); - if (!intersection.has_no_area() && intersection.size.y < rect.size.y) { + if (intersection.has_area() && intersection.size.y < rect.size.y) { rect.position.y = top_rect.size.y; rect.size.y = rect.size.y - intersection.size.y; } @@ -1019,7 +1041,7 @@ Rect2i DisplayServerX11::screen_get_usable_rect(int p_screen) const { Rect2i bottom_rect(pos.x + bottom_start_x, pos.y + size.y - bottom, bottom_end_x - bottom_start_x, bottom); if (bottom_rect.size.y > 0) { Rect2i intersection = rect.intersection(bottom_rect); - if (!intersection.has_no_area() && right_rect.size.y < rect.size.y) { + if (intersection.has_area() && right_rect.size.y < rect.size.y) { rect.size.y = intersection.position.y - rect.position.y; } } @@ -1489,8 +1511,8 @@ void DisplayServerX11::window_set_current_screen(int p_screen, WindowID p_window XMoveResizeWindow(x11_display, wd.x11_window, position.x, position.y, size.x, size.y); } else { if (p_screen != window_get_current_screen(p_window)) { - Point2i position = screen_get_position(p_screen); - XMoveWindow(x11_display, wd.x11_window, position.x, position.y); + Vector2 ofs = window_get_position(p_window) - screen_get_position(window_get_current_screen(p_window)); + window_set_position(ofs + screen_get_position(p_screen), p_window); } } } @@ -1522,11 +1544,15 @@ void DisplayServerX11::window_set_transient(WindowID p_window, WindowID p_parent XSetTransientForHint(x11_display, wd_window.x11_window, None); + XWindowAttributes xwa; + XSync(x11_display, False); + XGetWindowAttributes(x11_display, wd_parent.x11_window, &xwa); + // Set focus to parent sub window to avoid losing all focus when closing a nested sub-menu. // RevertToPointerRoot is used to make sure we don't lose all focus in case // a subwindow and its parent are both destroyed. if (!wd_window.no_focus && !wd_window.is_popup && wd_window.focused) { - if (!wd_parent.no_focus && !wd_window.is_popup) { + if ((xwa.map_state == IsViewable) && !wd_parent.no_focus && !wd_window.is_popup) { XSetInputFocus(x11_display, wd_parent.x11_window, RevertToPointerRoot, CurrentTime); } } @@ -1819,6 +1845,47 @@ bool DisplayServerX11::_window_maximize_check(WindowID p_window, const char *p_a return retval; } +bool DisplayServerX11::_window_minimize_check(WindowID p_window) const { + const WindowData &wd = windows[p_window]; + + // Using ICCCM -- Inter-Client Communication Conventions Manual + Atom property = XInternAtom(x11_display, "WM_STATE", True); + if (property == None) { + return false; + } + + Atom type; + int format; + unsigned long len; + unsigned long remaining; + unsigned char *data = nullptr; + + int result = XGetWindowProperty( + x11_display, + wd.x11_window, + property, + 0, + 32, + False, + AnyPropertyType, + &type, + &format, + &len, + &remaining, + &data); + + if (result == Success && data) { + long *state = (long *)data; + if (state[0] == WM_IconicState) { + XFree(data); + return true; + } + XFree(data); + } + + return false; +} + bool DisplayServerX11::_window_fullscreen_check(WindowID p_window) const { ERR_FAIL_COND_V(!windows.has(p_window), false); const WindowData &wd = windows[p_window]; @@ -1865,6 +1932,18 @@ bool DisplayServerX11::_window_fullscreen_check(WindowID p_window) const { return retval; } +void DisplayServerX11::_validate_mode_on_map(WindowID p_window) { + // Check if we applied any window modes that didn't take effect while unmapped + const WindowData &wd = windows[p_window]; + if (wd.fullscreen && !_window_fullscreen_check(p_window)) { + _set_wm_fullscreen(p_window, true); + } else if (wd.maximized && !_window_maximize_check(p_window, "_NET_WM_STATE")) { + _set_wm_maximized(p_window, true); + } else if (wd.minimized && !_window_minimize_check(p_window)) { + _set_wm_minimized(p_window, true); + } +} + bool DisplayServerX11::window_is_maximize_allowed(WindowID p_window) const { _THREAD_SAFE_METHOD_ return _window_maximize_check(p_window, "_NET_WM_ALLOWED_ACTIONS"); @@ -1899,6 +1978,37 @@ void DisplayServerX11::_set_wm_maximized(WindowID p_window, bool p_enabled) { usleep(10000); } } + wd.maximized = p_enabled; +} + +void DisplayServerX11::_set_wm_minimized(WindowID p_window, bool p_enabled) { + WindowData &wd = windows[p_window]; + // Using ICCCM -- Inter-Client Communication Conventions Manual + XEvent xev; + Atom wm_change = XInternAtom(x11_display, "WM_CHANGE_STATE", False); + + memset(&xev, 0, sizeof(xev)); + xev.type = ClientMessage; + xev.xclient.window = wd.x11_window; + xev.xclient.message_type = wm_change; + xev.xclient.format = 32; + xev.xclient.data.l[0] = p_enabled ? WM_IconicState : WM_NormalState; + + XSendEvent(x11_display, DefaultRootWindow(x11_display), False, SubstructureRedirectMask | SubstructureNotifyMask, &xev); + + Atom wm_state = XInternAtom(x11_display, "_NET_WM_STATE", False); + Atom wm_hidden = XInternAtom(x11_display, "_NET_WM_STATE_HIDDEN", False); + + memset(&xev, 0, sizeof(xev)); + xev.type = ClientMessage; + xev.xclient.window = wd.x11_window; + xev.xclient.message_type = wm_state; + xev.xclient.format = 32; + xev.xclient.data.l[0] = p_enabled ? _NET_WM_STATE_ADD : _NET_WM_STATE_REMOVE; + xev.xclient.data.l[1] = wm_hidden; + + XSendEvent(x11_display, DefaultRootWindow(x11_display), False, SubstructureRedirectMask | SubstructureNotifyMask, &xev); + wd.minimized = p_enabled; } void DisplayServerX11::_set_wm_fullscreen(WindowID p_window, bool p_enabled) { @@ -1980,32 +2090,7 @@ void DisplayServerX11::window_set_mode(WindowMode p_mode, WindowID p_window) { //do nothing } break; case WINDOW_MODE_MINIMIZED: { - //Un-Minimize - // Using ICCCM -- Inter-Client Communication Conventions Manual - XEvent xev; - Atom wm_change = XInternAtom(x11_display, "WM_CHANGE_STATE", False); - - memset(&xev, 0, sizeof(xev)); - xev.type = ClientMessage; - xev.xclient.window = wd.x11_window; - xev.xclient.message_type = wm_change; - xev.xclient.format = 32; - xev.xclient.data.l[0] = WM_NormalState; - - XSendEvent(x11_display, DefaultRootWindow(x11_display), False, SubstructureRedirectMask | SubstructureNotifyMask, &xev); - - Atom wm_state = XInternAtom(x11_display, "_NET_WM_STATE", False); - Atom wm_hidden = XInternAtom(x11_display, "_NET_WM_STATE_HIDDEN", False); - - memset(&xev, 0, sizeof(xev)); - xev.type = ClientMessage; - xev.xclient.window = wd.x11_window; - xev.xclient.message_type = wm_state; - xev.xclient.format = 32; - xev.xclient.data.l[0] = _NET_WM_STATE_ADD; - xev.xclient.data.l[1] = wm_hidden; - - XSendEvent(x11_display, DefaultRootWindow(x11_display), False, SubstructureRedirectMask | SubstructureNotifyMask, &xev); + _set_wm_minimized(p_window, false); } break; case WINDOW_MODE_EXCLUSIVE_FULLSCREEN: case WINDOW_MODE_FULLSCREEN: { @@ -2034,31 +2119,7 @@ void DisplayServerX11::window_set_mode(WindowMode p_mode, WindowID p_window) { //do nothing } break; case WINDOW_MODE_MINIMIZED: { - // Using ICCCM -- Inter-Client Communication Conventions Manual - XEvent xev; - Atom wm_change = XInternAtom(x11_display, "WM_CHANGE_STATE", False); - - memset(&xev, 0, sizeof(xev)); - xev.type = ClientMessage; - xev.xclient.window = wd.x11_window; - xev.xclient.message_type = wm_change; - xev.xclient.format = 32; - xev.xclient.data.l[0] = WM_IconicState; - - XSendEvent(x11_display, DefaultRootWindow(x11_display), False, SubstructureRedirectMask | SubstructureNotifyMask, &xev); - - Atom wm_state = XInternAtom(x11_display, "_NET_WM_STATE", False); - Atom wm_hidden = XInternAtom(x11_display, "_NET_WM_STATE_HIDDEN", False); - - memset(&xev, 0, sizeof(xev)); - xev.type = ClientMessage; - xev.xclient.window = wd.x11_window; - xev.xclient.message_type = wm_state; - xev.xclient.format = 32; - xev.xclient.data.l[0] = _NET_WM_STATE_ADD; - xev.xclient.data.l[1] = wm_hidden; - - XSendEvent(x11_display, DefaultRootWindow(x11_display), False, SubstructureRedirectMask | SubstructureNotifyMask, &xev); + _set_wm_minimized(p_window, true); } break; case WINDOW_MODE_EXCLUSIVE_FULLSCREEN: case WINDOW_MODE_FULLSCREEN: { @@ -2093,40 +2154,9 @@ DisplayServer::WindowMode DisplayServerX11::window_get_mode(WindowID p_window) c return WINDOW_MODE_MAXIMIZED; } - { // Test minimized. - // Using ICCCM -- Inter-Client Communication Conventions Manual - Atom property = XInternAtom(x11_display, "WM_STATE", True); - if (property == None) { - return WINDOW_MODE_WINDOWED; - } - - Atom type; - int format; - unsigned long len; - unsigned long remaining; - unsigned char *data = nullptr; - - int result = XGetWindowProperty( - x11_display, - wd.x11_window, - property, - 0, - 32, - False, - AnyPropertyType, - &type, - &format, - &len, - &remaining, - &data); - - if (result == Success && data) { - long *state = (long *)data; - if (state[0] == WM_IconicState) { - XFree(data); - return WINDOW_MODE_MINIMIZED; - } - XFree(data); + { + if (_window_minimize_check(p_window)) { + return WINDOW_MODE_MINIMIZED; } } @@ -2191,7 +2221,7 @@ void DisplayServerX11::window_set_flag(WindowFlags p_flag, bool p_enabled, Windo } break; case WINDOW_FLAG_TRANSPARENT: { - //todo reimplement + wd.layered_window = p_enabled; } break; case WINDOW_FLAG_NO_FOCUS: { wd.no_focus = p_enabled; @@ -2244,7 +2274,7 @@ bool DisplayServerX11::window_get_flag(WindowFlags p_flag, WindowID p_window) co return wd.on_top; } break; case WINDOW_FLAG_TRANSPARENT: { - //todo reimplement + return wd.layered_window; } break; case WINDOW_FLAG_NO_FOCUS: { return wd.no_focus; @@ -3147,7 +3177,7 @@ void DisplayServerX11::_window_changed(XEvent *event) { Variant *rectp = ▭ Variant ret; Callable::CallError ce; - wd.rect_changed_callback.call((const Variant **)&rectp, 1, ret, ce); + wd.rect_changed_callback.callp((const Variant **)&rectp, 1, ret, ce); } } @@ -3168,7 +3198,7 @@ void DisplayServerX11::_dispatch_input_event(const Ref<InputEvent> &p_event) { if (windows.has(E->get())) { Callable callable = windows[E->get()].input_event_callback; if (callable.is_valid()) { - callable.call((const Variant **)&evp, 1, ret, ce); + callable.callp((const Variant **)&evp, 1, ret, ce); } } return; @@ -3181,7 +3211,7 @@ void DisplayServerX11::_dispatch_input_event(const Ref<InputEvent> &p_event) { if (windows.has(event_from_window->get_window_id())) { Callable callable = windows[event_from_window->get_window_id()].input_event_callback; if (callable.is_valid()) { - callable.call((const Variant **)&evp, 1, ret, ce); + callable.callp((const Variant **)&evp, 1, ret, ce); } } } else { @@ -3189,7 +3219,7 @@ void DisplayServerX11::_dispatch_input_event(const Ref<InputEvent> &p_event) { for (KeyValue<WindowID, WindowData> &E : windows) { Callable callable = E.value.input_event_callback; if (callable.is_valid()) { - callable.call((const Variant **)&evp, 1, ret, ce); + callable.callp((const Variant **)&evp, 1, ret, ce); } } } @@ -3201,7 +3231,7 @@ void DisplayServerX11::_send_window_event(const WindowData &wd, WindowEvent p_ev Variant *eventp = &event; Variant ret; Callable::CallError ce; - wd.event_callback.call((const Variant **)&eventp, 1, ret, ce); + wd.event_callback.callp((const Variant **)&eventp, 1, ret, ce); } } @@ -3646,12 +3676,19 @@ void DisplayServerX11::process_events() { const WindowData &wd = windows[window_id]; + XWindowAttributes xwa; + XSync(x11_display, False); + XGetWindowAttributes(x11_display, wd.x11_window, &xwa); + // Set focus when menu window is started. // RevertToPointerRoot is used to make sure we don't lose all focus in case // a subwindow and its parent are both destroyed. - if (!wd.no_focus && !wd.is_popup) { + if ((xwa.map_state == IsViewable) && !wd.no_focus && !wd.is_popup) { XSetInputFocus(x11_display, wd.x11_window, RevertToPointerRoot, CurrentTime); } + + // Have we failed to set fullscreen while the window was unmapped? + _validate_mode_on_map(window_id); } break; case Expose: { @@ -3671,8 +3708,7 @@ void DisplayServerX11::process_events() { case VisibilityNotify: { DEBUG_LOG_X11("[%u] VisibilityNotify window=%lu (%u), state=%u \n", frame, event.xvisibility.window, window_id, event.xvisibility.state); - XVisibilityEvent *visibility = (XVisibilityEvent *)&event; - windows[window_id].minimized = (visibility->state == VisibilityFullyObscured); + windows[window_id].minimized = _window_minimize_check(window_id); } break; case LeaveNotify: { @@ -4068,7 +4104,7 @@ void DisplayServerX11::process_events() { Variant *vp = &v; Variant ret; Callable::CallError ce; - windows[window_id].drop_files_callback.call((const Variant **)&vp, 1, ret, ce); + windows[window_id].drop_files_callback.callp((const Variant **)&vp, 1, ret, ce); } //Reply that all is well. @@ -4390,13 +4426,41 @@ DisplayServer *DisplayServerX11::create_func(const String &p_rendering_driver, W DisplayServerX11::WindowID DisplayServerX11::_create_window(WindowMode p_mode, VSyncMode p_vsync_mode, uint32_t p_flags, const Rect2i &p_rect) { //Create window - long visualMask = VisualScreenMask; - int numberOfVisuals; - XVisualInfo vInfoTemplate = {}; - vInfoTemplate.screen = DefaultScreen(x11_display); - XVisualInfo *visualInfo = XGetVisualInfo(x11_display, visualMask, &vInfoTemplate, &numberOfVisuals); + XVisualInfo visualInfo; + bool vi_selected = false; - Colormap colormap = XCreateColormap(x11_display, RootWindow(x11_display, vInfoTemplate.screen), visualInfo->visual, AllocNone); +#ifdef GLES3_ENABLED + if (gl_manager) { + visualInfo = gl_manager->get_vi(x11_display); + vi_selected = true; + } +#endif + + if (!vi_selected) { + long visualMask = VisualScreenMask; + int numberOfVisuals; + XVisualInfo vInfoTemplate = {}; + vInfoTemplate.screen = DefaultScreen(x11_display); + XVisualInfo *vi_list = XGetVisualInfo(x11_display, visualMask, &vInfoTemplate, &numberOfVisuals); + ERR_FAIL_COND_V(!vi_list, INVALID_WINDOW_ID); + + visualInfo = vi_list[0]; + if (OS::get_singleton()->is_layered_allowed()) { + for (int i = 0; i < numberOfVisuals; i++) { + XRenderPictFormat *pict_format = XRenderFindVisualFormat(x11_display, vi_list[i].visual); + if (!pict_format) { + continue; + } + visualInfo = vi_list[i]; + if (pict_format->direct.alphaMask > 0) { + break; + } + } + } + XFree(vi_list); + } + + Colormap colormap = XCreateColormap(x11_display, RootWindow(x11_display, visualInfo.screen), visualInfo.visual, AllocNone); XSetWindowAttributes windowAttributes = {}; windowAttributes.colormap = colormap; @@ -4406,6 +4470,13 @@ DisplayServerX11::WindowID DisplayServerX11::_create_window(WindowMode p_mode, V unsigned long valuemask = CWBorderPixel | CWColormap | CWEventMask; + if (OS::get_singleton()->is_layered_allowed()) { + windowAttributes.background_pixmap = None; + windowAttributes.background_pixel = 0; + windowAttributes.border_pixmap = None; + valuemask |= CWBackPixel; + } + WindowID id = window_id_counter++; WindowData &wd = windows[id]; @@ -4429,7 +4500,7 @@ DisplayServerX11::WindowID DisplayServerX11::_create_window(WindowMode p_mode, V } { - wd.x11_window = XCreateWindow(x11_display, RootWindow(x11_display, visualInfo->screen), p_rect.position.x, p_rect.position.y, p_rect.size.width > 0 ? p_rect.size.width : 1, p_rect.size.height > 0 ? p_rect.size.height : 1, 0, visualInfo->depth, InputOutput, visualInfo->visual, valuemask, &windowAttributes); + wd.x11_window = XCreateWindow(x11_display, RootWindow(x11_display, visualInfo.screen), p_rect.position.x, p_rect.position.y, p_rect.size.width > 0 ? p_rect.size.width : 1, p_rect.size.height > 0 ? p_rect.size.height : 1, 0, visualInfo.depth, InputOutput, visualInfo.visual, valuemask, &windowAttributes); // Enable receiving notification when the window is initialized (MapNotify) // so the focus can be set at the right time. @@ -4566,8 +4637,6 @@ DisplayServerX11::WindowID DisplayServerX11::_create_window(WindowMode p_mode, V XSync(x11_display, False); //XSetErrorHandler(oldHandler); - - XFree(visualInfo); } window_set_mode(p_mode, id); @@ -4831,6 +4900,8 @@ DisplayServerX11::DisplayServerX11(const String &p_rendering_driver, WindowMode } } show_window(main_window); + XSync(x11_display, False); + _validate_mode_on_map(main_window); #if defined(VULKAN_ENABLED) if (rendering_driver == "vulkan") { @@ -4977,21 +5048,22 @@ DisplayServerX11::DisplayServerX11(const String &p_rendering_driver, WindowMode } cursor_set_shape(CURSOR_BUSY); - XEvent xevent; - while (XPending(x11_display) > 0) { - XNextEvent(x11_display, &xevent); - if (xevent.type == ConfigureNotify) { - _window_changed(&xevent); - } + // Search the X11 event queue for ConfigureNotify events and process all + // that are currently queued early, so we can get the final window size + // for correctly drawing of the bootsplash. + XEvent config_event; + while (XCheckTypedEvent(x11_display, ConfigureNotify, &config_event)) { + _window_changed(&config_event); } - events_thread.start(_poll_events_thread, this); _update_real_mouse_position(windows[MAIN_WINDOW_ID]); #ifdef DBUS_ENABLED screensaver = memnew(FreeDesktopScreenSaver); - screen_set_keep_on(GLOBAL_DEF("display/window/energy_saving/keep_screen_on", true)); + screen_set_keep_on(GLOBAL_GET("display/window/energy_saving/keep_screen_on")); + + portal_desktop = memnew(FreeDesktopPortalDesktop); #endif r_error = OK; @@ -5077,6 +5149,7 @@ DisplayServerX11::~DisplayServerX11() { #ifdef DBUS_ENABLED memdelete(screensaver); + memdelete(portal_desktop); #endif } diff --git a/platform/linuxbsd/display_server_x11.h b/platform/linuxbsd/display_server_x11.h index 9ce6a557db..ea03b2328c 100644 --- a/platform/linuxbsd/display_server_x11.h +++ b/platform/linuxbsd/display_server_x11.h @@ -60,6 +60,7 @@ #endif #if defined(DBUS_ENABLED) +#include "freedesktop_portal_desktop.h" #include "freedesktop_screensaver.h" #endif @@ -120,6 +121,10 @@ class DisplayServerX11 : public DisplayServer { TTS_Linux *tts = nullptr; #endif +#if defined(DBUS_ENABLED) + FreeDesktopPortalDesktop *portal_desktop = nullptr; +#endif + struct WindowData { Window x11_window; ::XIC xic; @@ -152,7 +157,9 @@ class DisplayServerX11 : public DisplayServer { Vector2i last_position_before_fs; bool focused = true; bool minimized = false; + bool maximized = false; bool is_popup = false; + bool layered_window = false; Rect2i parent_safe_rect; @@ -245,8 +252,6 @@ class DisplayServerX11 : public DisplayServer { CursorShape current_cursor = CURSOR_ARROW; HashMap<CursorShape, Vector<Variant>> cursors_cache; - bool layered_window = false; - String rendering_driver; void set_wm_fullscreen(bool p_enabled); void set_wm_above(bool p_enabled); @@ -268,9 +273,12 @@ class DisplayServerX11 : public DisplayServer { void _update_real_mouse_position(const WindowData &wd); bool _window_maximize_check(WindowID p_window, const char *p_atom_name) const; bool _window_fullscreen_check(WindowID p_window) const; + bool _window_minimize_check(WindowID p_window) const; + void _validate_mode_on_map(WindowID p_window); void _update_size_hints(WindowID p_window); void _set_wm_fullscreen(WindowID p_window, bool p_enabled); void _set_wm_maximized(WindowID p_window, bool p_enabled); + void _set_wm_minimized(WindowID p_window, bool p_enabled); void _update_context(WindowData &wd); @@ -308,7 +316,7 @@ public: #ifdef SPEECHD_ENABLED virtual bool tts_is_speaking() const override; virtual bool tts_is_paused() const override; - virtual Array tts_get_voices() const override; + virtual TypedArray<Dictionary> tts_get_voices() const override; virtual void tts_speak(const String &p_text, const String &p_voice, int p_volume = 50, float p_pitch = 1.f, float p_rate = 1.f, int p_utterance_id = 0, bool p_interrupt = false) override; virtual void tts_pause() override; @@ -316,6 +324,11 @@ public: virtual void tts_stop() override; #endif +#if defined(DBUS_ENABLED) + virtual bool is_dark_mode_supported() const override; + virtual bool is_dark_mode() const override; +#endif + virtual void mouse_set_mode(MouseMode p_mode) override; virtual MouseMode mouse_get_mode() const override; diff --git a/platform/linuxbsd/export/export.cpp b/platform/linuxbsd/export/export.cpp index 4240e9adc0..990351d13f 100644 --- a/platform/linuxbsd/export/export.cpp +++ b/platform/linuxbsd/export/export.cpp @@ -30,6 +30,7 @@ #include "export.h" +#include "editor/export/editor_export.h" #include "export_plugin.h" void register_linuxbsd_exporter() { @@ -37,8 +38,6 @@ void register_linuxbsd_exporter() { platform.instantiate(); platform->set_logo(ImageTexture::create_from_image(memnew(Image(_linuxbsd_logo)))); platform->set_name("Linux/X11"); - platform->set_extension("x86_32"); - platform->set_extension("x86_64", "binary_format/64_bits"); platform->set_os_name("Linux"); platform->set_chmod_flags(0755); diff --git a/platform/linuxbsd/export/export_plugin.cpp b/platform/linuxbsd/export/export_plugin.cpp index 4e14920e79..4d45d3ba12 100644 --- a/platform/linuxbsd/export/export_plugin.cpp +++ b/platform/linuxbsd/export/export_plugin.cpp @@ -79,31 +79,21 @@ Error EditorExportPlatformLinuxBSD::export_project(const Ref<EditorExportPreset> return err; } -void EditorExportPlatformLinuxBSD::set_extension(const String &p_extension, const String &p_feature_key) { - extensions[p_feature_key] = p_extension; -} - String EditorExportPlatformLinuxBSD::get_template_file_name(const String &p_target, const String &p_arch) const { - return "linux_x11_" + p_arch + "_" + p_target; + return "linux_" + p_target + "." + p_arch; } List<String> EditorExportPlatformLinuxBSD::get_binary_extensions(const Ref<EditorExportPreset> &p_preset) const { List<String> list; - for (const KeyValue<String, String> &E : extensions) { - if (p_preset->get(E.key)) { - list.push_back(extensions[E.key]); - return list; - } - } - - if (extensions.has("default")) { - list.push_back(extensions["default"]); - return list; - } - + list.push_back(p_preset->get("binary_format/architecture")); return list; } +void EditorExportPlatformLinuxBSD::get_export_options(List<ExportOption> *r_options) { + EditorExportPlatformPC::get_export_options(r_options); + r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "binary_format/architecture", PROPERTY_HINT_ENUM, "x86_64,x86_32,arm64,arm32,rv64,ppc64,ppc32"), "x86_64")); +} + Error EditorExportPlatformLinuxBSD::fixup_embedded_pck(const String &p_path, int64_t p_embedded_start, int64_t p_embedded_size) { // Patch the header of the "pck" section in the ELF file so that it corresponds to the embedded data diff --git a/platform/linuxbsd/export/export_plugin.h b/platform/linuxbsd/export/export_plugin.h index e04bcc20f9..4d6737498b 100644 --- a/platform/linuxbsd/export/export_plugin.h +++ b/platform/linuxbsd/export/export_plugin.h @@ -32,21 +32,21 @@ #define LINUXBSD_EXPORT_PLUGIN_H #include "core/io/file_access.h" -#include "editor/editor_export.h" #include "editor/editor_settings.h" +#include "editor/export/editor_export_platform_pc.h" #include "platform/linuxbsd/logo.gen.h" #include "scene/resources/texture.h" class EditorExportPlatformLinuxBSD : public EditorExportPlatformPC { - HashMap<String, String> extensions; Error _export_debug_script(const Ref<EditorExportPreset> &p_preset, const String &p_app_name, const String &p_pkg_name, const String &p_path); public: void set_extension(const String &p_extension, const String &p_feature_key = "default"); virtual List<String> get_binary_extensions(const Ref<EditorExportPreset> &p_preset) const override; + virtual void get_export_options(List<ExportOption> *r_options) override; virtual Error export_project(const Ref<EditorExportPreset> &p_preset, bool p_debug, const String &p_path, int p_flags = 0) override; virtual String get_template_file_name(const String &p_target, const String &p_arch) const override; virtual Error fixup_embedded_pck(const String &p_path, int64_t p_embedded_start, int64_t p_embedded_size) override; }; -#endif +#endif // LINUXBSD_EXPORT_PLUGIN_H diff --git a/platform/linuxbsd/fontconfig-so_wrap.c b/platform/linuxbsd/fontconfig-so_wrap.c new file mode 100644 index 0000000000..1a915faf98 --- /dev/null +++ b/platform/linuxbsd/fontconfig-so_wrap.c @@ -0,0 +1,2091 @@ +// This file is generated. Do not edit! +// see https://github.com/hpvb/dynload-wrapper for details +// generated by ./generate-wrapper.py 0.3 on 2022-07-29 05:40:07 +// flags: ./generate-wrapper.py --include /usr/include/fontconfig/fontconfig.h --sys-include <fontconfig/fontconfig.h> --soname libfontconfig.so --init-name fontconfig --output-header fontconfig-so_wrap.h --output-implementation fontconfig-so_wrap.c --omit-prefix FcCharSet +// +#include <stdint.h> + +#define FcBlanksCreate FcBlanksCreate_dylibloader_orig_fontconfig +#define FcBlanksDestroy FcBlanksDestroy_dylibloader_orig_fontconfig +#define FcBlanksAdd FcBlanksAdd_dylibloader_orig_fontconfig +#define FcBlanksIsMember FcBlanksIsMember_dylibloader_orig_fontconfig +#define FcCacheDir FcCacheDir_dylibloader_orig_fontconfig +#define FcCacheCopySet FcCacheCopySet_dylibloader_orig_fontconfig +#define FcCacheSubdir FcCacheSubdir_dylibloader_orig_fontconfig +#define FcCacheNumSubdir FcCacheNumSubdir_dylibloader_orig_fontconfig +#define FcCacheNumFont FcCacheNumFont_dylibloader_orig_fontconfig +#define FcDirCacheUnlink FcDirCacheUnlink_dylibloader_orig_fontconfig +#define FcDirCacheValid FcDirCacheValid_dylibloader_orig_fontconfig +#define FcDirCacheClean FcDirCacheClean_dylibloader_orig_fontconfig +#define FcCacheCreateTagFile FcCacheCreateTagFile_dylibloader_orig_fontconfig +#define FcConfigHome FcConfigHome_dylibloader_orig_fontconfig +#define FcConfigEnableHome FcConfigEnableHome_dylibloader_orig_fontconfig +#define FcConfigFilename FcConfigFilename_dylibloader_orig_fontconfig +#define FcConfigCreate FcConfigCreate_dylibloader_orig_fontconfig +#define FcConfigReference FcConfigReference_dylibloader_orig_fontconfig +#define FcConfigDestroy FcConfigDestroy_dylibloader_orig_fontconfig +#define FcConfigSetCurrent FcConfigSetCurrent_dylibloader_orig_fontconfig +#define FcConfigGetCurrent FcConfigGetCurrent_dylibloader_orig_fontconfig +#define FcConfigUptoDate FcConfigUptoDate_dylibloader_orig_fontconfig +#define FcConfigBuildFonts FcConfigBuildFonts_dylibloader_orig_fontconfig +#define FcConfigGetFontDirs FcConfigGetFontDirs_dylibloader_orig_fontconfig +#define FcConfigGetConfigDirs FcConfigGetConfigDirs_dylibloader_orig_fontconfig +#define FcConfigGetConfigFiles FcConfigGetConfigFiles_dylibloader_orig_fontconfig +#define FcConfigGetCache FcConfigGetCache_dylibloader_orig_fontconfig +#define FcConfigGetBlanks FcConfigGetBlanks_dylibloader_orig_fontconfig +#define FcConfigGetCacheDirs FcConfigGetCacheDirs_dylibloader_orig_fontconfig +#define FcConfigGetRescanInterval FcConfigGetRescanInterval_dylibloader_orig_fontconfig +#define FcConfigSetRescanInterval FcConfigSetRescanInterval_dylibloader_orig_fontconfig +#define FcConfigGetFonts FcConfigGetFonts_dylibloader_orig_fontconfig +#define FcConfigAppFontAddFile FcConfigAppFontAddFile_dylibloader_orig_fontconfig +#define FcConfigAppFontAddDir FcConfigAppFontAddDir_dylibloader_orig_fontconfig +#define FcConfigAppFontClear FcConfigAppFontClear_dylibloader_orig_fontconfig +#define FcConfigSubstituteWithPat FcConfigSubstituteWithPat_dylibloader_orig_fontconfig +#define FcConfigSubstitute FcConfigSubstitute_dylibloader_orig_fontconfig +#define FcConfigGetSysRoot FcConfigGetSysRoot_dylibloader_orig_fontconfig +#define FcConfigSetSysRoot FcConfigSetSysRoot_dylibloader_orig_fontconfig +#define FcValuePrint FcValuePrint_dylibloader_orig_fontconfig +#define FcPatternPrint FcPatternPrint_dylibloader_orig_fontconfig +#define FcFontSetPrint FcFontSetPrint_dylibloader_orig_fontconfig +#define FcGetDefaultLangs FcGetDefaultLangs_dylibloader_orig_fontconfig +#define FcDefaultSubstitute FcDefaultSubstitute_dylibloader_orig_fontconfig +#define FcFileIsDir FcFileIsDir_dylibloader_orig_fontconfig +#define FcFileScan FcFileScan_dylibloader_orig_fontconfig +#define FcDirScan FcDirScan_dylibloader_orig_fontconfig +#define FcDirSave FcDirSave_dylibloader_orig_fontconfig +#define FcDirCacheLoad FcDirCacheLoad_dylibloader_orig_fontconfig +#define FcDirCacheRescan FcDirCacheRescan_dylibloader_orig_fontconfig +#define FcDirCacheRead FcDirCacheRead_dylibloader_orig_fontconfig +#define FcDirCacheLoadFile FcDirCacheLoadFile_dylibloader_orig_fontconfig +#define FcDirCacheUnload FcDirCacheUnload_dylibloader_orig_fontconfig +#define FcFreeTypeQuery FcFreeTypeQuery_dylibloader_orig_fontconfig +#define FcFontSetCreate FcFontSetCreate_dylibloader_orig_fontconfig +#define FcFontSetDestroy FcFontSetDestroy_dylibloader_orig_fontconfig +#define FcFontSetAdd FcFontSetAdd_dylibloader_orig_fontconfig +#define FcInitLoadConfig FcInitLoadConfig_dylibloader_orig_fontconfig +#define FcInitLoadConfigAndFonts FcInitLoadConfigAndFonts_dylibloader_orig_fontconfig +#define FcInit FcInit_dylibloader_orig_fontconfig +#define FcFini FcFini_dylibloader_orig_fontconfig +#define FcGetVersion FcGetVersion_dylibloader_orig_fontconfig +#define FcInitReinitialize FcInitReinitialize_dylibloader_orig_fontconfig +#define FcInitBringUptoDate FcInitBringUptoDate_dylibloader_orig_fontconfig +#define FcGetLangs FcGetLangs_dylibloader_orig_fontconfig +#define FcLangNormalize FcLangNormalize_dylibloader_orig_fontconfig +#define FcLangGetCharSet FcLangGetCharSet_dylibloader_orig_fontconfig +#define FcLangSetCreate FcLangSetCreate_dylibloader_orig_fontconfig +#define FcLangSetDestroy FcLangSetDestroy_dylibloader_orig_fontconfig +#define FcLangSetCopy FcLangSetCopy_dylibloader_orig_fontconfig +#define FcLangSetAdd FcLangSetAdd_dylibloader_orig_fontconfig +#define FcLangSetDel FcLangSetDel_dylibloader_orig_fontconfig +#define FcLangSetHasLang FcLangSetHasLang_dylibloader_orig_fontconfig +#define FcLangSetCompare FcLangSetCompare_dylibloader_orig_fontconfig +#define FcLangSetContains FcLangSetContains_dylibloader_orig_fontconfig +#define FcLangSetEqual FcLangSetEqual_dylibloader_orig_fontconfig +#define FcLangSetHash FcLangSetHash_dylibloader_orig_fontconfig +#define FcLangSetGetLangs FcLangSetGetLangs_dylibloader_orig_fontconfig +#define FcLangSetUnion FcLangSetUnion_dylibloader_orig_fontconfig +#define FcLangSetSubtract FcLangSetSubtract_dylibloader_orig_fontconfig +#define FcObjectSetCreate FcObjectSetCreate_dylibloader_orig_fontconfig +#define FcObjectSetAdd FcObjectSetAdd_dylibloader_orig_fontconfig +#define FcObjectSetDestroy FcObjectSetDestroy_dylibloader_orig_fontconfig +#define FcObjectSetVaBuild FcObjectSetVaBuild_dylibloader_orig_fontconfig +#define FcObjectSetBuild FcObjectSetBuild_dylibloader_orig_fontconfig +#define FcFontSetList FcFontSetList_dylibloader_orig_fontconfig +#define FcFontList FcFontList_dylibloader_orig_fontconfig +#define FcAtomicCreate FcAtomicCreate_dylibloader_orig_fontconfig +#define FcAtomicLock FcAtomicLock_dylibloader_orig_fontconfig +#define FcAtomicNewFile FcAtomicNewFile_dylibloader_orig_fontconfig +#define FcAtomicOrigFile FcAtomicOrigFile_dylibloader_orig_fontconfig +#define FcAtomicReplaceOrig FcAtomicReplaceOrig_dylibloader_orig_fontconfig +#define FcAtomicDeleteNew FcAtomicDeleteNew_dylibloader_orig_fontconfig +#define FcAtomicUnlock FcAtomicUnlock_dylibloader_orig_fontconfig +#define FcAtomicDestroy FcAtomicDestroy_dylibloader_orig_fontconfig +#define FcFontSetMatch FcFontSetMatch_dylibloader_orig_fontconfig +#define FcFontMatch FcFontMatch_dylibloader_orig_fontconfig +#define FcFontRenderPrepare FcFontRenderPrepare_dylibloader_orig_fontconfig +#define FcFontSetSort FcFontSetSort_dylibloader_orig_fontconfig +#define FcFontSort FcFontSort_dylibloader_orig_fontconfig +#define FcFontSetSortDestroy FcFontSetSortDestroy_dylibloader_orig_fontconfig +#define FcMatrixCopy FcMatrixCopy_dylibloader_orig_fontconfig +#define FcMatrixEqual FcMatrixEqual_dylibloader_orig_fontconfig +#define FcMatrixMultiply FcMatrixMultiply_dylibloader_orig_fontconfig +#define FcMatrixRotate FcMatrixRotate_dylibloader_orig_fontconfig +#define FcMatrixScale FcMatrixScale_dylibloader_orig_fontconfig +#define FcMatrixShear FcMatrixShear_dylibloader_orig_fontconfig +#define FcNameRegisterObjectTypes FcNameRegisterObjectTypes_dylibloader_orig_fontconfig +#define FcNameUnregisterObjectTypes FcNameUnregisterObjectTypes_dylibloader_orig_fontconfig +#define FcNameGetObjectType FcNameGetObjectType_dylibloader_orig_fontconfig +#define FcNameRegisterConstants FcNameRegisterConstants_dylibloader_orig_fontconfig +#define FcNameUnregisterConstants FcNameUnregisterConstants_dylibloader_orig_fontconfig +#define FcNameGetConstant FcNameGetConstant_dylibloader_orig_fontconfig +#define FcNameConstant FcNameConstant_dylibloader_orig_fontconfig +#define FcNameParse FcNameParse_dylibloader_orig_fontconfig +#define FcNameUnparse FcNameUnparse_dylibloader_orig_fontconfig +#define FcPatternCreate FcPatternCreate_dylibloader_orig_fontconfig +#define FcPatternDuplicate FcPatternDuplicate_dylibloader_orig_fontconfig +#define FcPatternReference FcPatternReference_dylibloader_orig_fontconfig +#define FcPatternFilter FcPatternFilter_dylibloader_orig_fontconfig +#define FcValueDestroy FcValueDestroy_dylibloader_orig_fontconfig +#define FcValueEqual FcValueEqual_dylibloader_orig_fontconfig +#define FcValueSave FcValueSave_dylibloader_orig_fontconfig +#define FcPatternDestroy FcPatternDestroy_dylibloader_orig_fontconfig +#define FcPatternEqual FcPatternEqual_dylibloader_orig_fontconfig +#define FcPatternEqualSubset FcPatternEqualSubset_dylibloader_orig_fontconfig +#define FcPatternHash FcPatternHash_dylibloader_orig_fontconfig +#define FcPatternAdd FcPatternAdd_dylibloader_orig_fontconfig +#define FcPatternAddWeak FcPatternAddWeak_dylibloader_orig_fontconfig +#define FcPatternGet FcPatternGet_dylibloader_orig_fontconfig +#define FcPatternGetWithBinding FcPatternGetWithBinding_dylibloader_orig_fontconfig +#define FcPatternDel FcPatternDel_dylibloader_orig_fontconfig +#define FcPatternRemove FcPatternRemove_dylibloader_orig_fontconfig +#define FcPatternAddInteger FcPatternAddInteger_dylibloader_orig_fontconfig +#define FcPatternAddDouble FcPatternAddDouble_dylibloader_orig_fontconfig +#define FcPatternAddString FcPatternAddString_dylibloader_orig_fontconfig +#define FcPatternAddMatrix FcPatternAddMatrix_dylibloader_orig_fontconfig +#define FcPatternAddCharSet FcPatternAddCharSet_dylibloader_orig_fontconfig +#define FcPatternAddBool FcPatternAddBool_dylibloader_orig_fontconfig +#define FcPatternAddLangSet FcPatternAddLangSet_dylibloader_orig_fontconfig +#define FcPatternAddRange FcPatternAddRange_dylibloader_orig_fontconfig +#define FcPatternGetInteger FcPatternGetInteger_dylibloader_orig_fontconfig +#define FcPatternGetDouble FcPatternGetDouble_dylibloader_orig_fontconfig +#define FcPatternGetString FcPatternGetString_dylibloader_orig_fontconfig +#define FcPatternGetMatrix FcPatternGetMatrix_dylibloader_orig_fontconfig +#define FcPatternGetCharSet FcPatternGetCharSet_dylibloader_orig_fontconfig +#define FcPatternGetBool FcPatternGetBool_dylibloader_orig_fontconfig +#define FcPatternGetLangSet FcPatternGetLangSet_dylibloader_orig_fontconfig +#define FcPatternGetRange FcPatternGetRange_dylibloader_orig_fontconfig +#define FcPatternVaBuild FcPatternVaBuild_dylibloader_orig_fontconfig +#define FcPatternBuild FcPatternBuild_dylibloader_orig_fontconfig +#define FcPatternFormat FcPatternFormat_dylibloader_orig_fontconfig +#define FcRangeCreateDouble FcRangeCreateDouble_dylibloader_orig_fontconfig +#define FcRangeCreateInteger FcRangeCreateInteger_dylibloader_orig_fontconfig +#define FcRangeDestroy FcRangeDestroy_dylibloader_orig_fontconfig +#define FcRangeCopy FcRangeCopy_dylibloader_orig_fontconfig +#define FcRangeGetDouble FcRangeGetDouble_dylibloader_orig_fontconfig +#define FcWeightFromOpenType FcWeightFromOpenType_dylibloader_orig_fontconfig +#define FcWeightToOpenType FcWeightToOpenType_dylibloader_orig_fontconfig +#define FcStrCopy FcStrCopy_dylibloader_orig_fontconfig +#define FcStrCopyFilename FcStrCopyFilename_dylibloader_orig_fontconfig +#define FcStrPlus FcStrPlus_dylibloader_orig_fontconfig +#define FcStrFree FcStrFree_dylibloader_orig_fontconfig +#define FcStrDowncase FcStrDowncase_dylibloader_orig_fontconfig +#define FcStrCmpIgnoreCase FcStrCmpIgnoreCase_dylibloader_orig_fontconfig +#define FcStrCmp FcStrCmp_dylibloader_orig_fontconfig +#define FcStrStrIgnoreCase FcStrStrIgnoreCase_dylibloader_orig_fontconfig +#define FcStrStr FcStrStr_dylibloader_orig_fontconfig +#define FcUtf8ToUcs4 FcUtf8ToUcs4_dylibloader_orig_fontconfig +#define FcUtf8Len FcUtf8Len_dylibloader_orig_fontconfig +#define FcUcs4ToUtf8 FcUcs4ToUtf8_dylibloader_orig_fontconfig +#define FcUtf16ToUcs4 FcUtf16ToUcs4_dylibloader_orig_fontconfig +#define FcUtf16Len FcUtf16Len_dylibloader_orig_fontconfig +#define FcStrDirname FcStrDirname_dylibloader_orig_fontconfig +#define FcStrBasename FcStrBasename_dylibloader_orig_fontconfig +#define FcStrSetCreate FcStrSetCreate_dylibloader_orig_fontconfig +#define FcStrSetMember FcStrSetMember_dylibloader_orig_fontconfig +#define FcStrSetEqual FcStrSetEqual_dylibloader_orig_fontconfig +#define FcStrSetAdd FcStrSetAdd_dylibloader_orig_fontconfig +#define FcStrSetAddFilename FcStrSetAddFilename_dylibloader_orig_fontconfig +#define FcStrSetDel FcStrSetDel_dylibloader_orig_fontconfig +#define FcStrSetDestroy FcStrSetDestroy_dylibloader_orig_fontconfig +#define FcStrListCreate FcStrListCreate_dylibloader_orig_fontconfig +#define FcStrListFirst FcStrListFirst_dylibloader_orig_fontconfig +#define FcStrListNext FcStrListNext_dylibloader_orig_fontconfig +#define FcStrListDone FcStrListDone_dylibloader_orig_fontconfig +#define FcConfigParseAndLoad FcConfigParseAndLoad_dylibloader_orig_fontconfig +#define FcConfigParseAndLoadFromMemory FcConfigParseAndLoadFromMemory_dylibloader_orig_fontconfig +#include <fontconfig/fontconfig.h> +#undef FcBlanksCreate +#undef FcBlanksDestroy +#undef FcBlanksAdd +#undef FcBlanksIsMember +#undef FcCacheDir +#undef FcCacheCopySet +#undef FcCacheSubdir +#undef FcCacheNumSubdir +#undef FcCacheNumFont +#undef FcDirCacheUnlink +#undef FcDirCacheValid +#undef FcDirCacheClean +#undef FcCacheCreateTagFile +#undef FcConfigHome +#undef FcConfigEnableHome +#undef FcConfigFilename +#undef FcConfigCreate +#undef FcConfigReference +#undef FcConfigDestroy +#undef FcConfigSetCurrent +#undef FcConfigGetCurrent +#undef FcConfigUptoDate +#undef FcConfigBuildFonts +#undef FcConfigGetFontDirs +#undef FcConfigGetConfigDirs +#undef FcConfigGetConfigFiles +#undef FcConfigGetCache +#undef FcConfigGetBlanks +#undef FcConfigGetCacheDirs +#undef FcConfigGetRescanInterval +#undef FcConfigSetRescanInterval +#undef FcConfigGetFonts +#undef FcConfigAppFontAddFile +#undef FcConfigAppFontAddDir +#undef FcConfigAppFontClear +#undef FcConfigSubstituteWithPat +#undef FcConfigSubstitute +#undef FcConfigGetSysRoot +#undef FcConfigSetSysRoot +#undef FcValuePrint +#undef FcPatternPrint +#undef FcFontSetPrint +#undef FcGetDefaultLangs +#undef FcDefaultSubstitute +#undef FcFileIsDir +#undef FcFileScan +#undef FcDirScan +#undef FcDirSave +#undef FcDirCacheLoad +#undef FcDirCacheRescan +#undef FcDirCacheRead +#undef FcDirCacheLoadFile +#undef FcDirCacheUnload +#undef FcFreeTypeQuery +#undef FcFontSetCreate +#undef FcFontSetDestroy +#undef FcFontSetAdd +#undef FcInitLoadConfig +#undef FcInitLoadConfigAndFonts +#undef FcInit +#undef FcFini +#undef FcGetVersion +#undef FcInitReinitialize +#undef FcInitBringUptoDate +#undef FcGetLangs +#undef FcLangNormalize +#undef FcLangGetCharSet +#undef FcLangSetCreate +#undef FcLangSetDestroy +#undef FcLangSetCopy +#undef FcLangSetAdd +#undef FcLangSetDel +#undef FcLangSetHasLang +#undef FcLangSetCompare +#undef FcLangSetContains +#undef FcLangSetEqual +#undef FcLangSetHash +#undef FcLangSetGetLangs +#undef FcLangSetUnion +#undef FcLangSetSubtract +#undef FcObjectSetCreate +#undef FcObjectSetAdd +#undef FcObjectSetDestroy +#undef FcObjectSetVaBuild +#undef FcObjectSetBuild +#undef FcFontSetList +#undef FcFontList +#undef FcAtomicCreate +#undef FcAtomicLock +#undef FcAtomicNewFile +#undef FcAtomicOrigFile +#undef FcAtomicReplaceOrig +#undef FcAtomicDeleteNew +#undef FcAtomicUnlock +#undef FcAtomicDestroy +#undef FcFontSetMatch +#undef FcFontMatch +#undef FcFontRenderPrepare +#undef FcFontSetSort +#undef FcFontSort +#undef FcFontSetSortDestroy +#undef FcMatrixCopy +#undef FcMatrixEqual +#undef FcMatrixMultiply +#undef FcMatrixRotate +#undef FcMatrixScale +#undef FcMatrixShear +#undef FcNameRegisterObjectTypes +#undef FcNameUnregisterObjectTypes +#undef FcNameGetObjectType +#undef FcNameRegisterConstants +#undef FcNameUnregisterConstants +#undef FcNameGetConstant +#undef FcNameConstant +#undef FcNameParse +#undef FcNameUnparse +#undef FcPatternCreate +#undef FcPatternDuplicate +#undef FcPatternReference +#undef FcPatternFilter +#undef FcValueDestroy +#undef FcValueEqual +#undef FcValueSave +#undef FcPatternDestroy +#undef FcPatternEqual +#undef FcPatternEqualSubset +#undef FcPatternHash +#undef FcPatternAdd +#undef FcPatternAddWeak +#undef FcPatternGet +#undef FcPatternGetWithBinding +#undef FcPatternDel +#undef FcPatternRemove +#undef FcPatternAddInteger +#undef FcPatternAddDouble +#undef FcPatternAddString +#undef FcPatternAddMatrix +#undef FcPatternAddCharSet +#undef FcPatternAddBool +#undef FcPatternAddLangSet +#undef FcPatternAddRange +#undef FcPatternGetInteger +#undef FcPatternGetDouble +#undef FcPatternGetString +#undef FcPatternGetMatrix +#undef FcPatternGetCharSet +#undef FcPatternGetBool +#undef FcPatternGetLangSet +#undef FcPatternGetRange +#undef FcPatternVaBuild +#undef FcPatternBuild +#undef FcPatternFormat +#undef FcRangeCreateDouble +#undef FcRangeCreateInteger +#undef FcRangeDestroy +#undef FcRangeCopy +#undef FcRangeGetDouble +#undef FcWeightFromOpenType +#undef FcWeightToOpenType +#undef FcStrCopy +#undef FcStrCopyFilename +#undef FcStrPlus +#undef FcStrFree +#undef FcStrDowncase +#undef FcStrCmpIgnoreCase +#undef FcStrCmp +#undef FcStrStrIgnoreCase +#undef FcStrStr +#undef FcUtf8ToUcs4 +#undef FcUtf8Len +#undef FcUcs4ToUtf8 +#undef FcUtf16ToUcs4 +#undef FcUtf16Len +#undef FcStrDirname +#undef FcStrBasename +#undef FcStrSetCreate +#undef FcStrSetMember +#undef FcStrSetEqual +#undef FcStrSetAdd +#undef FcStrSetAddFilename +#undef FcStrSetDel +#undef FcStrSetDestroy +#undef FcStrListCreate +#undef FcStrListFirst +#undef FcStrListNext +#undef FcStrListDone +#undef FcConfigParseAndLoad +#undef FcConfigParseAndLoadFromMemory +#include <dlfcn.h> +#include <stdio.h> +FcBlanks* (*FcBlanksCreate_dylibloader_wrapper_fontconfig)( void); +void (*FcBlanksDestroy_dylibloader_wrapper_fontconfig)( FcBlanks*); +FcBool (*FcBlanksAdd_dylibloader_wrapper_fontconfig)( FcBlanks*, FcChar32); +FcBool (*FcBlanksIsMember_dylibloader_wrapper_fontconfig)( FcBlanks*, FcChar32); +const FcChar8* (*FcCacheDir_dylibloader_wrapper_fontconfig)(const FcCache*); +FcFontSet* (*FcCacheCopySet_dylibloader_wrapper_fontconfig)(const FcCache*); +const FcChar8* (*FcCacheSubdir_dylibloader_wrapper_fontconfig)(const FcCache*, int); +int (*FcCacheNumSubdir_dylibloader_wrapper_fontconfig)(const FcCache*); +int (*FcCacheNumFont_dylibloader_wrapper_fontconfig)(const FcCache*); +FcBool (*FcDirCacheUnlink_dylibloader_wrapper_fontconfig)(const FcChar8*, FcConfig*); +FcBool (*FcDirCacheValid_dylibloader_wrapper_fontconfig)(const FcChar8*); +FcBool (*FcDirCacheClean_dylibloader_wrapper_fontconfig)(const FcChar8*, FcBool); +void (*FcCacheCreateTagFile_dylibloader_wrapper_fontconfig)(const FcConfig*); +FcChar8* (*FcConfigHome_dylibloader_wrapper_fontconfig)( void); +FcBool (*FcConfigEnableHome_dylibloader_wrapper_fontconfig)( FcBool); +FcChar8* (*FcConfigFilename_dylibloader_wrapper_fontconfig)(const FcChar8*); +FcConfig* (*FcConfigCreate_dylibloader_wrapper_fontconfig)( void); +FcConfig* (*FcConfigReference_dylibloader_wrapper_fontconfig)( FcConfig*); +void (*FcConfigDestroy_dylibloader_wrapper_fontconfig)( FcConfig*); +FcBool (*FcConfigSetCurrent_dylibloader_wrapper_fontconfig)( FcConfig*); +FcConfig* (*FcConfigGetCurrent_dylibloader_wrapper_fontconfig)( void); +FcBool (*FcConfigUptoDate_dylibloader_wrapper_fontconfig)( FcConfig*); +FcBool (*FcConfigBuildFonts_dylibloader_wrapper_fontconfig)( FcConfig*); +FcStrList* (*FcConfigGetFontDirs_dylibloader_wrapper_fontconfig)( FcConfig*); +FcStrList* (*FcConfigGetConfigDirs_dylibloader_wrapper_fontconfig)( FcConfig*); +FcStrList* (*FcConfigGetConfigFiles_dylibloader_wrapper_fontconfig)( FcConfig*); +FcChar8* (*FcConfigGetCache_dylibloader_wrapper_fontconfig)( FcConfig*); +FcBlanks* (*FcConfigGetBlanks_dylibloader_wrapper_fontconfig)( FcConfig*); +FcStrList* (*FcConfigGetCacheDirs_dylibloader_wrapper_fontconfig)(const FcConfig*); +int (*FcConfigGetRescanInterval_dylibloader_wrapper_fontconfig)( FcConfig*); +FcBool (*FcConfigSetRescanInterval_dylibloader_wrapper_fontconfig)( FcConfig*, int); +FcFontSet* (*FcConfigGetFonts_dylibloader_wrapper_fontconfig)( FcConfig*, FcSetName); +FcBool (*FcConfigAppFontAddFile_dylibloader_wrapper_fontconfig)( FcConfig*,const FcChar8*); +FcBool (*FcConfigAppFontAddDir_dylibloader_wrapper_fontconfig)( FcConfig*,const FcChar8*); +void (*FcConfigAppFontClear_dylibloader_wrapper_fontconfig)( FcConfig*); +FcBool (*FcConfigSubstituteWithPat_dylibloader_wrapper_fontconfig)( FcConfig*, FcPattern*, FcPattern*, FcMatchKind); +FcBool (*FcConfigSubstitute_dylibloader_wrapper_fontconfig)( FcConfig*, FcPattern*, FcMatchKind); +const FcChar8* (*FcConfigGetSysRoot_dylibloader_wrapper_fontconfig)(const FcConfig*); +void (*FcConfigSetSysRoot_dylibloader_wrapper_fontconfig)( FcConfig*,const FcChar8*); +void (*FcValuePrint_dylibloader_wrapper_fontconfig)(const FcValue); +void (*FcPatternPrint_dylibloader_wrapper_fontconfig)(const FcPattern*); +void (*FcFontSetPrint_dylibloader_wrapper_fontconfig)(const FcFontSet*); +FcStrSet* (*FcGetDefaultLangs_dylibloader_wrapper_fontconfig)( void); +void (*FcDefaultSubstitute_dylibloader_wrapper_fontconfig)( FcPattern*); +FcBool (*FcFileIsDir_dylibloader_wrapper_fontconfig)(const FcChar8*); +FcBool (*FcFileScan_dylibloader_wrapper_fontconfig)( FcFontSet*, FcStrSet*, FcFileCache*, FcBlanks*,const FcChar8*, FcBool); +FcBool (*FcDirScan_dylibloader_wrapper_fontconfig)( FcFontSet*, FcStrSet*, FcFileCache*, FcBlanks*,const FcChar8*, FcBool); +FcBool (*FcDirSave_dylibloader_wrapper_fontconfig)( FcFontSet*, FcStrSet*,const FcChar8*); +FcCache* (*FcDirCacheLoad_dylibloader_wrapper_fontconfig)(const FcChar8*, FcConfig*, FcChar8**); +FcCache* (*FcDirCacheRescan_dylibloader_wrapper_fontconfig)(const FcChar8*, FcConfig*); +FcCache* (*FcDirCacheRead_dylibloader_wrapper_fontconfig)(const FcChar8*, FcBool, FcConfig*); +FcCache* (*FcDirCacheLoadFile_dylibloader_wrapper_fontconfig)(const FcChar8*,struct stat*); +void (*FcDirCacheUnload_dylibloader_wrapper_fontconfig)( FcCache*); +FcPattern* (*FcFreeTypeQuery_dylibloader_wrapper_fontconfig)(const FcChar8*, int, FcBlanks*, int*); +FcFontSet* (*FcFontSetCreate_dylibloader_wrapper_fontconfig)( void); +void (*FcFontSetDestroy_dylibloader_wrapper_fontconfig)( FcFontSet*); +FcBool (*FcFontSetAdd_dylibloader_wrapper_fontconfig)( FcFontSet*, FcPattern*); +FcConfig* (*FcInitLoadConfig_dylibloader_wrapper_fontconfig)( void); +FcConfig* (*FcInitLoadConfigAndFonts_dylibloader_wrapper_fontconfig)( void); +FcBool (*FcInit_dylibloader_wrapper_fontconfig)( void); +void (*FcFini_dylibloader_wrapper_fontconfig)( void); +int (*FcGetVersion_dylibloader_wrapper_fontconfig)( void); +FcBool (*FcInitReinitialize_dylibloader_wrapper_fontconfig)( void); +FcBool (*FcInitBringUptoDate_dylibloader_wrapper_fontconfig)( void); +FcStrSet* (*FcGetLangs_dylibloader_wrapper_fontconfig)( void); +FcChar8* (*FcLangNormalize_dylibloader_wrapper_fontconfig)(const FcChar8*); +const FcCharSet* (*FcLangGetCharSet_dylibloader_wrapper_fontconfig)(const FcChar8*); +FcLangSet* (*FcLangSetCreate_dylibloader_wrapper_fontconfig)( void); +void (*FcLangSetDestroy_dylibloader_wrapper_fontconfig)( FcLangSet*); +FcLangSet* (*FcLangSetCopy_dylibloader_wrapper_fontconfig)(const FcLangSet*); +FcBool (*FcLangSetAdd_dylibloader_wrapper_fontconfig)( FcLangSet*,const FcChar8*); +FcBool (*FcLangSetDel_dylibloader_wrapper_fontconfig)( FcLangSet*,const FcChar8*); +FcLangResult (*FcLangSetHasLang_dylibloader_wrapper_fontconfig)(const FcLangSet*,const FcChar8*); +FcLangResult (*FcLangSetCompare_dylibloader_wrapper_fontconfig)(const FcLangSet*,const FcLangSet*); +FcBool (*FcLangSetContains_dylibloader_wrapper_fontconfig)(const FcLangSet*,const FcLangSet*); +FcBool (*FcLangSetEqual_dylibloader_wrapper_fontconfig)(const FcLangSet*,const FcLangSet*); +FcChar32 (*FcLangSetHash_dylibloader_wrapper_fontconfig)(const FcLangSet*); +FcStrSet* (*FcLangSetGetLangs_dylibloader_wrapper_fontconfig)(const FcLangSet*); +FcLangSet* (*FcLangSetUnion_dylibloader_wrapper_fontconfig)(const FcLangSet*,const FcLangSet*); +FcLangSet* (*FcLangSetSubtract_dylibloader_wrapper_fontconfig)(const FcLangSet*,const FcLangSet*); +FcObjectSet* (*FcObjectSetCreate_dylibloader_wrapper_fontconfig)( void); +FcBool (*FcObjectSetAdd_dylibloader_wrapper_fontconfig)( FcObjectSet*,const char*); +void (*FcObjectSetDestroy_dylibloader_wrapper_fontconfig)( FcObjectSet*); +FcObjectSet* (*FcObjectSetVaBuild_dylibloader_wrapper_fontconfig)(const char*, va_list); +FcObjectSet* (*FcObjectSetBuild_dylibloader_wrapper_fontconfig)(const char*,...); +FcFontSet* (*FcFontSetList_dylibloader_wrapper_fontconfig)( FcConfig*, FcFontSet**, int, FcPattern*, FcObjectSet*); +FcFontSet* (*FcFontList_dylibloader_wrapper_fontconfig)( FcConfig*, FcPattern*, FcObjectSet*); +FcAtomic* (*FcAtomicCreate_dylibloader_wrapper_fontconfig)(const FcChar8*); +FcBool (*FcAtomicLock_dylibloader_wrapper_fontconfig)( FcAtomic*); +FcChar8* (*FcAtomicNewFile_dylibloader_wrapper_fontconfig)( FcAtomic*); +FcChar8* (*FcAtomicOrigFile_dylibloader_wrapper_fontconfig)( FcAtomic*); +FcBool (*FcAtomicReplaceOrig_dylibloader_wrapper_fontconfig)( FcAtomic*); +void (*FcAtomicDeleteNew_dylibloader_wrapper_fontconfig)( FcAtomic*); +void (*FcAtomicUnlock_dylibloader_wrapper_fontconfig)( FcAtomic*); +void (*FcAtomicDestroy_dylibloader_wrapper_fontconfig)( FcAtomic*); +FcPattern* (*FcFontSetMatch_dylibloader_wrapper_fontconfig)( FcConfig*, FcFontSet**, int, FcPattern*, FcResult*); +FcPattern* (*FcFontMatch_dylibloader_wrapper_fontconfig)( FcConfig*, FcPattern*, FcResult*); +FcPattern* (*FcFontRenderPrepare_dylibloader_wrapper_fontconfig)( FcConfig*, FcPattern*, FcPattern*); +FcFontSet* (*FcFontSetSort_dylibloader_wrapper_fontconfig)( FcConfig*, FcFontSet**, int, FcPattern*, FcBool, FcCharSet**, FcResult*); +FcFontSet* (*FcFontSort_dylibloader_wrapper_fontconfig)( FcConfig*, FcPattern*, FcBool, FcCharSet**, FcResult*); +void (*FcFontSetSortDestroy_dylibloader_wrapper_fontconfig)( FcFontSet*); +FcMatrix* (*FcMatrixCopy_dylibloader_wrapper_fontconfig)(const FcMatrix*); +FcBool (*FcMatrixEqual_dylibloader_wrapper_fontconfig)(const FcMatrix*,const FcMatrix*); +void (*FcMatrixMultiply_dylibloader_wrapper_fontconfig)( FcMatrix*,const FcMatrix*,const FcMatrix*); +void (*FcMatrixRotate_dylibloader_wrapper_fontconfig)( FcMatrix*, double, double); +void (*FcMatrixScale_dylibloader_wrapper_fontconfig)( FcMatrix*, double, double); +void (*FcMatrixShear_dylibloader_wrapper_fontconfig)( FcMatrix*, double, double); +FcBool (*FcNameRegisterObjectTypes_dylibloader_wrapper_fontconfig)(const FcObjectType*, int); +FcBool (*FcNameUnregisterObjectTypes_dylibloader_wrapper_fontconfig)(const FcObjectType*, int); +const FcObjectType* (*FcNameGetObjectType_dylibloader_wrapper_fontconfig)(const char*); +FcBool (*FcNameRegisterConstants_dylibloader_wrapper_fontconfig)(const FcConstant*, int); +FcBool (*FcNameUnregisterConstants_dylibloader_wrapper_fontconfig)(const FcConstant*, int); +const FcConstant* (*FcNameGetConstant_dylibloader_wrapper_fontconfig)(const FcChar8*); +FcBool (*FcNameConstant_dylibloader_wrapper_fontconfig)(const FcChar8*, int*); +FcPattern* (*FcNameParse_dylibloader_wrapper_fontconfig)(const FcChar8*); +FcChar8* (*FcNameUnparse_dylibloader_wrapper_fontconfig)( FcPattern*); +FcPattern* (*FcPatternCreate_dylibloader_wrapper_fontconfig)( void); +FcPattern* (*FcPatternDuplicate_dylibloader_wrapper_fontconfig)(const FcPattern*); +void (*FcPatternReference_dylibloader_wrapper_fontconfig)( FcPattern*); +FcPattern* (*FcPatternFilter_dylibloader_wrapper_fontconfig)( FcPattern*,const FcObjectSet*); +void (*FcValueDestroy_dylibloader_wrapper_fontconfig)( FcValue); +FcBool (*FcValueEqual_dylibloader_wrapper_fontconfig)( FcValue, FcValue); +FcValue (*FcValueSave_dylibloader_wrapper_fontconfig)( FcValue); +void (*FcPatternDestroy_dylibloader_wrapper_fontconfig)( FcPattern*); +FcBool (*FcPatternEqual_dylibloader_wrapper_fontconfig)(const FcPattern*,const FcPattern*); +FcBool (*FcPatternEqualSubset_dylibloader_wrapper_fontconfig)(const FcPattern*,const FcPattern*,const FcObjectSet*); +FcChar32 (*FcPatternHash_dylibloader_wrapper_fontconfig)(const FcPattern*); +FcBool (*FcPatternAdd_dylibloader_wrapper_fontconfig)( FcPattern*,const char*, FcValue, FcBool); +FcBool (*FcPatternAddWeak_dylibloader_wrapper_fontconfig)( FcPattern*,const char*, FcValue, FcBool); +FcResult (*FcPatternGet_dylibloader_wrapper_fontconfig)(const FcPattern*,const char*, int, FcValue*); +FcResult (*FcPatternGetWithBinding_dylibloader_wrapper_fontconfig)(const FcPattern*,const char*, int, FcValue*, FcValueBinding*); +FcBool (*FcPatternDel_dylibloader_wrapper_fontconfig)( FcPattern*,const char*); +FcBool (*FcPatternRemove_dylibloader_wrapper_fontconfig)( FcPattern*,const char*, int); +FcBool (*FcPatternAddInteger_dylibloader_wrapper_fontconfig)( FcPattern*,const char*, int); +FcBool (*FcPatternAddDouble_dylibloader_wrapper_fontconfig)( FcPattern*,const char*, double); +FcBool (*FcPatternAddString_dylibloader_wrapper_fontconfig)( FcPattern*,const char*,const FcChar8*); +FcBool (*FcPatternAddMatrix_dylibloader_wrapper_fontconfig)( FcPattern*,const char*,const FcMatrix*); +FcBool (*FcPatternAddCharSet_dylibloader_wrapper_fontconfig)( FcPattern*,const char*,const FcCharSet*); +FcBool (*FcPatternAddBool_dylibloader_wrapper_fontconfig)( FcPattern*,const char*, FcBool); +FcBool (*FcPatternAddLangSet_dylibloader_wrapper_fontconfig)( FcPattern*,const char*,const FcLangSet*); +FcBool (*FcPatternAddRange_dylibloader_wrapper_fontconfig)( FcPattern*,const char*,const FcRange*); +FcResult (*FcPatternGetInteger_dylibloader_wrapper_fontconfig)(const FcPattern*,const char*, int, int*); +FcResult (*FcPatternGetDouble_dylibloader_wrapper_fontconfig)(const FcPattern*,const char*, int, double*); +FcResult (*FcPatternGetString_dylibloader_wrapper_fontconfig)(const FcPattern*,const char*, int, FcChar8**); +FcResult (*FcPatternGetMatrix_dylibloader_wrapper_fontconfig)(const FcPattern*,const char*, int, FcMatrix**); +FcResult (*FcPatternGetCharSet_dylibloader_wrapper_fontconfig)(const FcPattern*,const char*, int, FcCharSet**); +FcResult (*FcPatternGetBool_dylibloader_wrapper_fontconfig)(const FcPattern*,const char*, int, FcBool*); +FcResult (*FcPatternGetLangSet_dylibloader_wrapper_fontconfig)(const FcPattern*,const char*, int, FcLangSet**); +FcResult (*FcPatternGetRange_dylibloader_wrapper_fontconfig)(const FcPattern*,const char*, int, FcRange**); +FcPattern* (*FcPatternVaBuild_dylibloader_wrapper_fontconfig)( FcPattern*, va_list); +FcPattern* (*FcPatternBuild_dylibloader_wrapper_fontconfig)( FcPattern*,...); +FcChar8* (*FcPatternFormat_dylibloader_wrapper_fontconfig)( FcPattern*,const FcChar8*); +FcRange* (*FcRangeCreateDouble_dylibloader_wrapper_fontconfig)( double, double); +FcRange* (*FcRangeCreateInteger_dylibloader_wrapper_fontconfig)( FcChar32, FcChar32); +void (*FcRangeDestroy_dylibloader_wrapper_fontconfig)( FcRange*); +FcRange* (*FcRangeCopy_dylibloader_wrapper_fontconfig)(const FcRange*); +FcBool (*FcRangeGetDouble_dylibloader_wrapper_fontconfig)(const FcRange*, double*, double*); +int (*FcWeightFromOpenType_dylibloader_wrapper_fontconfig)( int); +int (*FcWeightToOpenType_dylibloader_wrapper_fontconfig)( int); +FcChar8* (*FcStrCopy_dylibloader_wrapper_fontconfig)(const FcChar8*); +FcChar8* (*FcStrCopyFilename_dylibloader_wrapper_fontconfig)(const FcChar8*); +FcChar8* (*FcStrPlus_dylibloader_wrapper_fontconfig)(const FcChar8*,const FcChar8*); +void (*FcStrFree_dylibloader_wrapper_fontconfig)( FcChar8*); +FcChar8* (*FcStrDowncase_dylibloader_wrapper_fontconfig)(const FcChar8*); +int (*FcStrCmpIgnoreCase_dylibloader_wrapper_fontconfig)(const FcChar8*,const FcChar8*); +int (*FcStrCmp_dylibloader_wrapper_fontconfig)(const FcChar8*,const FcChar8*); +const FcChar8* (*FcStrStrIgnoreCase_dylibloader_wrapper_fontconfig)(const FcChar8*,const FcChar8*); +const FcChar8* (*FcStrStr_dylibloader_wrapper_fontconfig)(const FcChar8*,const FcChar8*); +int (*FcUtf8ToUcs4_dylibloader_wrapper_fontconfig)(const FcChar8*, FcChar32*, int); +FcBool (*FcUtf8Len_dylibloader_wrapper_fontconfig)(const FcChar8*, int, int*, int*); +int (*FcUcs4ToUtf8_dylibloader_wrapper_fontconfig)( FcChar32, FcChar8 [6]); +int (*FcUtf16ToUcs4_dylibloader_wrapper_fontconfig)(const FcChar8*, FcEndian, FcChar32*, int); +FcBool (*FcUtf16Len_dylibloader_wrapper_fontconfig)(const FcChar8*, FcEndian, int, int*, int*); +FcChar8* (*FcStrDirname_dylibloader_wrapper_fontconfig)(const FcChar8*); +FcChar8* (*FcStrBasename_dylibloader_wrapper_fontconfig)(const FcChar8*); +FcStrSet* (*FcStrSetCreate_dylibloader_wrapper_fontconfig)( void); +FcBool (*FcStrSetMember_dylibloader_wrapper_fontconfig)( FcStrSet*,const FcChar8*); +FcBool (*FcStrSetEqual_dylibloader_wrapper_fontconfig)( FcStrSet*, FcStrSet*); +FcBool (*FcStrSetAdd_dylibloader_wrapper_fontconfig)( FcStrSet*,const FcChar8*); +FcBool (*FcStrSetAddFilename_dylibloader_wrapper_fontconfig)( FcStrSet*,const FcChar8*); +FcBool (*FcStrSetDel_dylibloader_wrapper_fontconfig)( FcStrSet*,const FcChar8*); +void (*FcStrSetDestroy_dylibloader_wrapper_fontconfig)( FcStrSet*); +FcStrList* (*FcStrListCreate_dylibloader_wrapper_fontconfig)( FcStrSet*); +void (*FcStrListFirst_dylibloader_wrapper_fontconfig)( FcStrList*); +FcChar8* (*FcStrListNext_dylibloader_wrapper_fontconfig)( FcStrList*); +void (*FcStrListDone_dylibloader_wrapper_fontconfig)( FcStrList*); +FcBool (*FcConfigParseAndLoad_dylibloader_wrapper_fontconfig)( FcConfig*,const FcChar8*, FcBool); +FcBool (*FcConfigParseAndLoadFromMemory_dylibloader_wrapper_fontconfig)( FcConfig*,const FcChar8*, FcBool); +int initialize_fontconfig(int verbose) { + void *handle; + char *error; + handle = dlopen("libfontconfig.so", RTLD_LAZY); + if (!handle) { + if (verbose) { + fprintf(stderr, "%s\n", dlerror()); + } + return(1); + } + dlerror(); +// FcBlanksCreate + *(void **) (&FcBlanksCreate_dylibloader_wrapper_fontconfig) = dlsym(handle, "FcBlanksCreate"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// FcBlanksDestroy + *(void **) (&FcBlanksDestroy_dylibloader_wrapper_fontconfig) = dlsym(handle, "FcBlanksDestroy"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// FcBlanksAdd + *(void **) (&FcBlanksAdd_dylibloader_wrapper_fontconfig) = dlsym(handle, "FcBlanksAdd"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// FcBlanksIsMember + *(void **) (&FcBlanksIsMember_dylibloader_wrapper_fontconfig) = dlsym(handle, "FcBlanksIsMember"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// FcCacheDir + *(void **) (&FcCacheDir_dylibloader_wrapper_fontconfig) = dlsym(handle, "FcCacheDir"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// FcCacheCopySet + *(void **) (&FcCacheCopySet_dylibloader_wrapper_fontconfig) = dlsym(handle, "FcCacheCopySet"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// FcCacheSubdir + *(void **) (&FcCacheSubdir_dylibloader_wrapper_fontconfig) = dlsym(handle, "FcCacheSubdir"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// FcCacheNumSubdir + *(void **) (&FcCacheNumSubdir_dylibloader_wrapper_fontconfig) = dlsym(handle, "FcCacheNumSubdir"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// FcCacheNumFont + *(void **) (&FcCacheNumFont_dylibloader_wrapper_fontconfig) = dlsym(handle, "FcCacheNumFont"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// FcDirCacheUnlink + *(void **) (&FcDirCacheUnlink_dylibloader_wrapper_fontconfig) = dlsym(handle, "FcDirCacheUnlink"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// FcDirCacheValid + *(void **) (&FcDirCacheValid_dylibloader_wrapper_fontconfig) = dlsym(handle, "FcDirCacheValid"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// FcDirCacheClean + *(void **) (&FcDirCacheClean_dylibloader_wrapper_fontconfig) = dlsym(handle, "FcDirCacheClean"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// FcCacheCreateTagFile + *(void **) (&FcCacheCreateTagFile_dylibloader_wrapper_fontconfig) = dlsym(handle, "FcCacheCreateTagFile"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// FcConfigHome + *(void **) (&FcConfigHome_dylibloader_wrapper_fontconfig) = dlsym(handle, "FcConfigHome"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// FcConfigEnableHome + *(void **) (&FcConfigEnableHome_dylibloader_wrapper_fontconfig) = dlsym(handle, "FcConfigEnableHome"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// FcConfigFilename + *(void **) (&FcConfigFilename_dylibloader_wrapper_fontconfig) = dlsym(handle, "FcConfigFilename"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// FcConfigCreate + *(void **) (&FcConfigCreate_dylibloader_wrapper_fontconfig) = dlsym(handle, "FcConfigCreate"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// FcConfigReference + *(void **) (&FcConfigReference_dylibloader_wrapper_fontconfig) = dlsym(handle, "FcConfigReference"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// FcConfigDestroy + *(void **) (&FcConfigDestroy_dylibloader_wrapper_fontconfig) = dlsym(handle, "FcConfigDestroy"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// FcConfigSetCurrent + *(void **) (&FcConfigSetCurrent_dylibloader_wrapper_fontconfig) = dlsym(handle, "FcConfigSetCurrent"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// FcConfigGetCurrent + *(void **) (&FcConfigGetCurrent_dylibloader_wrapper_fontconfig) = dlsym(handle, "FcConfigGetCurrent"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// FcConfigUptoDate + *(void **) (&FcConfigUptoDate_dylibloader_wrapper_fontconfig) = dlsym(handle, "FcConfigUptoDate"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// FcConfigBuildFonts + *(void **) (&FcConfigBuildFonts_dylibloader_wrapper_fontconfig) = dlsym(handle, "FcConfigBuildFonts"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// FcConfigGetFontDirs + *(void **) (&FcConfigGetFontDirs_dylibloader_wrapper_fontconfig) = dlsym(handle, "FcConfigGetFontDirs"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// FcConfigGetConfigDirs + *(void **) (&FcConfigGetConfigDirs_dylibloader_wrapper_fontconfig) = dlsym(handle, "FcConfigGetConfigDirs"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// FcConfigGetConfigFiles + *(void **) (&FcConfigGetConfigFiles_dylibloader_wrapper_fontconfig) = dlsym(handle, "FcConfigGetConfigFiles"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// FcConfigGetCache + *(void **) (&FcConfigGetCache_dylibloader_wrapper_fontconfig) = dlsym(handle, "FcConfigGetCache"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// FcConfigGetBlanks + *(void **) (&FcConfigGetBlanks_dylibloader_wrapper_fontconfig) = dlsym(handle, "FcConfigGetBlanks"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// FcConfigGetCacheDirs + *(void **) (&FcConfigGetCacheDirs_dylibloader_wrapper_fontconfig) = dlsym(handle, "FcConfigGetCacheDirs"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// FcConfigGetRescanInterval + *(void **) (&FcConfigGetRescanInterval_dylibloader_wrapper_fontconfig) = dlsym(handle, "FcConfigGetRescanInterval"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// FcConfigSetRescanInterval + *(void **) (&FcConfigSetRescanInterval_dylibloader_wrapper_fontconfig) = dlsym(handle, "FcConfigSetRescanInterval"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// FcConfigGetFonts + *(void **) (&FcConfigGetFonts_dylibloader_wrapper_fontconfig) = dlsym(handle, "FcConfigGetFonts"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// FcConfigAppFontAddFile + *(void **) (&FcConfigAppFontAddFile_dylibloader_wrapper_fontconfig) = dlsym(handle, "FcConfigAppFontAddFile"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// FcConfigAppFontAddDir + *(void **) (&FcConfigAppFontAddDir_dylibloader_wrapper_fontconfig) = dlsym(handle, "FcConfigAppFontAddDir"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// FcConfigAppFontClear + *(void **) (&FcConfigAppFontClear_dylibloader_wrapper_fontconfig) = dlsym(handle, "FcConfigAppFontClear"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// FcConfigSubstituteWithPat + *(void **) (&FcConfigSubstituteWithPat_dylibloader_wrapper_fontconfig) = dlsym(handle, "FcConfigSubstituteWithPat"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// FcConfigSubstitute + *(void **) (&FcConfigSubstitute_dylibloader_wrapper_fontconfig) = dlsym(handle, "FcConfigSubstitute"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// FcConfigGetSysRoot + *(void **) (&FcConfigGetSysRoot_dylibloader_wrapper_fontconfig) = dlsym(handle, "FcConfigGetSysRoot"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// FcConfigSetSysRoot + *(void **) (&FcConfigSetSysRoot_dylibloader_wrapper_fontconfig) = dlsym(handle, "FcConfigSetSysRoot"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// FcValuePrint + *(void **) (&FcValuePrint_dylibloader_wrapper_fontconfig) = dlsym(handle, "FcValuePrint"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// FcPatternPrint + *(void **) (&FcPatternPrint_dylibloader_wrapper_fontconfig) = dlsym(handle, "FcPatternPrint"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// FcFontSetPrint + *(void **) (&FcFontSetPrint_dylibloader_wrapper_fontconfig) = dlsym(handle, "FcFontSetPrint"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// FcGetDefaultLangs + *(void **) (&FcGetDefaultLangs_dylibloader_wrapper_fontconfig) = dlsym(handle, "FcGetDefaultLangs"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// FcDefaultSubstitute + *(void **) (&FcDefaultSubstitute_dylibloader_wrapper_fontconfig) = dlsym(handle, "FcDefaultSubstitute"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// FcFileIsDir + *(void **) (&FcFileIsDir_dylibloader_wrapper_fontconfig) = dlsym(handle, "FcFileIsDir"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// FcFileScan + *(void **) (&FcFileScan_dylibloader_wrapper_fontconfig) = dlsym(handle, "FcFileScan"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// FcDirScan + *(void **) (&FcDirScan_dylibloader_wrapper_fontconfig) = dlsym(handle, "FcDirScan"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// FcDirSave + *(void **) (&FcDirSave_dylibloader_wrapper_fontconfig) = dlsym(handle, "FcDirSave"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// FcDirCacheLoad + *(void **) (&FcDirCacheLoad_dylibloader_wrapper_fontconfig) = dlsym(handle, "FcDirCacheLoad"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// FcDirCacheRescan + *(void **) (&FcDirCacheRescan_dylibloader_wrapper_fontconfig) = dlsym(handle, "FcDirCacheRescan"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// FcDirCacheRead + *(void **) (&FcDirCacheRead_dylibloader_wrapper_fontconfig) = dlsym(handle, "FcDirCacheRead"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// FcDirCacheLoadFile + *(void **) (&FcDirCacheLoadFile_dylibloader_wrapper_fontconfig) = dlsym(handle, "FcDirCacheLoadFile"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// FcDirCacheUnload + *(void **) (&FcDirCacheUnload_dylibloader_wrapper_fontconfig) = dlsym(handle, "FcDirCacheUnload"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// FcFreeTypeQuery + *(void **) (&FcFreeTypeQuery_dylibloader_wrapper_fontconfig) = dlsym(handle, "FcFreeTypeQuery"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// FcFontSetCreate + *(void **) (&FcFontSetCreate_dylibloader_wrapper_fontconfig) = dlsym(handle, "FcFontSetCreate"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// FcFontSetDestroy + *(void **) (&FcFontSetDestroy_dylibloader_wrapper_fontconfig) = dlsym(handle, "FcFontSetDestroy"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// FcFontSetAdd + *(void **) (&FcFontSetAdd_dylibloader_wrapper_fontconfig) = dlsym(handle, "FcFontSetAdd"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// FcInitLoadConfig + *(void **) (&FcInitLoadConfig_dylibloader_wrapper_fontconfig) = dlsym(handle, "FcInitLoadConfig"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// FcInitLoadConfigAndFonts + *(void **) (&FcInitLoadConfigAndFonts_dylibloader_wrapper_fontconfig) = dlsym(handle, "FcInitLoadConfigAndFonts"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// FcInit + *(void **) (&FcInit_dylibloader_wrapper_fontconfig) = dlsym(handle, "FcInit"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// FcFini + *(void **) (&FcFini_dylibloader_wrapper_fontconfig) = dlsym(handle, "FcFini"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// FcGetVersion + *(void **) (&FcGetVersion_dylibloader_wrapper_fontconfig) = dlsym(handle, "FcGetVersion"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// FcInitReinitialize + *(void **) (&FcInitReinitialize_dylibloader_wrapper_fontconfig) = dlsym(handle, "FcInitReinitialize"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// FcInitBringUptoDate + *(void **) (&FcInitBringUptoDate_dylibloader_wrapper_fontconfig) = dlsym(handle, "FcInitBringUptoDate"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// FcGetLangs + *(void **) (&FcGetLangs_dylibloader_wrapper_fontconfig) = dlsym(handle, "FcGetLangs"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// FcLangNormalize + *(void **) (&FcLangNormalize_dylibloader_wrapper_fontconfig) = dlsym(handle, "FcLangNormalize"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// FcLangGetCharSet + *(void **) (&FcLangGetCharSet_dylibloader_wrapper_fontconfig) = dlsym(handle, "FcLangGetCharSet"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// FcLangSetCreate + *(void **) (&FcLangSetCreate_dylibloader_wrapper_fontconfig) = dlsym(handle, "FcLangSetCreate"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// FcLangSetDestroy + *(void **) (&FcLangSetDestroy_dylibloader_wrapper_fontconfig) = dlsym(handle, "FcLangSetDestroy"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// FcLangSetCopy + *(void **) (&FcLangSetCopy_dylibloader_wrapper_fontconfig) = dlsym(handle, "FcLangSetCopy"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// FcLangSetAdd + *(void **) (&FcLangSetAdd_dylibloader_wrapper_fontconfig) = dlsym(handle, "FcLangSetAdd"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// FcLangSetDel + *(void **) (&FcLangSetDel_dylibloader_wrapper_fontconfig) = dlsym(handle, "FcLangSetDel"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// FcLangSetHasLang + *(void **) (&FcLangSetHasLang_dylibloader_wrapper_fontconfig) = dlsym(handle, "FcLangSetHasLang"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// FcLangSetCompare + *(void **) (&FcLangSetCompare_dylibloader_wrapper_fontconfig) = dlsym(handle, "FcLangSetCompare"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// FcLangSetContains + *(void **) (&FcLangSetContains_dylibloader_wrapper_fontconfig) = dlsym(handle, "FcLangSetContains"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// FcLangSetEqual + *(void **) (&FcLangSetEqual_dylibloader_wrapper_fontconfig) = dlsym(handle, "FcLangSetEqual"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// FcLangSetHash + *(void **) (&FcLangSetHash_dylibloader_wrapper_fontconfig) = dlsym(handle, "FcLangSetHash"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// FcLangSetGetLangs + *(void **) (&FcLangSetGetLangs_dylibloader_wrapper_fontconfig) = dlsym(handle, "FcLangSetGetLangs"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// FcLangSetUnion + *(void **) (&FcLangSetUnion_dylibloader_wrapper_fontconfig) = dlsym(handle, "FcLangSetUnion"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// FcLangSetSubtract + *(void **) (&FcLangSetSubtract_dylibloader_wrapper_fontconfig) = dlsym(handle, "FcLangSetSubtract"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// FcObjectSetCreate + *(void **) (&FcObjectSetCreate_dylibloader_wrapper_fontconfig) = dlsym(handle, "FcObjectSetCreate"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// FcObjectSetAdd + *(void **) (&FcObjectSetAdd_dylibloader_wrapper_fontconfig) = dlsym(handle, "FcObjectSetAdd"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// FcObjectSetDestroy + *(void **) (&FcObjectSetDestroy_dylibloader_wrapper_fontconfig) = dlsym(handle, "FcObjectSetDestroy"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// FcObjectSetVaBuild + *(void **) (&FcObjectSetVaBuild_dylibloader_wrapper_fontconfig) = dlsym(handle, "FcObjectSetVaBuild"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// FcObjectSetBuild + *(void **) (&FcObjectSetBuild_dylibloader_wrapper_fontconfig) = dlsym(handle, "FcObjectSetBuild"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// FcFontSetList + *(void **) (&FcFontSetList_dylibloader_wrapper_fontconfig) = dlsym(handle, "FcFontSetList"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// FcFontList + *(void **) (&FcFontList_dylibloader_wrapper_fontconfig) = dlsym(handle, "FcFontList"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// FcAtomicCreate + *(void **) (&FcAtomicCreate_dylibloader_wrapper_fontconfig) = dlsym(handle, "FcAtomicCreate"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// FcAtomicLock + *(void **) (&FcAtomicLock_dylibloader_wrapper_fontconfig) = dlsym(handle, "FcAtomicLock"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// FcAtomicNewFile + *(void **) (&FcAtomicNewFile_dylibloader_wrapper_fontconfig) = dlsym(handle, "FcAtomicNewFile"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// FcAtomicOrigFile + *(void **) (&FcAtomicOrigFile_dylibloader_wrapper_fontconfig) = dlsym(handle, "FcAtomicOrigFile"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// FcAtomicReplaceOrig + *(void **) (&FcAtomicReplaceOrig_dylibloader_wrapper_fontconfig) = dlsym(handle, "FcAtomicReplaceOrig"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// FcAtomicDeleteNew + *(void **) (&FcAtomicDeleteNew_dylibloader_wrapper_fontconfig) = dlsym(handle, "FcAtomicDeleteNew"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// FcAtomicUnlock + *(void **) (&FcAtomicUnlock_dylibloader_wrapper_fontconfig) = dlsym(handle, "FcAtomicUnlock"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// FcAtomicDestroy + *(void **) (&FcAtomicDestroy_dylibloader_wrapper_fontconfig) = dlsym(handle, "FcAtomicDestroy"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// FcFontSetMatch + *(void **) (&FcFontSetMatch_dylibloader_wrapper_fontconfig) = dlsym(handle, "FcFontSetMatch"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// FcFontMatch + *(void **) (&FcFontMatch_dylibloader_wrapper_fontconfig) = dlsym(handle, "FcFontMatch"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// FcFontRenderPrepare + *(void **) (&FcFontRenderPrepare_dylibloader_wrapper_fontconfig) = dlsym(handle, "FcFontRenderPrepare"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// FcFontSetSort + *(void **) (&FcFontSetSort_dylibloader_wrapper_fontconfig) = dlsym(handle, "FcFontSetSort"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// FcFontSort + *(void **) (&FcFontSort_dylibloader_wrapper_fontconfig) = dlsym(handle, "FcFontSort"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// FcFontSetSortDestroy + *(void **) (&FcFontSetSortDestroy_dylibloader_wrapper_fontconfig) = dlsym(handle, "FcFontSetSortDestroy"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// FcMatrixCopy + *(void **) (&FcMatrixCopy_dylibloader_wrapper_fontconfig) = dlsym(handle, "FcMatrixCopy"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// FcMatrixEqual + *(void **) (&FcMatrixEqual_dylibloader_wrapper_fontconfig) = dlsym(handle, "FcMatrixEqual"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// FcMatrixMultiply + *(void **) (&FcMatrixMultiply_dylibloader_wrapper_fontconfig) = dlsym(handle, "FcMatrixMultiply"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// FcMatrixRotate + *(void **) (&FcMatrixRotate_dylibloader_wrapper_fontconfig) = dlsym(handle, "FcMatrixRotate"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// FcMatrixScale + *(void **) (&FcMatrixScale_dylibloader_wrapper_fontconfig) = dlsym(handle, "FcMatrixScale"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// FcMatrixShear + *(void **) (&FcMatrixShear_dylibloader_wrapper_fontconfig) = dlsym(handle, "FcMatrixShear"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// FcNameRegisterObjectTypes + *(void **) (&FcNameRegisterObjectTypes_dylibloader_wrapper_fontconfig) = dlsym(handle, "FcNameRegisterObjectTypes"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// FcNameUnregisterObjectTypes + *(void **) (&FcNameUnregisterObjectTypes_dylibloader_wrapper_fontconfig) = dlsym(handle, "FcNameUnregisterObjectTypes"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// FcNameGetObjectType + *(void **) (&FcNameGetObjectType_dylibloader_wrapper_fontconfig) = dlsym(handle, "FcNameGetObjectType"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// FcNameRegisterConstants + *(void **) (&FcNameRegisterConstants_dylibloader_wrapper_fontconfig) = dlsym(handle, "FcNameRegisterConstants"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// FcNameUnregisterConstants + *(void **) (&FcNameUnregisterConstants_dylibloader_wrapper_fontconfig) = dlsym(handle, "FcNameUnregisterConstants"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// FcNameGetConstant + *(void **) (&FcNameGetConstant_dylibloader_wrapper_fontconfig) = dlsym(handle, "FcNameGetConstant"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// FcNameConstant + *(void **) (&FcNameConstant_dylibloader_wrapper_fontconfig) = dlsym(handle, "FcNameConstant"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// FcNameParse + *(void **) (&FcNameParse_dylibloader_wrapper_fontconfig) = dlsym(handle, "FcNameParse"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// FcNameUnparse + *(void **) (&FcNameUnparse_dylibloader_wrapper_fontconfig) = dlsym(handle, "FcNameUnparse"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// FcPatternCreate + *(void **) (&FcPatternCreate_dylibloader_wrapper_fontconfig) = dlsym(handle, "FcPatternCreate"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// FcPatternDuplicate + *(void **) (&FcPatternDuplicate_dylibloader_wrapper_fontconfig) = dlsym(handle, "FcPatternDuplicate"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// FcPatternReference + *(void **) (&FcPatternReference_dylibloader_wrapper_fontconfig) = dlsym(handle, "FcPatternReference"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// FcPatternFilter + *(void **) (&FcPatternFilter_dylibloader_wrapper_fontconfig) = dlsym(handle, "FcPatternFilter"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// FcValueDestroy + *(void **) (&FcValueDestroy_dylibloader_wrapper_fontconfig) = dlsym(handle, "FcValueDestroy"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// FcValueEqual + *(void **) (&FcValueEqual_dylibloader_wrapper_fontconfig) = dlsym(handle, "FcValueEqual"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// FcValueSave + *(void **) (&FcValueSave_dylibloader_wrapper_fontconfig) = dlsym(handle, "FcValueSave"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// FcPatternDestroy + *(void **) (&FcPatternDestroy_dylibloader_wrapper_fontconfig) = dlsym(handle, "FcPatternDestroy"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// FcPatternEqual + *(void **) (&FcPatternEqual_dylibloader_wrapper_fontconfig) = dlsym(handle, "FcPatternEqual"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// FcPatternEqualSubset + *(void **) (&FcPatternEqualSubset_dylibloader_wrapper_fontconfig) = dlsym(handle, "FcPatternEqualSubset"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// FcPatternHash + *(void **) (&FcPatternHash_dylibloader_wrapper_fontconfig) = dlsym(handle, "FcPatternHash"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// FcPatternAdd + *(void **) (&FcPatternAdd_dylibloader_wrapper_fontconfig) = dlsym(handle, "FcPatternAdd"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// FcPatternAddWeak + *(void **) (&FcPatternAddWeak_dylibloader_wrapper_fontconfig) = dlsym(handle, "FcPatternAddWeak"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// FcPatternGet + *(void **) (&FcPatternGet_dylibloader_wrapper_fontconfig) = dlsym(handle, "FcPatternGet"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// FcPatternGetWithBinding + *(void **) (&FcPatternGetWithBinding_dylibloader_wrapper_fontconfig) = dlsym(handle, "FcPatternGetWithBinding"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// FcPatternDel + *(void **) (&FcPatternDel_dylibloader_wrapper_fontconfig) = dlsym(handle, "FcPatternDel"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// FcPatternRemove + *(void **) (&FcPatternRemove_dylibloader_wrapper_fontconfig) = dlsym(handle, "FcPatternRemove"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// FcPatternAddInteger + *(void **) (&FcPatternAddInteger_dylibloader_wrapper_fontconfig) = dlsym(handle, "FcPatternAddInteger"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// FcPatternAddDouble + *(void **) (&FcPatternAddDouble_dylibloader_wrapper_fontconfig) = dlsym(handle, "FcPatternAddDouble"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// FcPatternAddString + *(void **) (&FcPatternAddString_dylibloader_wrapper_fontconfig) = dlsym(handle, "FcPatternAddString"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// FcPatternAddMatrix + *(void **) (&FcPatternAddMatrix_dylibloader_wrapper_fontconfig) = dlsym(handle, "FcPatternAddMatrix"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// FcPatternAddCharSet + *(void **) (&FcPatternAddCharSet_dylibloader_wrapper_fontconfig) = dlsym(handle, "FcPatternAddCharSet"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// FcPatternAddBool + *(void **) (&FcPatternAddBool_dylibloader_wrapper_fontconfig) = dlsym(handle, "FcPatternAddBool"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// FcPatternAddLangSet + *(void **) (&FcPatternAddLangSet_dylibloader_wrapper_fontconfig) = dlsym(handle, "FcPatternAddLangSet"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// FcPatternAddRange + *(void **) (&FcPatternAddRange_dylibloader_wrapper_fontconfig) = dlsym(handle, "FcPatternAddRange"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// FcPatternGetInteger + *(void **) (&FcPatternGetInteger_dylibloader_wrapper_fontconfig) = dlsym(handle, "FcPatternGetInteger"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// FcPatternGetDouble + *(void **) (&FcPatternGetDouble_dylibloader_wrapper_fontconfig) = dlsym(handle, "FcPatternGetDouble"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// FcPatternGetString + *(void **) (&FcPatternGetString_dylibloader_wrapper_fontconfig) = dlsym(handle, "FcPatternGetString"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// FcPatternGetMatrix + *(void **) (&FcPatternGetMatrix_dylibloader_wrapper_fontconfig) = dlsym(handle, "FcPatternGetMatrix"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// FcPatternGetCharSet + *(void **) (&FcPatternGetCharSet_dylibloader_wrapper_fontconfig) = dlsym(handle, "FcPatternGetCharSet"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// FcPatternGetBool + *(void **) (&FcPatternGetBool_dylibloader_wrapper_fontconfig) = dlsym(handle, "FcPatternGetBool"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// FcPatternGetLangSet + *(void **) (&FcPatternGetLangSet_dylibloader_wrapper_fontconfig) = dlsym(handle, "FcPatternGetLangSet"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// FcPatternGetRange + *(void **) (&FcPatternGetRange_dylibloader_wrapper_fontconfig) = dlsym(handle, "FcPatternGetRange"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// FcPatternVaBuild + *(void **) (&FcPatternVaBuild_dylibloader_wrapper_fontconfig) = dlsym(handle, "FcPatternVaBuild"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// FcPatternBuild + *(void **) (&FcPatternBuild_dylibloader_wrapper_fontconfig) = dlsym(handle, "FcPatternBuild"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// FcPatternFormat + *(void **) (&FcPatternFormat_dylibloader_wrapper_fontconfig) = dlsym(handle, "FcPatternFormat"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// FcRangeCreateDouble + *(void **) (&FcRangeCreateDouble_dylibloader_wrapper_fontconfig) = dlsym(handle, "FcRangeCreateDouble"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// FcRangeCreateInteger + *(void **) (&FcRangeCreateInteger_dylibloader_wrapper_fontconfig) = dlsym(handle, "FcRangeCreateInteger"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// FcRangeDestroy + *(void **) (&FcRangeDestroy_dylibloader_wrapper_fontconfig) = dlsym(handle, "FcRangeDestroy"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// FcRangeCopy + *(void **) (&FcRangeCopy_dylibloader_wrapper_fontconfig) = dlsym(handle, "FcRangeCopy"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// FcRangeGetDouble + *(void **) (&FcRangeGetDouble_dylibloader_wrapper_fontconfig) = dlsym(handle, "FcRangeGetDouble"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// FcWeightFromOpenType + *(void **) (&FcWeightFromOpenType_dylibloader_wrapper_fontconfig) = dlsym(handle, "FcWeightFromOpenType"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// FcWeightToOpenType + *(void **) (&FcWeightToOpenType_dylibloader_wrapper_fontconfig) = dlsym(handle, "FcWeightToOpenType"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// FcStrCopy + *(void **) (&FcStrCopy_dylibloader_wrapper_fontconfig) = dlsym(handle, "FcStrCopy"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// FcStrCopyFilename + *(void **) (&FcStrCopyFilename_dylibloader_wrapper_fontconfig) = dlsym(handle, "FcStrCopyFilename"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// FcStrPlus + *(void **) (&FcStrPlus_dylibloader_wrapper_fontconfig) = dlsym(handle, "FcStrPlus"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// FcStrFree + *(void **) (&FcStrFree_dylibloader_wrapper_fontconfig) = dlsym(handle, "FcStrFree"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// FcStrDowncase + *(void **) (&FcStrDowncase_dylibloader_wrapper_fontconfig) = dlsym(handle, "FcStrDowncase"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// FcStrCmpIgnoreCase + *(void **) (&FcStrCmpIgnoreCase_dylibloader_wrapper_fontconfig) = dlsym(handle, "FcStrCmpIgnoreCase"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// FcStrCmp + *(void **) (&FcStrCmp_dylibloader_wrapper_fontconfig) = dlsym(handle, "FcStrCmp"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// FcStrStrIgnoreCase + *(void **) (&FcStrStrIgnoreCase_dylibloader_wrapper_fontconfig) = dlsym(handle, "FcStrStrIgnoreCase"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// FcStrStr + *(void **) (&FcStrStr_dylibloader_wrapper_fontconfig) = dlsym(handle, "FcStrStr"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// FcUtf8ToUcs4 + *(void **) (&FcUtf8ToUcs4_dylibloader_wrapper_fontconfig) = dlsym(handle, "FcUtf8ToUcs4"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// FcUtf8Len + *(void **) (&FcUtf8Len_dylibloader_wrapper_fontconfig) = dlsym(handle, "FcUtf8Len"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// FcUcs4ToUtf8 + *(void **) (&FcUcs4ToUtf8_dylibloader_wrapper_fontconfig) = dlsym(handle, "FcUcs4ToUtf8"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// FcUtf16ToUcs4 + *(void **) (&FcUtf16ToUcs4_dylibloader_wrapper_fontconfig) = dlsym(handle, "FcUtf16ToUcs4"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// FcUtf16Len + *(void **) (&FcUtf16Len_dylibloader_wrapper_fontconfig) = dlsym(handle, "FcUtf16Len"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// FcStrDirname + *(void **) (&FcStrDirname_dylibloader_wrapper_fontconfig) = dlsym(handle, "FcStrDirname"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// FcStrBasename + *(void **) (&FcStrBasename_dylibloader_wrapper_fontconfig) = dlsym(handle, "FcStrBasename"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// FcStrSetCreate + *(void **) (&FcStrSetCreate_dylibloader_wrapper_fontconfig) = dlsym(handle, "FcStrSetCreate"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// FcStrSetMember + *(void **) (&FcStrSetMember_dylibloader_wrapper_fontconfig) = dlsym(handle, "FcStrSetMember"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// FcStrSetEqual + *(void **) (&FcStrSetEqual_dylibloader_wrapper_fontconfig) = dlsym(handle, "FcStrSetEqual"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// FcStrSetAdd + *(void **) (&FcStrSetAdd_dylibloader_wrapper_fontconfig) = dlsym(handle, "FcStrSetAdd"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// FcStrSetAddFilename + *(void **) (&FcStrSetAddFilename_dylibloader_wrapper_fontconfig) = dlsym(handle, "FcStrSetAddFilename"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// FcStrSetDel + *(void **) (&FcStrSetDel_dylibloader_wrapper_fontconfig) = dlsym(handle, "FcStrSetDel"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// FcStrSetDestroy + *(void **) (&FcStrSetDestroy_dylibloader_wrapper_fontconfig) = dlsym(handle, "FcStrSetDestroy"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// FcStrListCreate + *(void **) (&FcStrListCreate_dylibloader_wrapper_fontconfig) = dlsym(handle, "FcStrListCreate"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// FcStrListFirst + *(void **) (&FcStrListFirst_dylibloader_wrapper_fontconfig) = dlsym(handle, "FcStrListFirst"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// FcStrListNext + *(void **) (&FcStrListNext_dylibloader_wrapper_fontconfig) = dlsym(handle, "FcStrListNext"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// FcStrListDone + *(void **) (&FcStrListDone_dylibloader_wrapper_fontconfig) = dlsym(handle, "FcStrListDone"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// FcConfigParseAndLoad + *(void **) (&FcConfigParseAndLoad_dylibloader_wrapper_fontconfig) = dlsym(handle, "FcConfigParseAndLoad"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// FcConfigParseAndLoadFromMemory + *(void **) (&FcConfigParseAndLoadFromMemory_dylibloader_wrapper_fontconfig) = dlsym(handle, "FcConfigParseAndLoadFromMemory"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +return 0; +} diff --git a/platform/linuxbsd/fontconfig-so_wrap.h b/platform/linuxbsd/fontconfig-so_wrap.h new file mode 100644 index 0000000000..f0794cce8b --- /dev/null +++ b/platform/linuxbsd/fontconfig-so_wrap.h @@ -0,0 +1,770 @@ +#ifndef DYLIBLOAD_WRAPPER_FONTCONFIG +#define DYLIBLOAD_WRAPPER_FONTCONFIG +// This file is generated. Do not edit! +// see https://github.com/hpvb/dynload-wrapper for details +// generated by ./generate-wrapper.py 0.3 on 2022-07-29 05:40:07 +// flags: ./generate-wrapper.py --include /usr/include/fontconfig/fontconfig.h --sys-include <fontconfig/fontconfig.h> --soname libfontconfig.so --init-name fontconfig --output-header fontconfig-so_wrap.h --output-implementation fontconfig-so_wrap.c --omit-prefix FcCharSet +// +#include <stdint.h> + +#define FcBlanksCreate FcBlanksCreate_dylibloader_orig_fontconfig +#define FcBlanksDestroy FcBlanksDestroy_dylibloader_orig_fontconfig +#define FcBlanksAdd FcBlanksAdd_dylibloader_orig_fontconfig +#define FcBlanksIsMember FcBlanksIsMember_dylibloader_orig_fontconfig +#define FcCacheDir FcCacheDir_dylibloader_orig_fontconfig +#define FcCacheCopySet FcCacheCopySet_dylibloader_orig_fontconfig +#define FcCacheSubdir FcCacheSubdir_dylibloader_orig_fontconfig +#define FcCacheNumSubdir FcCacheNumSubdir_dylibloader_orig_fontconfig +#define FcCacheNumFont FcCacheNumFont_dylibloader_orig_fontconfig +#define FcDirCacheUnlink FcDirCacheUnlink_dylibloader_orig_fontconfig +#define FcDirCacheValid FcDirCacheValid_dylibloader_orig_fontconfig +#define FcDirCacheClean FcDirCacheClean_dylibloader_orig_fontconfig +#define FcCacheCreateTagFile FcCacheCreateTagFile_dylibloader_orig_fontconfig +#define FcConfigHome FcConfigHome_dylibloader_orig_fontconfig +#define FcConfigEnableHome FcConfigEnableHome_dylibloader_orig_fontconfig +#define FcConfigFilename FcConfigFilename_dylibloader_orig_fontconfig +#define FcConfigCreate FcConfigCreate_dylibloader_orig_fontconfig +#define FcConfigReference FcConfigReference_dylibloader_orig_fontconfig +#define FcConfigDestroy FcConfigDestroy_dylibloader_orig_fontconfig +#define FcConfigSetCurrent FcConfigSetCurrent_dylibloader_orig_fontconfig +#define FcConfigGetCurrent FcConfigGetCurrent_dylibloader_orig_fontconfig +#define FcConfigUptoDate FcConfigUptoDate_dylibloader_orig_fontconfig +#define FcConfigBuildFonts FcConfigBuildFonts_dylibloader_orig_fontconfig +#define FcConfigGetFontDirs FcConfigGetFontDirs_dylibloader_orig_fontconfig +#define FcConfigGetConfigDirs FcConfigGetConfigDirs_dylibloader_orig_fontconfig +#define FcConfigGetConfigFiles FcConfigGetConfigFiles_dylibloader_orig_fontconfig +#define FcConfigGetCache FcConfigGetCache_dylibloader_orig_fontconfig +#define FcConfigGetBlanks FcConfigGetBlanks_dylibloader_orig_fontconfig +#define FcConfigGetCacheDirs FcConfigGetCacheDirs_dylibloader_orig_fontconfig +#define FcConfigGetRescanInterval FcConfigGetRescanInterval_dylibloader_orig_fontconfig +#define FcConfigSetRescanInterval FcConfigSetRescanInterval_dylibloader_orig_fontconfig +#define FcConfigGetFonts FcConfigGetFonts_dylibloader_orig_fontconfig +#define FcConfigAppFontAddFile FcConfigAppFontAddFile_dylibloader_orig_fontconfig +#define FcConfigAppFontAddDir FcConfigAppFontAddDir_dylibloader_orig_fontconfig +#define FcConfigAppFontClear FcConfigAppFontClear_dylibloader_orig_fontconfig +#define FcConfigSubstituteWithPat FcConfigSubstituteWithPat_dylibloader_orig_fontconfig +#define FcConfigSubstitute FcConfigSubstitute_dylibloader_orig_fontconfig +#define FcConfigGetSysRoot FcConfigGetSysRoot_dylibloader_orig_fontconfig +#define FcConfigSetSysRoot FcConfigSetSysRoot_dylibloader_orig_fontconfig +#define FcValuePrint FcValuePrint_dylibloader_orig_fontconfig +#define FcPatternPrint FcPatternPrint_dylibloader_orig_fontconfig +#define FcFontSetPrint FcFontSetPrint_dylibloader_orig_fontconfig +#define FcGetDefaultLangs FcGetDefaultLangs_dylibloader_orig_fontconfig +#define FcDefaultSubstitute FcDefaultSubstitute_dylibloader_orig_fontconfig +#define FcFileIsDir FcFileIsDir_dylibloader_orig_fontconfig +#define FcFileScan FcFileScan_dylibloader_orig_fontconfig +#define FcDirScan FcDirScan_dylibloader_orig_fontconfig +#define FcDirSave FcDirSave_dylibloader_orig_fontconfig +#define FcDirCacheLoad FcDirCacheLoad_dylibloader_orig_fontconfig +#define FcDirCacheRescan FcDirCacheRescan_dylibloader_orig_fontconfig +#define FcDirCacheRead FcDirCacheRead_dylibloader_orig_fontconfig +#define FcDirCacheLoadFile FcDirCacheLoadFile_dylibloader_orig_fontconfig +#define FcDirCacheUnload FcDirCacheUnload_dylibloader_orig_fontconfig +#define FcFreeTypeQuery FcFreeTypeQuery_dylibloader_orig_fontconfig +#define FcFontSetCreate FcFontSetCreate_dylibloader_orig_fontconfig +#define FcFontSetDestroy FcFontSetDestroy_dylibloader_orig_fontconfig +#define FcFontSetAdd FcFontSetAdd_dylibloader_orig_fontconfig +#define FcInitLoadConfig FcInitLoadConfig_dylibloader_orig_fontconfig +#define FcInitLoadConfigAndFonts FcInitLoadConfigAndFonts_dylibloader_orig_fontconfig +#define FcInit FcInit_dylibloader_orig_fontconfig +#define FcFini FcFini_dylibloader_orig_fontconfig +#define FcGetVersion FcGetVersion_dylibloader_orig_fontconfig +#define FcInitReinitialize FcInitReinitialize_dylibloader_orig_fontconfig +#define FcInitBringUptoDate FcInitBringUptoDate_dylibloader_orig_fontconfig +#define FcGetLangs FcGetLangs_dylibloader_orig_fontconfig +#define FcLangNormalize FcLangNormalize_dylibloader_orig_fontconfig +#define FcLangGetCharSet FcLangGetCharSet_dylibloader_orig_fontconfig +#define FcLangSetCreate FcLangSetCreate_dylibloader_orig_fontconfig +#define FcLangSetDestroy FcLangSetDestroy_dylibloader_orig_fontconfig +#define FcLangSetCopy FcLangSetCopy_dylibloader_orig_fontconfig +#define FcLangSetAdd FcLangSetAdd_dylibloader_orig_fontconfig +#define FcLangSetDel FcLangSetDel_dylibloader_orig_fontconfig +#define FcLangSetHasLang FcLangSetHasLang_dylibloader_orig_fontconfig +#define FcLangSetCompare FcLangSetCompare_dylibloader_orig_fontconfig +#define FcLangSetContains FcLangSetContains_dylibloader_orig_fontconfig +#define FcLangSetEqual FcLangSetEqual_dylibloader_orig_fontconfig +#define FcLangSetHash FcLangSetHash_dylibloader_orig_fontconfig +#define FcLangSetGetLangs FcLangSetGetLangs_dylibloader_orig_fontconfig +#define FcLangSetUnion FcLangSetUnion_dylibloader_orig_fontconfig +#define FcLangSetSubtract FcLangSetSubtract_dylibloader_orig_fontconfig +#define FcObjectSetCreate FcObjectSetCreate_dylibloader_orig_fontconfig +#define FcObjectSetAdd FcObjectSetAdd_dylibloader_orig_fontconfig +#define FcObjectSetDestroy FcObjectSetDestroy_dylibloader_orig_fontconfig +#define FcObjectSetVaBuild FcObjectSetVaBuild_dylibloader_orig_fontconfig +#define FcObjectSetBuild FcObjectSetBuild_dylibloader_orig_fontconfig +#define FcFontSetList FcFontSetList_dylibloader_orig_fontconfig +#define FcFontList FcFontList_dylibloader_orig_fontconfig +#define FcAtomicCreate FcAtomicCreate_dylibloader_orig_fontconfig +#define FcAtomicLock FcAtomicLock_dylibloader_orig_fontconfig +#define FcAtomicNewFile FcAtomicNewFile_dylibloader_orig_fontconfig +#define FcAtomicOrigFile FcAtomicOrigFile_dylibloader_orig_fontconfig +#define FcAtomicReplaceOrig FcAtomicReplaceOrig_dylibloader_orig_fontconfig +#define FcAtomicDeleteNew FcAtomicDeleteNew_dylibloader_orig_fontconfig +#define FcAtomicUnlock FcAtomicUnlock_dylibloader_orig_fontconfig +#define FcAtomicDestroy FcAtomicDestroy_dylibloader_orig_fontconfig +#define FcFontSetMatch FcFontSetMatch_dylibloader_orig_fontconfig +#define FcFontMatch FcFontMatch_dylibloader_orig_fontconfig +#define FcFontRenderPrepare FcFontRenderPrepare_dylibloader_orig_fontconfig +#define FcFontSetSort FcFontSetSort_dylibloader_orig_fontconfig +#define FcFontSort FcFontSort_dylibloader_orig_fontconfig +#define FcFontSetSortDestroy FcFontSetSortDestroy_dylibloader_orig_fontconfig +#define FcMatrixCopy FcMatrixCopy_dylibloader_orig_fontconfig +#define FcMatrixEqual FcMatrixEqual_dylibloader_orig_fontconfig +#define FcMatrixMultiply FcMatrixMultiply_dylibloader_orig_fontconfig +#define FcMatrixRotate FcMatrixRotate_dylibloader_orig_fontconfig +#define FcMatrixScale FcMatrixScale_dylibloader_orig_fontconfig +#define FcMatrixShear FcMatrixShear_dylibloader_orig_fontconfig +#define FcNameRegisterObjectTypes FcNameRegisterObjectTypes_dylibloader_orig_fontconfig +#define FcNameUnregisterObjectTypes FcNameUnregisterObjectTypes_dylibloader_orig_fontconfig +#define FcNameGetObjectType FcNameGetObjectType_dylibloader_orig_fontconfig +#define FcNameRegisterConstants FcNameRegisterConstants_dylibloader_orig_fontconfig +#define FcNameUnregisterConstants FcNameUnregisterConstants_dylibloader_orig_fontconfig +#define FcNameGetConstant FcNameGetConstant_dylibloader_orig_fontconfig +#define FcNameConstant FcNameConstant_dylibloader_orig_fontconfig +#define FcNameParse FcNameParse_dylibloader_orig_fontconfig +#define FcNameUnparse FcNameUnparse_dylibloader_orig_fontconfig +#define FcPatternCreate FcPatternCreate_dylibloader_orig_fontconfig +#define FcPatternDuplicate FcPatternDuplicate_dylibloader_orig_fontconfig +#define FcPatternReference FcPatternReference_dylibloader_orig_fontconfig +#define FcPatternFilter FcPatternFilter_dylibloader_orig_fontconfig +#define FcValueDestroy FcValueDestroy_dylibloader_orig_fontconfig +#define FcValueEqual FcValueEqual_dylibloader_orig_fontconfig +#define FcValueSave FcValueSave_dylibloader_orig_fontconfig +#define FcPatternDestroy FcPatternDestroy_dylibloader_orig_fontconfig +#define FcPatternEqual FcPatternEqual_dylibloader_orig_fontconfig +#define FcPatternEqualSubset FcPatternEqualSubset_dylibloader_orig_fontconfig +#define FcPatternHash FcPatternHash_dylibloader_orig_fontconfig +#define FcPatternAdd FcPatternAdd_dylibloader_orig_fontconfig +#define FcPatternAddWeak FcPatternAddWeak_dylibloader_orig_fontconfig +#define FcPatternGet FcPatternGet_dylibloader_orig_fontconfig +#define FcPatternGetWithBinding FcPatternGetWithBinding_dylibloader_orig_fontconfig +#define FcPatternDel FcPatternDel_dylibloader_orig_fontconfig +#define FcPatternRemove FcPatternRemove_dylibloader_orig_fontconfig +#define FcPatternAddInteger FcPatternAddInteger_dylibloader_orig_fontconfig +#define FcPatternAddDouble FcPatternAddDouble_dylibloader_orig_fontconfig +#define FcPatternAddString FcPatternAddString_dylibloader_orig_fontconfig +#define FcPatternAddMatrix FcPatternAddMatrix_dylibloader_orig_fontconfig +#define FcPatternAddCharSet FcPatternAddCharSet_dylibloader_orig_fontconfig +#define FcPatternAddBool FcPatternAddBool_dylibloader_orig_fontconfig +#define FcPatternAddLangSet FcPatternAddLangSet_dylibloader_orig_fontconfig +#define FcPatternAddRange FcPatternAddRange_dylibloader_orig_fontconfig +#define FcPatternGetInteger FcPatternGetInteger_dylibloader_orig_fontconfig +#define FcPatternGetDouble FcPatternGetDouble_dylibloader_orig_fontconfig +#define FcPatternGetString FcPatternGetString_dylibloader_orig_fontconfig +#define FcPatternGetMatrix FcPatternGetMatrix_dylibloader_orig_fontconfig +#define FcPatternGetCharSet FcPatternGetCharSet_dylibloader_orig_fontconfig +#define FcPatternGetBool FcPatternGetBool_dylibloader_orig_fontconfig +#define FcPatternGetLangSet FcPatternGetLangSet_dylibloader_orig_fontconfig +#define FcPatternGetRange FcPatternGetRange_dylibloader_orig_fontconfig +#define FcPatternVaBuild FcPatternVaBuild_dylibloader_orig_fontconfig +#define FcPatternBuild FcPatternBuild_dylibloader_orig_fontconfig +#define FcPatternFormat FcPatternFormat_dylibloader_orig_fontconfig +#define FcRangeCreateDouble FcRangeCreateDouble_dylibloader_orig_fontconfig +#define FcRangeCreateInteger FcRangeCreateInteger_dylibloader_orig_fontconfig +#define FcRangeDestroy FcRangeDestroy_dylibloader_orig_fontconfig +#define FcRangeCopy FcRangeCopy_dylibloader_orig_fontconfig +#define FcRangeGetDouble FcRangeGetDouble_dylibloader_orig_fontconfig +#define FcWeightFromOpenType FcWeightFromOpenType_dylibloader_orig_fontconfig +#define FcWeightToOpenType FcWeightToOpenType_dylibloader_orig_fontconfig +#define FcStrCopy FcStrCopy_dylibloader_orig_fontconfig +#define FcStrCopyFilename FcStrCopyFilename_dylibloader_orig_fontconfig +#define FcStrPlus FcStrPlus_dylibloader_orig_fontconfig +#define FcStrFree FcStrFree_dylibloader_orig_fontconfig +#define FcStrDowncase FcStrDowncase_dylibloader_orig_fontconfig +#define FcStrCmpIgnoreCase FcStrCmpIgnoreCase_dylibloader_orig_fontconfig +#define FcStrCmp FcStrCmp_dylibloader_orig_fontconfig +#define FcStrStrIgnoreCase FcStrStrIgnoreCase_dylibloader_orig_fontconfig +#define FcStrStr FcStrStr_dylibloader_orig_fontconfig +#define FcUtf8ToUcs4 FcUtf8ToUcs4_dylibloader_orig_fontconfig +#define FcUtf8Len FcUtf8Len_dylibloader_orig_fontconfig +#define FcUcs4ToUtf8 FcUcs4ToUtf8_dylibloader_orig_fontconfig +#define FcUtf16ToUcs4 FcUtf16ToUcs4_dylibloader_orig_fontconfig +#define FcUtf16Len FcUtf16Len_dylibloader_orig_fontconfig +#define FcStrDirname FcStrDirname_dylibloader_orig_fontconfig +#define FcStrBasename FcStrBasename_dylibloader_orig_fontconfig +#define FcStrSetCreate FcStrSetCreate_dylibloader_orig_fontconfig +#define FcStrSetMember FcStrSetMember_dylibloader_orig_fontconfig +#define FcStrSetEqual FcStrSetEqual_dylibloader_orig_fontconfig +#define FcStrSetAdd FcStrSetAdd_dylibloader_orig_fontconfig +#define FcStrSetAddFilename FcStrSetAddFilename_dylibloader_orig_fontconfig +#define FcStrSetDel FcStrSetDel_dylibloader_orig_fontconfig +#define FcStrSetDestroy FcStrSetDestroy_dylibloader_orig_fontconfig +#define FcStrListCreate FcStrListCreate_dylibloader_orig_fontconfig +#define FcStrListFirst FcStrListFirst_dylibloader_orig_fontconfig +#define FcStrListNext FcStrListNext_dylibloader_orig_fontconfig +#define FcStrListDone FcStrListDone_dylibloader_orig_fontconfig +#define FcConfigParseAndLoad FcConfigParseAndLoad_dylibloader_orig_fontconfig +#define FcConfigParseAndLoadFromMemory FcConfigParseAndLoadFromMemory_dylibloader_orig_fontconfig +#include <fontconfig/fontconfig.h> +#undef FcBlanksCreate +#undef FcBlanksDestroy +#undef FcBlanksAdd +#undef FcBlanksIsMember +#undef FcCacheDir +#undef FcCacheCopySet +#undef FcCacheSubdir +#undef FcCacheNumSubdir +#undef FcCacheNumFont +#undef FcDirCacheUnlink +#undef FcDirCacheValid +#undef FcDirCacheClean +#undef FcCacheCreateTagFile +#undef FcConfigHome +#undef FcConfigEnableHome +#undef FcConfigFilename +#undef FcConfigCreate +#undef FcConfigReference +#undef FcConfigDestroy +#undef FcConfigSetCurrent +#undef FcConfigGetCurrent +#undef FcConfigUptoDate +#undef FcConfigBuildFonts +#undef FcConfigGetFontDirs +#undef FcConfigGetConfigDirs +#undef FcConfigGetConfigFiles +#undef FcConfigGetCache +#undef FcConfigGetBlanks +#undef FcConfigGetCacheDirs +#undef FcConfigGetRescanInterval +#undef FcConfigSetRescanInterval +#undef FcConfigGetFonts +#undef FcConfigAppFontAddFile +#undef FcConfigAppFontAddDir +#undef FcConfigAppFontClear +#undef FcConfigSubstituteWithPat +#undef FcConfigSubstitute +#undef FcConfigGetSysRoot +#undef FcConfigSetSysRoot +#undef FcValuePrint +#undef FcPatternPrint +#undef FcFontSetPrint +#undef FcGetDefaultLangs +#undef FcDefaultSubstitute +#undef FcFileIsDir +#undef FcFileScan +#undef FcDirScan +#undef FcDirSave +#undef FcDirCacheLoad +#undef FcDirCacheRescan +#undef FcDirCacheRead +#undef FcDirCacheLoadFile +#undef FcDirCacheUnload +#undef FcFreeTypeQuery +#undef FcFontSetCreate +#undef FcFontSetDestroy +#undef FcFontSetAdd +#undef FcInitLoadConfig +#undef FcInitLoadConfigAndFonts +#undef FcInit +#undef FcFini +#undef FcGetVersion +#undef FcInitReinitialize +#undef FcInitBringUptoDate +#undef FcGetLangs +#undef FcLangNormalize +#undef FcLangGetCharSet +#undef FcLangSetCreate +#undef FcLangSetDestroy +#undef FcLangSetCopy +#undef FcLangSetAdd +#undef FcLangSetDel +#undef FcLangSetHasLang +#undef FcLangSetCompare +#undef FcLangSetContains +#undef FcLangSetEqual +#undef FcLangSetHash +#undef FcLangSetGetLangs +#undef FcLangSetUnion +#undef FcLangSetSubtract +#undef FcObjectSetCreate +#undef FcObjectSetAdd +#undef FcObjectSetDestroy +#undef FcObjectSetVaBuild +#undef FcObjectSetBuild +#undef FcFontSetList +#undef FcFontList +#undef FcAtomicCreate +#undef FcAtomicLock +#undef FcAtomicNewFile +#undef FcAtomicOrigFile +#undef FcAtomicReplaceOrig +#undef FcAtomicDeleteNew +#undef FcAtomicUnlock +#undef FcAtomicDestroy +#undef FcFontSetMatch +#undef FcFontMatch +#undef FcFontRenderPrepare +#undef FcFontSetSort +#undef FcFontSort +#undef FcFontSetSortDestroy +#undef FcMatrixCopy +#undef FcMatrixEqual +#undef FcMatrixMultiply +#undef FcMatrixRotate +#undef FcMatrixScale +#undef FcMatrixShear +#undef FcNameRegisterObjectTypes +#undef FcNameUnregisterObjectTypes +#undef FcNameGetObjectType +#undef FcNameRegisterConstants +#undef FcNameUnregisterConstants +#undef FcNameGetConstant +#undef FcNameConstant +#undef FcNameParse +#undef FcNameUnparse +#undef FcPatternCreate +#undef FcPatternDuplicate +#undef FcPatternReference +#undef FcPatternFilter +#undef FcValueDestroy +#undef FcValueEqual +#undef FcValueSave +#undef FcPatternDestroy +#undef FcPatternEqual +#undef FcPatternEqualSubset +#undef FcPatternHash +#undef FcPatternAdd +#undef FcPatternAddWeak +#undef FcPatternGet +#undef FcPatternGetWithBinding +#undef FcPatternDel +#undef FcPatternRemove +#undef FcPatternAddInteger +#undef FcPatternAddDouble +#undef FcPatternAddString +#undef FcPatternAddMatrix +#undef FcPatternAddCharSet +#undef FcPatternAddBool +#undef FcPatternAddLangSet +#undef FcPatternAddRange +#undef FcPatternGetInteger +#undef FcPatternGetDouble +#undef FcPatternGetString +#undef FcPatternGetMatrix +#undef FcPatternGetCharSet +#undef FcPatternGetBool +#undef FcPatternGetLangSet +#undef FcPatternGetRange +#undef FcPatternVaBuild +#undef FcPatternBuild +#undef FcPatternFormat +#undef FcRangeCreateDouble +#undef FcRangeCreateInteger +#undef FcRangeDestroy +#undef FcRangeCopy +#undef FcRangeGetDouble +#undef FcWeightFromOpenType +#undef FcWeightToOpenType +#undef FcStrCopy +#undef FcStrCopyFilename +#undef FcStrPlus +#undef FcStrFree +#undef FcStrDowncase +#undef FcStrCmpIgnoreCase +#undef FcStrCmp +#undef FcStrStrIgnoreCase +#undef FcStrStr +#undef FcUtf8ToUcs4 +#undef FcUtf8Len +#undef FcUcs4ToUtf8 +#undef FcUtf16ToUcs4 +#undef FcUtf16Len +#undef FcStrDirname +#undef FcStrBasename +#undef FcStrSetCreate +#undef FcStrSetMember +#undef FcStrSetEqual +#undef FcStrSetAdd +#undef FcStrSetAddFilename +#undef FcStrSetDel +#undef FcStrSetDestroy +#undef FcStrListCreate +#undef FcStrListFirst +#undef FcStrListNext +#undef FcStrListDone +#undef FcConfigParseAndLoad +#undef FcConfigParseAndLoadFromMemory +#ifdef __cplusplus +extern "C" { +#endif +#define FcBlanksCreate FcBlanksCreate_dylibloader_wrapper_fontconfig +#define FcBlanksDestroy FcBlanksDestroy_dylibloader_wrapper_fontconfig +#define FcBlanksAdd FcBlanksAdd_dylibloader_wrapper_fontconfig +#define FcBlanksIsMember FcBlanksIsMember_dylibloader_wrapper_fontconfig +#define FcCacheDir FcCacheDir_dylibloader_wrapper_fontconfig +#define FcCacheCopySet FcCacheCopySet_dylibloader_wrapper_fontconfig +#define FcCacheSubdir FcCacheSubdir_dylibloader_wrapper_fontconfig +#define FcCacheNumSubdir FcCacheNumSubdir_dylibloader_wrapper_fontconfig +#define FcCacheNumFont FcCacheNumFont_dylibloader_wrapper_fontconfig +#define FcDirCacheUnlink FcDirCacheUnlink_dylibloader_wrapper_fontconfig +#define FcDirCacheValid FcDirCacheValid_dylibloader_wrapper_fontconfig +#define FcDirCacheClean FcDirCacheClean_dylibloader_wrapper_fontconfig +#define FcCacheCreateTagFile FcCacheCreateTagFile_dylibloader_wrapper_fontconfig +#define FcConfigHome FcConfigHome_dylibloader_wrapper_fontconfig +#define FcConfigEnableHome FcConfigEnableHome_dylibloader_wrapper_fontconfig +#define FcConfigFilename FcConfigFilename_dylibloader_wrapper_fontconfig +#define FcConfigCreate FcConfigCreate_dylibloader_wrapper_fontconfig +#define FcConfigReference FcConfigReference_dylibloader_wrapper_fontconfig +#define FcConfigDestroy FcConfigDestroy_dylibloader_wrapper_fontconfig +#define FcConfigSetCurrent FcConfigSetCurrent_dylibloader_wrapper_fontconfig +#define FcConfigGetCurrent FcConfigGetCurrent_dylibloader_wrapper_fontconfig +#define FcConfigUptoDate FcConfigUptoDate_dylibloader_wrapper_fontconfig +#define FcConfigBuildFonts FcConfigBuildFonts_dylibloader_wrapper_fontconfig +#define FcConfigGetFontDirs FcConfigGetFontDirs_dylibloader_wrapper_fontconfig +#define FcConfigGetConfigDirs FcConfigGetConfigDirs_dylibloader_wrapper_fontconfig +#define FcConfigGetConfigFiles FcConfigGetConfigFiles_dylibloader_wrapper_fontconfig +#define FcConfigGetCache FcConfigGetCache_dylibloader_wrapper_fontconfig +#define FcConfigGetBlanks FcConfigGetBlanks_dylibloader_wrapper_fontconfig +#define FcConfigGetCacheDirs FcConfigGetCacheDirs_dylibloader_wrapper_fontconfig +#define FcConfigGetRescanInterval FcConfigGetRescanInterval_dylibloader_wrapper_fontconfig +#define FcConfigSetRescanInterval FcConfigSetRescanInterval_dylibloader_wrapper_fontconfig +#define FcConfigGetFonts FcConfigGetFonts_dylibloader_wrapper_fontconfig +#define FcConfigAppFontAddFile FcConfigAppFontAddFile_dylibloader_wrapper_fontconfig +#define FcConfigAppFontAddDir FcConfigAppFontAddDir_dylibloader_wrapper_fontconfig +#define FcConfigAppFontClear FcConfigAppFontClear_dylibloader_wrapper_fontconfig +#define FcConfigSubstituteWithPat FcConfigSubstituteWithPat_dylibloader_wrapper_fontconfig +#define FcConfigSubstitute FcConfigSubstitute_dylibloader_wrapper_fontconfig +#define FcConfigGetSysRoot FcConfigGetSysRoot_dylibloader_wrapper_fontconfig +#define FcConfigSetSysRoot FcConfigSetSysRoot_dylibloader_wrapper_fontconfig +#define FcValuePrint FcValuePrint_dylibloader_wrapper_fontconfig +#define FcPatternPrint FcPatternPrint_dylibloader_wrapper_fontconfig +#define FcFontSetPrint FcFontSetPrint_dylibloader_wrapper_fontconfig +#define FcGetDefaultLangs FcGetDefaultLangs_dylibloader_wrapper_fontconfig +#define FcDefaultSubstitute FcDefaultSubstitute_dylibloader_wrapper_fontconfig +#define FcFileIsDir FcFileIsDir_dylibloader_wrapper_fontconfig +#define FcFileScan FcFileScan_dylibloader_wrapper_fontconfig +#define FcDirScan FcDirScan_dylibloader_wrapper_fontconfig +#define FcDirSave FcDirSave_dylibloader_wrapper_fontconfig +#define FcDirCacheLoad FcDirCacheLoad_dylibloader_wrapper_fontconfig +#define FcDirCacheRescan FcDirCacheRescan_dylibloader_wrapper_fontconfig +#define FcDirCacheRead FcDirCacheRead_dylibloader_wrapper_fontconfig +#define FcDirCacheLoadFile FcDirCacheLoadFile_dylibloader_wrapper_fontconfig +#define FcDirCacheUnload FcDirCacheUnload_dylibloader_wrapper_fontconfig +#define FcFreeTypeQuery FcFreeTypeQuery_dylibloader_wrapper_fontconfig +#define FcFontSetCreate FcFontSetCreate_dylibloader_wrapper_fontconfig +#define FcFontSetDestroy FcFontSetDestroy_dylibloader_wrapper_fontconfig +#define FcFontSetAdd FcFontSetAdd_dylibloader_wrapper_fontconfig +#define FcInitLoadConfig FcInitLoadConfig_dylibloader_wrapper_fontconfig +#define FcInitLoadConfigAndFonts FcInitLoadConfigAndFonts_dylibloader_wrapper_fontconfig +#define FcInit FcInit_dylibloader_wrapper_fontconfig +#define FcFini FcFini_dylibloader_wrapper_fontconfig +#define FcGetVersion FcGetVersion_dylibloader_wrapper_fontconfig +#define FcInitReinitialize FcInitReinitialize_dylibloader_wrapper_fontconfig +#define FcInitBringUptoDate FcInitBringUptoDate_dylibloader_wrapper_fontconfig +#define FcGetLangs FcGetLangs_dylibloader_wrapper_fontconfig +#define FcLangNormalize FcLangNormalize_dylibloader_wrapper_fontconfig +#define FcLangGetCharSet FcLangGetCharSet_dylibloader_wrapper_fontconfig +#define FcLangSetCreate FcLangSetCreate_dylibloader_wrapper_fontconfig +#define FcLangSetDestroy FcLangSetDestroy_dylibloader_wrapper_fontconfig +#define FcLangSetCopy FcLangSetCopy_dylibloader_wrapper_fontconfig +#define FcLangSetAdd FcLangSetAdd_dylibloader_wrapper_fontconfig +#define FcLangSetDel FcLangSetDel_dylibloader_wrapper_fontconfig +#define FcLangSetHasLang FcLangSetHasLang_dylibloader_wrapper_fontconfig +#define FcLangSetCompare FcLangSetCompare_dylibloader_wrapper_fontconfig +#define FcLangSetContains FcLangSetContains_dylibloader_wrapper_fontconfig +#define FcLangSetEqual FcLangSetEqual_dylibloader_wrapper_fontconfig +#define FcLangSetHash FcLangSetHash_dylibloader_wrapper_fontconfig +#define FcLangSetGetLangs FcLangSetGetLangs_dylibloader_wrapper_fontconfig +#define FcLangSetUnion FcLangSetUnion_dylibloader_wrapper_fontconfig +#define FcLangSetSubtract FcLangSetSubtract_dylibloader_wrapper_fontconfig +#define FcObjectSetCreate FcObjectSetCreate_dylibloader_wrapper_fontconfig +#define FcObjectSetAdd FcObjectSetAdd_dylibloader_wrapper_fontconfig +#define FcObjectSetDestroy FcObjectSetDestroy_dylibloader_wrapper_fontconfig +#define FcObjectSetVaBuild FcObjectSetVaBuild_dylibloader_wrapper_fontconfig +#define FcObjectSetBuild FcObjectSetBuild_dylibloader_wrapper_fontconfig +#define FcFontSetList FcFontSetList_dylibloader_wrapper_fontconfig +#define FcFontList FcFontList_dylibloader_wrapper_fontconfig +#define FcAtomicCreate FcAtomicCreate_dylibloader_wrapper_fontconfig +#define FcAtomicLock FcAtomicLock_dylibloader_wrapper_fontconfig +#define FcAtomicNewFile FcAtomicNewFile_dylibloader_wrapper_fontconfig +#define FcAtomicOrigFile FcAtomicOrigFile_dylibloader_wrapper_fontconfig +#define FcAtomicReplaceOrig FcAtomicReplaceOrig_dylibloader_wrapper_fontconfig +#define FcAtomicDeleteNew FcAtomicDeleteNew_dylibloader_wrapper_fontconfig +#define FcAtomicUnlock FcAtomicUnlock_dylibloader_wrapper_fontconfig +#define FcAtomicDestroy FcAtomicDestroy_dylibloader_wrapper_fontconfig +#define FcFontSetMatch FcFontSetMatch_dylibloader_wrapper_fontconfig +#define FcFontMatch FcFontMatch_dylibloader_wrapper_fontconfig +#define FcFontRenderPrepare FcFontRenderPrepare_dylibloader_wrapper_fontconfig +#define FcFontSetSort FcFontSetSort_dylibloader_wrapper_fontconfig +#define FcFontSort FcFontSort_dylibloader_wrapper_fontconfig +#define FcFontSetSortDestroy FcFontSetSortDestroy_dylibloader_wrapper_fontconfig +#define FcMatrixCopy FcMatrixCopy_dylibloader_wrapper_fontconfig +#define FcMatrixEqual FcMatrixEqual_dylibloader_wrapper_fontconfig +#define FcMatrixMultiply FcMatrixMultiply_dylibloader_wrapper_fontconfig +#define FcMatrixRotate FcMatrixRotate_dylibloader_wrapper_fontconfig +#define FcMatrixScale FcMatrixScale_dylibloader_wrapper_fontconfig +#define FcMatrixShear FcMatrixShear_dylibloader_wrapper_fontconfig +#define FcNameRegisterObjectTypes FcNameRegisterObjectTypes_dylibloader_wrapper_fontconfig +#define FcNameUnregisterObjectTypes FcNameUnregisterObjectTypes_dylibloader_wrapper_fontconfig +#define FcNameGetObjectType FcNameGetObjectType_dylibloader_wrapper_fontconfig +#define FcNameRegisterConstants FcNameRegisterConstants_dylibloader_wrapper_fontconfig +#define FcNameUnregisterConstants FcNameUnregisterConstants_dylibloader_wrapper_fontconfig +#define FcNameGetConstant FcNameGetConstant_dylibloader_wrapper_fontconfig +#define FcNameConstant FcNameConstant_dylibloader_wrapper_fontconfig +#define FcNameParse FcNameParse_dylibloader_wrapper_fontconfig +#define FcNameUnparse FcNameUnparse_dylibloader_wrapper_fontconfig +#define FcPatternCreate FcPatternCreate_dylibloader_wrapper_fontconfig +#define FcPatternDuplicate FcPatternDuplicate_dylibloader_wrapper_fontconfig +#define FcPatternReference FcPatternReference_dylibloader_wrapper_fontconfig +#define FcPatternFilter FcPatternFilter_dylibloader_wrapper_fontconfig +#define FcValueDestroy FcValueDestroy_dylibloader_wrapper_fontconfig +#define FcValueEqual FcValueEqual_dylibloader_wrapper_fontconfig +#define FcValueSave FcValueSave_dylibloader_wrapper_fontconfig +#define FcPatternDestroy FcPatternDestroy_dylibloader_wrapper_fontconfig +#define FcPatternEqual FcPatternEqual_dylibloader_wrapper_fontconfig +#define FcPatternEqualSubset FcPatternEqualSubset_dylibloader_wrapper_fontconfig +#define FcPatternHash FcPatternHash_dylibloader_wrapper_fontconfig +#define FcPatternAdd FcPatternAdd_dylibloader_wrapper_fontconfig +#define FcPatternAddWeak FcPatternAddWeak_dylibloader_wrapper_fontconfig +#define FcPatternGet FcPatternGet_dylibloader_wrapper_fontconfig +#define FcPatternGetWithBinding FcPatternGetWithBinding_dylibloader_wrapper_fontconfig +#define FcPatternDel FcPatternDel_dylibloader_wrapper_fontconfig +#define FcPatternRemove FcPatternRemove_dylibloader_wrapper_fontconfig +#define FcPatternAddInteger FcPatternAddInteger_dylibloader_wrapper_fontconfig +#define FcPatternAddDouble FcPatternAddDouble_dylibloader_wrapper_fontconfig +#define FcPatternAddString FcPatternAddString_dylibloader_wrapper_fontconfig +#define FcPatternAddMatrix FcPatternAddMatrix_dylibloader_wrapper_fontconfig +#define FcPatternAddCharSet FcPatternAddCharSet_dylibloader_wrapper_fontconfig +#define FcPatternAddBool FcPatternAddBool_dylibloader_wrapper_fontconfig +#define FcPatternAddLangSet FcPatternAddLangSet_dylibloader_wrapper_fontconfig +#define FcPatternAddRange FcPatternAddRange_dylibloader_wrapper_fontconfig +#define FcPatternGetInteger FcPatternGetInteger_dylibloader_wrapper_fontconfig +#define FcPatternGetDouble FcPatternGetDouble_dylibloader_wrapper_fontconfig +#define FcPatternGetString FcPatternGetString_dylibloader_wrapper_fontconfig +#define FcPatternGetMatrix FcPatternGetMatrix_dylibloader_wrapper_fontconfig +#define FcPatternGetCharSet FcPatternGetCharSet_dylibloader_wrapper_fontconfig +#define FcPatternGetBool FcPatternGetBool_dylibloader_wrapper_fontconfig +#define FcPatternGetLangSet FcPatternGetLangSet_dylibloader_wrapper_fontconfig +#define FcPatternGetRange FcPatternGetRange_dylibloader_wrapper_fontconfig +#define FcPatternVaBuild FcPatternVaBuild_dylibloader_wrapper_fontconfig +#define FcPatternBuild FcPatternBuild_dylibloader_wrapper_fontconfig +#define FcPatternFormat FcPatternFormat_dylibloader_wrapper_fontconfig +#define FcRangeCreateDouble FcRangeCreateDouble_dylibloader_wrapper_fontconfig +#define FcRangeCreateInteger FcRangeCreateInteger_dylibloader_wrapper_fontconfig +#define FcRangeDestroy FcRangeDestroy_dylibloader_wrapper_fontconfig +#define FcRangeCopy FcRangeCopy_dylibloader_wrapper_fontconfig +#define FcRangeGetDouble FcRangeGetDouble_dylibloader_wrapper_fontconfig +#define FcWeightFromOpenType FcWeightFromOpenType_dylibloader_wrapper_fontconfig +#define FcWeightToOpenType FcWeightToOpenType_dylibloader_wrapper_fontconfig +#define FcStrCopy FcStrCopy_dylibloader_wrapper_fontconfig +#define FcStrCopyFilename FcStrCopyFilename_dylibloader_wrapper_fontconfig +#define FcStrPlus FcStrPlus_dylibloader_wrapper_fontconfig +#define FcStrFree FcStrFree_dylibloader_wrapper_fontconfig +#define FcStrDowncase FcStrDowncase_dylibloader_wrapper_fontconfig +#define FcStrCmpIgnoreCase FcStrCmpIgnoreCase_dylibloader_wrapper_fontconfig +#define FcStrCmp FcStrCmp_dylibloader_wrapper_fontconfig +#define FcStrStrIgnoreCase FcStrStrIgnoreCase_dylibloader_wrapper_fontconfig +#define FcStrStr FcStrStr_dylibloader_wrapper_fontconfig +#define FcUtf8ToUcs4 FcUtf8ToUcs4_dylibloader_wrapper_fontconfig +#define FcUtf8Len FcUtf8Len_dylibloader_wrapper_fontconfig +#define FcUcs4ToUtf8 FcUcs4ToUtf8_dylibloader_wrapper_fontconfig +#define FcUtf16ToUcs4 FcUtf16ToUcs4_dylibloader_wrapper_fontconfig +#define FcUtf16Len FcUtf16Len_dylibloader_wrapper_fontconfig +#define FcStrDirname FcStrDirname_dylibloader_wrapper_fontconfig +#define FcStrBasename FcStrBasename_dylibloader_wrapper_fontconfig +#define FcStrSetCreate FcStrSetCreate_dylibloader_wrapper_fontconfig +#define FcStrSetMember FcStrSetMember_dylibloader_wrapper_fontconfig +#define FcStrSetEqual FcStrSetEqual_dylibloader_wrapper_fontconfig +#define FcStrSetAdd FcStrSetAdd_dylibloader_wrapper_fontconfig +#define FcStrSetAddFilename FcStrSetAddFilename_dylibloader_wrapper_fontconfig +#define FcStrSetDel FcStrSetDel_dylibloader_wrapper_fontconfig +#define FcStrSetDestroy FcStrSetDestroy_dylibloader_wrapper_fontconfig +#define FcStrListCreate FcStrListCreate_dylibloader_wrapper_fontconfig +#define FcStrListFirst FcStrListFirst_dylibloader_wrapper_fontconfig +#define FcStrListNext FcStrListNext_dylibloader_wrapper_fontconfig +#define FcStrListDone FcStrListDone_dylibloader_wrapper_fontconfig +#define FcConfigParseAndLoad FcConfigParseAndLoad_dylibloader_wrapper_fontconfig +#define FcConfigParseAndLoadFromMemory FcConfigParseAndLoadFromMemory_dylibloader_wrapper_fontconfig +extern FcBlanks* (*FcBlanksCreate_dylibloader_wrapper_fontconfig)( void); +extern void (*FcBlanksDestroy_dylibloader_wrapper_fontconfig)( FcBlanks*); +extern FcBool (*FcBlanksAdd_dylibloader_wrapper_fontconfig)( FcBlanks*, FcChar32); +extern FcBool (*FcBlanksIsMember_dylibloader_wrapper_fontconfig)( FcBlanks*, FcChar32); +extern const FcChar8* (*FcCacheDir_dylibloader_wrapper_fontconfig)(const FcCache*); +extern FcFontSet* (*FcCacheCopySet_dylibloader_wrapper_fontconfig)(const FcCache*); +extern const FcChar8* (*FcCacheSubdir_dylibloader_wrapper_fontconfig)(const FcCache*, int); +extern int (*FcCacheNumSubdir_dylibloader_wrapper_fontconfig)(const FcCache*); +extern int (*FcCacheNumFont_dylibloader_wrapper_fontconfig)(const FcCache*); +extern FcBool (*FcDirCacheUnlink_dylibloader_wrapper_fontconfig)(const FcChar8*, FcConfig*); +extern FcBool (*FcDirCacheValid_dylibloader_wrapper_fontconfig)(const FcChar8*); +extern FcBool (*FcDirCacheClean_dylibloader_wrapper_fontconfig)(const FcChar8*, FcBool); +extern void (*FcCacheCreateTagFile_dylibloader_wrapper_fontconfig)(const FcConfig*); +extern FcChar8* (*FcConfigHome_dylibloader_wrapper_fontconfig)( void); +extern FcBool (*FcConfigEnableHome_dylibloader_wrapper_fontconfig)( FcBool); +extern FcChar8* (*FcConfigFilename_dylibloader_wrapper_fontconfig)(const FcChar8*); +extern FcConfig* (*FcConfigCreate_dylibloader_wrapper_fontconfig)( void); +extern FcConfig* (*FcConfigReference_dylibloader_wrapper_fontconfig)( FcConfig*); +extern void (*FcConfigDestroy_dylibloader_wrapper_fontconfig)( FcConfig*); +extern FcBool (*FcConfigSetCurrent_dylibloader_wrapper_fontconfig)( FcConfig*); +extern FcConfig* (*FcConfigGetCurrent_dylibloader_wrapper_fontconfig)( void); +extern FcBool (*FcConfigUptoDate_dylibloader_wrapper_fontconfig)( FcConfig*); +extern FcBool (*FcConfigBuildFonts_dylibloader_wrapper_fontconfig)( FcConfig*); +extern FcStrList* (*FcConfigGetFontDirs_dylibloader_wrapper_fontconfig)( FcConfig*); +extern FcStrList* (*FcConfigGetConfigDirs_dylibloader_wrapper_fontconfig)( FcConfig*); +extern FcStrList* (*FcConfigGetConfigFiles_dylibloader_wrapper_fontconfig)( FcConfig*); +extern FcChar8* (*FcConfigGetCache_dylibloader_wrapper_fontconfig)( FcConfig*); +extern FcBlanks* (*FcConfigGetBlanks_dylibloader_wrapper_fontconfig)( FcConfig*); +extern FcStrList* (*FcConfigGetCacheDirs_dylibloader_wrapper_fontconfig)(const FcConfig*); +extern int (*FcConfigGetRescanInterval_dylibloader_wrapper_fontconfig)( FcConfig*); +extern FcBool (*FcConfigSetRescanInterval_dylibloader_wrapper_fontconfig)( FcConfig*, int); +extern FcFontSet* (*FcConfigGetFonts_dylibloader_wrapper_fontconfig)( FcConfig*, FcSetName); +extern FcBool (*FcConfigAppFontAddFile_dylibloader_wrapper_fontconfig)( FcConfig*,const FcChar8*); +extern FcBool (*FcConfigAppFontAddDir_dylibloader_wrapper_fontconfig)( FcConfig*,const FcChar8*); +extern void (*FcConfigAppFontClear_dylibloader_wrapper_fontconfig)( FcConfig*); +extern FcBool (*FcConfigSubstituteWithPat_dylibloader_wrapper_fontconfig)( FcConfig*, FcPattern*, FcPattern*, FcMatchKind); +extern FcBool (*FcConfigSubstitute_dylibloader_wrapper_fontconfig)( FcConfig*, FcPattern*, FcMatchKind); +extern const FcChar8* (*FcConfigGetSysRoot_dylibloader_wrapper_fontconfig)(const FcConfig*); +extern void (*FcConfigSetSysRoot_dylibloader_wrapper_fontconfig)( FcConfig*,const FcChar8*); +extern void (*FcValuePrint_dylibloader_wrapper_fontconfig)(const FcValue); +extern void (*FcPatternPrint_dylibloader_wrapper_fontconfig)(const FcPattern*); +extern void (*FcFontSetPrint_dylibloader_wrapper_fontconfig)(const FcFontSet*); +extern FcStrSet* (*FcGetDefaultLangs_dylibloader_wrapper_fontconfig)( void); +extern void (*FcDefaultSubstitute_dylibloader_wrapper_fontconfig)( FcPattern*); +extern FcBool (*FcFileIsDir_dylibloader_wrapper_fontconfig)(const FcChar8*); +extern FcBool (*FcFileScan_dylibloader_wrapper_fontconfig)( FcFontSet*, FcStrSet*, FcFileCache*, FcBlanks*,const FcChar8*, FcBool); +extern FcBool (*FcDirScan_dylibloader_wrapper_fontconfig)( FcFontSet*, FcStrSet*, FcFileCache*, FcBlanks*,const FcChar8*, FcBool); +extern FcBool (*FcDirSave_dylibloader_wrapper_fontconfig)( FcFontSet*, FcStrSet*,const FcChar8*); +extern FcCache* (*FcDirCacheLoad_dylibloader_wrapper_fontconfig)(const FcChar8*, FcConfig*, FcChar8**); +extern FcCache* (*FcDirCacheRescan_dylibloader_wrapper_fontconfig)(const FcChar8*, FcConfig*); +extern FcCache* (*FcDirCacheRead_dylibloader_wrapper_fontconfig)(const FcChar8*, FcBool, FcConfig*); +extern FcCache* (*FcDirCacheLoadFile_dylibloader_wrapper_fontconfig)(const FcChar8*,struct stat*); +extern void (*FcDirCacheUnload_dylibloader_wrapper_fontconfig)( FcCache*); +extern FcPattern* (*FcFreeTypeQuery_dylibloader_wrapper_fontconfig)(const FcChar8*, int, FcBlanks*, int*); +extern FcFontSet* (*FcFontSetCreate_dylibloader_wrapper_fontconfig)( void); +extern void (*FcFontSetDestroy_dylibloader_wrapper_fontconfig)( FcFontSet*); +extern FcBool (*FcFontSetAdd_dylibloader_wrapper_fontconfig)( FcFontSet*, FcPattern*); +extern FcConfig* (*FcInitLoadConfig_dylibloader_wrapper_fontconfig)( void); +extern FcConfig* (*FcInitLoadConfigAndFonts_dylibloader_wrapper_fontconfig)( void); +extern FcBool (*FcInit_dylibloader_wrapper_fontconfig)( void); +extern void (*FcFini_dylibloader_wrapper_fontconfig)( void); +extern int (*FcGetVersion_dylibloader_wrapper_fontconfig)( void); +extern FcBool (*FcInitReinitialize_dylibloader_wrapper_fontconfig)( void); +extern FcBool (*FcInitBringUptoDate_dylibloader_wrapper_fontconfig)( void); +extern FcStrSet* (*FcGetLangs_dylibloader_wrapper_fontconfig)( void); +extern FcChar8* (*FcLangNormalize_dylibloader_wrapper_fontconfig)(const FcChar8*); +extern const FcCharSet* (*FcLangGetCharSet_dylibloader_wrapper_fontconfig)(const FcChar8*); +extern FcLangSet* (*FcLangSetCreate_dylibloader_wrapper_fontconfig)( void); +extern void (*FcLangSetDestroy_dylibloader_wrapper_fontconfig)( FcLangSet*); +extern FcLangSet* (*FcLangSetCopy_dylibloader_wrapper_fontconfig)(const FcLangSet*); +extern FcBool (*FcLangSetAdd_dylibloader_wrapper_fontconfig)( FcLangSet*,const FcChar8*); +extern FcBool (*FcLangSetDel_dylibloader_wrapper_fontconfig)( FcLangSet*,const FcChar8*); +extern FcLangResult (*FcLangSetHasLang_dylibloader_wrapper_fontconfig)(const FcLangSet*,const FcChar8*); +extern FcLangResult (*FcLangSetCompare_dylibloader_wrapper_fontconfig)(const FcLangSet*,const FcLangSet*); +extern FcBool (*FcLangSetContains_dylibloader_wrapper_fontconfig)(const FcLangSet*,const FcLangSet*); +extern FcBool (*FcLangSetEqual_dylibloader_wrapper_fontconfig)(const FcLangSet*,const FcLangSet*); +extern FcChar32 (*FcLangSetHash_dylibloader_wrapper_fontconfig)(const FcLangSet*); +extern FcStrSet* (*FcLangSetGetLangs_dylibloader_wrapper_fontconfig)(const FcLangSet*); +extern FcLangSet* (*FcLangSetUnion_dylibloader_wrapper_fontconfig)(const FcLangSet*,const FcLangSet*); +extern FcLangSet* (*FcLangSetSubtract_dylibloader_wrapper_fontconfig)(const FcLangSet*,const FcLangSet*); +extern FcObjectSet* (*FcObjectSetCreate_dylibloader_wrapper_fontconfig)( void); +extern FcBool (*FcObjectSetAdd_dylibloader_wrapper_fontconfig)( FcObjectSet*,const char*); +extern void (*FcObjectSetDestroy_dylibloader_wrapper_fontconfig)( FcObjectSet*); +extern FcObjectSet* (*FcObjectSetVaBuild_dylibloader_wrapper_fontconfig)(const char*, va_list); +extern FcObjectSet* (*FcObjectSetBuild_dylibloader_wrapper_fontconfig)(const char*,...); +extern FcFontSet* (*FcFontSetList_dylibloader_wrapper_fontconfig)( FcConfig*, FcFontSet**, int, FcPattern*, FcObjectSet*); +extern FcFontSet* (*FcFontList_dylibloader_wrapper_fontconfig)( FcConfig*, FcPattern*, FcObjectSet*); +extern FcAtomic* (*FcAtomicCreate_dylibloader_wrapper_fontconfig)(const FcChar8*); +extern FcBool (*FcAtomicLock_dylibloader_wrapper_fontconfig)( FcAtomic*); +extern FcChar8* (*FcAtomicNewFile_dylibloader_wrapper_fontconfig)( FcAtomic*); +extern FcChar8* (*FcAtomicOrigFile_dylibloader_wrapper_fontconfig)( FcAtomic*); +extern FcBool (*FcAtomicReplaceOrig_dylibloader_wrapper_fontconfig)( FcAtomic*); +extern void (*FcAtomicDeleteNew_dylibloader_wrapper_fontconfig)( FcAtomic*); +extern void (*FcAtomicUnlock_dylibloader_wrapper_fontconfig)( FcAtomic*); +extern void (*FcAtomicDestroy_dylibloader_wrapper_fontconfig)( FcAtomic*); +extern FcPattern* (*FcFontSetMatch_dylibloader_wrapper_fontconfig)( FcConfig*, FcFontSet**, int, FcPattern*, FcResult*); +extern FcPattern* (*FcFontMatch_dylibloader_wrapper_fontconfig)( FcConfig*, FcPattern*, FcResult*); +extern FcPattern* (*FcFontRenderPrepare_dylibloader_wrapper_fontconfig)( FcConfig*, FcPattern*, FcPattern*); +extern FcFontSet* (*FcFontSetSort_dylibloader_wrapper_fontconfig)( FcConfig*, FcFontSet**, int, FcPattern*, FcBool, FcCharSet**, FcResult*); +extern FcFontSet* (*FcFontSort_dylibloader_wrapper_fontconfig)( FcConfig*, FcPattern*, FcBool, FcCharSet**, FcResult*); +extern void (*FcFontSetSortDestroy_dylibloader_wrapper_fontconfig)( FcFontSet*); +extern FcMatrix* (*FcMatrixCopy_dylibloader_wrapper_fontconfig)(const FcMatrix*); +extern FcBool (*FcMatrixEqual_dylibloader_wrapper_fontconfig)(const FcMatrix*,const FcMatrix*); +extern void (*FcMatrixMultiply_dylibloader_wrapper_fontconfig)( FcMatrix*,const FcMatrix*,const FcMatrix*); +extern void (*FcMatrixRotate_dylibloader_wrapper_fontconfig)( FcMatrix*, double, double); +extern void (*FcMatrixScale_dylibloader_wrapper_fontconfig)( FcMatrix*, double, double); +extern void (*FcMatrixShear_dylibloader_wrapper_fontconfig)( FcMatrix*, double, double); +extern FcBool (*FcNameRegisterObjectTypes_dylibloader_wrapper_fontconfig)(const FcObjectType*, int); +extern FcBool (*FcNameUnregisterObjectTypes_dylibloader_wrapper_fontconfig)(const FcObjectType*, int); +extern const FcObjectType* (*FcNameGetObjectType_dylibloader_wrapper_fontconfig)(const char*); +extern FcBool (*FcNameRegisterConstants_dylibloader_wrapper_fontconfig)(const FcConstant*, int); +extern FcBool (*FcNameUnregisterConstants_dylibloader_wrapper_fontconfig)(const FcConstant*, int); +extern const FcConstant* (*FcNameGetConstant_dylibloader_wrapper_fontconfig)(const FcChar8*); +extern FcBool (*FcNameConstant_dylibloader_wrapper_fontconfig)(const FcChar8*, int*); +extern FcPattern* (*FcNameParse_dylibloader_wrapper_fontconfig)(const FcChar8*); +extern FcChar8* (*FcNameUnparse_dylibloader_wrapper_fontconfig)( FcPattern*); +extern FcPattern* (*FcPatternCreate_dylibloader_wrapper_fontconfig)( void); +extern FcPattern* (*FcPatternDuplicate_dylibloader_wrapper_fontconfig)(const FcPattern*); +extern void (*FcPatternReference_dylibloader_wrapper_fontconfig)( FcPattern*); +extern FcPattern* (*FcPatternFilter_dylibloader_wrapper_fontconfig)( FcPattern*,const FcObjectSet*); +extern void (*FcValueDestroy_dylibloader_wrapper_fontconfig)( FcValue); +extern FcBool (*FcValueEqual_dylibloader_wrapper_fontconfig)( FcValue, FcValue); +extern FcValue (*FcValueSave_dylibloader_wrapper_fontconfig)( FcValue); +extern void (*FcPatternDestroy_dylibloader_wrapper_fontconfig)( FcPattern*); +extern FcBool (*FcPatternEqual_dylibloader_wrapper_fontconfig)(const FcPattern*,const FcPattern*); +extern FcBool (*FcPatternEqualSubset_dylibloader_wrapper_fontconfig)(const FcPattern*,const FcPattern*,const FcObjectSet*); +extern FcChar32 (*FcPatternHash_dylibloader_wrapper_fontconfig)(const FcPattern*); +extern FcBool (*FcPatternAdd_dylibloader_wrapper_fontconfig)( FcPattern*,const char*, FcValue, FcBool); +extern FcBool (*FcPatternAddWeak_dylibloader_wrapper_fontconfig)( FcPattern*,const char*, FcValue, FcBool); +extern FcResult (*FcPatternGet_dylibloader_wrapper_fontconfig)(const FcPattern*,const char*, int, FcValue*); +extern FcResult (*FcPatternGetWithBinding_dylibloader_wrapper_fontconfig)(const FcPattern*,const char*, int, FcValue*, FcValueBinding*); +extern FcBool (*FcPatternDel_dylibloader_wrapper_fontconfig)( FcPattern*,const char*); +extern FcBool (*FcPatternRemove_dylibloader_wrapper_fontconfig)( FcPattern*,const char*, int); +extern FcBool (*FcPatternAddInteger_dylibloader_wrapper_fontconfig)( FcPattern*,const char*, int); +extern FcBool (*FcPatternAddDouble_dylibloader_wrapper_fontconfig)( FcPattern*,const char*, double); +extern FcBool (*FcPatternAddString_dylibloader_wrapper_fontconfig)( FcPattern*,const char*,const FcChar8*); +extern FcBool (*FcPatternAddMatrix_dylibloader_wrapper_fontconfig)( FcPattern*,const char*,const FcMatrix*); +extern FcBool (*FcPatternAddCharSet_dylibloader_wrapper_fontconfig)( FcPattern*,const char*,const FcCharSet*); +extern FcBool (*FcPatternAddBool_dylibloader_wrapper_fontconfig)( FcPattern*,const char*, FcBool); +extern FcBool (*FcPatternAddLangSet_dylibloader_wrapper_fontconfig)( FcPattern*,const char*,const FcLangSet*); +extern FcBool (*FcPatternAddRange_dylibloader_wrapper_fontconfig)( FcPattern*,const char*,const FcRange*); +extern FcResult (*FcPatternGetInteger_dylibloader_wrapper_fontconfig)(const FcPattern*,const char*, int, int*); +extern FcResult (*FcPatternGetDouble_dylibloader_wrapper_fontconfig)(const FcPattern*,const char*, int, double*); +extern FcResult (*FcPatternGetString_dylibloader_wrapper_fontconfig)(const FcPattern*,const char*, int, FcChar8**); +extern FcResult (*FcPatternGetMatrix_dylibloader_wrapper_fontconfig)(const FcPattern*,const char*, int, FcMatrix**); +extern FcResult (*FcPatternGetCharSet_dylibloader_wrapper_fontconfig)(const FcPattern*,const char*, int, FcCharSet**); +extern FcResult (*FcPatternGetBool_dylibloader_wrapper_fontconfig)(const FcPattern*,const char*, int, FcBool*); +extern FcResult (*FcPatternGetLangSet_dylibloader_wrapper_fontconfig)(const FcPattern*,const char*, int, FcLangSet**); +extern FcResult (*FcPatternGetRange_dylibloader_wrapper_fontconfig)(const FcPattern*,const char*, int, FcRange**); +extern FcPattern* (*FcPatternVaBuild_dylibloader_wrapper_fontconfig)( FcPattern*, va_list); +extern FcPattern* (*FcPatternBuild_dylibloader_wrapper_fontconfig)( FcPattern*,...); +extern FcChar8* (*FcPatternFormat_dylibloader_wrapper_fontconfig)( FcPattern*,const FcChar8*); +extern FcRange* (*FcRangeCreateDouble_dylibloader_wrapper_fontconfig)( double, double); +extern FcRange* (*FcRangeCreateInteger_dylibloader_wrapper_fontconfig)( FcChar32, FcChar32); +extern void (*FcRangeDestroy_dylibloader_wrapper_fontconfig)( FcRange*); +extern FcRange* (*FcRangeCopy_dylibloader_wrapper_fontconfig)(const FcRange*); +extern FcBool (*FcRangeGetDouble_dylibloader_wrapper_fontconfig)(const FcRange*, double*, double*); +extern int (*FcWeightFromOpenType_dylibloader_wrapper_fontconfig)( int); +extern int (*FcWeightToOpenType_dylibloader_wrapper_fontconfig)( int); +extern FcChar8* (*FcStrCopy_dylibloader_wrapper_fontconfig)(const FcChar8*); +extern FcChar8* (*FcStrCopyFilename_dylibloader_wrapper_fontconfig)(const FcChar8*); +extern FcChar8* (*FcStrPlus_dylibloader_wrapper_fontconfig)(const FcChar8*,const FcChar8*); +extern void (*FcStrFree_dylibloader_wrapper_fontconfig)( FcChar8*); +extern FcChar8* (*FcStrDowncase_dylibloader_wrapper_fontconfig)(const FcChar8*); +extern int (*FcStrCmpIgnoreCase_dylibloader_wrapper_fontconfig)(const FcChar8*,const FcChar8*); +extern int (*FcStrCmp_dylibloader_wrapper_fontconfig)(const FcChar8*,const FcChar8*); +extern const FcChar8* (*FcStrStrIgnoreCase_dylibloader_wrapper_fontconfig)(const FcChar8*,const FcChar8*); +extern const FcChar8* (*FcStrStr_dylibloader_wrapper_fontconfig)(const FcChar8*,const FcChar8*); +extern int (*FcUtf8ToUcs4_dylibloader_wrapper_fontconfig)(const FcChar8*, FcChar32*, int); +extern FcBool (*FcUtf8Len_dylibloader_wrapper_fontconfig)(const FcChar8*, int, int*, int*); +extern int (*FcUcs4ToUtf8_dylibloader_wrapper_fontconfig)( FcChar32, FcChar8 [6]); +extern int (*FcUtf16ToUcs4_dylibloader_wrapper_fontconfig)(const FcChar8*, FcEndian, FcChar32*, int); +extern FcBool (*FcUtf16Len_dylibloader_wrapper_fontconfig)(const FcChar8*, FcEndian, int, int*, int*); +extern FcChar8* (*FcStrDirname_dylibloader_wrapper_fontconfig)(const FcChar8*); +extern FcChar8* (*FcStrBasename_dylibloader_wrapper_fontconfig)(const FcChar8*); +extern FcStrSet* (*FcStrSetCreate_dylibloader_wrapper_fontconfig)( void); +extern FcBool (*FcStrSetMember_dylibloader_wrapper_fontconfig)( FcStrSet*,const FcChar8*); +extern FcBool (*FcStrSetEqual_dylibloader_wrapper_fontconfig)( FcStrSet*, FcStrSet*); +extern FcBool (*FcStrSetAdd_dylibloader_wrapper_fontconfig)( FcStrSet*,const FcChar8*); +extern FcBool (*FcStrSetAddFilename_dylibloader_wrapper_fontconfig)( FcStrSet*,const FcChar8*); +extern FcBool (*FcStrSetDel_dylibloader_wrapper_fontconfig)( FcStrSet*,const FcChar8*); +extern void (*FcStrSetDestroy_dylibloader_wrapper_fontconfig)( FcStrSet*); +extern FcStrList* (*FcStrListCreate_dylibloader_wrapper_fontconfig)( FcStrSet*); +extern void (*FcStrListFirst_dylibloader_wrapper_fontconfig)( FcStrList*); +extern FcChar8* (*FcStrListNext_dylibloader_wrapper_fontconfig)( FcStrList*); +extern void (*FcStrListDone_dylibloader_wrapper_fontconfig)( FcStrList*); +extern FcBool (*FcConfigParseAndLoad_dylibloader_wrapper_fontconfig)( FcConfig*,const FcChar8*, FcBool); +extern FcBool (*FcConfigParseAndLoadFromMemory_dylibloader_wrapper_fontconfig)( FcConfig*,const FcChar8*, FcBool); +int initialize_fontconfig(int verbose); +#ifdef __cplusplus +} +#endif +#endif diff --git a/platform/linuxbsd/freedesktop_portal_desktop.cpp b/platform/linuxbsd/freedesktop_portal_desktop.cpp new file mode 100644 index 0000000000..ed54084694 --- /dev/null +++ b/platform/linuxbsd/freedesktop_portal_desktop.cpp @@ -0,0 +1,135 @@ +/*************************************************************************/ +/* freedesktop_portal_desktop.cpp */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ + +#include "freedesktop_portal_desktop.h" + +#ifdef DBUS_ENABLED + +#include "core/error/error_macros.h" +#include "core/os/os.h" +#include "core/string/ustring.h" + +#include "dbus-so_wrap.h" + +#include "core/variant/variant.h" + +#define BUS_OBJECT_NAME "org.freedesktop.portal.Desktop" +#define BUS_OBJECT_PATH "/org/freedesktop/portal/desktop" + +#define BUS_INTERFACE_SETTINGS "org.freedesktop.portal.Settings" + +static bool try_parse_variant(DBusMessage *p_reply_message, int p_type, void *r_value) { + DBusMessageIter iter[3]; + + dbus_message_iter_init(p_reply_message, &iter[0]); + if (dbus_message_iter_get_arg_type(&iter[0]) != DBUS_TYPE_VARIANT) { + return false; + } + + dbus_message_iter_recurse(&iter[0], &iter[1]); + if (dbus_message_iter_get_arg_type(&iter[1]) != DBUS_TYPE_VARIANT) { + return false; + } + + dbus_message_iter_recurse(&iter[1], &iter[2]); + if (dbus_message_iter_get_arg_type(&iter[2]) != p_type) { + return false; + } + + dbus_message_iter_get_basic(&iter[2], r_value); + return true; +} + +bool FreeDesktopPortalDesktop::read_setting(const char *p_namespace, const char *p_key, int p_type, void *r_value) { + if (unsupported) { + return false; + } + + DBusError error; + dbus_error_init(&error); + + DBusConnection *bus = dbus_bus_get(DBUS_BUS_SESSION, &error); + if (dbus_error_is_set(&error)) { + dbus_error_free(&error); + unsupported = true; + if (OS::get_singleton()->is_stdout_verbose()) { + ERR_PRINT(String() + "Error opening D-Bus connection: " + error.message); + } + return false; + } + + DBusMessage *message = dbus_message_new_method_call( + BUS_OBJECT_NAME, BUS_OBJECT_PATH, BUS_INTERFACE_SETTINGS, + "Read"); + dbus_message_append_args( + message, + DBUS_TYPE_STRING, &p_namespace, + DBUS_TYPE_STRING, &p_key, + DBUS_TYPE_INVALID); + + DBusMessage *reply = dbus_connection_send_with_reply_and_block(bus, message, 50, &error); + dbus_message_unref(message); + if (dbus_error_is_set(&error)) { + dbus_error_free(&error); + dbus_connection_unref(bus); + if (OS::get_singleton()->is_stdout_verbose()) { + ERR_PRINT(String() + "Error on D-Bus communication: " + error.message); + } + return false; + } + + bool success = try_parse_variant(reply, p_type, r_value); + + dbus_message_unref(reply); + dbus_connection_unref(bus); + + return success; +} + +uint32_t FreeDesktopPortalDesktop::get_appearance_color_scheme() { + if (unsupported) { + return 0; + } + + uint32_t value = 0; + read_setting("org.freedesktop.appearance", "color-scheme", DBUS_TYPE_UINT32, &value); + return value; +} + +FreeDesktopPortalDesktop::FreeDesktopPortalDesktop() { +#ifdef DEBUG_ENABLED + int dylibloader_verbose = 1; +#else + int dylibloader_verbose = 0; +#endif + unsupported = (initialize_dbus(dylibloader_verbose) != 0); +} + +#endif // DBUS_ENABLED diff --git a/platform/linuxbsd/freedesktop_portal_desktop.h b/platform/linuxbsd/freedesktop_portal_desktop.h new file mode 100644 index 0000000000..3d976b1ede --- /dev/null +++ b/platform/linuxbsd/freedesktop_portal_desktop.h @@ -0,0 +1,59 @@ +/*************************************************************************/ +/* freedesktop_portal_desktop.h */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ + +#ifndef FREEDESKTOP_PORTAL_DESKTOP_H +#define FREEDESKTOP_PORTAL_DESKTOP_H + +#ifdef DBUS_ENABLED + +#include <stdint.h> + +class FreeDesktopPortalDesktop { +private: + bool unsupported = false; + + // Read a setting from org.freekdesktop.portal.Settings + bool read_setting(const char *p_namespace, const char *p_key, int p_type, void *r_value); + +public: + FreeDesktopPortalDesktop(); + + bool is_supported() { return !unsupported; } + + // Retrieve the system's preferred color scheme. + // 0: No preference or unknown. + // 1: Prefer dark appearance. + // 2: Prefer light appearance. + uint32_t get_appearance_color_scheme(); +}; + +#endif // DBUS_ENABLED + +#endif // FREEDESKTOP_PORTAL_DESKTOP_H diff --git a/platform/linuxbsd/freedesktop_screensaver.cpp b/platform/linuxbsd/freedesktop_screensaver.cpp index 1e93334e40..fa3f7fbfea 100644 --- a/platform/linuxbsd/freedesktop_screensaver.cpp +++ b/platform/linuxbsd/freedesktop_screensaver.cpp @@ -34,7 +34,7 @@ #include "core/config/project_settings.h" -#include <dbus/dbus.h> +#include "dbus-so_wrap.h" #define BUS_OBJECT_NAME "org.freedesktop.ScreenSaver" #define BUS_OBJECT_PATH "/org/freedesktop/ScreenSaver" @@ -126,4 +126,13 @@ void FreeDesktopScreenSaver::uninhibit() { dbus_connection_unref(bus); } +FreeDesktopScreenSaver::FreeDesktopScreenSaver() { +#ifdef DEBUG_ENABLED + int dylibloader_verbose = 1; +#else + int dylibloader_verbose = 0; +#endif + unsupported = (initialize_dbus(dylibloader_verbose) != 0); +} + #endif // DBUS_ENABLED diff --git a/platform/linuxbsd/freedesktop_screensaver.h b/platform/linuxbsd/freedesktop_screensaver.h index b2303791bd..1a8b010cd5 100644 --- a/platform/linuxbsd/freedesktop_screensaver.h +++ b/platform/linuxbsd/freedesktop_screensaver.h @@ -28,9 +28,11 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ +#ifndef FREEDESKTOP_SCREENSAVER_H +#define FREEDESKTOP_SCREENSAVER_H + #ifdef DBUS_ENABLED -#include <dbus/dbus.h> #include <stdint.h> class FreeDesktopScreenSaver { @@ -39,9 +41,11 @@ private: bool unsupported = false; public: - FreeDesktopScreenSaver() {} + FreeDesktopScreenSaver(); void inhibit(); void uninhibit(); }; #endif // DBUS_ENABLED + +#endif // FREEDESKTOP_SCREENSAVER_H diff --git a/platform/linuxbsd/gl_manager_x11.cpp b/platform/linuxbsd/gl_manager_x11.cpp index d3fb1d6705..838be2c042 100644 --- a/platform/linuxbsd/gl_manager_x11.cpp +++ b/platform/linuxbsd/gl_manager_x11.cpp @@ -127,10 +127,6 @@ Error GLManager_X11::_create_context(GLDisplay &gl_display) { GLXFBConfig fbconfig = nullptr; XVisualInfo *vi = nullptr; - gl_display.x_swa.event_mask = StructureNotifyMask; - gl_display.x_swa.border_pixel = 0; - gl_display.x_valuemask = CWBorderPixel | CWColormap | CWEventMask; - if (OS::get_singleton()->is_layered_allowed()) { GLXFBConfig *fbc = glXChooseFBConfig(x11_display, DefaultScreen(x11_display), visual_attribs_layered, &fbcount); ERR_FAIL_COND_V(!fbc, ERR_UNCONFIGURED); @@ -156,12 +152,6 @@ Error GLManager_X11::_create_context(GLDisplay &gl_display) { XFree(fbc); ERR_FAIL_COND_V(!fbconfig, ERR_UNCONFIGURED); - - gl_display.x_swa.background_pixmap = None; - gl_display.x_swa.background_pixel = 0; - gl_display.x_swa.border_pixmap = None; - gl_display.x_valuemask |= CWBackPixel; - } else { GLXFBConfig *fbc = glXChooseFBConfig(x11_display, DefaultScreen(x11_display), visual_attribs, &fbcount); ERR_FAIL_COND_V(!fbc, ERR_UNCONFIGURED); @@ -189,8 +179,6 @@ Error GLManager_X11::_create_context(GLDisplay &gl_display) { } break; } - gl_display.x_swa.colormap = XCreateColormap(x11_display, RootWindow(x11_display, vi->screen), vi->visual, AllocNone); - XSync(x11_display, False); XSetErrorHandler(oldHandler); @@ -205,6 +193,10 @@ Error GLManager_X11::_create_context(GLDisplay &gl_display) { return OK; } +XVisualInfo GLManager_X11::get_vi(Display *p_display) { + return _displays[_find_or_create_display(p_display)].x_vi; +} + Error GLManager_X11::window_create(DisplayServer::WindowID p_window_id, ::Window p_window, Display *p_display, int p_width, int p_height) { // make sure vector is big enough... // we can mirror the external vector, it is simpler @@ -223,8 +215,6 @@ Error GLManager_X11::window_create(DisplayServer::WindowID p_window_id, ::Window // the display could be invalid .. check NYI GLDisplay &gl_display = _displays[win.gldisplay_id]; - //const XVisualInfo &vi = gl_display.x_vi; - //XSetWindowAttributes &swa = gl_display.x_swa; ::Display *x11_display = gl_display.x11_display; ::Window &x11_window = win.x11_window; @@ -266,7 +256,11 @@ void GLManager_X11::release_current() { if (!_current_window) { return; } - glXMakeCurrent(_x_windisp.x11_display, None, nullptr); + + if (!glXMakeCurrent(_x_windisp.x11_display, None, nullptr)) { + ERR_PRINT("glXMakeCurrent failed"); + } + _current_window = nullptr; } void GLManager_X11::window_make_current(DisplayServer::WindowID p_window_id) { @@ -286,7 +280,9 @@ void GLManager_X11::window_make_current(DisplayServer::WindowID p_window_id) { const GLDisplay &disp = get_display(win.gldisplay_id); - glXMakeCurrent(disp.x11_display, win.x11_window, disp.context->glx_context); + if (!glXMakeCurrent(disp.x11_display, win.x11_window, disp.context->glx_context)) { + ERR_PRINT("glXMakeCurrent failed"); + } _internal_set_current_window(&win); } @@ -300,13 +296,12 @@ void GLManager_X11::make_current() { return; } const GLDisplay &disp = get_current_display(); - glXMakeCurrent(_x_windisp.x11_display, _x_windisp.x11_window, disp.context->glx_context); + if (!glXMakeCurrent(_x_windisp.x11_display, _x_windisp.x11_window, disp.context->glx_context)) { + ERR_PRINT("glXMakeCurrent failed"); + } } void GLManager_X11::swap_buffers() { - // NO NEED TO CALL SWAP BUFFERS for each window... - // see https://www.khronos.org/registry/OpenGL-Refpages/gl2.1/xhtml/glXSwapBuffers.xml - if (!_current_window) { return; } @@ -315,13 +310,16 @@ void GLManager_X11::swap_buffers() { return; } - // print_line("\tswap_buffers"); - - // only for debugging without drawing anything - // glClearColor(Math::randf(), 0, 1, 1); - //glClear(GL_COLOR_BUFFER_BIT); + // On X11, when enabled, transparancy is always active, so clear alpha manually. + if (OS::get_singleton()->is_layered_allowed()) { + if (!DisplayServer::get_singleton()->window_get_flag(DisplayServer::WINDOW_FLAG_TRANSPARENT, _current_window->window_id)) { + glColorMask(false, false, false, true); + glClearColor(0, 0, 0, 1); + glClear(GL_COLOR_BUFFER_BIT); + glColorMask(true, true, true, true); + } + } - //const GLDisplay &disp = get_current_display(); glXSwapBuffers(_x_windisp.x11_display, _x_windisp.x11_window); } diff --git a/platform/linuxbsd/gl_manager_x11.h b/platform/linuxbsd/gl_manager_x11.h index fb2c74a2b6..4f78c45c88 100644 --- a/platform/linuxbsd/gl_manager_x11.h +++ b/platform/linuxbsd/gl_manager_x11.h @@ -68,8 +68,6 @@ private: GLManager_X11_Private *context = nullptr; ::Display *x11_display; XVisualInfo x_vi; - XSetWindowAttributes x_swa; - unsigned long x_valuemask; }; // just for convenience, window and display struct @@ -102,6 +100,7 @@ private: Error _create_context(GLDisplay &gl_display); public: + XVisualInfo get_vi(Display *p_display); Error window_create(DisplayServer::WindowID p_window_id, ::Window p_window, Display *p_display, int p_width, int p_height); void window_destroy(DisplayServer::WindowID p_window_id); void window_resize(DisplayServer::WindowID p_window_id, int p_width, int p_height); diff --git a/platform/linuxbsd/os_linuxbsd.cpp b/platform/linuxbsd/os_linuxbsd.cpp index b73d4dc626..f0d7b6ede5 100644 --- a/platform/linuxbsd/os_linuxbsd.cpp +++ b/platform/linuxbsd/os_linuxbsd.cpp @@ -52,6 +52,10 @@ #include <sys/types.h> #include <unistd.h> +#ifdef FONTCONFIG_ENABLED +#include "fontconfig-so_wrap.h" +#endif + void OS_LinuxBSD::alert(const String &p_alert, const String &p_title) { const char *message_programs[] = { "zenity", "kdialog", "Xdialog", "xmessage" }; @@ -61,7 +65,7 @@ void OS_LinuxBSD::alert(const String &p_alert, const String &p_title) { for (int i = 0; i < path_elems.size(); i++) { for (uint64_t k = 0; k < sizeof(message_programs) / sizeof(char *); k++) { - String tested_path = path_elems[i].plus_file(message_programs[k]); + String tested_path = path_elems[i].path_join(message_programs[k]); if (FileAccess::exists(tested_path)) { program = tested_path; @@ -327,16 +331,111 @@ uint64_t OS_LinuxBSD::get_embedded_pck_offset() const { return off; } +Vector<String> OS_LinuxBSD::get_system_fonts() const { +#ifdef FONTCONFIG_ENABLED + if (!font_config_initialized) { + ERR_FAIL_V_MSG(Vector<String>(), "Unable to load fontconfig, system font support is disabled."); + } + HashSet<String> font_names; + Vector<String> ret; + + FcConfig *config = FcInitLoadConfigAndFonts(); + ERR_FAIL_COND_V(!config, ret); + + FcObjectSet *object_set = FcObjectSetBuild(FC_FAMILY, nullptr); + ERR_FAIL_COND_V(!object_set, ret); + + static const char *allowed_formats[] = { "TrueType", "CFF" }; + for (size_t i = 0; i < sizeof(allowed_formats) / sizeof(const char *); i++) { + FcPattern *pattern = FcPatternCreate(); + ERR_CONTINUE(!pattern); + + FcPatternAddBool(pattern, FC_SCALABLE, FcTrue); + FcPatternAddString(pattern, FC_FONTFORMAT, reinterpret_cast<const FcChar8 *>(allowed_formats[i])); + + FcFontSet *font_set = FcFontList(config, pattern, object_set); + if (font_set) { + for (int j = 0; j < font_set->nfont; j++) { + char *family_name = nullptr; + if (FcPatternGetString(font_set->fonts[j], FC_FAMILY, 0, reinterpret_cast<FcChar8 **>(&family_name)) == FcResultMatch) { + if (family_name) { + font_names.insert(String::utf8(family_name)); + } + } + } + FcFontSetDestroy(font_set); + } + FcPatternDestroy(pattern); + } + FcObjectSetDestroy(object_set); + FcConfigDestroy(config); + + for (const String &E : font_names) { + ret.push_back(E); + } + return ret; +#else + ERR_FAIL_V_MSG(Vector<String>(), "Godot was compiled without fontconfig, system font support is disabled."); +#endif +} + +String OS_LinuxBSD::get_system_font_path(const String &p_font_name, bool p_bold, bool p_italic) const { +#ifdef FONTCONFIG_ENABLED + if (!font_config_initialized) { + ERR_FAIL_V_MSG(String(), "Unable to load fontconfig, system font support is disabled."); + } + + String ret; + + FcConfig *config = FcInitLoadConfigAndFonts(); + ERR_FAIL_COND_V(!config, ret); + + FcObjectSet *object_set = FcObjectSetBuild(FC_FAMILY, FC_FILE, nullptr); + ERR_FAIL_COND_V(!object_set, ret); + + FcPattern *pattern = FcPatternCreate(); + if (pattern) { + FcPatternAddBool(pattern, FC_SCALABLE, FcTrue); + FcPatternAddString(pattern, FC_FAMILY, reinterpret_cast<const FcChar8 *>(p_font_name.utf8().get_data())); + FcPatternAddInteger(pattern, FC_WEIGHT, p_bold ? FC_WEIGHT_BOLD : FC_WEIGHT_NORMAL); + FcPatternAddInteger(pattern, FC_SLANT, p_italic ? FC_SLANT_ITALIC : FC_SLANT_ROMAN); + + FcConfigSubstitute(0, pattern, FcMatchPattern); + FcDefaultSubstitute(pattern); + + FcResult result; + FcPattern *match = FcFontMatch(0, pattern, &result); + if (match) { + char *file_name = nullptr; + if (FcPatternGetString(match, FC_FILE, 0, reinterpret_cast<FcChar8 **>(&file_name)) == FcResultMatch) { + if (file_name) { + ret = String::utf8(file_name); + } + } + + FcPatternDestroy(match); + } + FcPatternDestroy(pattern); + } + FcObjectSetDestroy(object_set); + FcConfigDestroy(config); + + return ret; +#else + ERR_FAIL_V_MSG(String(), "Godot was compiled without fontconfig, system font support is disabled."); +#endif +} + String OS_LinuxBSD::get_config_path() const { if (has_environment("XDG_CONFIG_HOME")) { if (get_environment("XDG_CONFIG_HOME").is_absolute_path()) { return get_environment("XDG_CONFIG_HOME"); } else { WARN_PRINT_ONCE("`XDG_CONFIG_HOME` is a relative path. Ignoring its value and falling back to `$HOME/.config` or `.` per the XDG Base Directory specification."); - return has_environment("HOME") ? get_environment("HOME").plus_file(".config") : "."; + return has_environment("HOME") ? get_environment("HOME").path_join(".config") : "."; } } else if (has_environment("HOME")) { - return get_environment("HOME").plus_file(".config"); + return get_environment("HOME").path_join(".config"); } else { return "."; } @@ -348,10 +447,10 @@ String OS_LinuxBSD::get_data_path() const { return get_environment("XDG_DATA_HOME"); } else { WARN_PRINT_ONCE("`XDG_DATA_HOME` is a relative path. Ignoring its value and falling back to `$HOME/.local/share` or `get_config_path()` per the XDG Base Directory specification."); - return has_environment("HOME") ? get_environment("HOME").plus_file(".local/share") : get_config_path(); + return has_environment("HOME") ? get_environment("HOME").path_join(".local/share") : get_config_path(); } } else if (has_environment("HOME")) { - return get_environment("HOME").plus_file(".local/share"); + return get_environment("HOME").path_join(".local/share"); } else { return get_config_path(); } @@ -363,10 +462,10 @@ String OS_LinuxBSD::get_cache_path() const { return get_environment("XDG_CACHE_HOME"); } else { WARN_PRINT_ONCE("`XDG_CACHE_HOME` is a relative path. Ignoring its value and falling back to `$HOME/.cache` or `get_config_path()` per the XDG Base Directory specification."); - return has_environment("HOME") ? get_environment("HOME").plus_file(".cache") : get_config_path(); + return has_environment("HOME") ? get_environment("HOME").path_join(".cache") : get_config_path(); } } else if (has_environment("HOME")) { - return get_environment("HOME").plus_file(".cache"); + return get_environment("HOME").path_join(".cache"); } else { return get_config_path(); } @@ -420,8 +519,6 @@ String OS_LinuxBSD::get_system_dir(SystemDir p_dir, bool p_shared_storage) const } void OS_LinuxBSD::run() { - force_quit = false; - if (!main_loop) { return; } @@ -433,7 +530,7 @@ void OS_LinuxBSD::run() { //int frames=0; //uint64_t frame=0; - while (!force_quit) { + while (true) { DisplayServer::get_singleton()->process_events(); // get rid of pending events #ifdef JOYDEV_ENABLED joypad->process_joypads(); @@ -589,10 +686,9 @@ Error OS_LinuxBSD::move_to_trash(const String &p_path) { String renamed_path = path.get_base_dir() + "/" + file_name; // Generates the .trashinfo file - OS::Date date = OS::get_singleton()->get_date(false); - OS::Time time = OS::get_singleton()->get_time(false); - String timestamp = vformat("%04d-%02d-%02dT%02d:%02d:", date.year, (int)date.month, date.day, time.hour, time.minute); - timestamp = vformat("%s%02d", timestamp, time.second); // vformat only supports up to 6 arguments. + OS::DateTime dt = OS::get_singleton()->get_datetime(false); + String timestamp = vformat("%04d-%02d-%02dT%02d:%02d:", dt.year, (int)dt.month, dt.day, dt.hour, dt.minute); + timestamp = vformat("%s%02d", timestamp, dt.second); // vformat only supports up to 6 arguments. String trash_info = "[Trash Info]\nPath=" + path.uri_encode() + "\nDeletionDate=" + timestamp + "\n"; { Error err; @@ -631,7 +727,6 @@ Error OS_LinuxBSD::move_to_trash(const String &p_path) { OS_LinuxBSD::OS_LinuxBSD() { main_loop = nullptr; - force_quit = false; #ifdef PULSEAUDIO_ENABLED AudioDriverManager::add_driver(&driver_pulseaudio); @@ -644,4 +739,13 @@ OS_LinuxBSD::OS_LinuxBSD() { #ifdef X11_ENABLED DisplayServerX11::register_x11_driver(); #endif + +#ifdef FONTCONFIG_ENABLED +#ifdef DEBUG_ENABLED + int dylibloader_verbose = 1; +#else + int dylibloader_verbose = 0; +#endif + font_config_initialized = (initialize_fontconfig(dylibloader_verbose) == 0); +#endif // FONTCONFIG_ENABLED } diff --git a/platform/linuxbsd/os_linuxbsd.h b/platform/linuxbsd/os_linuxbsd.h index 3f97b86eae..d5b2321316 100644 --- a/platform/linuxbsd/os_linuxbsd.h +++ b/platform/linuxbsd/os_linuxbsd.h @@ -43,7 +43,9 @@ class OS_LinuxBSD : public OS_Unix { virtual void delete_main_loop() override; - bool force_quit; +#ifdef FONTCONFIG_ENABLED + bool font_config_initialized = false; +#endif #ifdef JOYDEV_ENABLED JoypadLinux *joypad = nullptr; @@ -80,6 +82,9 @@ public: virtual uint64_t get_embedded_pck_offset() const override; + virtual Vector<String> get_system_fonts() const override; + virtual String get_system_font_path(const String &p_font_name, bool p_bold = false, bool p_italic = false) const override; + virtual String get_config_path() const override; virtual String get_data_path() const override; virtual String get_cache_path() const override; @@ -105,4 +110,4 @@ public: OS_LinuxBSD(); }; -#endif +#endif // OS_LINUXBSD_H diff --git a/platform/linuxbsd/vulkan_context_x11.h b/platform/linuxbsd/vulkan_context_x11.h index a89afa2eff..0c4a6cd278 100644 --- a/platform/linuxbsd/vulkan_context_x11.h +++ b/platform/linuxbsd/vulkan_context_x11.h @@ -28,8 +28,8 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ -#ifndef VULKAN_DEVICE_X11_H -#define VULKAN_DEVICE_X11_H +#ifndef VULKAN_CONTEXT_X11_H +#define VULKAN_CONTEXT_X11_H #include "drivers/vulkan/vulkan_context.h" #include <X11/Xlib.h> @@ -44,4 +44,4 @@ public: ~VulkanContextX11(); }; -#endif // VULKAN_DEVICE_X11_H +#endif // VULKAN_CONTEXT_X11_H diff --git a/platform/macos/README.md b/platform/macos/README.md new file mode 100644 index 0000000000..feead80736 --- /dev/null +++ b/platform/macos/README.md @@ -0,0 +1,19 @@ +# macOS platform port + +This folder contains the C++, Objective-C and Objective-C++ code for the macOS +platform port. + +See also [`misc/dist/macos`](/misc/dist/macos) folder for additional files used +by this platform. [`misc/dist/macos_tools.app`](/misc/dist/macos_tools.app) is +an `.app` bundle template used for packaging the macOS editor, while +[`misc/dist/macos_template.app`](/misc/dist/macos_template.app) is used for +packaging macOS export templates. + +## Documentation + +- [Compiling for macOS](https://docs.godotengine.org/en/latest/development/compiling/compiling_for_macos.html) + - Instructions on building this platform port from source. +- [Exporting for macOS](https://docs.godotengine.org/en/latest/tutorials/export/exporting_for_macos.html) + - Instructions on using the compiled export templates to export a project. +- [Running Godot apps on macOS](https://docs.godotengine.org/en/latest/tutorials/export/running_on_macos.html) + - Instructions on running Godot projects on macOS. diff --git a/platform/macos/SCsub b/platform/macos/SCsub new file mode 100644 index 0000000000..bbd461fba9 --- /dev/null +++ b/platform/macos/SCsub @@ -0,0 +1,32 @@ +#!/usr/bin/env python + +Import("env") + +from platform_methods import run_in_subprocess +import platform_macos_builders + +files = [ + "os_macos.mm", + "godot_application.mm", + "godot_application_delegate.mm", + "crash_handler_macos.mm", + "macos_terminal_logger.mm", + "display_server_macos.mm", + "godot_content_view.mm", + "godot_window_delegate.mm", + "godot_window.mm", + "key_mapping_macos.mm", + "godot_main_macos.mm", + "godot_menu_delegate.mm", + "godot_menu_item.mm", + "dir_access_macos.mm", + "tts_macos.mm", + "joypad_macos.cpp", + "vulkan_context_macos.mm", + "gl_manager_macos_legacy.mm", +] + +prog = env.add_program("#bin/godot", files) + +if env["debug_symbols"] and env["separate_debug_symbols"]: + env.AddPostAction(prog, run_in_subprocess(platform_macos_builders.make_debug_macos)) diff --git a/platform/osx/crash_handler_osx.h b/platform/macos/crash_handler_macos.h index 72938e5e0a..c9b0e77dc4 100644 --- a/platform/osx/crash_handler_osx.h +++ b/platform/macos/crash_handler_macos.h @@ -1,5 +1,5 @@ /*************************************************************************/ -/* crash_handler_osx.h */ +/* crash_handler_macos.h */ /*************************************************************************/ /* This file is part of: */ /* GODOT ENGINE */ @@ -28,8 +28,8 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ -#ifndef CRASH_HANDLER_OSX_H -#define CRASH_HANDLER_OSX_H +#ifndef CRASH_HANDLER_MACOS_H +#define CRASH_HANDLER_MACOS_H class CrashHandler { bool disabled; @@ -44,4 +44,4 @@ public: ~CrashHandler(); }; -#endif // CRASH_HANDLER_OSX_H +#endif // CRASH_HANDLER_MACOS_H diff --git a/platform/osx/crash_handler_osx.mm b/platform/macos/crash_handler_macos.mm index a798ba3b46..74bd012f0c 100644 --- a/platform/osx/crash_handler_osx.mm +++ b/platform/macos/crash_handler_macos.mm @@ -1,5 +1,5 @@ /*************************************************************************/ -/* crash_handler_osx.mm */ +/* crash_handler_macos.mm */ /*************************************************************************/ /* This file is part of: */ /* GODOT ENGINE */ @@ -28,7 +28,7 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ -#include "crash_handler_osx.h" +#include "crash_handler_macos.h" #include "core/config/project_settings.h" #include "core/os/os.h" diff --git a/platform/osx/detect.py b/platform/macos/detect.py index 47765cff71..bcf4776609 100644 --- a/platform/osx/detect.py +++ b/platform/macos/detect.py @@ -1,6 +1,7 @@ import os import sys from methods import detect_darwin_sdk_path +from platform_methods import detect_arch def is_active(): @@ -8,7 +9,7 @@ def is_active(): def get_name(): - return "OSX" + return "macOS" def can_build(): @@ -37,7 +38,11 @@ def get_opts(): def get_flags(): return [ + ("arch", detect_arch()), ("use_volk", False), + # Benefits of LTO for macOS (size, performance) haven't been clearly established yet. + # So for now we override the default value which may be set when using `production=yes`. + ("lto", "none"), ] @@ -52,11 +57,13 @@ def get_mvk_sdk_path(): return [int_or_zero(i) for i in a.split(".")] dirname = os.path.expanduser("~/VulkanSDK") - files = os.listdir(dirname) + if not os.path.exists(dirname): + return "" ver_file = "0.0.0.0" ver_num = ver_parse(ver_file) + files = os.listdir(dirname) for file in files: if os.path.isdir(os.path.join(dirname, file)): ver_comp = ver_parse(file) @@ -71,6 +78,15 @@ def get_mvk_sdk_path(): def configure(env): + # Validate arch. + supported_arches = ["x86_64", "arm64"] + if env["arch"] not in supported_arches: + print( + 'Unsupported CPU architecture "%s" for macOS. Supported architectures are: %s.' + % (env["arch"], ", ".join(supported_arches)) + ) + sys.exit() + ## Build type if env["target"] == "release": @@ -96,25 +112,20 @@ def configure(env): env.Prepend(CCFLAGS=["-g3"]) env.Prepend(LINKFLAGS=["-Xlinker", "-no_deduplicate"]) - ## Architecture - - # Mac OS X no longer runs on 32-bit since 10.7 which is unsupported since 2014 - # As such, we only support 64-bit - env["bits"] = "64" - ## Compiler configuration # Save this in environment for use by other modules if "OSXCROSS_ROOT" in os.environ: env["osxcross"] = True + # CPU architecture. if env["arch"] == "arm64": - print("Building for macOS 11.0+, platform arm64.") + print("Building for macOS 11.0+.") env.Append(ASFLAGS=["-arch", "arm64", "-mmacosx-version-min=11.0"]) env.Append(CCFLAGS=["-arch", "arm64", "-mmacosx-version-min=11.0"]) env.Append(LINKFLAGS=["-arch", "arm64", "-mmacosx-version-min=11.0"]) - else: - print("Building for macOS 10.12+, platform x86_64.") + elif env["arch"] == "x86_64": + print("Building for macOS 10.12+.") env.Append(ASFLAGS=["-arch", "x86_64", "-mmacosx-version-min=10.12"]) env.Append(CCFLAGS=["-arch", "x86_64", "-mmacosx-version-min=10.12"]) env.Append(LINKFLAGS=["-arch", "x86_64", "-mmacosx-version-min=10.12"]) @@ -134,12 +145,12 @@ def configure(env): env["CC"] = "clang" env["CXX"] = "clang++" - detect_darwin_sdk_path("osx", env) + detect_darwin_sdk_path("macos", env) env.Append(CCFLAGS=["-isysroot", "$MACOS_SDK_PATH"]) env.Append(LINKFLAGS=["-isysroot", "$MACOS_SDK_PATH"]) else: # osxcross build - root = os.environ.get("OSXCROSS_ROOT", 0) + root = os.environ.get("OSXCROSS_ROOT", "") if env["arch"] == "arm64": basecmd = root + "/target/bin/arm64-apple-" + env["osxcross_sdk"] + "-" else: @@ -158,6 +169,15 @@ def configure(env): env["RANLIB"] = basecmd + "ranlib" env["AS"] = basecmd + "as" + # LTO + if env["lto"] != "none": + if env["lto"] == "thin": + env.Append(CCFLAGS=["-flto=thin"]) + env.Append(LINKFLAGS=["-flto=thin"]) + else: + env.Append(CCFLAGS=["-flto"]) + env.Append(LINKFLAGS=["-flto"]) + if env["use_ubsan"] or env["use_asan"] or env["use_tsan"]: env.extra_suffix += ".san" env.Append(CCFLAGS=["-DSANITIZERS_ENABLED"]) @@ -185,14 +205,13 @@ def configure(env): ## Dependencies - if env["builtin_libtheora"]: - if env["arch"] != "arm64": - env["x86_libtheora_opt_gcc"] = True + if env["builtin_libtheora"] and env["arch"] == "x86_64": + env["x86_libtheora_opt_gcc"] = True ## Flags - env.Prepend(CPPPATH=["#platform/osx"]) - env.Append(CPPDEFINES=["OSX_ENABLED", "UNIX_ENABLED", "APPLE_STYLE_KEYS", "COREAUDIO_ENABLED", "COREMIDI_ENABLED"]) + env.Prepend(CPPPATH=["#platform/macos"]) + env.Append(CPPDEFINES=["MACOS_ENABLED", "UNIX_ENABLED", "COREAUDIO_ENABLED", "COREMIDI_ENABLED"]) env.Append( LINKFLAGS=[ "-framework", @@ -241,7 +260,7 @@ def configure(env): env.Append(LINKFLAGS=["-L" + mvk_path]) if not mvk_found: mvk_path = get_mvk_sdk_path() - if os.path.isfile(os.path.join(mvk_path, "libMoltenVK.a")): + if mvk_path and os.path.isfile(os.path.join(mvk_path, "libMoltenVK.a")): mvk_found = True env.Append(LINKFLAGS=["-L" + mvk_path]) if not mvk_found: diff --git a/platform/osx/dir_access_osx.h b/platform/macos/dir_access_macos.h index 3c66c81d4f..920e69ef3e 100644 --- a/platform/osx/dir_access_osx.h +++ b/platform/macos/dir_access_macos.h @@ -1,5 +1,5 @@ /*************************************************************************/ -/* dir_access_osx.h */ +/* dir_access_macos.h */ /*************************************************************************/ /* This file is part of: */ /* GODOT ENGINE */ @@ -28,8 +28,8 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ -#ifndef DIR_ACCESS_OSX_H -#define DIR_ACCESS_OSX_H +#ifndef DIR_ACCESS_MACOS_H +#define DIR_ACCESS_MACOS_H #if defined(UNIX_ENABLED) || defined(LIBC_FILEIO_ENABLED) @@ -41,15 +41,16 @@ #include "core/io/dir_access.h" #include "drivers/unix/dir_access_unix.h" -class DirAccessOSX : public DirAccessUnix { +class DirAccessMacOS : public DirAccessUnix { protected: - virtual String fix_unicode_name(const char *p_name) const; + virtual String fix_unicode_name(const char *p_name) const override; - virtual int get_drive_count(); - virtual String get_drive(int p_drive); + virtual int get_drive_count() override; + virtual String get_drive(int p_drive) override; - virtual bool is_hidden(const String &p_name); + virtual bool is_hidden(const String &p_name) override; }; -#endif //UNIX ENABLED -#endif +#endif // UNIX ENABLED || LIBC_FILEIO_ENABLED + +#endif // DIR_ACCESS_MACOS_H diff --git a/platform/osx/dir_access_osx.mm b/platform/macos/dir_access_macos.mm index 6bafb9470d..3373cada1f 100644 --- a/platform/osx/dir_access_osx.mm +++ b/platform/macos/dir_access_macos.mm @@ -1,5 +1,5 @@ /*************************************************************************/ -/* dir_access_osx.mm */ +/* dir_access_macos.mm */ /*************************************************************************/ /* This file is part of: */ /* GODOT ENGINE */ @@ -28,7 +28,7 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ -#include "dir_access_osx.h" +#include "dir_access_macos.h" #if defined(UNIX_ENABLED) || defined(LIBC_FILEIO_ENABLED) @@ -37,7 +37,7 @@ #import <AppKit/NSWorkspace.h> #import <Foundation/Foundation.h> -String DirAccessOSX::fix_unicode_name(const char *p_name) const { +String DirAccessMacOS::fix_unicode_name(const char *p_name) const { String fname; NSString *nsstr = [[NSString stringWithUTF8String:p_name] precomposedStringWithCanonicalMapping]; @@ -46,14 +46,14 @@ String DirAccessOSX::fix_unicode_name(const char *p_name) const { return fname; } -int DirAccessOSX::get_drive_count() { +int DirAccessMacOS::get_drive_count() { NSArray *res_keys = [NSArray arrayWithObjects:NSURLVolumeURLKey, NSURLIsSystemImmutableKey, nil]; NSArray *vols = [[NSFileManager defaultManager] mountedVolumeURLsIncludingResourceValuesForKeys:res_keys options:NSVolumeEnumerationSkipHiddenVolumes]; return [vols count]; } -String DirAccessOSX::get_drive(int p_drive) { +String DirAccessMacOS::get_drive(int p_drive) { NSArray *res_keys = [NSArray arrayWithObjects:NSURLVolumeURLKey, NSURLIsSystemImmutableKey, nil]; NSArray *vols = [[NSFileManager defaultManager] mountedVolumeURLsIncludingResourceValuesForKeys:res_keys options:NSVolumeEnumerationSkipHiddenVolumes]; int count = [vols count]; @@ -68,8 +68,8 @@ String DirAccessOSX::get_drive(int p_drive) { return volname; } -bool DirAccessOSX::is_hidden(const String &p_name) { - String f = get_current_dir().plus_file(p_name); +bool DirAccessMacOS::is_hidden(const String &p_name) { + String f = get_current_dir().path_join(p_name); NSURL *url = [NSURL fileURLWithPath:@(f.utf8().get_data())]; NSNumber *hidden = nil; if (![url getResourceValue:&hidden forKey:NSURLIsHiddenKey error:nil]) { @@ -78,4 +78,4 @@ bool DirAccessOSX::is_hidden(const String &p_name) { return [hidden boolValue]; } -#endif //posix_enabled +#endif // UNIX_ENABLED || LIBC_FILEIO_ENABLED diff --git a/platform/osx/display_server_osx.h b/platform/macos/display_server_macos.h index 9575cb29a2..769cba2de5 100644 --- a/platform/osx/display_server_osx.h +++ b/platform/macos/display_server_macos.h @@ -1,5 +1,5 @@ /*************************************************************************/ -/* display_server_osx.h */ +/* display_server_macos.h */ /*************************************************************************/ /* This file is part of: */ /* GODOT ENGINE */ @@ -28,8 +28,8 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ -#ifndef DISPLAY_SERVER_OSX_H -#define DISPLAY_SERVER_OSX_H +#ifndef DISPLAY_SERVER_MACOS_H +#define DISPLAY_SERVER_MACOS_H #define BitMap _QDBitMap // Suppress deprecated QuickDraw definition. @@ -37,12 +37,12 @@ #include "servers/display_server.h" #if defined(GLES3_ENABLED) -#include "gl_manager_osx_legacy.h" +#include "gl_manager_macos_legacy.h" #endif // GLES3_ENABLED #if defined(VULKAN_ENABLED) #include "drivers/vulkan/rendering_device_vulkan.h" -#include "platform/osx/vulkan_context_osx.h" +#include "platform/macos/vulkan_context_macos.h" #endif // VULKAN_ENABLED #import <AppKit/AppKit.h> @@ -50,19 +50,20 @@ #import <ApplicationServices/ApplicationServices.h> #import <CoreVideo/CoreVideo.h> #import <Foundation/Foundation.h> +#import <IOKit/pwr_mgt/IOPMLib.h> #undef BitMap #undef CursorShape -class DisplayServerOSX : public DisplayServer { - GDCLASS(DisplayServerOSX, DisplayServer) +class DisplayServerMacOS : public DisplayServer { + GDCLASS(DisplayServerMacOS, DisplayServer) _THREAD_SAFE_CLASS_ public: struct KeyEvent { WindowID window_id = INVALID_WINDOW_ID; - unsigned int osx_state = false; + unsigned int macos_state = false; bool pressed = false; bool echo = false; bool raw = false; @@ -115,10 +116,10 @@ public: private: #if defined(GLES3_ENABLED) - GLManager_OSX *gl_manager = nullptr; + GLManager_MacOS *gl_manager = nullptr; #endif #if defined(VULKAN_ENABLED) - VulkanContextOSX *context_vulkan = nullptr; + VulkanContextMacOS *context_vulkan = nullptr; RenderingDeviceVulkan *rendering_device_vulkan = nullptr; #endif String rendering_driver; @@ -139,6 +140,7 @@ private: int key_event_pos = 0; id tts = nullptr; + id menu_delegate = nullptr; Point2i im_selection; String im_text; @@ -171,6 +173,8 @@ private: HashMap<WindowID, WindowData> windows; + IOPMAssertionID screen_keep_on_assertion = kIOPMNullAssertionID; + const NSMenu *_get_menu_root(const String &p_menu_root) const; NSMenu *_get_menu_root(const String &p_menu_root); @@ -193,6 +197,9 @@ private: static NSCursor *_cursor_from_selector(SEL p_selector, SEL p_fallback = nil); + bool _has_help_menu() const; + NSMenuItem *_menu_add_item(const String &p_menu_root, const String &p_label, Key p_accel, int p_index, int *r_out); + public: NSMenu *get_dock_menu() const; void menu_callback(id p_sender); @@ -203,7 +210,7 @@ public: void send_event(NSEvent *p_event); void send_window_event(const WindowData &p_wd, WindowEvent p_event); void release_pressed_events(); - void get_key_modifier_state(unsigned int p_osx_state, Ref<InputEventWithModifiers> r_state) const; + void get_key_modifier_state(unsigned int p_macos_state, Ref<InputEventWithModifiers> r_state) const; void update_mouse_pos(WindowData &p_wd, NSPoint p_location_in_window); void push_to_key_event_buffer(const KeyEvent &p_event); void update_im_text(const Point2i &p_selection, const String &p_text); @@ -221,15 +228,15 @@ public: virtual bool has_feature(Feature p_feature) const override; virtual String get_name() const override; - virtual void global_menu_add_item(const String &p_menu_root, const String &p_label, const Callable &p_callback = Callable(), const Variant &p_tag = Variant(), Key p_accel = Key::NONE, int p_index = -1) override; - virtual void global_menu_add_check_item(const String &p_menu_root, const String &p_label, const Callable &p_callback = Callable(), const Variant &p_tag = Variant(), Key p_accel = Key::NONE, int p_index = -1) override; - virtual void global_menu_add_icon_item(const String &p_menu_root, const Ref<Texture2D> &p_icon, const String &p_label, const Callable &p_callback = Callable(), const Variant &p_tag = Variant(), Key p_accel = Key::NONE, int p_index = -1) override; - virtual void global_menu_add_icon_check_item(const String &p_menu_root, const Ref<Texture2D> &p_icon, const String &p_label, const Callable &p_callback = Callable(), const Variant &p_tag = Variant(), Key p_accel = Key::NONE, int p_index = -1) override; - virtual void global_menu_add_radio_check_item(const String &p_menu_root, const String &p_label, const Callable &p_callback = Callable(), const Variant &p_tag = Variant(), Key p_accel = Key::NONE, int p_index = -1) override; - virtual void global_menu_add_icon_radio_check_item(const String &p_menu_root, const Ref<Texture2D> &p_icon, const String &p_label, const Callable &p_callback = Callable(), const Variant &p_tag = Variant(), Key p_accel = Key::NONE, int p_index = -1) override; - virtual void global_menu_add_multistate_item(const String &p_menu_root, const String &p_label, int p_max_states, int p_default_state, const Callable &p_callback = Callable(), const Variant &p_tag = Variant(), Key p_accel = Key::NONE, int p_index = -1) override; - virtual void global_menu_add_submenu_item(const String &p_menu_root, const String &p_label, const String &p_submenu, int p_index = -1) override; - virtual void global_menu_add_separator(const String &p_menu_root, int p_index = -1) override; + virtual int global_menu_add_submenu_item(const String &p_menu_root, const String &p_label, const String &p_submenu, int p_index = -1) override; + virtual int global_menu_add_item(const String &p_menu_root, const String &p_label, const Callable &p_callback = Callable(), const Callable &p_key_callback = Callable(), const Variant &p_tag = Variant(), Key p_accel = Key::NONE, int p_index = -1) override; + virtual int global_menu_add_check_item(const String &p_menu_root, const String &p_label, const Callable &p_callback = Callable(), const Callable &p_key_callback = Callable(), const Variant &p_tag = Variant(), Key p_accel = Key::NONE, int p_index = -1) override; + virtual int global_menu_add_icon_item(const String &p_menu_root, const Ref<Texture2D> &p_icon, const String &p_label, const Callable &p_callback = Callable(), const Callable &p_key_callback = Callable(), const Variant &p_tag = Variant(), Key p_accel = Key::NONE, int p_index = -1) override; + virtual int global_menu_add_icon_check_item(const String &p_menu_root, const Ref<Texture2D> &p_icon, const String &p_label, const Callable &p_callback = Callable(), const Callable &p_key_callback = Callable(), const Variant &p_tag = Variant(), Key p_accel = Key::NONE, int p_index = -1) override; + virtual int global_menu_add_radio_check_item(const String &p_menu_root, const String &p_label, const Callable &p_callback = Callable(), const Callable &p_key_callback = Callable(), const Variant &p_tag = Variant(), Key p_accel = Key::NONE, int p_index = -1) override; + virtual int global_menu_add_icon_radio_check_item(const String &p_menu_root, const Ref<Texture2D> &p_icon, const String &p_label, const Callable &p_callback = Callable(), const Callable &p_key_callback = Callable(), const Variant &p_tag = Variant(), Key p_accel = Key::NONE, int p_index = -1) override; + virtual int global_menu_add_multistate_item(const String &p_menu_root, const String &p_label, int p_max_states, int p_default_state, const Callable &p_callback = Callable(), const Callable &p_key_callback = Callable(), const Variant &p_tag = Variant(), Key p_accel = Key::NONE, int p_index = -1) override; + virtual int global_menu_add_separator(const String &p_menu_root, int p_index = -1) override; virtual int global_menu_get_item_index_from_text(const String &p_menu_root, const String &p_text) const override; virtual int global_menu_get_item_index_from_tag(const String &p_menu_root, const Variant &p_tag) const override; @@ -238,6 +245,7 @@ public: virtual bool global_menu_is_item_checkable(const String &p_menu_root, int p_idx) const override; virtual bool global_menu_is_item_radio_checkable(const String &p_menu_root, int p_idx) const override; virtual Callable global_menu_get_item_callback(const String &p_menu_root, int p_idx) const override; + virtual Callable global_menu_get_item_key_callback(const String &p_menu_root, int p_idx) const override; virtual Variant global_menu_get_item_tag(const String &p_menu_root, int p_idx) const override; virtual String global_menu_get_item_text(const String &p_menu_root, int p_idx) const override; virtual String global_menu_get_item_submenu(const String &p_menu_root, int p_idx) const override; @@ -247,11 +255,13 @@ public: virtual int global_menu_get_item_state(const String &p_menu_root, int p_idx) const override; virtual int global_menu_get_item_max_states(const String &p_menu_root, int p_idx) const override; virtual Ref<Texture2D> global_menu_get_item_icon(const String &p_menu_root, int p_idx) const override; + virtual int global_menu_get_item_indentation_level(const String &p_menu_root, int p_idx) const override; virtual void global_menu_set_item_checked(const String &p_menu_root, int p_idx, bool p_checked) override; virtual void global_menu_set_item_checkable(const String &p_menu_root, int p_idx, bool p_checkable) override; virtual void global_menu_set_item_radio_checkable(const String &p_menu_root, int p_idx, bool p_checkable) override; virtual void global_menu_set_item_callback(const String &p_menu_root, int p_idx, const Callable &p_callback) override; + virtual void global_menu_set_item_key_callback(const String &p_menu_root, int p_idx, const Callable &p_key_callback) override; virtual void global_menu_set_item_tag(const String &p_menu_root, int p_idx, const Variant &p_tag) override; virtual void global_menu_set_item_text(const String &p_menu_root, int p_idx, const String &p_text) override; virtual void global_menu_set_item_submenu(const String &p_menu_root, int p_idx, const String &p_submenu) override; @@ -261,6 +271,7 @@ public: virtual void global_menu_set_item_state(const String &p_menu_root, int p_idx, int p_state) override; virtual void global_menu_set_item_max_states(const String &p_menu_root, int p_idx, int p_max_states) override; virtual void global_menu_set_item_icon(const String &p_menu_root, int p_idx, const Ref<Texture2D> &p_icon) override; + virtual void global_menu_set_item_indentation_level(const String &p_menu_root, int p_idx, int p_level) override; virtual int global_menu_get_item_count(const String &p_menu_root) const override; @@ -269,13 +280,17 @@ public: virtual bool tts_is_speaking() const override; virtual bool tts_is_paused() const override; - virtual Array tts_get_voices() const override; + virtual TypedArray<Dictionary> tts_get_voices() const override; virtual void tts_speak(const String &p_text, const String &p_voice, int p_volume = 50, float p_pitch = 1.f, float p_rate = 1.f, int p_utterance_id = 0, bool p_interrupt = false) override; virtual void tts_pause() override; virtual void tts_resume() override; virtual void tts_stop() override; + virtual bool is_dark_mode_supported() const override; + virtual bool is_dark_mode() const override; + virtual Color get_accent_color() const override; + virtual Error dialog_show(String p_title, String p_description, Vector<String> p_buttons, const Callable &p_callback) override; virtual Error dialog_input_text(String p_title, String p_description, String p_partial, const Callable &p_callback) override; @@ -299,6 +314,8 @@ public: virtual float screen_get_max_scale() const override; virtual Rect2i screen_get_usable_rect(int p_screen = SCREEN_OF_MAIN_WINDOW) const override; virtual float screen_get_refresh_rate(int p_screen = SCREEN_OF_MAIN_WINDOW) const override; + virtual void screen_set_keep_on(bool p_enable) override; + virtual bool screen_is_kept_on() const override; virtual Vector<int> get_window_list() const override; @@ -367,6 +384,11 @@ public: virtual void window_set_vsync_mode(DisplayServer::VSyncMode p_vsync_mode, WindowID p_window = MAIN_WINDOW_ID) override; virtual DisplayServer::VSyncMode window_get_vsync_mode(WindowID p_vsync_mode) const override; + virtual bool window_maximize_on_title_dbl_click() const override; + virtual bool window_minimize_on_title_dbl_click() const override; + + virtual Vector2i window_get_safe_title_margins(WindowID p_window = MAIN_WINDOW_ID) const override; + virtual Point2i ime_get_selection() const override; virtual String ime_get_text() const override; @@ -397,10 +419,10 @@ public: static DisplayServer *create_func(const String &p_rendering_driver, WindowMode p_mode, VSyncMode p_vsync_mode, uint32_t p_flags, const Vector2i &p_resolution, Error &r_error); static Vector<String> get_rendering_drivers_func(); - static void register_osx_driver(); + static void register_macos_driver(); - DisplayServerOSX(const String &p_rendering_driver, WindowMode p_mode, VSyncMode p_vsync_mode, uint32_t p_flags, const Vector2i &p_resolution, Error &r_error); - ~DisplayServerOSX(); + DisplayServerMacOS(const String &p_rendering_driver, WindowMode p_mode, VSyncMode p_vsync_mode, uint32_t p_flags, const Vector2i &p_resolution, Error &r_error); + ~DisplayServerMacOS(); }; -#endif // DISPLAY_SERVER_OSX_H +#endif // DISPLAY_SERVER_MACOS_H diff --git a/platform/osx/display_server_osx.mm b/platform/macos/display_server_macos.mm index 91d64b50f0..91c6da5d13 100644 --- a/platform/osx/display_server_osx.mm +++ b/platform/macos/display_server_macos.mm @@ -1,5 +1,5 @@ /*************************************************************************/ -/* display_server_osx.mm */ +/* display_server_macos.mm */ /*************************************************************************/ /* This file is part of: */ /* GODOT ENGINE */ @@ -28,17 +28,19 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ -#include "display_server_osx.h" +#include "display_server_macos.h" #include "godot_content_view.h" +#include "godot_menu_delegate.h" #include "godot_menu_item.h" #include "godot_window.h" #include "godot_window_delegate.h" -#include "key_mapping_osx.h" -#include "os_osx.h" +#include "key_mapping_macos.h" +#include "os_macos.h" -#include "tts_osx.h" +#include "tts_macos.h" +#include "core/config/project_settings.h" #include "core/io/marshalls.h" #include "core/math/geometry_2d.h" #include "core/os/keyboard.h" @@ -60,9 +62,9 @@ #include "servers/rendering/renderer_rd/renderer_compositor_rd.h" #endif -const NSMenu *DisplayServerOSX::_get_menu_root(const String &p_menu_root) const { +const NSMenu *DisplayServerMacOS::_get_menu_root(const String &p_menu_root) const { const NSMenu *menu = nullptr; - if (p_menu_root == "") { + if (p_menu_root == "" || p_menu_root.to_lower() == "_main") { // Main menu. menu = [NSApp mainMenu]; } else if (p_menu_root.to_lower() == "_dock") { @@ -81,9 +83,9 @@ const NSMenu *DisplayServerOSX::_get_menu_root(const String &p_menu_root) const return menu; } -NSMenu *DisplayServerOSX::_get_menu_root(const String &p_menu_root) { +NSMenu *DisplayServerMacOS::_get_menu_root(const String &p_menu_root) { NSMenu *menu = nullptr; - if (p_menu_root == "") { + if (p_menu_root == "" || p_menu_root.to_lower() == "_main") { // Main menu. menu = [NSApp mainMenu]; } else if (p_menu_root.to_lower() == "_dock") { @@ -94,6 +96,7 @@ NSMenu *DisplayServerOSX::_get_menu_root(const String &p_menu_root) { if (!submenu.has(p_menu_root)) { NSMenu *n_menu = [[NSMenu alloc] initWithTitle:[NSString stringWithUTF8String:p_menu_root.utf8().get_data()]]; [n_menu setAutoenablesItems:NO]; + [n_menu setDelegate:menu_delegate]; submenu[p_menu_root] = n_menu; } menu = submenu[p_menu_root]; @@ -105,7 +108,7 @@ NSMenu *DisplayServerOSX::_get_menu_root(const String &p_menu_root) { return menu; } -DisplayServerOSX::WindowID DisplayServerOSX::_create_window(WindowMode p_mode, VSyncMode p_vsync_mode, const Rect2i &p_rect) { +DisplayServerMacOS::WindowID DisplayServerMacOS::_create_window(WindowMode p_mode, VSyncMode p_vsync_mode, const Rect2i &p_rect) { WindowID id; const float scale = screen_get_max_scale(); { @@ -163,6 +166,7 @@ DisplayServerOSX::WindowID DisplayServerOSX::_create_window(WindowMode p_mode, V ERR_FAIL_COND_V_MSG(err != OK, INVALID_WINDOW_ID, "Can't create an OpenGL context"); } #endif + [wd.window_view updateLayerDelegate]; id = window_id_counter++; windows[id] = wd; } @@ -193,7 +197,7 @@ DisplayServerOSX::WindowID DisplayServerOSX::_create_window(WindowMode p_mode, V return id; } -void DisplayServerOSX::_update_window_style(WindowData p_wd) { +void DisplayServerMacOS::_update_window_style(WindowData p_wd) { bool borderless_full = false; if (p_wd.borderless) { @@ -222,7 +226,7 @@ void DisplayServerOSX::_update_window_style(WindowData p_wd) { } } -void DisplayServerOSX::_set_window_per_pixel_transparency_enabled(bool p_enabled, WindowID p_window) { +void DisplayServerMacOS::_set_window_per_pixel_transparency_enabled(bool p_enabled, WindowID p_window) { ERR_FAIL_COND(!windows.has(p_window)); WindowData &wd = windows[p_window]; @@ -267,7 +271,7 @@ void DisplayServerOSX::_set_window_per_pixel_transparency_enabled(bool p_enabled } } -void DisplayServerOSX::_update_displays_arrangement() { +void DisplayServerMacOS::_update_displays_arrangement() { origin = Point2i(); for (int i = 0; i < get_screen_count(); i++) { @@ -282,20 +286,20 @@ void DisplayServerOSX::_update_displays_arrangement() { displays_arrangement_dirty = false; } -Point2i DisplayServerOSX::_get_screens_origin() const { +Point2i DisplayServerMacOS::_get_screens_origin() const { // Returns the native top-left screen coordinate of the smallest rectangle // that encompasses all screens. Needed in get_screen_position(), // window_get_position, and window_set_position() // to convert between OS X native screen coordinates and the ones expected by Godot. if (displays_arrangement_dirty) { - const_cast<DisplayServerOSX *>(this)->_update_displays_arrangement(); + const_cast<DisplayServerMacOS *>(this)->_update_displays_arrangement(); } return origin; } -Point2i DisplayServerOSX::_get_native_screen_position(int p_screen) const { +Point2i DisplayServerMacOS::_get_native_screen_position(int p_screen) const { NSArray *screenArray = [NSScreen screens]; if ((NSUInteger)p_screen < [screenArray count]) { NSRect nsrect = [[screenArray objectAtIndex:p_screen] frame]; @@ -306,18 +310,18 @@ Point2i DisplayServerOSX::_get_native_screen_position(int p_screen) const { return Point2i(); } -void DisplayServerOSX::_displays_arrangement_changed(CGDirectDisplayID display_id, CGDisplayChangeSummaryFlags flags, void *user_info) { - DisplayServerOSX *ds = (DisplayServerOSX *)DisplayServer::get_singleton(); +void DisplayServerMacOS::_displays_arrangement_changed(CGDirectDisplayID display_id, CGDisplayChangeSummaryFlags flags, void *user_info) { + DisplayServerMacOS *ds = (DisplayServerMacOS *)DisplayServer::get_singleton(); if (ds) { ds->displays_arrangement_dirty = true; } } -void DisplayServerOSX::_dispatch_input_events(const Ref<InputEvent> &p_event) { - ((DisplayServerOSX *)(get_singleton()))->_dispatch_input_event(p_event); +void DisplayServerMacOS::_dispatch_input_events(const Ref<InputEvent> &p_event) { + ((DisplayServerMacOS *)(get_singleton()))->_dispatch_input_event(p_event); } -void DisplayServerOSX::_dispatch_input_event(const Ref<InputEvent> &p_event) { +void DisplayServerMacOS::_dispatch_input_event(const Ref<InputEvent> &p_event) { _THREAD_SAFE_METHOD_ if (!in_dispatch_input_event) { in_dispatch_input_event = true; @@ -334,7 +338,7 @@ void DisplayServerOSX::_dispatch_input_event(const Ref<InputEvent> &p_event) { if (windows.has(E->get())) { Callable callable = windows[E->get()].input_event_callback; if (callable.is_valid()) { - callable.call((const Variant **)&evp, 1, ret, ce); + callable.callp((const Variant **)&evp, 1, ret, ce); } } in_dispatch_input_event = false; @@ -348,7 +352,7 @@ void DisplayServerOSX::_dispatch_input_event(const Ref<InputEvent> &p_event) { if (windows.has(event_from_window->get_window_id())) { Callable callable = windows[event_from_window->get_window_id()].input_event_callback; if (callable.is_valid()) { - callable.call((const Variant **)&evp, 1, ret, ce); + callable.callp((const Variant **)&evp, 1, ret, ce); } } } else { @@ -356,7 +360,7 @@ void DisplayServerOSX::_dispatch_input_event(const Ref<InputEvent> &p_event) { for (KeyValue<WindowID, WindowData> &E : windows) { Callable callable = E.value.input_event_callback; if (callable.is_valid()) { - callable.call((const Variant **)&evp, 1, ret, ce); + callable.callp((const Variant **)&evp, 1, ret, ce); } } } @@ -364,12 +368,12 @@ void DisplayServerOSX::_dispatch_input_event(const Ref<InputEvent> &p_event) { } } -void DisplayServerOSX::_push_input(const Ref<InputEvent> &p_event) { +void DisplayServerMacOS::_push_input(const Ref<InputEvent> &p_event) { Ref<InputEvent> ev = p_event; Input::get_singleton()->parse_input_event(ev); } -void DisplayServerOSX::_process_key_events() { +void DisplayServerMacOS::_process_key_events() { Ref<InputEventKey> k; for (int i = 0; i < key_event_pos; i++) { const KeyEvent &ke = key_event_buffer[i]; @@ -378,7 +382,7 @@ void DisplayServerOSX::_process_key_events() { k.instantiate(); k->set_window_id(ke.window_id); - get_key_modifier_state(ke.osx_state, k); + get_key_modifier_state(ke.macos_state, k); k->set_pressed(ke.pressed); k->set_echo(ke.echo); k->set_keycode(ke.keycode); @@ -392,7 +396,7 @@ void DisplayServerOSX::_process_key_events() { k.instantiate(); k->set_window_id(ke.window_id); - get_key_modifier_state(ke.osx_state, k); + get_key_modifier_state(ke.macos_state, k); k->set_pressed(ke.pressed); k->set_echo(ke.echo); k->set_keycode(Key::NONE); @@ -405,7 +409,7 @@ void DisplayServerOSX::_process_key_events() { k.instantiate(); k->set_window_id(ke.window_id); - get_key_modifier_state(ke.osx_state, k); + get_key_modifier_state(ke.macos_state, k); k->set_pressed(ke.pressed); k->set_echo(ke.echo); k->set_keycode(ke.keycode); @@ -423,7 +427,7 @@ void DisplayServerOSX::_process_key_events() { key_event_pos = 0; } -void DisplayServerOSX::_update_keyboard_layouts() { +void DisplayServerMacOS::_update_keyboard_layouts() { kbd_layouts.clear(); current_layout = 0; @@ -468,14 +472,14 @@ void DisplayServerOSX::_update_keyboard_layouts() { keyboard_layout_dirty = false; } -void DisplayServerOSX::_keyboard_layout_changed(CFNotificationCenterRef center, void *observer, CFStringRef name, const void *object, CFDictionaryRef user_info) { - DisplayServerOSX *ds = (DisplayServerOSX *)DisplayServer::get_singleton(); +void DisplayServerMacOS::_keyboard_layout_changed(CFNotificationCenterRef center, void *observer, CFStringRef name, const void *object, CFDictionaryRef user_info) { + DisplayServerMacOS *ds = (DisplayServerMacOS *)DisplayServer::get_singleton(); if (ds) { ds->keyboard_layout_dirty = true; } } -NSImage *DisplayServerOSX::_convert_to_nsimg(Ref<Image> &p_image) const { +NSImage *DisplayServerMacOS::_convert_to_nsimg(Ref<Image> &p_image) const { p_image->convert(Image::FORMAT_RGBA8); NSBitmapImageRep *imgrep = [[NSBitmapImageRep alloc] initWithBitmapDataPlanes:NULL @@ -509,7 +513,7 @@ NSImage *DisplayServerOSX::_convert_to_nsimg(Ref<Image> &p_image) const { return nsimg; } -NSCursor *DisplayServerOSX::_cursor_from_selector(SEL p_selector, SEL p_fallback) { +NSCursor *DisplayServerMacOS::_cursor_from_selector(SEL p_selector, SEL p_fallback) { if ([NSCursor respondsToSelector:p_selector]) { id object = [NSCursor performSelector:p_selector]; if ([object isKindOfClass:[NSCursor class]]) { @@ -523,11 +527,11 @@ NSCursor *DisplayServerOSX::_cursor_from_selector(SEL p_selector, SEL p_fallback return [NSCursor arrowCursor]; } -NSMenu *DisplayServerOSX::get_dock_menu() const { +NSMenu *DisplayServerMacOS::get_dock_menu() const { return dock_menu; } -void DisplayServerOSX::menu_callback(id p_sender) { +void DisplayServerMacOS::menu_callback(id p_sender) { if (![p_sender representedObject]) { return; } @@ -555,20 +559,20 @@ void DisplayServerOSX::menu_callback(id p_sender) { Variant *tagp = &tag; Variant ret; Callable::CallError ce; - value->callback.call((const Variant **)&tagp, 1, ret, ce); + value->callback.callp((const Variant **)&tagp, 1, ret, ce); } } } -bool DisplayServerOSX::has_window(WindowID p_window) const { +bool DisplayServerMacOS::has_window(WindowID p_window) const { return windows.has(p_window); } -DisplayServerOSX::WindowData &DisplayServerOSX::get_window(WindowID p_window) { +DisplayServerMacOS::WindowData &DisplayServerMacOS::get_window(WindowID p_window) { return windows[p_window]; } -void DisplayServerOSX::send_event(NSEvent *p_event) { +void DisplayServerMacOS::send_event(NSEvent *p_event) { // Special case handling of command-period, which is traditionally a special // shortcut in macOS and doesn't arrive at our regular keyDown handler. if ([p_event type] == NSEventTypeKeyDown) { @@ -577,7 +581,7 @@ void DisplayServerOSX::send_event(NSEvent *p_event) { k.instantiate(); get_key_modifier_state([p_event modifierFlags], k); - k->set_window_id(DisplayServerOSX::INVALID_WINDOW_ID); + k->set_window_id(DisplayServerMacOS::INVALID_WINDOW_ID); k->set_pressed(true); k->set_keycode(Key::PERIOD); k->set_physical_keycode(Key::PERIOD); @@ -588,7 +592,7 @@ void DisplayServerOSX::send_event(NSEvent *p_event) { } } -void DisplayServerOSX::send_window_event(const WindowData &wd, WindowEvent p_event) { +void DisplayServerMacOS::send_window_event(const WindowData &wd, WindowEvent p_event) { _THREAD_SAFE_METHOD_ if (!wd.event_callback.is_null()) { @@ -596,25 +600,25 @@ void DisplayServerOSX::send_window_event(const WindowData &wd, WindowEvent p_eve Variant *eventp = &event; Variant ret; Callable::CallError ce; - wd.event_callback.call((const Variant **)&eventp, 1, ret, ce); + wd.event_callback.callp((const Variant **)&eventp, 1, ret, ce); } } -void DisplayServerOSX::release_pressed_events() { +void DisplayServerMacOS::release_pressed_events() { _THREAD_SAFE_METHOD_ if (Input::get_singleton()) { Input::get_singleton()->release_pressed_events(); } } -void DisplayServerOSX::get_key_modifier_state(unsigned int p_osx_state, Ref<InputEventWithModifiers> r_state) const { - r_state->set_shift_pressed((p_osx_state & NSEventModifierFlagShift)); - r_state->set_ctrl_pressed((p_osx_state & NSEventModifierFlagControl)); - r_state->set_alt_pressed((p_osx_state & NSEventModifierFlagOption)); - r_state->set_meta_pressed((p_osx_state & NSEventModifierFlagCommand)); +void DisplayServerMacOS::get_key_modifier_state(unsigned int p_macos_state, Ref<InputEventWithModifiers> r_state) const { + r_state->set_shift_pressed((p_macos_state & NSEventModifierFlagShift)); + r_state->set_ctrl_pressed((p_macos_state & NSEventModifierFlagControl)); + r_state->set_alt_pressed((p_macos_state & NSEventModifierFlagOption)); + r_state->set_meta_pressed((p_macos_state & NSEventModifierFlagCommand)); } -void DisplayServerOSX::update_mouse_pos(DisplayServerOSX::WindowData &p_wd, NSPoint p_location_in_window) { +void DisplayServerMacOS::update_mouse_pos(DisplayServerMacOS::WindowData &p_wd, NSPoint p_location_in_window) { const NSRect content_rect = [p_wd.window_view frame]; const float scale = screen_get_max_scale(); p_wd.mouse_pos.x = p_location_in_window.x * scale; @@ -622,33 +626,33 @@ void DisplayServerOSX::update_mouse_pos(DisplayServerOSX::WindowData &p_wd, NSPo Input::get_singleton()->set_mouse_position(p_wd.mouse_pos); } -void DisplayServerOSX::push_to_key_event_buffer(const DisplayServerOSX::KeyEvent &p_event) { +void DisplayServerMacOS::push_to_key_event_buffer(const DisplayServerMacOS::KeyEvent &p_event) { if (key_event_pos >= key_event_buffer.size()) { key_event_buffer.resize(1 + key_event_pos); } key_event_buffer.write[key_event_pos++] = p_event; } -void DisplayServerOSX::update_im_text(const Point2i &p_selection, const String &p_text) { +void DisplayServerMacOS::update_im_text(const Point2i &p_selection, const String &p_text) { im_selection = p_selection; im_text = p_text; OS::get_singleton()->get_main_loop()->notification(MainLoop::NOTIFICATION_OS_IME_UPDATE); } -void DisplayServerOSX::set_last_focused_window(WindowID p_window) { +void DisplayServerMacOS::set_last_focused_window(WindowID p_window) { last_focused_window = p_window; } -void DisplayServerOSX::set_is_resizing(bool p_is_resizing) { +void DisplayServerMacOS::set_is_resizing(bool p_is_resizing) { is_resizing = p_is_resizing; } -bool DisplayServerOSX::get_is_resizing() const { +bool DisplayServerMacOS::get_is_resizing() const { return is_resizing; } -void DisplayServerOSX::window_update(WindowID p_window) { +void DisplayServerMacOS::window_update(WindowID p_window) { #if defined(GLES3_ENABLED) if (gl_manager) { gl_manager->window_update(p_window); @@ -656,7 +660,7 @@ void DisplayServerOSX::window_update(WindowID p_window) { #endif } -void DisplayServerOSX::window_destroy(WindowID p_window) { +void DisplayServerMacOS::window_destroy(WindowID p_window) { #if defined(GLES3_ENABLED) if (gl_manager) { gl_manager->window_destroy(p_window); @@ -670,7 +674,7 @@ void DisplayServerOSX::window_destroy(WindowID p_window) { windows.erase(p_window); } -void DisplayServerOSX::window_resize(WindowID p_window, int p_width, int p_height) { +void DisplayServerMacOS::window_resize(WindowID p_window, int p_width, int p_height) { #if defined(GLES3_ENABLED) if (gl_manager) { gl_manager->window_resize(p_window, p_width, p_height); @@ -683,7 +687,7 @@ void DisplayServerOSX::window_resize(WindowID p_window, int p_width, int p_heigh #endif } -bool DisplayServerOSX::has_feature(Feature p_feature) const { +bool DisplayServerMacOS::has_feature(Feature p_feature) const { switch (p_feature) { case FEATURE_GLOBAL_MENU: case FEATURE_SUBWINDOWS: @@ -702,6 +706,7 @@ bool DisplayServerOSX::has_feature(Feature p_feature) const { //case FEATURE_KEEP_SCREEN_ON: case FEATURE_SWAP_BUFFERS: case FEATURE_TEXT_TO_SPEECH: + case FEATURE_EXTEND_TO_TITLE: return true; default: { } @@ -709,70 +714,96 @@ bool DisplayServerOSX::has_feature(Feature p_feature) const { return false; } -String DisplayServerOSX::get_name() const { - return "OSX"; +String DisplayServerMacOS::get_name() const { + return "macOS"; } -void DisplayServerOSX::global_menu_add_item(const String &p_menu_root, const String &p_label, const Callable &p_callback, const Variant &p_tag, Key p_accel, int p_index) { - _THREAD_SAFE_METHOD_ +bool DisplayServerMacOS::_has_help_menu() const { + if ([NSApp helpMenu]) { + return true; + } else { + NSMenu *menu = [NSApp mainMenu]; + const NSMenuItem *menu_item = [menu itemAtIndex:[menu numberOfItems] - 1]; + if (menu_item) { + String menu_name = String::utf8([[menu_item title] UTF8String]); + if (menu_name == "Help" || menu_name == RTR("Help")) { + return true; + } + } + return false; + } +} +NSMenuItem *DisplayServerMacOS::_menu_add_item(const String &p_menu_root, const String &p_label, Key p_accel, int p_index, int *r_out) { NSMenu *menu = _get_menu_root(p_menu_root); if (menu) { - String keycode = KeyMappingOSX::keycode_get_native_string(p_accel & KeyModifierMask::CODE_MASK); + String keycode = KeyMappingMacOS::keycode_get_native_string(p_accel & KeyModifierMask::CODE_MASK); NSMenuItem *menu_item; - if (p_index != -1) { - menu_item = [menu insertItemWithTitle:[NSString stringWithUTF8String:p_label.utf8().get_data()] action:@selector(globalMenuCallback:) keyEquivalent:[NSString stringWithUTF8String:keycode.utf8().get_data()] atIndex:p_index]; + int item_count = ((menu == [NSApp mainMenu]) && _has_help_menu()) ? [menu numberOfItems] - 1 : [menu numberOfItems]; + if ((menu == [NSApp mainMenu]) && (p_label == "Help" || p_label == RTR("Help"))) { + p_index = [menu numberOfItems]; + } else if (p_index < 0) { + p_index = item_count; } else { - menu_item = [menu addItemWithTitle:[NSString stringWithUTF8String:p_label.utf8().get_data()] action:@selector(globalMenuCallback:) keyEquivalent:[NSString stringWithUTF8String:keycode.utf8().get_data()]]; + if (menu == [NSApp mainMenu]) { // Skip Apple menu. + p_index++; + } + p_index = CLAMP(p_index, 0, item_count); } + menu_item = [menu insertItemWithTitle:[NSString stringWithUTF8String:p_label.utf8().get_data()] action:@selector(globalMenuCallback:) keyEquivalent:[NSString stringWithUTF8String:keycode.utf8().get_data()] atIndex:p_index]; + *r_out = (menu == [NSApp mainMenu]) ? p_index - 1 : p_index; + return menu_item; + } + return nullptr; +} + +int DisplayServerMacOS::global_menu_add_item(const String &p_menu_root, const String &p_label, const Callable &p_callback, const Callable &p_key_callback, const Variant &p_tag, Key p_accel, int p_index) { + _THREAD_SAFE_METHOD_ + + int out = -1; + NSMenuItem *menu_item = _menu_add_item(p_menu_root, p_label, p_accel, p_index, &out); + if (menu_item) { GodotMenuItem *obj = [[GodotMenuItem alloc] init]; obj->callback = p_callback; + obj->key_callback = p_key_callback; obj->meta = p_tag; obj->checkable_type = CHECKABLE_TYPE_NONE; obj->max_states = 0; obj->state = 0; - [menu_item setKeyEquivalentModifierMask:KeyMappingOSX::keycode_get_native_mask(p_accel)]; + [menu_item setKeyEquivalentModifierMask:KeyMappingMacOS::keycode_get_native_mask(p_accel)]; [menu_item setRepresentedObject:obj]; } + return out; } -void DisplayServerOSX::global_menu_add_check_item(const String &p_menu_root, const String &p_label, const Callable &p_callback, const Variant &p_tag, Key p_accel, int p_index) { +int DisplayServerMacOS::global_menu_add_check_item(const String &p_menu_root, const String &p_label, const Callable &p_callback, const Callable &p_key_callback, const Variant &p_tag, Key p_accel, int p_index) { _THREAD_SAFE_METHOD_ - NSMenu *menu = _get_menu_root(p_menu_root); - if (menu) { - String keycode = KeyMappingOSX::keycode_get_native_string(p_accel & KeyModifierMask::CODE_MASK); - NSMenuItem *menu_item; - if (p_index != -1) { - menu_item = [menu insertItemWithTitle:[NSString stringWithUTF8String:p_label.utf8().get_data()] action:@selector(globalMenuCallback:) keyEquivalent:[NSString stringWithUTF8String:keycode.utf8().get_data()] atIndex:p_index]; - } else { - menu_item = [menu addItemWithTitle:[NSString stringWithUTF8String:p_label.utf8().get_data()] action:@selector(globalMenuCallback:) keyEquivalent:[NSString stringWithUTF8String:keycode.utf8().get_data()]]; - } + int out = -1; + NSMenuItem *menu_item = _menu_add_item(p_menu_root, p_label, p_accel, p_index, &out); + if (menu_item) { GodotMenuItem *obj = [[GodotMenuItem alloc] init]; obj->callback = p_callback; + obj->key_callback = p_key_callback; obj->meta = p_tag; obj->checkable_type = CHECKABLE_TYPE_CHECK_BOX; obj->max_states = 0; obj->state = 0; - [menu_item setKeyEquivalentModifierMask:KeyMappingOSX::keycode_get_native_mask(p_accel)]; + [menu_item setKeyEquivalentModifierMask:KeyMappingMacOS::keycode_get_native_mask(p_accel)]; [menu_item setRepresentedObject:obj]; } + return out; } -void DisplayServerOSX::global_menu_add_icon_item(const String &p_menu_root, const Ref<Texture2D> &p_icon, const String &p_label, const Callable &p_callback, const Variant &p_tag, Key p_accel, int p_index) { +int DisplayServerMacOS::global_menu_add_icon_item(const String &p_menu_root, const Ref<Texture2D> &p_icon, const String &p_label, const Callable &p_callback, const Callable &p_key_callback, const Variant &p_tag, Key p_accel, int p_index) { _THREAD_SAFE_METHOD_ - NSMenu *menu = _get_menu_root(p_menu_root); - if (menu) { - String keycode = KeyMappingOSX::keycode_get_native_string(p_accel & KeyModifierMask::CODE_MASK); - NSMenuItem *menu_item; - if (p_index != -1) { - menu_item = [menu insertItemWithTitle:[NSString stringWithUTF8String:p_label.utf8().get_data()] action:@selector(globalMenuCallback:) keyEquivalent:[NSString stringWithUTF8String:keycode.utf8().get_data()] atIndex:p_index]; - } else { - menu_item = [menu addItemWithTitle:[NSString stringWithUTF8String:p_label.utf8().get_data()] action:@selector(globalMenuCallback:) keyEquivalent:[NSString stringWithUTF8String:keycode.utf8().get_data()]]; - } + int out = -1; + NSMenuItem *menu_item = _menu_add_item(p_menu_root, p_label, p_accel, p_index, &out); + if (menu_item) { GodotMenuItem *obj = [[GodotMenuItem alloc] init]; obj->callback = p_callback; + obj->key_callback = p_key_callback; obj->meta = p_tag; obj->checkable_type = CHECKABLE_TYPE_NONE; obj->max_states = 0; @@ -786,25 +817,21 @@ void DisplayServerOSX::global_menu_add_icon_item(const String &p_menu_root, cons obj->img->resize(16, 16, Image::INTERPOLATE_LANCZOS); [menu_item setImage:_convert_to_nsimg(obj->img)]; } - [menu_item setKeyEquivalentModifierMask:KeyMappingOSX::keycode_get_native_mask(p_accel)]; + [menu_item setKeyEquivalentModifierMask:KeyMappingMacOS::keycode_get_native_mask(p_accel)]; [menu_item setRepresentedObject:obj]; } + return out; } -void DisplayServerOSX::global_menu_add_icon_check_item(const String &p_menu_root, const Ref<Texture2D> &p_icon, const String &p_label, const Callable &p_callback, const Variant &p_tag, Key p_accel, int p_index) { +int DisplayServerMacOS::global_menu_add_icon_check_item(const String &p_menu_root, const Ref<Texture2D> &p_icon, const String &p_label, const Callable &p_callback, const Callable &p_key_callback, const Variant &p_tag, Key p_accel, int p_index) { _THREAD_SAFE_METHOD_ - NSMenu *menu = _get_menu_root(p_menu_root); - if (menu) { - String keycode = KeyMappingOSX::keycode_get_native_string(p_accel & KeyModifierMask::CODE_MASK); - NSMenuItem *menu_item; - if (p_index != -1) { - menu_item = [menu insertItemWithTitle:[NSString stringWithUTF8String:p_label.utf8().get_data()] action:@selector(globalMenuCallback:) keyEquivalent:[NSString stringWithUTF8String:keycode.utf8().get_data()] atIndex:p_index]; - } else { - menu_item = [menu addItemWithTitle:[NSString stringWithUTF8String:p_label.utf8().get_data()] action:@selector(globalMenuCallback:) keyEquivalent:[NSString stringWithUTF8String:keycode.utf8().get_data()]]; - } + int out = -1; + NSMenuItem *menu_item = _menu_add_item(p_menu_root, p_label, p_accel, p_index, &out); + if (menu_item) { GodotMenuItem *obj = [[GodotMenuItem alloc] init]; obj->callback = p_callback; + obj->key_callback = p_key_callback; obj->meta = p_tag; obj->checkable_type = CHECKABLE_TYPE_CHECK_BOX; obj->max_states = 0; @@ -818,48 +845,40 @@ void DisplayServerOSX::global_menu_add_icon_check_item(const String &p_menu_root obj->img->resize(16, 16, Image::INTERPOLATE_LANCZOS); [menu_item setImage:_convert_to_nsimg(obj->img)]; } - [menu_item setKeyEquivalentModifierMask:KeyMappingOSX::keycode_get_native_mask(p_accel)]; + [menu_item setKeyEquivalentModifierMask:KeyMappingMacOS::keycode_get_native_mask(p_accel)]; [menu_item setRepresentedObject:obj]; } + return out; } -void DisplayServerOSX::global_menu_add_radio_check_item(const String &p_menu_root, const String &p_label, const Callable &p_callback, const Variant &p_tag, Key p_accel, int p_index) { +int DisplayServerMacOS::global_menu_add_radio_check_item(const String &p_menu_root, const String &p_label, const Callable &p_callback, const Callable &p_key_callback, const Variant &p_tag, Key p_accel, int p_index) { _THREAD_SAFE_METHOD_ - NSMenu *menu = _get_menu_root(p_menu_root); - if (menu) { - String keycode = KeyMappingOSX::keycode_get_native_string(p_accel & KeyModifierMask::CODE_MASK); - NSMenuItem *menu_item; - if (p_index != -1) { - menu_item = [menu insertItemWithTitle:[NSString stringWithUTF8String:p_label.utf8().get_data()] action:@selector(globalMenuCallback:) keyEquivalent:[NSString stringWithUTF8String:keycode.utf8().get_data()] atIndex:p_index]; - } else { - menu_item = [menu addItemWithTitle:[NSString stringWithUTF8String:p_label.utf8().get_data()] action:@selector(globalMenuCallback:) keyEquivalent:[NSString stringWithUTF8String:keycode.utf8().get_data()]]; - } + int out = -1; + NSMenuItem *menu_item = _menu_add_item(p_menu_root, p_label, p_accel, p_index, &out); + if (menu_item) { GodotMenuItem *obj = [[GodotMenuItem alloc] init]; obj->callback = p_callback; + obj->key_callback = p_key_callback; obj->meta = p_tag; obj->checkable_type = CHECKABLE_TYPE_RADIO_BUTTON; obj->max_states = 0; obj->state = 0; - [menu_item setKeyEquivalentModifierMask:KeyMappingOSX::keycode_get_native_mask(p_accel)]; + [menu_item setKeyEquivalentModifierMask:KeyMappingMacOS::keycode_get_native_mask(p_accel)]; [menu_item setRepresentedObject:obj]; } + return out; } -void DisplayServerOSX::global_menu_add_icon_radio_check_item(const String &p_menu_root, const Ref<Texture2D> &p_icon, const String &p_label, const Callable &p_callback, const Variant &p_tag, Key p_accel, int p_index) { +int DisplayServerMacOS::global_menu_add_icon_radio_check_item(const String &p_menu_root, const Ref<Texture2D> &p_icon, const String &p_label, const Callable &p_callback, const Callable &p_key_callback, const Variant &p_tag, Key p_accel, int p_index) { _THREAD_SAFE_METHOD_ - NSMenu *menu = _get_menu_root(p_menu_root); - if (menu) { - String keycode = KeyMappingOSX::keycode_get_native_string(p_accel & KeyModifierMask::CODE_MASK); - NSMenuItem *menu_item; - if (p_index != -1) { - menu_item = [menu insertItemWithTitle:[NSString stringWithUTF8String:p_label.utf8().get_data()] action:@selector(globalMenuCallback:) keyEquivalent:[NSString stringWithUTF8String:keycode.utf8().get_data()] atIndex:p_index]; - } else { - menu_item = [menu addItemWithTitle:[NSString stringWithUTF8String:p_label.utf8().get_data()] action:@selector(globalMenuCallback:) keyEquivalent:[NSString stringWithUTF8String:keycode.utf8().get_data()]]; - } + int out = -1; + NSMenuItem *menu_item = _menu_add_item(p_menu_root, p_label, p_accel, p_index, &out); + if (menu_item) { GodotMenuItem *obj = [[GodotMenuItem alloc] init]; obj->callback = p_callback; + obj->key_callback = p_key_callback; obj->meta = p_tag; obj->checkable_type = CHECKABLE_TYPE_RADIO_BUTTON; obj->max_states = 0; @@ -873,94 +892,123 @@ void DisplayServerOSX::global_menu_add_icon_radio_check_item(const String &p_men obj->img->resize(16, 16, Image::INTERPOLATE_LANCZOS); [menu_item setImage:_convert_to_nsimg(obj->img)]; } - [menu_item setKeyEquivalentModifierMask:KeyMappingOSX::keycode_get_native_mask(p_accel)]; + [menu_item setKeyEquivalentModifierMask:KeyMappingMacOS::keycode_get_native_mask(p_accel)]; [menu_item setRepresentedObject:obj]; } + return out; } -void DisplayServerOSX::global_menu_add_multistate_item(const String &p_menu_root, const String &p_label, int p_max_states, int p_default_state, const Callable &p_callback, const Variant &p_tag, Key p_accel, int p_index) { +int DisplayServerMacOS::global_menu_add_multistate_item(const String &p_menu_root, const String &p_label, int p_max_states, int p_default_state, const Callable &p_callback, const Callable &p_key_callback, const Variant &p_tag, Key p_accel, int p_index) { _THREAD_SAFE_METHOD_ - NSMenu *menu = _get_menu_root(p_menu_root); - if (menu) { - String keycode = KeyMappingOSX::keycode_get_native_string(p_accel & KeyModifierMask::CODE_MASK); - NSMenuItem *menu_item; - if (p_index != -1) { - menu_item = [menu insertItemWithTitle:[NSString stringWithUTF8String:p_label.utf8().get_data()] action:@selector(globalMenuCallback:) keyEquivalent:[NSString stringWithUTF8String:keycode.utf8().get_data()] atIndex:p_index]; - } else { - menu_item = [menu addItemWithTitle:[NSString stringWithUTF8String:p_label.utf8().get_data()] action:@selector(globalMenuCallback:) keyEquivalent:[NSString stringWithUTF8String:keycode.utf8().get_data()]]; - } + int out = -1; + NSMenuItem *menu_item = _menu_add_item(p_menu_root, p_label, p_accel, p_index, &out); + if (menu_item) { GodotMenuItem *obj = [[GodotMenuItem alloc] init]; obj->callback = p_callback; + obj->key_callback = p_key_callback; obj->meta = p_tag; obj->checkable_type = CHECKABLE_TYPE_NONE; obj->max_states = p_max_states; obj->state = p_default_state; - [menu_item setKeyEquivalentModifierMask:KeyMappingOSX::keycode_get_native_mask(p_accel)]; + [menu_item setKeyEquivalentModifierMask:KeyMappingMacOS::keycode_get_native_mask(p_accel)]; [menu_item setRepresentedObject:obj]; } + return out; } -void DisplayServerOSX::global_menu_add_submenu_item(const String &p_menu_root, const String &p_label, const String &p_submenu, int p_index) { +int DisplayServerMacOS::global_menu_add_submenu_item(const String &p_menu_root, const String &p_label, const String &p_submenu, int p_index) { _THREAD_SAFE_METHOD_ NSMenu *menu = _get_menu_root(p_menu_root); NSMenu *sub_menu = _get_menu_root(p_submenu); + int out = -1; if (menu && sub_menu) { if (sub_menu == menu) { ERR_PRINT("Can't set submenu to self!"); - return; + return -1; } if ([sub_menu supermenu]) { ERR_PRINT("Can't set submenu to menu that is already a submenu of some other menu!"); - return; + return -1; } NSMenuItem *menu_item; - if (p_index != -1) { - menu_item = [menu insertItemWithTitle:[NSString stringWithUTF8String:p_label.utf8().get_data()] action:nil keyEquivalent:@"" atIndex:p_index]; + int item_count = ((menu == [NSApp mainMenu]) && _has_help_menu()) ? [menu numberOfItems] - 1 : [menu numberOfItems]; + if ((menu == [NSApp mainMenu]) && (p_label == "Help" || p_label == RTR("Help"))) { + p_index = [menu numberOfItems]; + } else if (p_index < 0) { + p_index = item_count; } else { - menu_item = [menu addItemWithTitle:[NSString stringWithUTF8String:p_label.utf8().get_data()] action:nil keyEquivalent:@""]; + if (menu == [NSApp mainMenu]) { // Skip Apple menu. + p_index++; + } + p_index = CLAMP(p_index, 0, item_count); } + menu_item = [menu insertItemWithTitle:[NSString stringWithUTF8String:p_label.utf8().get_data()] action:nil keyEquivalent:@"" atIndex:p_index]; + out = (menu == [NSApp mainMenu]) ? p_index - 1 : p_index; + + GodotMenuItem *obj = [[GodotMenuItem alloc] init]; + obj->callback = Callable(); + obj->checkable_type = CHECKABLE_TYPE_NONE; + obj->max_states = 0; + obj->state = 0; + [menu_item setRepresentedObject:obj]; + [sub_menu setTitle:[NSString stringWithUTF8String:p_label.utf8().get_data()]]; [menu setSubmenu:sub_menu forItem:menu_item]; } + return out; } -void DisplayServerOSX::global_menu_add_separator(const String &p_menu_root, int p_index) { +int DisplayServerMacOS::global_menu_add_separator(const String &p_menu_root, int p_index) { _THREAD_SAFE_METHOD_ NSMenu *menu = _get_menu_root(p_menu_root); if (menu) { - if (p_index != -1) { - [menu insertItem:[NSMenuItem separatorItem] atIndex:p_index]; + if (menu == [NSApp mainMenu]) { // Do not add separators into main menu. + return -1; + } + if (p_index < 0) { + p_index = [menu numberOfItems]; } else { - [menu addItem:[NSMenuItem separatorItem]]; + p_index = CLAMP(p_index, 0, [menu numberOfItems]); } + [menu insertItem:[NSMenuItem separatorItem] atIndex:p_index]; + return p_index; } + return -1; } -int DisplayServerOSX::global_menu_get_item_index_from_text(const String &p_menu_root, const String &p_text) const { +int DisplayServerMacOS::global_menu_get_item_index_from_text(const String &p_menu_root, const String &p_text) const { _THREAD_SAFE_METHOD_ const NSMenu *menu = _get_menu_root(p_menu_root); if (menu) { - return [menu indexOfItemWithTitle:[NSString stringWithUTF8String:p_text.utf8().get_data()]]; + if (menu == [NSApp mainMenu]) { // Skip Apple menu. + return [menu indexOfItemWithTitle:[NSString stringWithUTF8String:p_text.utf8().get_data()]] - 1; + } else { + return [menu indexOfItemWithTitle:[NSString stringWithUTF8String:p_text.utf8().get_data()]]; + } } return -1; } -int DisplayServerOSX::global_menu_get_item_index_from_tag(const String &p_menu_root, const Variant &p_tag) const { +int DisplayServerMacOS::global_menu_get_item_index_from_tag(const String &p_menu_root, const Variant &p_tag) const { _THREAD_SAFE_METHOD_ const NSMenu *menu = _get_menu_root(p_menu_root); if (menu) { - for (NSInteger i = 0; i < [menu numberOfItems]; i++) { + for (NSInteger i = (menu == [NSApp mainMenu]) ? 1 : 0; i < [menu numberOfItems]; i++) { const NSMenuItem *menu_item = [menu itemAtIndex:i]; if (menu_item) { const GodotMenuItem *obj = [menu_item representedObject]; if (obj && obj->meta == p_tag) { - return i; + if (menu == [NSApp mainMenu]) { // Skip Apple menu. + return i - 1; + } else { + return i; + } } } } @@ -969,11 +1017,16 @@ int DisplayServerOSX::global_menu_get_item_index_from_tag(const String &p_menu_r return -1; } -bool DisplayServerOSX::global_menu_is_item_checked(const String &p_menu_root, int p_idx) const { +bool DisplayServerMacOS::global_menu_is_item_checked(const String &p_menu_root, int p_idx) const { _THREAD_SAFE_METHOD_ const NSMenu *menu = _get_menu_root(p_menu_root); if (menu) { + ERR_FAIL_COND_V(p_idx < 0, false); + if (menu == [NSApp mainMenu]) { // Skip Apple menu. + p_idx++; + } + ERR_FAIL_COND_V(p_idx >= [menu numberOfItems], false); const NSMenuItem *menu_item = [menu itemAtIndex:p_idx]; if (menu_item) { return ([menu_item state] == NSControlStateValueOn); @@ -982,11 +1035,16 @@ bool DisplayServerOSX::global_menu_is_item_checked(const String &p_menu_root, in return false; } -bool DisplayServerOSX::global_menu_is_item_checkable(const String &p_menu_root, int p_idx) const { +bool DisplayServerMacOS::global_menu_is_item_checkable(const String &p_menu_root, int p_idx) const { _THREAD_SAFE_METHOD_ const NSMenu *menu = _get_menu_root(p_menu_root); if (menu) { + ERR_FAIL_COND_V(p_idx < 0, false); + if (menu == [NSApp mainMenu]) { // Skip Apple menu. + p_idx++; + } + ERR_FAIL_COND_V(p_idx >= [menu numberOfItems], false); const NSMenuItem *menu_item = [menu itemAtIndex:p_idx]; if (menu_item) { GodotMenuItem *obj = [menu_item representedObject]; @@ -998,11 +1056,16 @@ bool DisplayServerOSX::global_menu_is_item_checkable(const String &p_menu_root, return false; } -bool DisplayServerOSX::global_menu_is_item_radio_checkable(const String &p_menu_root, int p_idx) const { +bool DisplayServerMacOS::global_menu_is_item_radio_checkable(const String &p_menu_root, int p_idx) const { _THREAD_SAFE_METHOD_ const NSMenu *menu = _get_menu_root(p_menu_root); if (menu) { + ERR_FAIL_COND_V(p_idx < 0, false); + if (menu == [NSApp mainMenu]) { // Skip Apple menu. + p_idx++; + } + ERR_FAIL_COND_V(p_idx >= [menu numberOfItems], false); const NSMenuItem *menu_item = [menu itemAtIndex:p_idx]; if (menu_item) { GodotMenuItem *obj = [menu_item representedObject]; @@ -1014,11 +1077,16 @@ bool DisplayServerOSX::global_menu_is_item_radio_checkable(const String &p_menu_ return false; } -Callable DisplayServerOSX::global_menu_get_item_callback(const String &p_menu_root, int p_idx) const { +Callable DisplayServerMacOS::global_menu_get_item_callback(const String &p_menu_root, int p_idx) const { _THREAD_SAFE_METHOD_ const NSMenu *menu = _get_menu_root(p_menu_root); if (menu) { + ERR_FAIL_COND_V(p_idx < 0, Callable()); + if (menu == [NSApp mainMenu]) { // Skip Apple menu. + p_idx++; + } + ERR_FAIL_COND_V(p_idx >= [menu numberOfItems], Callable()); const NSMenuItem *menu_item = [menu itemAtIndex:p_idx]; if (menu_item) { GodotMenuItem *obj = [menu_item representedObject]; @@ -1030,11 +1098,37 @@ Callable DisplayServerOSX::global_menu_get_item_callback(const String &p_menu_ro return Callable(); } -Variant DisplayServerOSX::global_menu_get_item_tag(const String &p_menu_root, int p_idx) const { +Callable DisplayServerMacOS::global_menu_get_item_key_callback(const String &p_menu_root, int p_idx) const { + _THREAD_SAFE_METHOD_ + + const NSMenu *menu = _get_menu_root(p_menu_root); + if (menu) { + ERR_FAIL_COND_V(p_idx < 0, Callable()); + if (menu == [NSApp mainMenu]) { // Skip Apple menu. + p_idx++; + } + ERR_FAIL_COND_V(p_idx >= [menu numberOfItems], Callable()); + const NSMenuItem *menu_item = [menu itemAtIndex:p_idx]; + if (menu_item) { + GodotMenuItem *obj = [menu_item representedObject]; + if (obj) { + return obj->key_callback; + } + } + } + return Callable(); +} + +Variant DisplayServerMacOS::global_menu_get_item_tag(const String &p_menu_root, int p_idx) const { _THREAD_SAFE_METHOD_ const NSMenu *menu = _get_menu_root(p_menu_root); if (menu) { + ERR_FAIL_COND_V(p_idx < 0, Variant()); + if (menu == [NSApp mainMenu]) { // Skip Apple menu. + p_idx++; + } + ERR_FAIL_COND_V(p_idx >= [menu numberOfItems], Variant()); const NSMenuItem *menu_item = [menu itemAtIndex:p_idx]; if (menu_item) { GodotMenuItem *obj = [menu_item representedObject]; @@ -1046,11 +1140,16 @@ Variant DisplayServerOSX::global_menu_get_item_tag(const String &p_menu_root, in return Variant(); } -String DisplayServerOSX::global_menu_get_item_text(const String &p_menu_root, int p_idx) const { +String DisplayServerMacOS::global_menu_get_item_text(const String &p_menu_root, int p_idx) const { _THREAD_SAFE_METHOD_ const NSMenu *menu = _get_menu_root(p_menu_root); if (menu) { + ERR_FAIL_COND_V(p_idx < 0, String()); + if (menu == [NSApp mainMenu]) { // Skip Apple menu. + p_idx++; + } + ERR_FAIL_COND_V(p_idx >= [menu numberOfItems], String()); const NSMenuItem *menu_item = [menu itemAtIndex:p_idx]; if (menu_item) { return String::utf8([[menu_item title] UTF8String]); @@ -1059,11 +1158,16 @@ String DisplayServerOSX::global_menu_get_item_text(const String &p_menu_root, in return String(); } -String DisplayServerOSX::global_menu_get_item_submenu(const String &p_menu_root, int p_idx) const { +String DisplayServerMacOS::global_menu_get_item_submenu(const String &p_menu_root, int p_idx) const { _THREAD_SAFE_METHOD_ const NSMenu *menu = _get_menu_root(p_menu_root); if (menu) { + ERR_FAIL_COND_V(p_idx < 0, String()); + if (menu == [NSApp mainMenu]) { // Skip Apple menu. + p_idx++; + } + ERR_FAIL_COND_V(p_idx >= [menu numberOfItems], String()); const NSMenuItem *menu_item = [menu itemAtIndex:p_idx]; if (menu_item) { const NSMenu *sub_menu = [menu_item submenu]; @@ -1079,11 +1183,16 @@ String DisplayServerOSX::global_menu_get_item_submenu(const String &p_menu_root, return String(); } -Key DisplayServerOSX::global_menu_get_item_accelerator(const String &p_menu_root, int p_idx) const { +Key DisplayServerMacOS::global_menu_get_item_accelerator(const String &p_menu_root, int p_idx) const { _THREAD_SAFE_METHOD_ const NSMenu *menu = _get_menu_root(p_menu_root); if (menu) { + ERR_FAIL_COND_V(p_idx < 0, Key::NONE); + if (menu == [NSApp mainMenu]) { // Skip Apple menu. + p_idx++; + } + ERR_FAIL_COND_V(p_idx >= [menu numberOfItems], Key::NONE); const NSMenuItem *menu_item = [menu itemAtIndex:p_idx]; if (menu_item) { String ret = String::utf8([[menu_item keyEquivalent] UTF8String]); @@ -1110,11 +1219,16 @@ Key DisplayServerOSX::global_menu_get_item_accelerator(const String &p_menu_root return Key::NONE; } -bool DisplayServerOSX::global_menu_is_item_disabled(const String &p_menu_root, int p_idx) const { +bool DisplayServerMacOS::global_menu_is_item_disabled(const String &p_menu_root, int p_idx) const { _THREAD_SAFE_METHOD_ const NSMenu *menu = _get_menu_root(p_menu_root); if (menu) { + ERR_FAIL_COND_V(p_idx < 0, false); + if (menu == [NSApp mainMenu]) { // Skip Apple menu. + p_idx++; + } + ERR_FAIL_COND_V(p_idx >= [menu numberOfItems], false); const NSMenuItem *menu_item = [menu itemAtIndex:p_idx]; if (menu_item) { return ![menu_item isEnabled]; @@ -1123,11 +1237,16 @@ bool DisplayServerOSX::global_menu_is_item_disabled(const String &p_menu_root, i return false; } -String DisplayServerOSX::global_menu_get_item_tooltip(const String &p_menu_root, int p_idx) const { +String DisplayServerMacOS::global_menu_get_item_tooltip(const String &p_menu_root, int p_idx) const { _THREAD_SAFE_METHOD_ const NSMenu *menu = _get_menu_root(p_menu_root); if (menu) { + ERR_FAIL_COND_V(p_idx < 0, String()); + if (menu == [NSApp mainMenu]) { // Skip Apple menu. + p_idx++; + } + ERR_FAIL_COND_V(p_idx >= [menu numberOfItems], String()); const NSMenuItem *menu_item = [menu itemAtIndex:p_idx]; if (menu_item) { return String::utf8([[menu_item toolTip] UTF8String]); @@ -1136,11 +1255,16 @@ String DisplayServerOSX::global_menu_get_item_tooltip(const String &p_menu_root, return String(); } -int DisplayServerOSX::global_menu_get_item_state(const String &p_menu_root, int p_idx) const { +int DisplayServerMacOS::global_menu_get_item_state(const String &p_menu_root, int p_idx) const { _THREAD_SAFE_METHOD_ const NSMenu *menu = _get_menu_root(p_menu_root); if (menu) { + ERR_FAIL_COND_V(p_idx < 0, 0); + if (menu == [NSApp mainMenu]) { // Skip Apple menu. + p_idx++; + } + ERR_FAIL_COND_V(p_idx >= [menu numberOfItems], 0); const NSMenuItem *menu_item = [menu itemAtIndex:p_idx]; if (menu_item) { GodotMenuItem *obj = [menu_item representedObject]; @@ -1152,11 +1276,16 @@ int DisplayServerOSX::global_menu_get_item_state(const String &p_menu_root, int return 0; } -int DisplayServerOSX::global_menu_get_item_max_states(const String &p_menu_root, int p_idx) const { +int DisplayServerMacOS::global_menu_get_item_max_states(const String &p_menu_root, int p_idx) const { _THREAD_SAFE_METHOD_ const NSMenu *menu = _get_menu_root(p_menu_root); if (menu) { + ERR_FAIL_COND_V(p_idx < 0, 0); + if (menu == [NSApp mainMenu]) { // Skip Apple menu. + p_idx++; + } + ERR_FAIL_COND_V(p_idx >= [menu numberOfItems], 0); const NSMenuItem *menu_item = [menu itemAtIndex:p_idx]; if (menu_item) { GodotMenuItem *obj = [menu_item representedObject]; @@ -1168,11 +1297,16 @@ int DisplayServerOSX::global_menu_get_item_max_states(const String &p_menu_root, return 0; } -Ref<Texture2D> DisplayServerOSX::global_menu_get_item_icon(const String &p_menu_root, int p_idx) const { +Ref<Texture2D> DisplayServerMacOS::global_menu_get_item_icon(const String &p_menu_root, int p_idx) const { _THREAD_SAFE_METHOD_ const NSMenu *menu = _get_menu_root(p_menu_root); if (menu) { + ERR_FAIL_COND_V(p_idx < 0, Ref<Texture2D>()); + if (menu == [NSApp mainMenu]) { // Skip Apple menu. + p_idx++; + } + ERR_FAIL_COND_V(p_idx >= [menu numberOfItems], Ref<Texture2D>()); const NSMenuItem *menu_item = [menu itemAtIndex:p_idx]; if (menu_item) { GodotMenuItem *obj = [menu_item representedObject]; @@ -1186,14 +1320,34 @@ Ref<Texture2D> DisplayServerOSX::global_menu_get_item_icon(const String &p_menu_ return Ref<Texture2D>(); } -void DisplayServerOSX::global_menu_set_item_checked(const String &p_menu_root, int p_idx, bool p_checked) { +int DisplayServerMacOS::global_menu_get_item_indentation_level(const String &p_menu_root, int p_idx) const { + _THREAD_SAFE_METHOD_ + + const NSMenu *menu = _get_menu_root(p_menu_root); + if (menu) { + ERR_FAIL_COND_V(p_idx < 0, 0); + if (menu == [NSApp mainMenu]) { // Skip Apple menu. + p_idx++; + } + ERR_FAIL_COND_V(p_idx >= [menu numberOfItems], 0); + const NSMenuItem *menu_item = [menu itemAtIndex:p_idx]; + if (menu_item) { + return [menu_item indentationLevel]; + } + } + return 0; +} + +void DisplayServerMacOS::global_menu_set_item_checked(const String &p_menu_root, int p_idx, bool p_checked) { _THREAD_SAFE_METHOD_ NSMenu *menu = _get_menu_root(p_menu_root); if (menu) { - if ((menu == [NSApp mainMenu]) && (p_idx == 0)) { // Do not edit Apple menu. - return; + ERR_FAIL_COND(p_idx < 0); + if (menu == [NSApp mainMenu]) { // Skip Apple menu. + p_idx++; } + ERR_FAIL_COND(p_idx >= [menu numberOfItems]); NSMenuItem *menu_item = [menu itemAtIndex:p_idx]; if (menu_item) { if (p_checked) { @@ -1205,78 +1359,111 @@ void DisplayServerOSX::global_menu_set_item_checked(const String &p_menu_root, i } } -void DisplayServerOSX::global_menu_set_item_checkable(const String &p_menu_root, int p_idx, bool p_checkable) { +void DisplayServerMacOS::global_menu_set_item_checkable(const String &p_menu_root, int p_idx, bool p_checkable) { _THREAD_SAFE_METHOD_ NSMenu *menu = _get_menu_root(p_menu_root); if (menu) { - if ((menu == [NSApp mainMenu]) && (p_idx == 0)) { // Do not edit Apple menu. - return; + ERR_FAIL_COND(p_idx < 0); + if (menu == [NSApp mainMenu]) { // Skip Apple menu. + p_idx++; } + ERR_FAIL_COND(p_idx >= [menu numberOfItems]); NSMenuItem *menu_item = [menu itemAtIndex:p_idx]; if (menu_item) { GodotMenuItem *obj = [menu_item representedObject]; + ERR_FAIL_COND(!obj); obj->checkable_type = (p_checkable) ? CHECKABLE_TYPE_CHECK_BOX : CHECKABLE_TYPE_NONE; } } } -void DisplayServerOSX::global_menu_set_item_radio_checkable(const String &p_menu_root, int p_idx, bool p_checkable) { +void DisplayServerMacOS::global_menu_set_item_radio_checkable(const String &p_menu_root, int p_idx, bool p_checkable) { _THREAD_SAFE_METHOD_ NSMenu *menu = _get_menu_root(p_menu_root); if (menu) { - if ((menu == [NSApp mainMenu]) && (p_idx == 0)) { // Do not edit Apple menu. - return; + ERR_FAIL_COND(p_idx < 0); + if (menu == [NSApp mainMenu]) { // Skip Apple menu. + p_idx++; } + ERR_FAIL_COND(p_idx >= [menu numberOfItems]); NSMenuItem *menu_item = [menu itemAtIndex:p_idx]; if (menu_item) { GodotMenuItem *obj = [menu_item representedObject]; + ERR_FAIL_COND(!obj); obj->checkable_type = (p_checkable) ? CHECKABLE_TYPE_RADIO_BUTTON : CHECKABLE_TYPE_NONE; } } } -void DisplayServerOSX::global_menu_set_item_callback(const String &p_menu_root, int p_idx, const Callable &p_callback) { +void DisplayServerMacOS::global_menu_set_item_callback(const String &p_menu_root, int p_idx, const Callable &p_callback) { _THREAD_SAFE_METHOD_ NSMenu *menu = _get_menu_root(p_menu_root); if (menu) { - if ((menu == [NSApp mainMenu]) && (p_idx == 0)) { // Do not edit Apple menu. - return; + ERR_FAIL_COND(p_idx < 0); + if (menu == [NSApp mainMenu]) { // Skip Apple menu. + p_idx++; } + ERR_FAIL_COND(p_idx >= [menu numberOfItems]); NSMenuItem *menu_item = [menu itemAtIndex:p_idx]; if (menu_item) { GodotMenuItem *obj = [menu_item representedObject]; + ERR_FAIL_COND(!obj); obj->callback = p_callback; } } } -void DisplayServerOSX::global_menu_set_item_tag(const String &p_menu_root, int p_idx, const Variant &p_tag) { +void DisplayServerMacOS::global_menu_set_item_key_callback(const String &p_menu_root, int p_idx, const Callable &p_key_callback) { _THREAD_SAFE_METHOD_ NSMenu *menu = _get_menu_root(p_menu_root); if (menu) { - if ((menu == [NSApp mainMenu]) && (p_idx == 0)) { // Do not edit Apple menu. - return; + ERR_FAIL_COND(p_idx < 0); + if (menu == [NSApp mainMenu]) { // Skip Apple menu. + p_idx++; } + ERR_FAIL_COND(p_idx >= [menu numberOfItems]); NSMenuItem *menu_item = [menu itemAtIndex:p_idx]; if (menu_item) { GodotMenuItem *obj = [menu_item representedObject]; + ERR_FAIL_COND(!obj); + obj->key_callback = p_key_callback; + } + } +} + +void DisplayServerMacOS::global_menu_set_item_tag(const String &p_menu_root, int p_idx, const Variant &p_tag) { + _THREAD_SAFE_METHOD_ + + NSMenu *menu = _get_menu_root(p_menu_root); + if (menu) { + ERR_FAIL_COND(p_idx < 0); + if (menu == [NSApp mainMenu]) { // Skip Apple menu. + p_idx++; + } + ERR_FAIL_COND(p_idx >= [menu numberOfItems]); + NSMenuItem *menu_item = [menu itemAtIndex:p_idx]; + if (menu_item) { + GodotMenuItem *obj = [menu_item representedObject]; + ERR_FAIL_COND(!obj); obj->meta = p_tag; } } } -void DisplayServerOSX::global_menu_set_item_text(const String &p_menu_root, int p_idx, const String &p_text) { +void DisplayServerMacOS::global_menu_set_item_text(const String &p_menu_root, int p_idx, const String &p_text) { _THREAD_SAFE_METHOD_ NSMenu *menu = _get_menu_root(p_menu_root); if (menu) { - if ((menu == [NSApp mainMenu]) && (p_idx == 0)) { // Do not edit Apple menu. - return; + ERR_FAIL_COND(p_idx < 0); + if (menu == [NSApp mainMenu]) { // Skip Apple menu. + p_idx++; } + ERR_FAIL_COND(p_idx >= [menu numberOfItems]); NSMenuItem *menu_item = [menu itemAtIndex:p_idx]; if (menu_item) { [menu_item setTitle:[NSString stringWithUTF8String:p_text.utf8().get_data()]]; @@ -1284,7 +1471,7 @@ void DisplayServerOSX::global_menu_set_item_text(const String &p_menu_root, int } } -void DisplayServerOSX::global_menu_set_item_submenu(const String &p_menu_root, int p_idx, const String &p_submenu) { +void DisplayServerMacOS::global_menu_set_item_submenu(const String &p_menu_root, int p_idx, const String &p_submenu) { _THREAD_SAFE_METHOD_ NSMenu *menu = _get_menu_root(p_menu_root); @@ -1298,9 +1485,11 @@ void DisplayServerOSX::global_menu_set_item_submenu(const String &p_menu_root, i ERR_PRINT("Can't set submenu to menu that is already a submenu of some other menu!"); return; } - if ((menu == [NSApp mainMenu]) && (p_idx == 0)) { // Do not edit Apple menu. - return; + ERR_FAIL_COND(p_idx < 0); + if (menu == [NSApp mainMenu]) { // Skip Apple menu. + p_idx++; } + ERR_FAIL_COND(p_idx >= [menu numberOfItems]); NSMenuItem *menu_item = [menu itemAtIndex:p_idx]; if (menu_item) { [menu setSubmenu:sub_menu forItem:menu_item]; @@ -1308,31 +1497,35 @@ void DisplayServerOSX::global_menu_set_item_submenu(const String &p_menu_root, i } } -void DisplayServerOSX::global_menu_set_item_accelerator(const String &p_menu_root, int p_idx, Key p_keycode) { +void DisplayServerMacOS::global_menu_set_item_accelerator(const String &p_menu_root, int p_idx, Key p_keycode) { _THREAD_SAFE_METHOD_ NSMenu *menu = _get_menu_root(p_menu_root); if (menu) { - if ((menu == [NSApp mainMenu]) && (p_idx == 0)) { // Do not edit Apple menu. - return; + ERR_FAIL_COND(p_idx < 0); + if (menu == [NSApp mainMenu]) { // Skip Apple menu. + p_idx++; } + ERR_FAIL_COND(p_idx >= [menu numberOfItems]); NSMenuItem *menu_item = [menu itemAtIndex:p_idx]; if (menu_item) { - [menu_item setKeyEquivalentModifierMask:KeyMappingOSX::keycode_get_native_mask(p_keycode)]; - String keycode = KeyMappingOSX::keycode_get_native_string(p_keycode & KeyModifierMask::CODE_MASK); + [menu_item setKeyEquivalentModifierMask:KeyMappingMacOS::keycode_get_native_mask(p_keycode)]; + String keycode = KeyMappingMacOS::keycode_get_native_string(p_keycode & KeyModifierMask::CODE_MASK); [menu_item setKeyEquivalent:[NSString stringWithUTF8String:keycode.utf8().get_data()]]; } } } -void DisplayServerOSX::global_menu_set_item_disabled(const String &p_menu_root, int p_idx, bool p_disabled) { +void DisplayServerMacOS::global_menu_set_item_disabled(const String &p_menu_root, int p_idx, bool p_disabled) { _THREAD_SAFE_METHOD_ NSMenu *menu = _get_menu_root(p_menu_root); if (menu) { - if ((menu == [NSApp mainMenu]) && (p_idx == 0)) { // Do not edit Apple menu. - return; + ERR_FAIL_COND(p_idx < 0); + if (menu == [NSApp mainMenu]) { // Skip Apple menu. + p_idx++; } + ERR_FAIL_COND(p_idx >= [menu numberOfItems]); NSMenuItem *menu_item = [menu itemAtIndex:p_idx]; if (menu_item) { [menu_item setEnabled:(!p_disabled)]; @@ -1340,14 +1533,16 @@ void DisplayServerOSX::global_menu_set_item_disabled(const String &p_menu_root, } } -void DisplayServerOSX::global_menu_set_item_tooltip(const String &p_menu_root, int p_idx, const String &p_tooltip) { +void DisplayServerMacOS::global_menu_set_item_tooltip(const String &p_menu_root, int p_idx, const String &p_tooltip) { _THREAD_SAFE_METHOD_ NSMenu *menu = _get_menu_root(p_menu_root); if (menu) { - if ((menu == [NSApp mainMenu]) && (p_idx == 0)) { // Do not edit Apple menu. - return; + ERR_FAIL_COND(p_idx < 0); + if (menu == [NSApp mainMenu]) { // Skip Apple menu. + p_idx++; } + ERR_FAIL_COND(p_idx >= [menu numberOfItems]); NSMenuItem *menu_item = [menu itemAtIndex:p_idx]; if (menu_item) { [menu_item setToolTip:[NSString stringWithUTF8String:p_tooltip.utf8().get_data()]]; @@ -1355,53 +1550,58 @@ void DisplayServerOSX::global_menu_set_item_tooltip(const String &p_menu_root, i } } -void DisplayServerOSX::global_menu_set_item_state(const String &p_menu_root, int p_idx, int p_state) { +void DisplayServerMacOS::global_menu_set_item_state(const String &p_menu_root, int p_idx, int p_state) { _THREAD_SAFE_METHOD_ NSMenu *menu = _get_menu_root(p_menu_root); if (menu) { - if ((menu == [NSApp mainMenu]) && (p_idx == 0)) { // Do not edit Apple menu. - return; + ERR_FAIL_COND(p_idx < 0); + if (menu == [NSApp mainMenu]) { // Skip Apple menu. + p_idx++; } + ERR_FAIL_COND(p_idx >= [menu numberOfItems]); NSMenuItem *menu_item = [menu itemAtIndex:p_idx]; if (menu_item) { GodotMenuItem *obj = [menu_item representedObject]; - if (obj) { - obj->state = p_state; - } + ERR_FAIL_COND(!obj); + obj->state = p_state; } } } -void DisplayServerOSX::global_menu_set_item_max_states(const String &p_menu_root, int p_idx, int p_max_states) { +void DisplayServerMacOS::global_menu_set_item_max_states(const String &p_menu_root, int p_idx, int p_max_states) { _THREAD_SAFE_METHOD_ NSMenu *menu = _get_menu_root(p_menu_root); if (menu) { - if ((menu == [NSApp mainMenu]) && (p_idx == 0)) { // Do not edit Apple menu. - return; + ERR_FAIL_COND(p_idx < 0); + if (menu == [NSApp mainMenu]) { // Skip Apple menu. + p_idx++; } + ERR_FAIL_COND(p_idx >= [menu numberOfItems]); NSMenuItem *menu_item = [menu itemAtIndex:p_idx]; if (menu_item) { GodotMenuItem *obj = [menu_item representedObject]; - if (obj) { - obj->max_states = p_max_states; - } + ERR_FAIL_COND(!obj); + obj->max_states = p_max_states; } } } -void DisplayServerOSX::global_menu_set_item_icon(const String &p_menu_root, int p_idx, const Ref<Texture2D> &p_icon) { +void DisplayServerMacOS::global_menu_set_item_icon(const String &p_menu_root, int p_idx, const Ref<Texture2D> &p_icon) { _THREAD_SAFE_METHOD_ NSMenu *menu = _get_menu_root(p_menu_root); if (menu) { - if ((menu == [NSApp mainMenu]) && (p_idx == 0)) { // Do not edit Apple menu. - return; + ERR_FAIL_COND(p_idx < 0); + if (menu == [NSApp mainMenu]) { // Skip Apple menu. + p_idx++; } + ERR_FAIL_COND(p_idx >= [menu numberOfItems]); NSMenuItem *menu_item = [menu itemAtIndex:p_idx]; if (menu_item) { GodotMenuItem *obj = [menu_item representedObject]; + ERR_FAIL_COND(!obj); if (p_icon.is_valid()) { obj->img = p_icon->get_image(); obj->img = obj->img->duplicate(); @@ -1418,30 +1618,53 @@ void DisplayServerOSX::global_menu_set_item_icon(const String &p_menu_root, int } } -int DisplayServerOSX::global_menu_get_item_count(const String &p_menu_root) const { +void DisplayServerMacOS::global_menu_set_item_indentation_level(const String &p_menu_root, int p_idx, int p_level) { + _THREAD_SAFE_METHOD_ + + NSMenu *menu = _get_menu_root(p_menu_root); + if (menu) { + ERR_FAIL_COND(p_idx < 0); + if (menu == [NSApp mainMenu]) { // Skip Apple menu. + p_idx++; + } + ERR_FAIL_COND(p_idx >= [menu numberOfItems]); + NSMenuItem *menu_item = [menu itemAtIndex:p_idx]; + if (menu_item) { + [menu_item setIndentationLevel:p_level]; + } + } +} + +int DisplayServerMacOS::global_menu_get_item_count(const String &p_menu_root) const { _THREAD_SAFE_METHOD_ const NSMenu *menu = _get_menu_root(p_menu_root); if (menu) { - return [menu numberOfItems]; + if (menu == [NSApp mainMenu]) { // Skip Apple menu. + return [menu numberOfItems] - 1; + } else { + return [menu numberOfItems]; + } } else { return 0; } } -void DisplayServerOSX::global_menu_remove_item(const String &p_menu_root, int p_idx) { +void DisplayServerMacOS::global_menu_remove_item(const String &p_menu_root, int p_idx) { _THREAD_SAFE_METHOD_ NSMenu *menu = _get_menu_root(p_menu_root); if (menu) { - if ((menu == [NSApp mainMenu]) && (p_idx == 0)) { // Do not delete Apple menu. - return; + ERR_FAIL_COND(p_idx < 0); + if (menu == [NSApp mainMenu]) { // Skip Apple menu. + p_idx++; } + ERR_FAIL_COND(p_idx >= [menu numberOfItems]); [menu removeItemAtIndex:p_idx]; } } -void DisplayServerOSX::global_menu_clear(const String &p_menu_root) { +void DisplayServerMacOS::global_menu_clear(const String &p_menu_root) { _THREAD_SAFE_METHOD_ NSMenu *menu = _get_menu_root(p_menu_root); @@ -1452,45 +1675,83 @@ void DisplayServerOSX::global_menu_clear(const String &p_menu_root) { NSMenuItem *menu_item = [menu addItemWithTitle:@"" action:nil keyEquivalent:@""]; [menu setSubmenu:apple_menu forItem:menu_item]; } + if (submenu.has(p_menu_root)) { + submenu.erase(p_menu_root); + } } } -bool DisplayServerOSX::tts_is_speaking() const { +bool DisplayServerMacOS::tts_is_speaking() const { ERR_FAIL_COND_V(!tts, false); return [tts isSpeaking]; } -bool DisplayServerOSX::tts_is_paused() const { +bool DisplayServerMacOS::tts_is_paused() const { ERR_FAIL_COND_V(!tts, false); return [tts isPaused]; } -Array DisplayServerOSX::tts_get_voices() const { +TypedArray<Dictionary> DisplayServerMacOS::tts_get_voices() const { ERR_FAIL_COND_V(!tts, Array()); return [tts getVoices]; } -void DisplayServerOSX::tts_speak(const String &p_text, const String &p_voice, int p_volume, float p_pitch, float p_rate, int p_utterance_id, bool p_interrupt) { +void DisplayServerMacOS::tts_speak(const String &p_text, const String &p_voice, int p_volume, float p_pitch, float p_rate, int p_utterance_id, bool p_interrupt) { ERR_FAIL_COND(!tts); [tts speak:p_text voice:p_voice volume:p_volume pitch:p_pitch rate:p_rate utterance_id:p_utterance_id interrupt:p_interrupt]; } -void DisplayServerOSX::tts_pause() { +void DisplayServerMacOS::tts_pause() { ERR_FAIL_COND(!tts); [tts pauseSpeaking]; } -void DisplayServerOSX::tts_resume() { +void DisplayServerMacOS::tts_resume() { ERR_FAIL_COND(!tts); [tts resumeSpeaking]; } -void DisplayServerOSX::tts_stop() { +void DisplayServerMacOS::tts_stop() { ERR_FAIL_COND(!tts); [tts stopSpeaking]; } -Error DisplayServerOSX::dialog_show(String p_title, String p_description, Vector<String> p_buttons, const Callable &p_callback) { +bool DisplayServerMacOS::is_dark_mode_supported() const { + if (@available(macOS 10.14, *)) { + return true; + } else { + return false; + } +} + +bool DisplayServerMacOS::is_dark_mode() const { + if (@available(macOS 10.14, *)) { + if (![[NSUserDefaults standardUserDefaults] objectForKey:@"AppleInterfaceStyle"]) { + return false; + } else { + return ([[[NSUserDefaults standardUserDefaults] stringForKey:@"AppleInterfaceStyle"] isEqual:@"Dark"]); + } + } else { + return false; + } +} + +Color DisplayServerMacOS::get_accent_color() const { + if (@available(macOS 10.14, *)) { + NSColor *color = [[NSColor controlAccentColor] colorUsingColorSpace:[NSColorSpace genericRGBColorSpace]]; + if (color) { + CGFloat components[4]; + [color getRed:&components[0] green:&components[1] blue:&components[2] alpha:&components[3]]; + return Color(components[0], components[1], components[2], components[3]); + } else { + return Color(0, 0, 0, 0); + } + } else { + return Color(0, 0, 0, 0); + } +} + +Error DisplayServerMacOS::dialog_show(String p_title, String p_description, Vector<String> p_buttons, const Callable &p_callback) { _THREAD_SAFE_METHOD_ NSAlert *window = [[NSAlert alloc] init]; @@ -1522,13 +1783,13 @@ Error DisplayServerOSX::dialog_show(String p_title, String p_description, Vector Variant *buttonp = &button; Variant ret; Callable::CallError ce; - p_callback.call((const Variant **)&buttonp, 1, ret, ce); + p_callback.callp((const Variant **)&buttonp, 1, ret, ce); } return OK; } -Error DisplayServerOSX::dialog_input_text(String p_title, String p_description, String p_partial, const Callable &p_callback) { +Error DisplayServerMacOS::dialog_input_text(String p_title, String p_description, String p_partial, const Callable &p_callback) { _THREAD_SAFE_METHOD_ NSAlert *window = [[NSAlert alloc] init]; @@ -1554,13 +1815,13 @@ Error DisplayServerOSX::dialog_input_text(String p_title, String p_description, Variant *textp = &text; Variant ret; Callable::CallError ce; - p_callback.call((const Variant **)&textp, 1, ret, ce); + p_callback.callp((const Variant **)&textp, 1, ret, ce); } return OK; } -void DisplayServerOSX::mouse_set_mode(MouseMode p_mode) { +void DisplayServerMacOS::mouse_set_mode(MouseMode p_mode) { _THREAD_SAFE_METHOD_ if (p_mode == mouse_mode) { @@ -1615,11 +1876,11 @@ void DisplayServerOSX::mouse_set_mode(MouseMode p_mode) { } } -DisplayServer::MouseMode DisplayServerOSX::mouse_get_mode() const { +DisplayServer::MouseMode DisplayServerMacOS::mouse_get_mode() const { return mouse_mode; } -bool DisplayServerOSX::update_mouse_wrap(WindowData &p_wd, NSPoint &r_delta, NSPoint &r_mpos, NSTimeInterval p_timestamp) { +bool DisplayServerMacOS::update_mouse_wrap(WindowData &p_wd, NSPoint &r_delta, NSPoint &r_mpos, NSTimeInterval p_timestamp) { _THREAD_SAFE_METHOD_ if (ignore_warp) { @@ -1641,7 +1902,7 @@ bool DisplayServerOSX::update_mouse_wrap(WindowData &p_wd, NSPoint &r_delta, NSP List<WarpEvent>::Element *F = warp_events.front(); while (F) { if (F->get().timestamp < p_timestamp) { - List<DisplayServerOSX::WarpEvent>::Element *E = F; + List<DisplayServerMacOS::WarpEvent>::Element *E = F; r_delta.x -= E->get().delta.x; r_delta.y -= E->get().delta.y; F = F->next(); @@ -1669,7 +1930,7 @@ bool DisplayServerOSX::update_mouse_wrap(WindowData &p_wd, NSPoint &r_delta, NSP // Save warp data. last_warp = [[NSProcessInfo processInfo] systemUptime]; - DisplayServerOSX::WarpEvent ev; + DisplayServerMacOS::WarpEvent ev; ev.timestamp = last_warp; ev.delta = r_delta; warp_events.push_back(ev); @@ -1678,7 +1939,7 @@ bool DisplayServerOSX::update_mouse_wrap(WindowData &p_wd, NSPoint &r_delta, NSP return false; } -void DisplayServerOSX::warp_mouse(const Point2i &p_position) { +void DisplayServerMacOS::warp_mouse(const Point2i &p_position) { _THREAD_SAFE_METHOD_ if (mouse_mode != MOUSE_MODE_CAPTURED) { @@ -1705,7 +1966,7 @@ void DisplayServerOSX::warp_mouse(const Point2i &p_position) { } } -Point2i DisplayServerOSX::mouse_get_position() const { +Point2i DisplayServerMacOS::mouse_get_position() const { _THREAD_SAFE_METHOD_ const NSPoint mouse_pos = [NSEvent mouseLocation]; @@ -1724,15 +1985,15 @@ Point2i DisplayServerOSX::mouse_get_position() const { return Vector2i(); } -void DisplayServerOSX::mouse_set_button_state(MouseButton p_state) { +void DisplayServerMacOS::mouse_set_button_state(MouseButton p_state) { last_button_state = p_state; } -MouseButton DisplayServerOSX::mouse_get_button_state() const { +MouseButton DisplayServerMacOS::mouse_get_button_state() const { return last_button_state; } -void DisplayServerOSX::clipboard_set(const String &p_text) { +void DisplayServerMacOS::clipboard_set(const String &p_text) { _THREAD_SAFE_METHOD_ NSString *copiedString = [NSString stringWithUTF8String:p_text.utf8().get_data()]; @@ -1743,7 +2004,7 @@ void DisplayServerOSX::clipboard_set(const String &p_text) { [pasteboard writeObjects:copiedStringArray]; } -String DisplayServerOSX::clipboard_get() const { +String DisplayServerMacOS::clipboard_get() const { _THREAD_SAFE_METHOD_ NSPasteboard *pasteboard = [NSPasteboard generalPasteboard]; @@ -1764,14 +2025,14 @@ String DisplayServerOSX::clipboard_get() const { return ret; } -int DisplayServerOSX::get_screen_count() const { +int DisplayServerMacOS::get_screen_count() const { _THREAD_SAFE_METHOD_ NSArray *screenArray = [NSScreen screens]; return [screenArray count]; } -Point2i DisplayServerOSX::screen_get_position(int p_screen) const { +Point2i DisplayServerMacOS::screen_get_position(int p_screen) const { _THREAD_SAFE_METHOD_ if (p_screen == SCREEN_OF_MAIN_WINDOW) { @@ -1785,7 +2046,7 @@ Point2i DisplayServerOSX::screen_get_position(int p_screen) const { return position; } -Size2i DisplayServerOSX::screen_get_size(int p_screen) const { +Size2i DisplayServerMacOS::screen_get_size(int p_screen) const { _THREAD_SAFE_METHOD_ if (p_screen == SCREEN_OF_MAIN_WINDOW) { @@ -1802,7 +2063,7 @@ Size2i DisplayServerOSX::screen_get_size(int p_screen) const { return Size2i(); } -int DisplayServerOSX::screen_get_dpi(int p_screen) const { +int DisplayServerMacOS::screen_get_dpi(int p_screen) const { _THREAD_SAFE_METHOD_ if (p_screen == SCREEN_OF_MAIN_WINDOW) { @@ -1826,7 +2087,7 @@ int DisplayServerOSX::screen_get_dpi(int p_screen) const { return 72; } -float DisplayServerOSX::screen_get_scale(int p_screen) const { +float DisplayServerMacOS::screen_get_scale(int p_screen) const { _THREAD_SAFE_METHOD_ if (p_screen == SCREEN_OF_MAIN_WINDOW) { @@ -1844,14 +2105,14 @@ float DisplayServerOSX::screen_get_scale(int p_screen) const { return 1.f; } -float DisplayServerOSX::screen_get_max_scale() const { +float DisplayServerMacOS::screen_get_max_scale() const { _THREAD_SAFE_METHOD_ // Note: Do not update max display scale on screen configuration change, existing editor windows can't be rescaled on the fly. return display_max_scale; } -Rect2i DisplayServerOSX::screen_get_usable_rect(int p_screen) const { +Rect2i DisplayServerMacOS::screen_get_usable_rect(int p_screen) const { _THREAD_SAFE_METHOD_ if (p_screen == SCREEN_OF_MAIN_WINDOW) { @@ -1873,7 +2134,7 @@ Rect2i DisplayServerOSX::screen_get_usable_rect(int p_screen) const { return Rect2i(); } -float DisplayServerOSX::screen_get_refresh_rate(int p_screen) const { +float DisplayServerMacOS::screen_get_refresh_rate(int p_screen) const { _THREAD_SAFE_METHOD_ if (p_screen == SCREEN_OF_MAIN_WINDOW) { @@ -1891,7 +2152,25 @@ float DisplayServerOSX::screen_get_refresh_rate(int p_screen) const { return SCREEN_REFRESH_RATE_FALLBACK; } -Vector<DisplayServer::WindowID> DisplayServerOSX::get_window_list() const { +bool DisplayServerMacOS::screen_is_kept_on() const { + return (screen_keep_on_assertion); +} + +void DisplayServerMacOS::screen_set_keep_on(bool p_enable) { + if (screen_keep_on_assertion) { + IOPMAssertionRelease(screen_keep_on_assertion); + screen_keep_on_assertion = kIOPMNullAssertionID; + } + + if (p_enable) { + String app_name_string = ProjectSettings::get_singleton()->get("application/config/name"); + NSString *name = [NSString stringWithUTF8String:(app_name_string.is_empty() ? "Godot Engine" : app_name_string.utf8().get_data())]; + NSString *reason = @"Godot Engine running with display/window/energy_saving/keep_screen_on = true"; + IOPMAssertionCreateWithDescription(kIOPMAssertPreventUserIdleDisplaySleep, (__bridge CFStringRef)name, (__bridge CFStringRef)reason, (__bridge CFStringRef)reason, nullptr, 0, nullptr, &screen_keep_on_assertion); + } +} + +Vector<DisplayServer::WindowID> DisplayServerMacOS::get_window_list() const { _THREAD_SAFE_METHOD_ Vector<int> ret; @@ -1901,7 +2180,7 @@ Vector<DisplayServer::WindowID> DisplayServerOSX::get_window_list() const { return ret; } -DisplayServer::WindowID DisplayServerOSX::create_sub_window(WindowMode p_mode, VSyncMode p_vsync_mode, uint32_t p_flags, const Rect2i &p_rect) { +DisplayServer::WindowID DisplayServerMacOS::create_sub_window(WindowMode p_mode, VSyncMode p_vsync_mode, uint32_t p_flags, const Rect2i &p_rect) { _THREAD_SAFE_METHOD_ WindowID id = _create_window(p_mode, p_vsync_mode, p_rect); @@ -1914,7 +2193,7 @@ DisplayServer::WindowID DisplayServerOSX::create_sub_window(WindowMode p_mode, V return id; } -void DisplayServerOSX::show_window(WindowID p_id) { +void DisplayServerMacOS::show_window(WindowID p_id) { WindowData &wd = windows[p_id]; popup_open(p_id); @@ -1925,7 +2204,7 @@ void DisplayServerOSX::show_window(WindowID p_id) { } } -void DisplayServerOSX::delete_sub_window(WindowID p_id) { +void DisplayServerMacOS::delete_sub_window(WindowID p_id) { _THREAD_SAFE_METHOD_ ERR_FAIL_COND(!windows.has(p_id)); @@ -1937,7 +2216,7 @@ void DisplayServerOSX::delete_sub_window(WindowID p_id) { [wd.window_object close]; } -void DisplayServerOSX::window_set_rect_changed_callback(const Callable &p_callable, WindowID p_window) { +void DisplayServerMacOS::window_set_rect_changed_callback(const Callable &p_callable, WindowID p_window) { _THREAD_SAFE_METHOD_ ERR_FAIL_COND(!windows.has(p_window)); @@ -1945,7 +2224,7 @@ void DisplayServerOSX::window_set_rect_changed_callback(const Callable &p_callab wd.rect_changed_callback = p_callable; } -void DisplayServerOSX::window_set_window_event_callback(const Callable &p_callable, WindowID p_window) { +void DisplayServerMacOS::window_set_window_event_callback(const Callable &p_callable, WindowID p_window) { _THREAD_SAFE_METHOD_ ERR_FAIL_COND(!windows.has(p_window)); @@ -1953,7 +2232,7 @@ void DisplayServerOSX::window_set_window_event_callback(const Callable &p_callab wd.event_callback = p_callable; } -void DisplayServerOSX::window_set_input_event_callback(const Callable &p_callable, WindowID p_window) { +void DisplayServerMacOS::window_set_input_event_callback(const Callable &p_callable, WindowID p_window) { _THREAD_SAFE_METHOD_ ERR_FAIL_COND(!windows.has(p_window)); @@ -1961,21 +2240,21 @@ void DisplayServerOSX::window_set_input_event_callback(const Callable &p_callabl wd.input_event_callback = p_callable; } -void DisplayServerOSX::window_set_input_text_callback(const Callable &p_callable, WindowID p_window) { +void DisplayServerMacOS::window_set_input_text_callback(const Callable &p_callable, WindowID p_window) { _THREAD_SAFE_METHOD_ ERR_FAIL_COND(!windows.has(p_window)); WindowData &wd = windows[p_window]; wd.input_text_callback = p_callable; } -void DisplayServerOSX::window_set_drop_files_callback(const Callable &p_callable, WindowID p_window) { +void DisplayServerMacOS::window_set_drop_files_callback(const Callable &p_callable, WindowID p_window) { _THREAD_SAFE_METHOD_ ERR_FAIL_COND(!windows.has(p_window)); WindowData &wd = windows[p_window]; wd.drop_files_callback = p_callable; } -void DisplayServerOSX::window_set_title(const String &p_title, WindowID p_window) { +void DisplayServerMacOS::window_set_title(const String &p_title, WindowID p_window) { _THREAD_SAFE_METHOD_ ERR_FAIL_COND(!windows.has(p_window)); @@ -1984,7 +2263,7 @@ void DisplayServerOSX::window_set_title(const String &p_title, WindowID p_window [wd.window_object setTitle:[NSString stringWithUTF8String:p_title.utf8().get_data()]]; } -void DisplayServerOSX::window_set_mouse_passthrough(const Vector<Vector2> &p_region, WindowID p_window) { +void DisplayServerMacOS::window_set_mouse_passthrough(const Vector<Vector2> &p_region, WindowID p_window) { _THREAD_SAFE_METHOD_ ERR_FAIL_COND(!windows.has(p_window)); @@ -1993,7 +2272,7 @@ void DisplayServerOSX::window_set_mouse_passthrough(const Vector<Vector2> &p_reg wd.mpath = p_region; } -int DisplayServerOSX::window_get_current_screen(WindowID p_window) const { +int DisplayServerMacOS::window_get_current_screen(WindowID p_window) const { _THREAD_SAFE_METHOD_ ERR_FAIL_COND_V(!windows.has(p_window), -1); const WindowData &wd = windows[p_window]; @@ -2002,12 +2281,16 @@ int DisplayServerOSX::window_get_current_screen(WindowID p_window) const { return (index == NSNotFound) ? 0 : index; } -void DisplayServerOSX::window_set_current_screen(int p_screen, WindowID p_window) { +void DisplayServerMacOS::window_set_current_screen(int p_screen, WindowID p_window) { _THREAD_SAFE_METHOD_ ERR_FAIL_COND(!windows.has(p_window)); WindowData &wd = windows[p_window]; + if (window_get_current_screen(p_window) == p_screen) { + return; + } + bool was_fullscreen = false; if (wd.fullscreen) { // Temporary exit fullscreen mode to move window. @@ -2024,7 +2307,7 @@ void DisplayServerOSX::window_set_current_screen(int p_screen, WindowID p_window } } -void DisplayServerOSX::window_set_exclusive(WindowID p_window, bool p_exclusive) { +void DisplayServerMacOS::window_set_exclusive(WindowID p_window, bool p_exclusive) { _THREAD_SAFE_METHOD_ ERR_FAIL_COND(!windows.has(p_window)); WindowData &wd = windows[p_window]; @@ -2042,7 +2325,7 @@ void DisplayServerOSX::window_set_exclusive(WindowID p_window, bool p_exclusive) } } -Point2i DisplayServerOSX::window_get_position(WindowID p_window) const { +Point2i DisplayServerMacOS::window_get_position(WindowID p_window) const { _THREAD_SAFE_METHOD_ ERR_FAIL_COND_V(!windows.has(p_window), Point2i()); @@ -2065,7 +2348,7 @@ Point2i DisplayServerOSX::window_get_position(WindowID p_window) const { return pos; } -void DisplayServerOSX::window_set_position(const Point2i &p_position, WindowID p_window) { +void DisplayServerMacOS::window_set_position(const Point2i &p_position, WindowID p_window) { _THREAD_SAFE_METHOD_ ERR_FAIL_COND(!windows.has(p_window)); @@ -2093,7 +2376,7 @@ void DisplayServerOSX::window_set_position(const Point2i &p_position, WindowID p update_mouse_pos(wd, [wd.window_object mouseLocationOutsideOfEventStream]); } -void DisplayServerOSX::window_set_transient(WindowID p_window, WindowID p_parent) { +void DisplayServerMacOS::window_set_transient(WindowID p_window, WindowID p_parent) { _THREAD_SAFE_METHOD_ ERR_FAIL_COND(p_window == p_parent); @@ -2132,7 +2415,7 @@ void DisplayServerOSX::window_set_transient(WindowID p_window, WindowID p_parent } } -void DisplayServerOSX::window_set_max_size(const Size2i p_size, WindowID p_window) { +void DisplayServerMacOS::window_set_max_size(const Size2i p_size, WindowID p_window) { _THREAD_SAFE_METHOD_ ERR_FAIL_COND(!windows.has(p_window)); @@ -2152,7 +2435,7 @@ void DisplayServerOSX::window_set_max_size(const Size2i p_size, WindowID p_windo } } -Size2i DisplayServerOSX::window_get_max_size(WindowID p_window) const { +Size2i DisplayServerMacOS::window_get_max_size(WindowID p_window) const { _THREAD_SAFE_METHOD_ ERR_FAIL_COND_V(!windows.has(p_window), Size2i()); @@ -2160,7 +2443,7 @@ Size2i DisplayServerOSX::window_get_max_size(WindowID p_window) const { return wd.max_size; } -void DisplayServerOSX::window_set_min_size(const Size2i p_size, WindowID p_window) { +void DisplayServerMacOS::window_set_min_size(const Size2i p_size, WindowID p_window) { _THREAD_SAFE_METHOD_ ERR_FAIL_COND(!windows.has(p_window)); @@ -2180,7 +2463,7 @@ void DisplayServerOSX::window_set_min_size(const Size2i p_size, WindowID p_windo } } -Size2i DisplayServerOSX::window_get_min_size(WindowID p_window) const { +Size2i DisplayServerMacOS::window_get_min_size(WindowID p_window) const { _THREAD_SAFE_METHOD_ ERR_FAIL_COND_V(!windows.has(p_window), Size2i()); @@ -2189,7 +2472,7 @@ Size2i DisplayServerOSX::window_get_min_size(WindowID p_window) const { return wd.min_size; } -void DisplayServerOSX::window_set_size(const Size2i p_size, WindowID p_window) { +void DisplayServerMacOS::window_set_size(const Size2i p_size, WindowID p_window) { _THREAD_SAFE_METHOD_ ERR_FAIL_COND(!windows.has(p_window)); @@ -2213,7 +2496,7 @@ void DisplayServerOSX::window_set_size(const Size2i p_size, WindowID p_window) { _update_window_style(wd); } -Size2i DisplayServerOSX::window_get_size(WindowID p_window) const { +Size2i DisplayServerMacOS::window_get_size(WindowID p_window) const { _THREAD_SAFE_METHOD_ ERR_FAIL_COND_V(!windows.has(p_window), Size2i()); @@ -2221,7 +2504,7 @@ Size2i DisplayServerOSX::window_get_size(WindowID p_window) const { return wd.size; } -Size2i DisplayServerOSX::window_get_real_size(WindowID p_window) const { +Size2i DisplayServerMacOS::window_get_real_size(WindowID p_window) const { _THREAD_SAFE_METHOD_ ERR_FAIL_COND_V(!windows.has(p_window), Size2i()); @@ -2230,7 +2513,7 @@ Size2i DisplayServerOSX::window_get_real_size(WindowID p_window) const { return Size2i(frame.size.width, frame.size.height) * screen_get_max_scale(); } -void DisplayServerOSX::window_set_mode(WindowMode p_mode, WindowID p_window) { +void DisplayServerMacOS::window_set_mode(WindowMode p_mode, WindowID p_window) { _THREAD_SAFE_METHOD_ ERR_FAIL_COND(!windows.has(p_window)); @@ -2299,7 +2582,7 @@ void DisplayServerOSX::window_set_mode(WindowMode p_mode, WindowID p_window) { } } -DisplayServer::WindowMode DisplayServerOSX::window_get_mode(WindowID p_window) const { +DisplayServer::WindowMode DisplayServerMacOS::window_get_mode(WindowID p_window) const { _THREAD_SAFE_METHOD_ ERR_FAIL_COND_V(!windows.has(p_window), WINDOW_MODE_WINDOWED); @@ -2321,11 +2604,50 @@ DisplayServer::WindowMode DisplayServerOSX::window_get_mode(WindowID p_window) c return WINDOW_MODE_WINDOWED; } -bool DisplayServerOSX::window_is_maximize_allowed(WindowID p_window) const { +bool DisplayServerMacOS::window_is_maximize_allowed(WindowID p_window) const { return true; } -void DisplayServerOSX::window_set_flag(WindowFlags p_flag, bool p_enabled, WindowID p_window) { +bool DisplayServerMacOS::window_maximize_on_title_dbl_click() const { + id value = [[NSUserDefaults standardUserDefaults] objectForKey:@"AppleActionOnDoubleClick"]; + if ([value isKindOfClass:[NSString class]]) { + return [value isEqualToString:@"Maximize"]; + } + return false; +} + +bool DisplayServerMacOS::window_minimize_on_title_dbl_click() const { + id value = [[NSUserDefaults standardUserDefaults] objectForKey:@"AppleActionOnDoubleClick"]; + if ([value isKindOfClass:[NSString class]]) { + return [value isEqualToString:@"Minimize"]; + } + return false; +} + +Vector2i DisplayServerMacOS::window_get_safe_title_margins(WindowID p_window) const { + _THREAD_SAFE_METHOD_ + + ERR_FAIL_COND_V(!windows.has(p_window), Vector2i()); + const WindowData &wd = windows[p_window]; + + float max_x = 0.f; + NSButton *cb = [wd.window_object standardWindowButton:NSWindowCloseButton]; + if (cb) { + max_x = MAX(max_x, [cb frame].origin.x + [cb frame].size.width); + } + NSButton *mb = [wd.window_object standardWindowButton:NSWindowMiniaturizeButton]; + if (mb) { + max_x = MAX(max_x, [mb frame].origin.x + [mb frame].size.width); + } + NSButton *zb = [wd.window_object standardWindowButton:NSWindowZoomButton]; + if (zb) { + max_x = MAX(max_x, [zb frame].origin.x + [zb frame].size.width); + } + + return Vector2i(max_x * screen_get_max_scale(), 0); +} + +void DisplayServerMacOS::window_set_flag(WindowFlags p_flag, bool p_enabled, WindowID p_window) { _THREAD_SAFE_METHOD_ ERR_FAIL_COND(!windows.has(p_window)); @@ -2343,6 +2665,19 @@ void DisplayServerOSX::window_set_flag(WindowFlags p_flag, bool p_enabled, Windo [wd.window_object setStyleMask:[wd.window_object styleMask] | NSWindowStyleMaskResizable]; } } break; + case WINDOW_FLAG_EXTEND_TO_TITLE: { + NSRect rect = [wd.window_object frame]; + if (p_enabled) { + [wd.window_object setTitlebarAppearsTransparent:YES]; + [wd.window_object setTitleVisibility:NSWindowTitleHidden]; + [wd.window_object setStyleMask:[wd.window_object styleMask] | NSWindowStyleMaskFullSizeContentView]; + } else { + [wd.window_object setTitlebarAppearsTransparent:NO]; + [wd.window_object setTitleVisibility:NSWindowTitleVisible]; + [wd.window_object setStyleMask:[wd.window_object styleMask] & ~NSWindowStyleMaskFullSizeContentView]; + } + [wd.window_object setFrame:rect display:YES]; + } break; case WINDOW_FLAG_BORDERLESS: { // OrderOut prevents a lose focus bug with the window. if ([wd.window_object isVisible]) { @@ -2400,7 +2735,7 @@ void DisplayServerOSX::window_set_flag(WindowFlags p_flag, bool p_enabled, Windo } } -bool DisplayServerOSX::window_get_flag(WindowFlags p_flag, WindowID p_window) const { +bool DisplayServerMacOS::window_get_flag(WindowFlags p_flag, WindowID p_window) const { _THREAD_SAFE_METHOD_ ERR_FAIL_COND_V(!windows.has(p_window), false); @@ -2410,6 +2745,9 @@ bool DisplayServerOSX::window_get_flag(WindowFlags p_flag, WindowID p_window) co case WINDOW_FLAG_RESIZE_DISABLED: { return wd.resize_disabled; } break; + case WINDOW_FLAG_EXTEND_TO_TITLE: { + return [wd.window_object styleMask] & NSWindowStyleMaskFullSizeContentView; + } break; case WINDOW_FLAG_BORDERLESS: { return [wd.window_object styleMask] == NSWindowStyleMaskBorderless; } break; @@ -2436,12 +2774,12 @@ bool DisplayServerOSX::window_get_flag(WindowFlags p_flag, WindowID p_window) co return false; } -void DisplayServerOSX::window_request_attention(WindowID p_window) { +void DisplayServerMacOS::window_request_attention(WindowID p_window) { // It's app global, ignore window id. [NSApp requestUserAttention:NSCriticalRequest]; } -void DisplayServerOSX::window_move_to_foreground(WindowID p_window) { +void DisplayServerMacOS::window_move_to_foreground(WindowID p_window) { _THREAD_SAFE_METHOD_ ERR_FAIL_COND(!windows.has(p_window)); @@ -2455,11 +2793,11 @@ void DisplayServerOSX::window_move_to_foreground(WindowID p_window) { } } -bool DisplayServerOSX::window_can_draw(WindowID p_window) const { +bool DisplayServerMacOS::window_can_draw(WindowID p_window) const { return window_get_mode(p_window) != WINDOW_MODE_MINIMIZED; } -bool DisplayServerOSX::can_any_window_draw() const { +bool DisplayServerMacOS::can_any_window_draw() const { _THREAD_SAFE_METHOD_ for (const KeyValue<WindowID, WindowData> &E : windows) { @@ -2470,7 +2808,7 @@ bool DisplayServerOSX::can_any_window_draw() const { return false; } -void DisplayServerOSX::window_set_ime_active(const bool p_active, WindowID p_window) { +void DisplayServerMacOS::window_set_ime_active(const bool p_active, WindowID p_window) { _THREAD_SAFE_METHOD_ ERR_FAIL_COND(!windows.has(p_window)); @@ -2483,7 +2821,7 @@ void DisplayServerOSX::window_set_ime_active(const bool p_active, WindowID p_win } } -void DisplayServerOSX::window_set_ime_position(const Point2i &p_pos, WindowID p_window) { +void DisplayServerMacOS::window_set_ime_position(const Point2i &p_pos, WindowID p_window) { _THREAD_SAFE_METHOD_ ERR_FAIL_COND(!windows.has(p_window)); @@ -2492,7 +2830,7 @@ void DisplayServerOSX::window_set_ime_position(const Point2i &p_pos, WindowID p_ wd.im_position = p_pos; } -DisplayServer::WindowID DisplayServerOSX::get_window_at_screen_position(const Point2i &p_position) const { +DisplayServer::WindowID DisplayServerMacOS::get_window_at_screen_position(const Point2i &p_position) const { Point2i position = p_position; position.y *= -1; position += _get_screens_origin(); @@ -2507,7 +2845,7 @@ DisplayServer::WindowID DisplayServerOSX::get_window_at_screen_position(const Po return INVALID_WINDOW_ID; } -int64_t DisplayServerOSX::window_get_native_handle(HandleType p_handle_type, WindowID p_window) const { +int64_t DisplayServerMacOS::window_get_native_handle(HandleType p_handle_type, WindowID p_window) const { ERR_FAIL_COND_V(!windows.has(p_window), 0); switch (p_handle_type) { case DISPLAY_HANDLE: { @@ -2525,27 +2863,27 @@ int64_t DisplayServerOSX::window_get_native_handle(HandleType p_handle_type, Win } } -void DisplayServerOSX::window_attach_instance_id(ObjectID p_instance, WindowID p_window) { +void DisplayServerMacOS::window_attach_instance_id(ObjectID p_instance, WindowID p_window) { _THREAD_SAFE_METHOD_ ERR_FAIL_COND(!windows.has(p_window)); windows[p_window].instance_id = p_instance; } -ObjectID DisplayServerOSX::window_get_attached_instance_id(WindowID p_window) const { +ObjectID DisplayServerMacOS::window_get_attached_instance_id(WindowID p_window) const { _THREAD_SAFE_METHOD_ ERR_FAIL_COND_V(!windows.has(p_window), ObjectID()); return windows[p_window].instance_id; } -void DisplayServerOSX::gl_window_make_current(DisplayServer::WindowID p_window_id) { +void DisplayServerMacOS::gl_window_make_current(DisplayServer::WindowID p_window_id) { #if defined(GLES3_ENABLED) gl_manager->window_make_current(p_window_id); #endif } -void DisplayServerOSX::window_set_vsync_mode(DisplayServer::VSyncMode p_vsync_mode, WindowID p_window) { +void DisplayServerMacOS::window_set_vsync_mode(DisplayServer::VSyncMode p_vsync_mode, WindowID p_window) { _THREAD_SAFE_METHOD_ #if defined(GLES3_ENABLED) if (gl_manager) { @@ -2559,7 +2897,7 @@ void DisplayServerOSX::window_set_vsync_mode(DisplayServer::VSyncMode p_vsync_mo #endif } -DisplayServer::VSyncMode DisplayServerOSX::window_get_vsync_mode(WindowID p_window) const { +DisplayServer::VSyncMode DisplayServerMacOS::window_get_vsync_mode(WindowID p_window) const { _THREAD_SAFE_METHOD_ #if defined(GLES3_ENABLED) if (gl_manager) { @@ -2574,15 +2912,15 @@ DisplayServer::VSyncMode DisplayServerOSX::window_get_vsync_mode(WindowID p_wind return DisplayServer::VSYNC_ENABLED; } -Point2i DisplayServerOSX::ime_get_selection() const { +Point2i DisplayServerMacOS::ime_get_selection() const { return im_selection; } -String DisplayServerOSX::ime_get_text() const { +String DisplayServerMacOS::ime_get_text() const { return im_text; } -void DisplayServerOSX::cursor_update_shape() { +void DisplayServerMacOS::cursor_update_shape() { _THREAD_SAFE_METHOD_ if (cursors[cursor_shape] != nullptr) { @@ -2646,7 +2984,7 @@ void DisplayServerOSX::cursor_update_shape() { } } -void DisplayServerOSX::cursor_set_shape(CursorShape p_shape) { +void DisplayServerMacOS::cursor_set_shape(CursorShape p_shape) { _THREAD_SAFE_METHOD_ ERR_FAIL_INDEX(p_shape, CURSOR_MAX); @@ -2664,11 +3002,11 @@ void DisplayServerOSX::cursor_set_shape(CursorShape p_shape) { cursor_update_shape(); } -DisplayServerOSX::CursorShape DisplayServerOSX::cursor_get_shape() const { +DisplayServerMacOS::CursorShape DisplayServerMacOS::cursor_get_shape() const { return cursor_shape; } -void DisplayServerOSX::cursor_set_custom_image(const Ref<Resource> &p_cursor, CursorShape p_shape, const Vector2 &p_hotspot) { +void DisplayServerMacOS::cursor_set_custom_image(const Ref<Resource> &p_cursor, CursorShape p_shape, const Vector2 &p_hotspot) { _THREAD_SAFE_METHOD_ if (p_cursor.is_valid()) { @@ -2780,20 +3118,20 @@ void DisplayServerOSX::cursor_set_custom_image(const Ref<Resource> &p_cursor, Cu } } -bool DisplayServerOSX::get_swap_cancel_ok() { +bool DisplayServerMacOS::get_swap_cancel_ok() { return false; } -int DisplayServerOSX::keyboard_get_layout_count() const { +int DisplayServerMacOS::keyboard_get_layout_count() const { if (keyboard_layout_dirty) { - const_cast<DisplayServerOSX *>(this)->_update_keyboard_layouts(); + const_cast<DisplayServerMacOS *>(this)->_update_keyboard_layouts(); } return kbd_layouts.size(); } -void DisplayServerOSX::keyboard_set_current_layout(int p_index) { +void DisplayServerMacOS::keyboard_set_current_layout(int p_index) { if (keyboard_layout_dirty) { - const_cast<DisplayServerOSX *>(this)->_update_keyboard_layouts(); + const_cast<DisplayServerMacOS *>(this)->_update_keyboard_layouts(); } ERR_FAIL_INDEX(p_index, kbd_layouts.size()); @@ -2821,44 +3159,44 @@ void DisplayServerOSX::keyboard_set_current_layout(int p_index) { } } -int DisplayServerOSX::keyboard_get_current_layout() const { +int DisplayServerMacOS::keyboard_get_current_layout() const { if (keyboard_layout_dirty) { - const_cast<DisplayServerOSX *>(this)->_update_keyboard_layouts(); + const_cast<DisplayServerMacOS *>(this)->_update_keyboard_layouts(); } return current_layout; } -String DisplayServerOSX::keyboard_get_layout_language(int p_index) const { +String DisplayServerMacOS::keyboard_get_layout_language(int p_index) const { if (keyboard_layout_dirty) { - const_cast<DisplayServerOSX *>(this)->_update_keyboard_layouts(); + const_cast<DisplayServerMacOS *>(this)->_update_keyboard_layouts(); } ERR_FAIL_INDEX_V(p_index, kbd_layouts.size(), ""); return kbd_layouts[p_index].code; } -String DisplayServerOSX::keyboard_get_layout_name(int p_index) const { +String DisplayServerMacOS::keyboard_get_layout_name(int p_index) const { if (keyboard_layout_dirty) { - const_cast<DisplayServerOSX *>(this)->_update_keyboard_layouts(); + const_cast<DisplayServerMacOS *>(this)->_update_keyboard_layouts(); } ERR_FAIL_INDEX_V(p_index, kbd_layouts.size(), ""); return kbd_layouts[p_index].name; } -Key DisplayServerOSX::keyboard_get_keycode_from_physical(Key p_keycode) const { +Key DisplayServerMacOS::keyboard_get_keycode_from_physical(Key p_keycode) const { if (p_keycode == Key::PAUSE) { return p_keycode; } Key modifiers = p_keycode & KeyModifierMask::MODIFIER_MASK; Key keycode_no_mod = p_keycode & KeyModifierMask::CODE_MASK; - unsigned int osx_keycode = KeyMappingOSX::unmap_key((Key)keycode_no_mod); - return (Key)(KeyMappingOSX::remap_key(osx_keycode, 0) | modifiers); + unsigned int macos_keycode = KeyMappingMacOS::unmap_key((Key)keycode_no_mod); + return (Key)(KeyMappingMacOS::remap_key(macos_keycode, 0) | modifiers); } -void DisplayServerOSX::process_events() { +void DisplayServerMacOS::process_events() { _THREAD_SAFE_METHOD_ while (true) { @@ -2901,7 +3239,7 @@ void DisplayServerOSX::process_events() { } } -void DisplayServerOSX::force_process_and_drop_events() { +void DisplayServerMacOS::force_process_and_drop_events() { _THREAD_SAFE_METHOD_ drop_events = true; @@ -2909,13 +3247,13 @@ void DisplayServerOSX::force_process_and_drop_events() { drop_events = false; } -void DisplayServerOSX::release_rendering_thread() { +void DisplayServerMacOS::release_rendering_thread() { } -void DisplayServerOSX::make_rendering_thread() { +void DisplayServerMacOS::make_rendering_thread() { } -void DisplayServerOSX::swap_buffers() { +void DisplayServerMacOS::swap_buffers() { #if defined(GLES3_ENABLED) if (gl_manager) { gl_manager->swap_buffers(); @@ -2923,7 +3261,7 @@ void DisplayServerOSX::swap_buffers() { #endif } -void DisplayServerOSX::set_native_icon(const String &p_filename) { +void DisplayServerMacOS::set_native_icon(const String &p_filename) { _THREAD_SAFE_METHOD_ Ref<FileAccess> f = FileAccess::open(p_filename, FileAccess::READ); @@ -2943,7 +3281,7 @@ void DisplayServerOSX::set_native_icon(const String &p_filename) { [NSApp setApplicationIconImage:icon]; } -void DisplayServerOSX::set_icon(const Ref<Image> &p_icon) { +void DisplayServerMacOS::set_icon(const Ref<Image> &p_icon) { _THREAD_SAFE_METHOD_ Ref<Image> img = p_icon; @@ -2982,15 +3320,15 @@ void DisplayServerOSX::set_icon(const Ref<Image> &p_icon) { [NSApp setApplicationIconImage:nsimg]; } -DisplayServer *DisplayServerOSX::create_func(const String &p_rendering_driver, WindowMode p_mode, VSyncMode p_vsync_mode, uint32_t p_flags, const Vector2i &p_resolution, Error &r_error) { - DisplayServer *ds = memnew(DisplayServerOSX(p_rendering_driver, p_mode, p_vsync_mode, p_flags, p_resolution, r_error)); +DisplayServer *DisplayServerMacOS::create_func(const String &p_rendering_driver, WindowMode p_mode, VSyncMode p_vsync_mode, uint32_t p_flags, const Vector2i &p_resolution, Error &r_error) { + DisplayServer *ds = memnew(DisplayServerMacOS(p_rendering_driver, p_mode, p_vsync_mode, p_flags, p_resolution, r_error)); if (r_error != OK) { OS::get_singleton()->alert("Your video card driver does not support any of the supported Vulkan or OpenGL versions.", "Unable to initialize Video driver"); } return ds; } -Vector<String> DisplayServerOSX::get_rendering_drivers_func() { +Vector<String> DisplayServerMacOS::get_rendering_drivers_func() { Vector<String> drivers; #if defined(VULKAN_ENABLED) @@ -3003,11 +3341,11 @@ Vector<String> DisplayServerOSX::get_rendering_drivers_func() { return drivers; } -void DisplayServerOSX::register_osx_driver() { - register_create_function("osx", create_func, get_rendering_drivers_func); +void DisplayServerMacOS::register_macos_driver() { + register_create_function("macos", create_func, get_rendering_drivers_func); } -DisplayServer::WindowID DisplayServerOSX::window_get_active_popup() const { +DisplayServer::WindowID DisplayServerMacOS::window_get_active_popup() const { const List<WindowID>::Element *E = popup_list.back(); if (E) { return E->get(); @@ -3016,7 +3354,7 @@ DisplayServer::WindowID DisplayServerOSX::window_get_active_popup() const { } } -void DisplayServerOSX::window_set_popup_safe_rect(WindowID p_window, const Rect2i &p_rect) { +void DisplayServerMacOS::window_set_popup_safe_rect(WindowID p_window, const Rect2i &p_rect) { _THREAD_SAFE_METHOD_ ERR_FAIL_COND(!windows.has(p_window)); @@ -3024,7 +3362,7 @@ void DisplayServerOSX::window_set_popup_safe_rect(WindowID p_window, const Rect2 wd.parent_safe_rect = p_rect; } -Rect2i DisplayServerOSX::window_get_popup_safe_rect(WindowID p_window) const { +Rect2i DisplayServerMacOS::window_get_popup_safe_rect(WindowID p_window) const { _THREAD_SAFE_METHOD_ ERR_FAIL_COND_V(!windows.has(p_window), Rect2i()); @@ -3032,7 +3370,7 @@ Rect2i DisplayServerOSX::window_get_popup_safe_rect(WindowID p_window) const { return wd.parent_safe_rect; } -void DisplayServerOSX::popup_open(WindowID p_window) { +void DisplayServerMacOS::popup_open(WindowID p_window) { _THREAD_SAFE_METHOD_ WindowData &wd = windows[p_window]; @@ -3050,7 +3388,7 @@ void DisplayServerOSX::popup_open(WindowID p_window) { } } if (C) { - send_window_event(windows[C->get()], DisplayServerOSX::WINDOW_EVENT_CLOSE_REQUEST); + send_window_event(windows[C->get()], DisplayServerMacOS::WINDOW_EVENT_CLOSE_REQUEST); } if (was_empty && popup_list.is_empty()) { @@ -3062,7 +3400,7 @@ void DisplayServerOSX::popup_open(WindowID p_window) { } } -void DisplayServerOSX::popup_close(WindowID p_window) { +void DisplayServerMacOS::popup_close(WindowID p_window) { _THREAD_SAFE_METHOD_ bool was_empty = popup_list.is_empty(); @@ -3072,7 +3410,7 @@ void DisplayServerOSX::popup_close(WindowID p_window) { WindowID win_id = E->get(); popup_list.erase(E); - send_window_event(windows[win_id], DisplayServerOSX::WINDOW_EVENT_CLOSE_REQUEST); + send_window_event(windows[win_id], DisplayServerMacOS::WINDOW_EVENT_CLOSE_REQUEST); E = F; } if (!was_empty && popup_list.is_empty()) { @@ -3081,7 +3419,7 @@ void DisplayServerOSX::popup_close(WindowID p_window) { } } -bool DisplayServerOSX::mouse_process_popups(bool p_close) { +bool DisplayServerMacOS::mouse_process_popups(bool p_close) { _THREAD_SAFE_METHOD_ bool was_empty = popup_list.is_empty(); @@ -3090,7 +3428,7 @@ bool DisplayServerOSX::mouse_process_popups(bool p_close) { // Close all popups. List<WindowID>::Element *E = popup_list.front(); if (E) { - send_window_event(windows[E->get()], DisplayServerOSX::WINDOW_EVENT_CLOSE_REQUEST); + send_window_event(windows[E->get()], DisplayServerMacOS::WINDOW_EVENT_CLOSE_REQUEST); closed = true; } if (!was_empty) { @@ -3122,7 +3460,7 @@ bool DisplayServerOSX::mouse_process_popups(bool p_close) { } } if (C) { - send_window_event(windows[C->get()], DisplayServerOSX::WINDOW_EVENT_CLOSE_REQUEST); + send_window_event(windows[C->get()], DisplayServerMacOS::WINDOW_EVENT_CLOSE_REQUEST); closed = true; } if (!was_empty && popup_list.is_empty()) { @@ -3133,7 +3471,7 @@ bool DisplayServerOSX::mouse_process_popups(bool p_close) { return closed; } -DisplayServerOSX::DisplayServerOSX(const String &p_rendering_driver, WindowMode p_mode, VSyncMode p_vsync_mode, uint32_t p_flags, const Vector2i &p_resolution, Error &r_error) { +DisplayServerMacOS::DisplayServerMacOS(const String &p_rendering_driver, WindowMode p_mode, VSyncMode p_vsync_mode, uint32_t p_flags, const Vector2i &p_resolution, Error &r_error) { Input::get_singleton()->set_event_dispatch_function(_dispatch_input_events); r_error = OK; @@ -3160,7 +3498,7 @@ DisplayServerOSX::DisplayServerOSX(const String &p_rendering_driver, WindowMode CGDisplayRegisterReconfigurationCallback(_displays_arrangement_changed, nullptr); // Init TTS - tts = [[TTS_OSX alloc] init]; + tts = [[TTS_MacOS alloc] init]; NSMenuItem *menu_item; NSString *title; @@ -3199,7 +3537,7 @@ DisplayServerOSX::DisplayServerOSX(const String &p_rendering_driver, WindowMode [apple_menu addItem:[NSMenuItem separatorItem]]; - title = [NSString stringWithFormat:NSLocalizedString(@"Quit %@", nil), nsappname]; + title = [NSString stringWithFormat:NSLocalizedString(@"\t\tQuit %@", nil), nsappname]; [apple_menu addItemWithTitle:title action:@selector(terminate:) keyEquivalent:@"q"]; // Add items to the menu bar. @@ -3208,14 +3546,16 @@ DisplayServerOSX::DisplayServerOSX(const String &p_rendering_driver, WindowMode [main_menu setSubmenu:apple_menu forItem:menu_item]; [main_menu setAutoenablesItems:NO]; + menu_delegate = [[GodotMenuDelegate alloc] init]; + //!!!!!!!!!!!!!!!!!!!!!!!!!! //TODO - do Vulkan and OpenGL support checks, driver selection and fallback rendering_driver = p_rendering_driver; #if defined(GLES3_ENABLED) if (rendering_driver == "opengl3") { - GLManager_OSX::ContextType opengl_api_type = GLManager_OSX::GLES_3_0_COMPATIBLE; - gl_manager = memnew(GLManager_OSX(opengl_api_type)); + GLManager_MacOS::ContextType opengl_api_type = GLManager_MacOS::GLES_3_0_COMPATIBLE; + gl_manager = memnew(GLManager_MacOS(opengl_api_type)); if (gl_manager->initialize() != OK) { memdelete(gl_manager); gl_manager = nullptr; @@ -3227,7 +3567,7 @@ DisplayServerOSX::DisplayServerOSX(const String &p_rendering_driver, WindowMode #endif #if defined(VULKAN_ENABLED) if (rendering_driver == "vulkan") { - context_vulkan = memnew(VulkanContextOSX); + context_vulkan = memnew(VulkanContextMacOS); if (context_vulkan->initialize() != OK) { memdelete(context_vulkan); context_vulkan = nullptr; @@ -3262,9 +3602,16 @@ DisplayServerOSX::DisplayServerOSX(const String &p_rendering_driver, WindowMode RendererCompositorRD::make_current(); } #endif + + screen_set_keep_on(GLOBAL_GET("display/window/energy_saving/keep_screen_on")); } -DisplayServerOSX::~DisplayServerOSX() { +DisplayServerMacOS::~DisplayServerMacOS() { + if (screen_keep_on_assertion) { + IOPMAssertionRelease(screen_keep_on_assertion); + screen_keep_on_assertion = kIOPMNullAssertionID; + } + // Destroy all windows. for (HashMap<WindowID, WindowData>::Iterator E = windows.begin(); E;) { HashMap<WindowID, WindowData>::Iterator F = E; diff --git a/platform/osx/export/codesign.cpp b/platform/macos/export/codesign.cpp index fd044c00cc..c2bdf555d0 100644 --- a/platform/osx/export/codesign.cpp +++ b/platform/macos/export/codesign.cpp @@ -172,7 +172,7 @@ bool CodeSignCodeResources::add_file1(const String &p_root, const String &p_path f.name = p_path; f.optional = (found == CRMatch::CR_MATCH_OPTIONAL); f.nested = false; - f.hash = hash_sha1_base64(p_root.plus_file(p_path)); + f.hash = hash_sha1_base64(p_root.path_join(p_path)); print_verbose(vformat("CodeSign/CodeResources: File(V1) %s hash1:%s", f.name, f.hash)); files1.push_back(f); @@ -182,7 +182,7 @@ bool CodeSignCodeResources::add_file1(const String &p_root, const String &p_path bool CodeSignCodeResources::add_file2(const String &p_root, const String &p_path) { CRMatch found = match_rules2(p_path); if (found == CRMatch::CR_MATCH_NESTED) { - return add_nested_file(p_root, p_path, p_root.plus_file(p_path)); + return add_nested_file(p_root, p_path, p_root.path_join(p_path)); } if (found != CRMatch::CR_MATCH_YES && found != CRMatch::CR_MATCH_OPTIONAL) { return true; // No match. @@ -192,8 +192,8 @@ bool CodeSignCodeResources::add_file2(const String &p_root, const String &p_path f.name = p_path; f.optional = (found == CRMatch::CR_MATCH_OPTIONAL); f.nested = false; - f.hash = hash_sha1_base64(p_root.plus_file(p_path)); - f.hash2 = hash_sha256_base64(p_root.plus_file(p_path)); + f.hash = hash_sha1_base64(p_root.path_join(p_path)); + f.hash2 = hash_sha256_base64(p_root.path_join(p_path)); print_verbose(vformat("CodeSign/CodeResources: File(V2) %s hash1:%s hash2:%s", f.name, f.hash, f.hash2)); @@ -214,17 +214,17 @@ bool CodeSignCodeResources::add_nested_file(const String &p_root, const String & Vector<String> files_to_add; if (LipO::is_lipo(p_exepath)) { - String tmp_path_name = EditorPaths::get_singleton()->get_cache_dir().plus_file("_lipo"); + String tmp_path_name = EditorPaths::get_singleton()->get_cache_dir().path_join("_lipo"); Error err = da->make_dir_recursive(tmp_path_name); ERR_FAIL_COND_V_MSG(err != OK, false, vformat("CodeSign/CodeResources: Failed to create \"%s\" subfolder.", tmp_path_name)); LipO lip; if (lip.open_file(p_exepath)) { for (int i = 0; i < lip.get_arch_count(); i++) { - if (!lip.extract_arch(i, tmp_path_name.plus_file("_rqexe_" + itos(i)))) { + if (!lip.extract_arch(i, tmp_path_name.path_join("_rqexe_" + itos(i)))) { CLEANUP(); ERR_FAIL_V_MSG(false, "CodeSign/CodeResources: Failed to extract thin binary."); } - files_to_add.push_back(tmp_path_name.plus_file("_rqexe_" + itos(i))); + files_to_add.push_back(tmp_path_name.path_join("_rqexe_" + itos(i))); } } } else if (MachO::is_macho(p_exepath)) { @@ -285,7 +285,7 @@ bool CodeSignCodeResources::add_nested_file(const String &p_root, const String & bool CodeSignCodeResources::add_folder_recursive(const String &p_root, const String &p_path, const String &p_main_exe_path) { Ref<DirAccess> da = DirAccess::create(DirAccess::ACCESS_FILESYSTEM); ERR_FAIL_COND_V(da.is_null(), false); - Error err = da->change_dir(p_root.plus_file(p_path)); + Error err = da->change_dir(p_root.path_join(p_path)); ERR_FAIL_COND_V(err != OK, false); bool ret = true; @@ -293,27 +293,27 @@ bool CodeSignCodeResources::add_folder_recursive(const String &p_root, const Str String n = da->get_next(); while (n != String()) { if (n != "." && n != "..") { - String path = p_root.plus_file(p_path).plus_file(n); + String path = p_root.path_join(p_path).path_join(n); if (path == p_main_exe_path) { n = da->get_next(); continue; // Skip main executable. } if (da->current_is_dir()) { - CRMatch found = match_rules2(p_path.plus_file(n)); + CRMatch found = match_rules2(p_path.path_join(n)); String fmw_ver = "Current"; // Framework version (default). String info_path; String main_exe; bool bundle = false; - if (da->file_exists(path.plus_file("Contents/Info.plist"))) { - info_path = path.plus_file("Contents/Info.plist"); - main_exe = path.plus_file("Contents/MacOS"); + if (da->file_exists(path.path_join("Contents/Info.plist"))) { + info_path = path.path_join("Contents/Info.plist"); + main_exe = path.path_join("Contents/MacOS"); bundle = true; - } else if (da->file_exists(path.plus_file(vformat("Versions/%s/Resources/Info.plist", fmw_ver)))) { - info_path = path.plus_file(vformat("Versions/%s/Resources/Info.plist", fmw_ver)); - main_exe = path.plus_file(vformat("Versions/%s", fmw_ver)); + } else if (da->file_exists(path.path_join(vformat("Versions/%s/Resources/Info.plist", fmw_ver)))) { + info_path = path.path_join(vformat("Versions/%s/Resources/Info.plist", fmw_ver)); + main_exe = path.path_join(vformat("Versions/%s", fmw_ver)); bundle = true; - } else if (da->file_exists(path.plus_file("Info.plist"))) { - info_path = path.plus_file("Info.plist"); + } else if (da->file_exists(path.path_join("Info.plist"))) { + info_path = path.path_join("Info.plist"); main_exe = path; bundle = true; } @@ -322,20 +322,20 @@ bool CodeSignCodeResources::add_folder_recursive(const String &p_root, const Str PList info_plist; if (info_plist.load_file(info_path)) { if (info_plist.get_root()->data_type == PList::PLNodeType::PL_NODE_TYPE_DICT && info_plist.get_root()->data_dict.has("CFBundleExecutable")) { - main_exe = main_exe.plus_file(String::utf8(info_plist.get_root()->data_dict["CFBundleExecutable"]->data_string.get_data())); + main_exe = main_exe.path_join(String::utf8(info_plist.get_root()->data_dict["CFBundleExecutable"]->data_string.get_data())); } else { ERR_FAIL_V_MSG(false, "CodeSign/CodeResources: Invalid Info.plist, no exe name."); } } else { ERR_FAIL_V_MSG(false, "CodeSign/CodeResources: Invalid Info.plist, can't load."); } - ret = ret && add_nested_file(p_root, p_path.plus_file(n), main_exe); + ret = ret && add_nested_file(p_root, p_path.path_join(n), main_exe); } else { - ret = ret && add_folder_recursive(p_root, p_path.plus_file(n), p_main_exe_path); + ret = ret && add_folder_recursive(p_root, p_path.path_join(n), p_main_exe_path); } } else { - ret = ret && add_file1(p_root, p_path.plus_file(n)); - ret = ret && add_file2(p_root, p_path.plus_file(n)); + ret = ret && add_file1(p_root, p_path.path_join(n)); + ret = ret && add_file2(p_root, p_path.path_join(n)); } } @@ -1222,7 +1222,7 @@ Error CodeSign::_codesign_file(bool p_use_hardened_runtime, bool p_force, const } if (info_plist.get_root()->data_type == PList::PLNodeType::PL_NODE_TYPE_DICT && info_plist.get_root()->data_dict.has("CFBundleExecutable")) { - main_exe = p_exe_path.plus_file(String::utf8(info_plist.get_root()->data_dict["CFBundleExecutable"]->data_string.get_data())); + main_exe = p_exe_path.path_join(String::utf8(info_plist.get_root()->data_dict["CFBundleExecutable"]->data_string.get_data())); } else { r_error_msg = TTR("Invalid Info.plist, no exe name."); ERR_FAIL_V_MSG(FAILED, "CodeSign: Invalid Info.plist, no exe name."); @@ -1244,7 +1244,7 @@ Error CodeSign::_codesign_file(bool p_use_hardened_runtime, bool p_force, const Vector<String> files_to_sign; if (LipO::is_lipo(main_exe)) { print_verbose(vformat("CodeSign: Executable is fat, extracting...")); - String tmp_path_name = EditorPaths::get_singleton()->get_cache_dir().plus_file("_lipo"); + String tmp_path_name = EditorPaths::get_singleton()->get_cache_dir().path_join("_lipo"); Error err = da->make_dir_recursive(tmp_path_name); if (err != OK) { r_error_msg = vformat(TTR("Failed to create \"%s\" subfolder."), tmp_path_name); @@ -1253,12 +1253,12 @@ Error CodeSign::_codesign_file(bool p_use_hardened_runtime, bool p_force, const LipO lip; if (lip.open_file(main_exe)) { for (int i = 0; i < lip.get_arch_count(); i++) { - if (!lip.extract_arch(i, tmp_path_name.plus_file("_exe_" + itos(i)))) { + if (!lip.extract_arch(i, tmp_path_name.path_join("_exe_" + itos(i)))) { CLEANUP(); r_error_msg = TTR("Failed to extract thin binary."); ERR_FAIL_V_MSG(FAILED, "CodeSign: Failed to extract thin binary."); } - files_to_sign.push_back(tmp_path_name.plus_file("_exe_" + itos(i))); + files_to_sign.push_back(tmp_path_name.path_join("_exe_" + itos(i))); } } } else if (MachO::is_macho(main_exe)) { @@ -1338,15 +1338,15 @@ Error CodeSign::_codesign_file(bool p_use_hardened_runtime, bool p_force, const r_error_msg = TTR("Failed to process nested resources."); ERR_FAIL_V_MSG(FAILED, "CodeSign: Failed to process nested resources."); } - Error err = da->make_dir_recursive(p_bundle_path.plus_file("_CodeSignature")); + Error err = da->make_dir_recursive(p_bundle_path.path_join("_CodeSignature")); if (err != OK) { CLEANUP(); r_error_msg = TTR("Failed to create _CodeSignature subfolder."); ERR_FAIL_V_MSG(FAILED, "CodeSign: Failed to create _CodeSignature subfolder."); } - cr.save_to_file(p_bundle_path.plus_file("_CodeSignature").plus_file("CodeResources")); - res_hash1 = file_hash_sha1(p_bundle_path.plus_file("_CodeSignature").plus_file("CodeResources")); - res_hash2 = file_hash_sha256(p_bundle_path.plus_file("_CodeSignature").plus_file("CodeResources")); + cr.save_to_file(p_bundle_path.path_join("_CodeSignature").path_join("CodeResources")); + res_hash1 = file_hash_sha1(p_bundle_path.path_join("_CodeSignature").path_join("CodeResources")); + res_hash2 = file_hash_sha256(p_bundle_path.path_join("_CodeSignature").path_join("CodeResources")); if (res_hash1.is_empty() || res_hash2.is_empty()) { CLEANUP(); r_error_msg = TTR("Failed to get CodeResources hash."); @@ -1530,18 +1530,18 @@ Error CodeSign::codesign(bool p_use_hardened_runtime, bool p_force, const String String bundle_path; bool bundle = false; bool ios_bundle = false; - if (da->file_exists(p_path.plus_file("Contents/Info.plist"))) { - info_path = p_path.plus_file("Contents/Info.plist"); - main_exe = p_path.plus_file("Contents/MacOS"); - bundle_path = p_path.plus_file("Contents"); + if (da->file_exists(p_path.path_join("Contents/Info.plist"))) { + info_path = p_path.path_join("Contents/Info.plist"); + main_exe = p_path.path_join("Contents/MacOS"); + bundle_path = p_path.path_join("Contents"); bundle = true; - } else if (da->file_exists(p_path.plus_file(vformat("Versions/%s/Resources/Info.plist", fmw_ver)))) { - info_path = p_path.plus_file(vformat("Versions/%s/Resources/Info.plist", fmw_ver)); - main_exe = p_path.plus_file(vformat("Versions/%s", fmw_ver)); - bundle_path = p_path.plus_file(vformat("Versions/%s", fmw_ver)); + } else if (da->file_exists(p_path.path_join(vformat("Versions/%s/Resources/Info.plist", fmw_ver)))) { + info_path = p_path.path_join(vformat("Versions/%s/Resources/Info.plist", fmw_ver)); + main_exe = p_path.path_join(vformat("Versions/%s", fmw_ver)); + bundle_path = p_path.path_join(vformat("Versions/%s", fmw_ver)); bundle = true; - } else if (da->file_exists(p_path.plus_file("Info.plist"))) { - info_path = p_path.plus_file("Info.plist"); + } else if (da->file_exists(p_path.path_join("Info.plist"))) { + info_path = p_path.path_join("Info.plist"); main_exe = p_path; bundle_path = p_path; bundle = true; diff --git a/platform/osx/export/codesign.h b/platform/macos/export/codesign.h index 3a08c0ea86..fea7b117d0 100644 --- a/platform/osx/export/codesign.h +++ b/platform/macos/export/codesign.h @@ -38,8 +38,8 @@ // - Requirements code generator is not implemented (only hard-coded requirements for the ad-hoc signing is supported). // - RFC5652/CMS blob generation is not implemented, supports ad-hoc signing only. -#ifndef CODESIGN_H -#define CODESIGN_H +#ifndef MACOS_CODESIGN_H +#define MACOS_CODESIGN_H #include "core/crypto/crypto_core.h" #include "core/io/dir_access.h" @@ -365,4 +365,4 @@ public: #endif // MODULE_REGEX_ENABLED -#endif // CODESIGN_H +#endif // MACOS_CODESIGN_H diff --git a/platform/osx/export/export.cpp b/platform/macos/export/export.cpp index bd35b39e9e..5f9cf22ccf 100644 --- a/platform/osx/export/export.cpp +++ b/platform/macos/export/export.cpp @@ -32,11 +32,17 @@ #include "export_plugin.h" -void register_osx_exporter() { - EDITOR_DEF("export/macos/force_builtin_codesign", false); - EditorSettings::get_singleton()->add_property_hint(PropertyInfo(Variant::BOOL, "export/macos/force_builtin_codesign", PROPERTY_HINT_NONE)); +void register_macos_exporter() { +#ifndef ANDROID_ENABLED + EDITOR_DEF("export/macos/rcodesign", ""); +#ifdef WINDOWS_ENABLED + EditorSettings::get_singleton()->add_property_hint(PropertyInfo(Variant::STRING, "export/macos/rcodesign", PROPERTY_HINT_GLOBAL_FILE, "*.exe")); +#else + EditorSettings::get_singleton()->add_property_hint(PropertyInfo(Variant::STRING, "export/macos/rcodesign", PROPERTY_HINT_GLOBAL_FILE)); +#endif +#endif - Ref<EditorExportPlatformOSX> platform; + Ref<EditorExportPlatformMacOS> platform; platform.instantiate(); EditorExport::get_singleton()->add_export_platform(platform); diff --git a/platform/iphone/export/export.h b/platform/macos/export/export.h index adb3c23957..260c691209 100644 --- a/platform/iphone/export/export.h +++ b/platform/macos/export/export.h @@ -28,9 +28,9 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ -#ifndef IPHONE_EXPORT_H -#define IPHONE_EXPORT_H +#ifndef MACOS_EXPORT_H +#define MACOS_EXPORT_H -void register_iphone_exporter(); +void register_macos_exporter(); -#endif // IPHONE_EXPORT_H +#endif // MACOS_EXPORT_H diff --git a/platform/osx/export/export_plugin.cpp b/platform/macos/export/export_plugin.cpp index a22d7e5e3d..070830c486 100644 --- a/platform/osx/export/export_plugin.cpp +++ b/platform/macos/export/export_plugin.cpp @@ -32,12 +32,13 @@ #include "codesign.h" +#include "core/string/translation.h" #include "editor/editor_node.h" #include "editor/editor_paths.h" #include "modules/modules_enabled.gen.h" // For regex. -void EditorExportPlatformOSX::get_preset_features(const Ref<EditorExportPreset> &p_preset, List<String> *r_features) { +void EditorExportPlatformMacOS::get_preset_features(const Ref<EditorExportPreset> &p_preset, List<String> *r_features) const { if (p_preset->get("texture_format/s3tc")) { r_features->push_back("s3tc"); } @@ -47,15 +48,54 @@ void EditorExportPlatformOSX::get_preset_features(const Ref<EditorExportPreset> if (p_preset->get("texture_format/etc2")) { r_features->push_back("etc2"); } - - r_features->push_back("64"); + r_features->push_back(p_preset->get("binary_format/architecture")); } -bool EditorExportPlatformOSX::get_export_option_visibility(const String &p_option, const HashMap<StringName, Variant> &p_options) const { - // These options are not supported by built-in codesign, used on non macOS host. - if (!OS::get_singleton()->has_feature("macos")) { - if (p_option == "codesign/identity" || p_option == "codesign/timestamp" || p_option == "codesign/hardened_runtime" || p_option == "codesign/custom_options" || p_option.begins_with("notarization/")) { - return false; +bool EditorExportPlatformMacOS::get_export_option_visibility(const EditorExportPreset *p_preset, const String &p_option, const HashMap<StringName, Variant> &p_options) const { + // Hide irrelevant code signing options. + if (p_preset) { + int codesign_tool = p_preset->get("codesign/codesign"); + switch (codesign_tool) { + case 1: { // built-in ad-hoc + if (p_option == "codesign/identity" || p_option == "codesign/certificate_file" || p_option == "codesign/certificate_password" || p_option == "codesign/custom_options") { + return false; + } + } break; + case 2: { // "rcodesign" + if (p_option == "codesign/identity") { + return false; + } + } break; +#ifdef MACOS_ENABLED + case 3: { // "codesign" + if (p_option == "codesign/certificate_file" || p_option == "codesign/certificate_password") { + return false; + } + } break; +#endif + default: { // disabled + if (p_option == "codesign/identity" || p_option == "codesign/certificate_file" || p_option == "codesign/certificate_password" || p_option == "codesign/custom_options" || p_option.begins_with("codesign/entitlements")) { + return false; + } + } break; + } + + // Hide irrelevant notarization options. + int notary_tool = p_preset->get("notarization/notarization"); + switch (notary_tool) { + case 1: { // "rcodesign" + if (p_option == "notarization/apple_id_name" || p_option == "notarization/apple_id_password" || p_option == "notarization/apple_team_id") { + return false; + } + } break; + case 2: { // "altool" + // All options are visible. + } break; + default: { // disabled + if (p_option == "notarization/apple_id_name" || p_option == "notarization/apple_id_password" || p_option == "notarization/apple_team_id" || p_option == "notarization/api_uuid" || p_option == "notarization/api_key") { + return false; + } + } break; } } @@ -68,7 +108,8 @@ bool EditorExportPlatformOSX::get_export_option_visibility(const String &p_optio return true; } -void EditorExportPlatformOSX::get_export_options(List<ExportOption> *r_options) { +void EditorExportPlatformMacOS::get_export_options(List<ExportOption> *r_options) { + r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "binary_format/architecture", PROPERTY_HINT_ENUM, "universal,x86_64,arm64", PROPERTY_USAGE_STORAGE), "universal")); r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "custom_template/debug", PROPERTY_HINT_GLOBAL_FILE, "*.zip"), "")); r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "custom_template/release", PROPERTY_HINT_GLOBAL_FILE, "*.zip"), "")); @@ -82,40 +123,22 @@ void EditorExportPlatformOSX::get_export_options(List<ExportOption> *r_options) r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "application/copyright"), "")); r_options->push_back(ExportOption(PropertyInfo(Variant::DICTIONARY, "application/copyright_localized", PROPERTY_HINT_LOCALIZABLE_STRING), Dictionary())); r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "display/high_res"), false)); - r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "privacy/microphone_usage_description", PROPERTY_HINT_PLACEHOLDER_TEXT, "Provide a message if you need to use the microphone"), "")); - r_options->push_back(ExportOption(PropertyInfo(Variant::DICTIONARY, "privacy/microphone_usage_description_localized", PROPERTY_HINT_LOCALIZABLE_STRING), Dictionary())); - r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "privacy/camera_usage_description", PROPERTY_HINT_PLACEHOLDER_TEXT, "Provide a message if you need to use the camera"), "")); - r_options->push_back(ExportOption(PropertyInfo(Variant::DICTIONARY, "privacy/camera_usage_description_localized", PROPERTY_HINT_LOCALIZABLE_STRING), Dictionary())); - r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "privacy/location_usage_description", PROPERTY_HINT_PLACEHOLDER_TEXT, "Provide a message if you need to use the location information"), "")); - r_options->push_back(ExportOption(PropertyInfo(Variant::DICTIONARY, "privacy/location_usage_description_localized", PROPERTY_HINT_LOCALIZABLE_STRING), Dictionary())); - r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "privacy/address_book_usage_description", PROPERTY_HINT_PLACEHOLDER_TEXT, "Provide a message if you need to use the address book"), "")); - r_options->push_back(ExportOption(PropertyInfo(Variant::DICTIONARY, "privacy/address_book_usage_description_localized", PROPERTY_HINT_LOCALIZABLE_STRING), Dictionary())); - r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "privacy/calendar_usage_description", PROPERTY_HINT_PLACEHOLDER_TEXT, "Provide a message if you need to use the calendar"), "")); - r_options->push_back(ExportOption(PropertyInfo(Variant::DICTIONARY, "privacy/calendar_usage_description_localized", PROPERTY_HINT_LOCALIZABLE_STRING), Dictionary())); - r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "privacy/photos_library_usage_description", PROPERTY_HINT_PLACEHOLDER_TEXT, "Provide a message if you need to use the photo library"), "")); - r_options->push_back(ExportOption(PropertyInfo(Variant::DICTIONARY, "privacy/photos_library_usage_description_localized", PROPERTY_HINT_LOCALIZABLE_STRING), Dictionary())); - r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "privacy/desktop_folder_usage_description", PROPERTY_HINT_PLACEHOLDER_TEXT, "Provide a message if you need to use Desktop folder"), "")); - r_options->push_back(ExportOption(PropertyInfo(Variant::DICTIONARY, "privacy/desktop_folder_usage_description_localized", PROPERTY_HINT_LOCALIZABLE_STRING), Dictionary())); - r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "privacy/documents_folder_usage_description", PROPERTY_HINT_PLACEHOLDER_TEXT, "Provide a message if you need to use Documents folder"), "")); - r_options->push_back(ExportOption(PropertyInfo(Variant::DICTIONARY, "privacy/documents_folder_usage_description_localized", PROPERTY_HINT_LOCALIZABLE_STRING), Dictionary())); - r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "privacy/downloads_folder_usage_description", PROPERTY_HINT_PLACEHOLDER_TEXT, "Provide a message if you need to use Downloads folder"), "")); - r_options->push_back(ExportOption(PropertyInfo(Variant::DICTIONARY, "privacy/downloads_folder_usage_description_localized", PROPERTY_HINT_LOCALIZABLE_STRING), Dictionary())); - r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "privacy/network_volumes_usage_description", PROPERTY_HINT_PLACEHOLDER_TEXT, "Provide a message if you need to use network volumes"), "")); - r_options->push_back(ExportOption(PropertyInfo(Variant::DICTIONARY, "privacy/network_volumes_usage_description_localized", PROPERTY_HINT_LOCALIZABLE_STRING), Dictionary())); - r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "privacy/removable_volumes_usage_description", PROPERTY_HINT_PLACEHOLDER_TEXT, "Provide a message if you need to use removable volumes"), "")); - r_options->push_back(ExportOption(PropertyInfo(Variant::DICTIONARY, "privacy/removable_volumes_usage_description_localized", PROPERTY_HINT_LOCALIZABLE_STRING), Dictionary())); - r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "codesign/enable"), true)); +#ifdef MACOS_ENABLED + r_options->push_back(ExportOption(PropertyInfo(Variant::INT, "codesign/codesign", PROPERTY_HINT_ENUM, "Disabled,Built-in (ad-hoc only),PyOxidizer rcodesign,Xcode codesign"), 3, true)); +#else + r_options->push_back(ExportOption(PropertyInfo(Variant::INT, "codesign/codesign", PROPERTY_HINT_ENUM, "Disabled,Built-in (ad-hoc only),PyOxidizer rcodesign"), 1, true)); +#endif + // "codesign" only options: r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "codesign/identity", PROPERTY_HINT_PLACEHOLDER_TEXT, "Type: Name (ID)"), "")); - r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "codesign/timestamp"), true)); - r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "codesign/replace_existing_signature"), true)); - r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "codesign/hardened_runtime"), true)); + // "rcodesign" only options: + r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "codesign/certificate_file", PROPERTY_HINT_GLOBAL_FILE, "*.pfx,*.p12"), "")); + r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "codesign/certificate_password", PROPERTY_HINT_PASSWORD), "")); + // "codesign" and "rcodesign" only options: r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "codesign/entitlements/custom_file", PROPERTY_HINT_GLOBAL_FILE, "*.plist"), "")); - r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "codesign/entitlements/allow_jit_code_execution"), false)); r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "codesign/entitlements/allow_unsigned_executable_memory"), false)); r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "codesign/entitlements/allow_dyld_environment_variables"), false)); - r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "codesign/entitlements/disable_library_validation"), false)); r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "codesign/entitlements/audio_input"), false)); r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "codesign/entitlements/camera"), false)); @@ -125,7 +148,6 @@ void EditorExportPlatformOSX::get_export_options(List<ExportOption> *r_options) r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "codesign/entitlements/photos_library"), false)); r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "codesign/entitlements/apple_events"), false)); r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "codesign/entitlements/debugging"), false)); - r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "codesign/entitlements/app_sandbox/enabled"), false)); r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "codesign/entitlements/app_sandbox/network_server"), false)); r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "codesign/entitlements/app_sandbox/network_client"), false)); @@ -136,13 +158,43 @@ void EditorExportPlatformOSX::get_export_options(List<ExportOption> *r_options) r_options->push_back(ExportOption(PropertyInfo(Variant::INT, "codesign/entitlements/app_sandbox/files_music", PROPERTY_HINT_ENUM, "No,Read-only,Read-write"), 0)); r_options->push_back(ExportOption(PropertyInfo(Variant::INT, "codesign/entitlements/app_sandbox/files_movies", PROPERTY_HINT_ENUM, "No,Read-only,Read-write"), 0)); r_options->push_back(ExportOption(PropertyInfo(Variant::ARRAY, "codesign/entitlements/app_sandbox/helper_executables", PROPERTY_HINT_ARRAY_TYPE, itos(Variant::STRING) + "/" + itos(PROPERTY_HINT_GLOBAL_FILE) + ":"), Array())); - r_options->push_back(ExportOption(PropertyInfo(Variant::PACKED_STRING_ARRAY, "codesign/custom_options"), PackedStringArray())); - r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "notarization/enable"), false)); +#ifdef MACOS_ENABLED + r_options->push_back(ExportOption(PropertyInfo(Variant::INT, "notarization/notarization", PROPERTY_HINT_ENUM, "Disabled,PyOxidizer rcodesign,Xcode altool"), 0, true)); +#else + r_options->push_back(ExportOption(PropertyInfo(Variant::INT, "notarization/notarization", PROPERTY_HINT_ENUM, "Disabled,PyOxidizer rcodesign"), 0, true)); +#endif + // "altool" only options: r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "notarization/apple_id_name", PROPERTY_HINT_PLACEHOLDER_TEXT, "Apple ID email"), "")); - r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "notarization/apple_id_password", PROPERTY_HINT_PLACEHOLDER_TEXT, "Enable two-factor authentication and provide app-specific password"), "")); + r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "notarization/apple_id_password", PROPERTY_HINT_PASSWORD, "Enable two-factor authentication and provide app-specific password"), "")); r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "notarization/apple_team_id", PROPERTY_HINT_PLACEHOLDER_TEXT, "Provide team ID if your Apple ID belongs to multiple teams"), "")); + // "altool" and "rcodesign" only options: + r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "notarization/api_uuid", PROPERTY_HINT_PLACEHOLDER_TEXT, "App Store Connect issuer ID"), "")); + r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "notarization/api_key", PROPERTY_HINT_PLACEHOLDER_TEXT, "App Store Connect API key ID"), "")); + + r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "privacy/microphone_usage_description", PROPERTY_HINT_PLACEHOLDER_TEXT, "Provide a message if you need to use the microphone"), "")); + r_options->push_back(ExportOption(PropertyInfo(Variant::DICTIONARY, "privacy/microphone_usage_description_localized", PROPERTY_HINT_LOCALIZABLE_STRING), Dictionary())); + r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "privacy/camera_usage_description", PROPERTY_HINT_PLACEHOLDER_TEXT, "Provide a message if you need to use the camera"), "")); + r_options->push_back(ExportOption(PropertyInfo(Variant::DICTIONARY, "privacy/camera_usage_description_localized", PROPERTY_HINT_LOCALIZABLE_STRING), Dictionary())); + r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "privacy/location_usage_description", PROPERTY_HINT_PLACEHOLDER_TEXT, "Provide a message if you need to use the location information"), "")); + r_options->push_back(ExportOption(PropertyInfo(Variant::DICTIONARY, "privacy/location_usage_description_localized", PROPERTY_HINT_LOCALIZABLE_STRING), Dictionary())); + r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "privacy/address_book_usage_description", PROPERTY_HINT_PLACEHOLDER_TEXT, "Provide a message if you need to use the address book"), "")); + r_options->push_back(ExportOption(PropertyInfo(Variant::DICTIONARY, "privacy/address_book_usage_description_localized", PROPERTY_HINT_LOCALIZABLE_STRING), Dictionary())); + r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "privacy/calendar_usage_description", PROPERTY_HINT_PLACEHOLDER_TEXT, "Provide a message if you need to use the calendar"), "")); + r_options->push_back(ExportOption(PropertyInfo(Variant::DICTIONARY, "privacy/calendar_usage_description_localized", PROPERTY_HINT_LOCALIZABLE_STRING), Dictionary())); + r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "privacy/photos_library_usage_description", PROPERTY_HINT_PLACEHOLDER_TEXT, "Provide a message if you need to use the photo library"), "")); + r_options->push_back(ExportOption(PropertyInfo(Variant::DICTIONARY, "privacy/photos_library_usage_description_localized", PROPERTY_HINT_LOCALIZABLE_STRING), Dictionary())); + r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "privacy/desktop_folder_usage_description", PROPERTY_HINT_PLACEHOLDER_TEXT, "Provide a message if you need to use Desktop folder"), "")); + r_options->push_back(ExportOption(PropertyInfo(Variant::DICTIONARY, "privacy/desktop_folder_usage_description_localized", PROPERTY_HINT_LOCALIZABLE_STRING), Dictionary())); + r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "privacy/documents_folder_usage_description", PROPERTY_HINT_PLACEHOLDER_TEXT, "Provide a message if you need to use Documents folder"), "")); + r_options->push_back(ExportOption(PropertyInfo(Variant::DICTIONARY, "privacy/documents_folder_usage_description_localized", PROPERTY_HINT_LOCALIZABLE_STRING), Dictionary())); + r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "privacy/downloads_folder_usage_description", PROPERTY_HINT_PLACEHOLDER_TEXT, "Provide a message if you need to use Downloads folder"), "")); + r_options->push_back(ExportOption(PropertyInfo(Variant::DICTIONARY, "privacy/downloads_folder_usage_description_localized", PROPERTY_HINT_LOCALIZABLE_STRING), Dictionary())); + r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "privacy/network_volumes_usage_description", PROPERTY_HINT_PLACEHOLDER_TEXT, "Provide a message if you need to use network volumes"), "")); + r_options->push_back(ExportOption(PropertyInfo(Variant::DICTIONARY, "privacy/network_volumes_usage_description_localized", PROPERTY_HINT_LOCALIZABLE_STRING), Dictionary())); + r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "privacy/removable_volumes_usage_description", PROPERTY_HINT_PLACEHOLDER_TEXT, "Provide a message if you need to use removable volumes"), "")); + r_options->push_back(ExportOption(PropertyInfo(Variant::DICTIONARY, "privacy/removable_volumes_usage_description_localized", PROPERTY_HINT_LOCALIZABLE_STRING), Dictionary())); r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "texture_format/s3tc"), true)); r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "texture_format/etc"), false)); @@ -214,7 +266,7 @@ void _rgba8_to_packbits_encode(int p_ch, int p_size, Vector<uint8_t> &p_source, memcpy(&p_dest.write[ofs], result.ptr(), res_size); } -void EditorExportPlatformOSX::_make_icon(const Ref<Image> &p_icon, Vector<uint8_t> &p_data) { +void EditorExportPlatformMacOS::_make_icon(const Ref<Image> &p_icon, Vector<uint8_t> &p_data) { Ref<ImageTexture> it = memnew(ImageTexture); Vector<uint8_t> data; @@ -253,8 +305,8 @@ void EditorExportPlatformOSX::_make_icon(const Ref<Image> &p_icon, Vector<uint8_ if (icon_infos[i].is_png) { // Encode PNG icon. it->set_image(copy); - String path = EditorPaths::get_singleton()->get_cache_dir().plus_file("icon.png"); - ResourceSaver::save(path, it); + String path = EditorPaths::get_singleton()->get_cache_dir().path_join("icon.png"); + ResourceSaver::save(it, path); { Ref<FileAccess> f = FileAccess::open(path, FileAccess::READ); @@ -320,7 +372,7 @@ void EditorExportPlatformOSX::_make_icon(const Ref<Image> &p_icon, Vector<uint8_ p_data = data; } -void EditorExportPlatformOSX::_fix_plist(const Ref<EditorExportPreset> &p_preset, Vector<uint8_t> &plist, const String &p_binary) { +void EditorExportPlatformMacOS::_fix_plist(const Ref<EditorExportPreset> &p_preset, Vector<uint8_t> &plist, const String &p_binary) { String str; String strnew; str.parse_utf8((const char *)plist.ptr(), plist.size()); @@ -407,168 +459,296 @@ void EditorExportPlatformOSX::_fix_plist(const Ref<EditorExportPreset> &p_preset } /** - * If we're running the OSX version of the Godot editor we'll: + * If we're running the macOS version of the Godot editor we'll: * - export our application bundle to a temporary folder * - attempt to code sign it * - and then wrap it up in a DMG */ -Error EditorExportPlatformOSX::_notarize(const Ref<EditorExportPreset> &p_preset, const String &p_path) { -#ifdef OSX_ENABLED - List<String> args; +Error EditorExportPlatformMacOS::_notarize(const Ref<EditorExportPreset> &p_preset, const String &p_path) { + int notary_tool = p_preset->get("notarization/notarization"); + switch (notary_tool) { + case 1: { // "rcodesign" + print_verbose("using rcodesign notarization..."); - args.push_back("altool"); - args.push_back("--notarize-app"); + String rcodesign = EditorSettings::get_singleton()->get("export/macos/rcodesign").operator String(); + if (rcodesign.is_empty()) { + add_message(EXPORT_MESSAGE_ERROR, TTR("Notarization"), TTR("rcodesign path is not set. Configure rcodesign path in the Editor Settings (Export > macOS > rcodesign).")); + return Error::FAILED; + } - args.push_back("--primary-bundle-id"); - args.push_back(p_preset->get("application/bundle_identifier")); + List<String> args; - args.push_back("--username"); - args.push_back(p_preset->get("notarization/apple_id_name")); + args.push_back("notary-submit"); - args.push_back("--password"); - args.push_back(p_preset->get("notarization/apple_id_password")); + if (p_preset->get("notarization/api_uuid") == "") { + add_message(EXPORT_MESSAGE_ERROR, TTR("Notarization"), TTR("App Store Connect issuer ID name not specified.")); + return Error::FAILED; + } + if (p_preset->get("notarization/api_key") == "") { + add_message(EXPORT_MESSAGE_ERROR, TTR("Notarization"), TTR("App Store Connect API key ID not specified.")); + return Error::FAILED; + } - args.push_back("--type"); - args.push_back("osx"); + args.push_back("--api-issuer"); + args.push_back(p_preset->get("notarization/api_uuid")); - if (p_preset->get("notarization/apple_team_id")) { - args.push_back("--asc-provider"); - args.push_back(p_preset->get("notarization/apple_team_id")); - } + args.push_back("--api-key"); + args.push_back(p_preset->get("notarization/api_key")); - args.push_back("--file"); - args.push_back(p_path); + args.push_back(p_path); - String str; - Error err = OS::get_singleton()->execute("xcrun", args, &str, nullptr, true); - if (err != OK || (str.find("not found") != -1) || (str.find("not recognized") != -1)) { - add_message(EXPORT_MESSAGE_WARNING, TTR("Notarization"), TTR("Could not start xcrun executable.")); - return err; - } + String str; + int exitcode = 0; - print_verbose("altool (" + p_path + "):\n" + str); - int rq_offset = str.find("RequestUUID"); - if (rq_offset == -1) { - add_message(EXPORT_MESSAGE_WARNING, TTR("Notarization"), TTR("Notarization failed.")); - return FAILED; - } else { - int next_nl = str.find("\n", rq_offset); - String request_uuid = (next_nl == -1) ? str.substr(rq_offset + 14, -1) : str.substr(rq_offset + 14, next_nl - rq_offset - 14); - add_message(EXPORT_MESSAGE_INFO, TTR("Notarization"), vformat(TTR("Notarization request UUID: \"%s\""), request_uuid)); - add_message(EXPORT_MESSAGE_INFO, TTR("Notarization"), TTR("The notarization process generally takes less than an hour. When the process is completed, you'll receive an email.")); - add_message(EXPORT_MESSAGE_INFO, TTR("Notarization"), "\t" + TTR("You can check progress manually by opening a Terminal and running the following command:")); - add_message(EXPORT_MESSAGE_INFO, TTR("Notarization"), "\t\t\"xcrun altool --notarization-history 0 -u <your email> -p <app-specific pwd>\""); - add_message(EXPORT_MESSAGE_INFO, TTR("Notarization"), "\t" + TTR("Run the following command to staple the notarization ticket to the exported application (optional):")); - add_message(EXPORT_MESSAGE_INFO, TTR("Notarization"), "\t\t\"xcrun stapler staple <app path>\""); - } + Error err = OS::get_singleton()->execute(rcodesign, args, &str, &exitcode, true); + if (err != OK) { + add_message(EXPORT_MESSAGE_WARNING, TTR("Notarization"), TTR("Could not start rcodesign executable.")); + return err; + } -#endif + int rq_offset = str.find("created submission ID:"); + if (exitcode != 0 || rq_offset == -1) { + print_line("rcodesign (" + p_path + "):\n" + str); + add_message(EXPORT_MESSAGE_WARNING, TTR("Notarization"), TTR("Notarization failed, see editor log for details.")); + return Error::FAILED; + } else { + print_verbose("rcodesign (" + p_path + "):\n" + str); + int next_nl = str.find("\n", rq_offset); + String request_uuid = (next_nl == -1) ? str.substr(rq_offset + 14, -1) : str.substr(rq_offset + 14, next_nl - rq_offset - 14); + add_message(EXPORT_MESSAGE_INFO, TTR("Notarization"), vformat(TTR("Notarization request UUID: \"%s\""), request_uuid)); + add_message(EXPORT_MESSAGE_INFO, TTR("Notarization"), TTR("The notarization process generally takes less than an hour.")); + add_message(EXPORT_MESSAGE_INFO, TTR("Notarization"), "\t" + TTR("You can check progress manually by opening a Terminal and running the following command:")); + add_message(EXPORT_MESSAGE_INFO, TTR("Notarization"), "\t\t\"rcodesign notary-log --api-issuer <api uuid> --api-key <api key> <request uuid>\""); + add_message(EXPORT_MESSAGE_INFO, TTR("Notarization"), "\t" + TTR("Run the following command to staple the notarization ticket to the exported application (optional):")); + add_message(EXPORT_MESSAGE_INFO, TTR("Notarization"), "\t\t\"rcodesign staple <app path>\""); + } + } break; +#ifdef MACOS_ENABLED + case 2: { // "altool" + print_verbose("using altool notarization..."); + + if (!FileAccess::exists("/usr/bin/xcrun") && !FileAccess::exists("/bin/xcrun")) { + add_message(EXPORT_MESSAGE_ERROR, TTR("Notarization"), TTR("Xcode command line tools are not installed.")); + return Error::FAILED; + } - return OK; -} + List<String> args; -Error EditorExportPlatformOSX::_code_sign(const Ref<EditorExportPreset> &p_preset, const String &p_path, const String &p_ent_path, bool p_warn) { - bool force_builtin_codesign = EditorSettings::get_singleton()->get("export/macos/force_builtin_codesign"); - bool ad_hoc = (p_preset->get("codesign/identity") == "" || p_preset->get("codesign/identity") == "-"); + args.push_back("altool"); + args.push_back("--notarize-app"); - if ((!FileAccess::exists("/usr/bin/codesign") && !FileAccess::exists("/bin/codesign")) || force_builtin_codesign) { - print_verbose("using built-in codesign..."); -#ifdef MODULE_REGEX_ENABLED + args.push_back("--primary-bundle-id"); + args.push_back(p_preset->get("application/bundle_identifier")); -#ifdef OSX_ENABLED - if (p_preset->get("codesign/timestamp") && p_warn) { - add_message(EXPORT_MESSAGE_INFO, TTR("Code Signing"), TTR("Timestamping is not compatible with ad-hoc signature, and was disabled!")); - } - if (p_preset->get("codesign/hardened_runtime") && p_warn) { - add_message(EXPORT_MESSAGE_INFO, TTR("Code Signing"), TTR("Hardened Runtime is not compatible with ad-hoc signature, and was disabled!")); - } + if (p_preset->get("notarization/apple_id_name") == "" && p_preset->get("notarization/api_uuid") == "") { + add_message(EXPORT_MESSAGE_ERROR, TTR("Notarization"), TTR("Neither Apple ID name nor App Store Connect issuer ID name not specified.")); + return Error::FAILED; + } + if (p_preset->get("notarization/apple_id_name") != "" && p_preset->get("notarization/api_uuid") != "") { + add_message(EXPORT_MESSAGE_ERROR, TTR("Notarization"), TTR("Both Apple ID name and App Store Connect issuer ID name are specified, only one should be set at the same time.")); + return Error::FAILED; + } + + if (p_preset->get("notarization/apple_id_name") != "") { + if (p_preset->get("notarization/apple_id_password") == "") { + add_message(EXPORT_MESSAGE_ERROR, TTR("Notarization"), TTR("Apple ID password not specified.")); + return Error::FAILED; + } + args.push_back("--username"); + args.push_back(p_preset->get("notarization/apple_id_name")); + + args.push_back("--password"); + args.push_back(p_preset->get("notarization/apple_id_password")); + } else { + if (p_preset->get("notarization/api_key") == "") { + add_message(EXPORT_MESSAGE_ERROR, TTR("Notarization"), TTR("App Store Connect API key ID not specified.")); + return Error::FAILED; + } + args.push_back("--apiIssuer"); + args.push_back(p_preset->get("notarization/api_uuid")); + + args.push_back("--apiKey"); + args.push_back(p_preset->get("notarization/api_key")); + } + + args.push_back("--type"); + args.push_back("osx"); + + if (p_preset->get("notarization/apple_team_id")) { + args.push_back("--asc-provider"); + args.push_back(p_preset->get("notarization/apple_team_id")); + } + + args.push_back("--file"); + args.push_back(p_path); + + String str; + int exitcode = 0; + Error err = OS::get_singleton()->execute("xcrun", args, &str, &exitcode, true); + if (err != OK) { + add_message(EXPORT_MESSAGE_WARNING, TTR("Notarization"), TTR("Could not start xcrun executable.")); + return err; + } + + int rq_offset = str.find("RequestUUID"); + if (exitcode != 0 || rq_offset == -1) { + print_line("xcrun altool (" + p_path + "):\n" + str); + add_message(EXPORT_MESSAGE_WARNING, TTR("Notarization"), TTR("Notarization failed, see editor log for details.")); + return Error::FAILED; + } else { + print_verbose("xcrun altool (" + p_path + "):\n" + str); + int next_nl = str.find("\n", rq_offset); + String request_uuid = (next_nl == -1) ? str.substr(rq_offset + 14, -1) : str.substr(rq_offset + 14, next_nl - rq_offset - 14); + add_message(EXPORT_MESSAGE_INFO, TTR("Notarization"), vformat(TTR("Notarization request UUID: \"%s\""), request_uuid)); + add_message(EXPORT_MESSAGE_INFO, TTR("Notarization"), TTR("The notarization process generally takes less than an hour. When the process is completed, you'll receive an email.")); + add_message(EXPORT_MESSAGE_INFO, TTR("Notarization"), "\t" + TTR("You can check progress manually by opening a Terminal and running the following command:")); + add_message(EXPORT_MESSAGE_INFO, TTR("Notarization"), "\t\t\"xcrun altool --notarization-history 0 -u <your email> -p <app-specific pwd>\""); + add_message(EXPORT_MESSAGE_INFO, TTR("Notarization"), "\t" + TTR("Run the following command to staple the notarization ticket to the exported application (optional):")); + add_message(EXPORT_MESSAGE_INFO, TTR("Notarization"), "\t\t\"xcrun stapler staple <app path>\""); + } + } break; #endif + default: { + }; + } + return OK; +} - String error_msg; - Error err = CodeSign::codesign(false, p_preset->get("codesign/replace_existing_signature"), p_path, p_ent_path, error_msg); - if (err != OK) { - add_message(EXPORT_MESSAGE_WARNING, TTR("Code Signing"), vformat(TTR("Built-in CodeSign failed with error \"%s\"."), error_msg)); - return FAILED; - } +Error EditorExportPlatformMacOS::_code_sign(const Ref<EditorExportPreset> &p_preset, const String &p_path, const String &p_ent_path, bool p_warn) { + int codesign_tool = p_preset->get("codesign/codesign"); + switch (codesign_tool) { + case 1: { // built-in ad-hoc + print_verbose("using built-in codesign..."); +#ifdef MODULE_REGEX_ENABLED + String error_msg; + Error err = CodeSign::codesign(false, true, p_path, p_ent_path, error_msg); + if (err != OK) { + add_message(EXPORT_MESSAGE_WARNING, TTR("Code Signing"), vformat(TTR("Built-in CodeSign failed with error \"%s\"."), error_msg)); + return Error::FAILED; + } #else - add_message(EXPORT_MESSAGE_WARNING, TTR("Code Signing"), TTR("Built-in CodeSign require regex module.")); + add_message(EXPORT_MESSAGE_WARNING, TTR("Code Signing"), TTR("Built-in CodeSign require regex module.")); #endif - return OK; - } else { - print_verbose("using external codesign..."); - List<String> args; - if (p_preset->get("codesign/timestamp")) { - if (ad_hoc) { - if (p_warn) { - add_message(EXPORT_MESSAGE_INFO, TTR("Code Signing"), TTR("Timestamping is not compatible with ad-hoc signature, and was disabled!")); - } - } else { - args.push_back("--timestamp"); + } break; + case 2: { // "rcodesign" + print_verbose("using rcodesign codesign..."); + + String rcodesign = EditorSettings::get_singleton()->get("export/macos/rcodesign").operator String(); + if (rcodesign.is_empty()) { + add_message(EXPORT_MESSAGE_ERROR, TTR("Code Signing"), TTR("Xrcodesign path is not set. Configure rcodesign path in the Editor Settings (Export > macOS > rcodesign).")); + return Error::FAILED; } - } - if (p_preset->get("codesign/hardened_runtime")) { - if (ad_hoc) { - if (p_warn) { - add_message(EXPORT_MESSAGE_INFO, TTR("Code Signing"), TTR("Hardened Runtime is not compatible with ad-hoc signature, and was disabled!")); - } + + List<String> args; + args.push_back("sign"); + + if (p_path.get_extension() != "dmg") { + args.push_back("--entitlements-xml-path"); + args.push_back(p_ent_path); + } + + String certificate_file = p_preset->get("codesign/certificate_file"); + String certificate_pass = p_preset->get("codesign/certificate_password"); + if (!certificate_file.is_empty() && !certificate_file.is_empty()) { + args.push_back("--p12-file"); + args.push_back(certificate_file); + args.push_back("--p12-password"); + args.push_back(certificate_pass); + } + + args.push_back("-v"); /* provide some more feedback */ + + args.push_back(p_path); + + String str; + int exitcode = 0; + + Error err = OS::get_singleton()->execute(rcodesign, args, &str, &exitcode, true); + if (err != OK) { + add_message(EXPORT_MESSAGE_WARNING, TTR("Code Signing"), TTR("Could not start rcodesign executable.")); + return err; + } + + if (exitcode != 0) { + print_line("rcodesign (" + p_path + "):\n" + str); + add_message(EXPORT_MESSAGE_WARNING, TTR("Code Signing"), TTR("Code signing failed, see editor log for details.")); + return Error::FAILED; } else { + print_verbose("rcodesign (" + p_path + "):\n" + str); + } + } break; +#ifdef MACOS_ENABLED + case 3: { // "codesign" + print_verbose("using xcode codesign..."); + + if (!FileAccess::exists("/usr/bin/codesign") && !FileAccess::exists("/bin/codesign")) { + add_message(EXPORT_MESSAGE_ERROR, TTR("Code Signing"), TTR("Xcode command line tools are not installed.")); + return Error::FAILED; + } + + bool ad_hoc = (p_preset->get("codesign/identity") == "" || p_preset->get("codesign/identity") == "-"); + + List<String> args; + if (!ad_hoc) { + args.push_back("--timestamp"); args.push_back("--options"); args.push_back("runtime"); } - } - - if (p_path.get_extension() != "dmg") { - args.push_back("--entitlements"); - args.push_back(p_ent_path); - } - PackedStringArray user_args = p_preset->get("codesign/custom_options"); - for (int i = 0; i < user_args.size(); i++) { - String user_arg = user_args[i].strip_edges(); - if (!user_arg.is_empty()) { - args.push_back(user_arg); + if (p_path.get_extension() != "dmg") { + args.push_back("--entitlements"); + args.push_back(p_ent_path); } - } - args.push_back("-s"); - if (ad_hoc) { - args.push_back("-"); - } else { - args.push_back(p_preset->get("codesign/identity")); - } + PackedStringArray user_args = p_preset->get("codesign/custom_options"); + for (int i = 0; i < user_args.size(); i++) { + String user_arg = user_args[i].strip_edges(); + if (!user_arg.is_empty()) { + args.push_back(user_arg); + } + } - args.push_back("-v"); /* provide some more feedback */ + args.push_back("-s"); + if (ad_hoc) { + args.push_back("-"); + } else { + args.push_back(p_preset->get("codesign/identity")); + } - if (p_preset->get("codesign/replace_existing_signature")) { + args.push_back("-v"); /* provide some more feedback */ args.push_back("-f"); - } - args.push_back(p_path); + args.push_back(p_path); - String str; - Error err = OS::get_singleton()->execute("codesign", args, &str, nullptr, true); - if (err != OK || (str.find("not found") != -1) || (str.find("not recognized") != -1)) { - add_message(EXPORT_MESSAGE_WARNING, TTR("Code Signing"), TTR("Could not start codesign executable, make sure Xcode command line tools are installed.")); - return err; - } + String str; + int exitcode = 0; - print_verbose("codesign (" + p_path + "):\n" + str); - if (str.find("no identity found") != -1) { - add_message(EXPORT_MESSAGE_WARNING, TTR("Code Signing"), TTR("No identity found.")); - return FAILED; - } - if ((str.find("unrecognized blob type") != -1) || (str.find("cannot read entitlement data") != -1)) { - add_message(EXPORT_MESSAGE_WARNING, TTR("Code Signing"), TTR("Invalid entitlements file.")); - return FAILED; - } - return OK; + Error err = OS::get_singleton()->execute("codesign", args, &str, nullptr, true); + if (err != OK) { + add_message(EXPORT_MESSAGE_WARNING, TTR("Code Signing"), TTR("Could not start codesign executable, make sure Xcode command line tools are installed.")); + return err; + } + + if (exitcode != 0) { + print_line("codesign (" + p_path + "):\n" + str); + add_message(EXPORT_MESSAGE_WARNING, TTR("Code Signing"), TTR("Code signing failed, see editor log for details.")); + return Error::FAILED; + } else { + print_verbose("codesign (" + p_path + "):\n" + str); + } + } break; +#endif + default: { + }; } + + return OK; } -Error EditorExportPlatformOSX::_code_sign_directory(const Ref<EditorExportPreset> &p_preset, const String &p_path, +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) { -#ifdef OSX_ENABLED +#ifdef MACOS_ENABLED static Vector<String> extensions_to_sign; if (extensions_to_sign.is_empty()) { @@ -586,7 +766,7 @@ Error EditorExportPlatformOSX::_code_sign_directory(const Ref<EditorExportPreset dir_access->list_dir_begin(); String current_file{ dir_access->get_next() }; while (!current_file.is_empty()) { - String current_file_path{ p_path.plus_file(current_file) }; + String current_file_path{ p_path.path_join(current_file) }; if (current_file == ".." || current_file == ".") { current_file = dir_access->get_next(); @@ -615,7 +795,7 @@ Error EditorExportPlatformOSX::_code_sign_directory(const Ref<EditorExportPreset return OK; } -Error EditorExportPlatformOSX::_copy_and_sign_files(Ref<DirAccess> &dir_access, const String &p_src_path, +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, bool p_should_error_on_non_code_sign) { @@ -644,14 +824,14 @@ Error EditorExportPlatformOSX::_copy_and_sign_files(Ref<DirAccess> &dir_access, return err; } -Error EditorExportPlatformOSX::_export_osx_plugins_for(Ref<EditorExportPlugin> p_editor_export_plugin, +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) { Error error{ OK }; - const Vector<String> &osx_plugins{ p_editor_export_plugin->get_osx_plugin_files() }; - for (int i = 0; i < osx_plugins.size(); ++i) { - String src_path{ ProjectSettings::get_singleton()->globalize_path(osx_plugins[i]) }; + 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); if (error != OK) { @@ -661,7 +841,7 @@ Error EditorExportPlatformOSX::_export_osx_plugins_for(Ref<EditorExportPlugin> p return error; } -Error EditorExportPlatformOSX::_create_dmg(const String &p_dmg_path, const String &p_pkg_name, const String &p_app_path_name) { +Error EditorExportPlatformMacOS::_create_dmg(const String &p_dmg_path, const String &p_pkg_name, const String &p_app_path_name) { List<String> args; if (FileAccess::exists(p_dmg_path)) { @@ -697,7 +877,7 @@ Error EditorExportPlatformOSX::_create_dmg(const String &p_dmg_path, const Strin return OK; } -Error EditorExportPlatformOSX::_export_debug_script(const Ref<EditorExportPreset> &p_preset, const String &p_app_name, const String &p_pkg_name, const String &p_path) { +Error EditorExportPlatformMacOS::_export_debug_script(const Ref<EditorExportPreset> &p_preset, const String &p_app_name, const String &p_pkg_name, const String &p_path) { Ref<FileAccess> f = FileAccess::open(p_path, FileAccess::WRITE); if (f.is_null()) { add_message(EXPORT_MESSAGE_ERROR, TTR("Debug Script Export"), vformat(TTR("Could not open file \"%s\"."), p_path)); @@ -706,19 +886,30 @@ Error EditorExportPlatformOSX::_export_debug_script(const Ref<EditorExportPreset f->store_line("#!/bin/sh"); f->store_line("echo -ne '\\033c\\033]0;" + p_app_name + "\\a'"); - f->store_line("function realpath() { python -c \"import os,sys; print(os.path.realpath(sys.argv[1]))\" \"$0\"; }"); - f->store_line("base_path=\"$(dirname \"$(realpath \"$0\")\")\""); - f->store_line("\"$base_path/" + p_pkg_name + "\" \"$@\""); + f->store_line(""); + f->store_line("function app_realpath() {"); + f->store_line(" SOURCE=$1"); + f->store_line(" while [ -h \"$SOURCE\" ]; do"); + f->store_line(" DIR=$(dirname \"$SOURCE\")"); + f->store_line(" SOURCE=$(readlink \"$SOURCE\")"); + f->store_line(" [[ $SOURCE != /* ]] && SOURCE=$DIR/$SOURCE"); + f->store_line(" done"); + f->store_line(" echo \"$( cd -P \"$( dirname \"$SOURCE\" )\" >/dev/null 2>&1 && pwd )\""); + f->store_line("}"); + f->store_line(""); + f->store_line("BASE_PATH=\"$(app_realpath \"${BASH_SOURCE[0]}\")\""); + f->store_line("\"$BASE_PATH/" + p_pkg_name + "\" \"$@\""); + f->store_line(""); return OK; } -Error EditorExportPlatformOSX::export_project(const Ref<EditorExportPreset> &p_preset, bool p_debug, const String &p_path, int p_flags) { +Error EditorExportPlatformMacOS::export_project(const Ref<EditorExportPreset> &p_preset, bool p_debug, const String &p_path, int p_flags) { ExportNotifier notifier(*this, p_preset, p_debug, p_path, p_flags); String src_pkg_name; - EditorProgress ep("export", "Exporting for OSX", 3, true); + EditorProgress ep("export", "Exporting for macOS", 3, true); if (p_debug) { src_pkg_name = p_preset->get("custom_template/debug"); @@ -728,7 +919,7 @@ Error EditorExportPlatformOSX::export_project(const Ref<EditorExportPreset> &p_p if (src_pkg_name.is_empty()) { String err; - src_pkg_name = find_export_template("osx.zip", &err); + src_pkg_name = find_export_template("macos.zip", &err); if (src_pkg_name.is_empty()) { add_message(EXPORT_MESSAGE_ERROR, TTR("Prepare Templates"), TTR("Export template not found.")); return ERR_FILE_NOT_FOUND; @@ -755,7 +946,8 @@ Error EditorExportPlatformOSX::export_project(const Ref<EditorExportPreset> &p_p int ret = unzGoToFirstFile(src_pkg_zip); - String binary_to_use = "godot_osx_" + String(p_debug ? "debug" : "release") + ".64"; + String architecture = p_preset->get("binary_format/architecture"); + String binary_to_use = "godot_macos_" + String(p_debug ? "debug" : "release") + "." + architecture; String pkg_name; if (String(ProjectSettings::get_singleton()->get("application/config/name")) != "") { @@ -788,9 +980,9 @@ Error EditorExportPlatformOSX::export_project(const Ref<EditorExportPreset> &p_p tmp_app_path_name = p_path; scr_path = p_path.get_basename() + ".command"; } else { - tmp_base_path_name = EditorPaths::get_singleton()->get_cache_dir().plus_file(pkg_name); - tmp_app_path_name = tmp_base_path_name.plus_file(tmp_app_dir_name); - scr_path = tmp_base_path_name.plus_file(pkg_name + ".command"); + tmp_base_path_name = EditorPaths::get_singleton()->get_cache_dir().path_join(pkg_name); + tmp_app_path_name = tmp_base_path_name.path_join(tmp_app_dir_name); + scr_path = tmp_base_path_name.path_join(pkg_name + ".command"); } print_verbose("Exporting to " + tmp_app_path_name); @@ -803,7 +995,9 @@ Error EditorExportPlatformOSX::export_project(const Ref<EditorExportPreset> &p_p err = ERR_CANT_CREATE; } - DirAccess::remove_file_or_error(scr_path); + if (FileAccess::exists(scr_path)) { + DirAccess::remove_file_or_error(scr_path); + } if (DirAccess::exists(tmp_app_path_name)) { String old_dir = tmp_app_dir->get_current_dir(); if (tmp_app_dir->change_dir(tmp_app_path_name) == OK) { @@ -906,54 +1100,58 @@ Error EditorExportPlatformOSX::export_project(const Ref<EditorExportPreset> &p_p f->store_line("NSHumanReadableCopyright = \"" + p_preset->get("application/copyright").operator String() + "\";"); } + HashSet<String> languages; for (const String &E : translations) { Ref<Translation> tr = ResourceLoader::load(E); - if (tr.is_valid()) { - String lang = tr->get_locale(); - String fname = tmp_app_path_name + "/Contents/Resources/" + lang + ".lproj"; - tmp_app_dir->make_dir_recursive(fname); - Ref<FileAccess> f = FileAccess::open(fname + "/InfoPlist.strings", FileAccess::WRITE); - f->store_line("/* Localized versions of Info.plist keys */"); - f->store_line(""); - if (appnames.has(lang)) { - f->store_line("CFBundleDisplayName = \"" + appnames[lang].operator String() + "\";"); - } - if (microphone_usage_descriptions.has(lang)) { - f->store_line("NSMicrophoneUsageDescription = \"" + microphone_usage_descriptions[lang].operator String() + "\";"); - } - if (camera_usage_descriptions.has(lang)) { - f->store_line("NSCameraUsageDescription = \"" + camera_usage_descriptions[lang].operator String() + "\";"); - } - if (location_usage_descriptions.has(lang)) { - f->store_line("NSLocationUsageDescription = \"" + location_usage_descriptions[lang].operator String() + "\";"); - } - if (address_book_usage_descriptions.has(lang)) { - f->store_line("NSContactsUsageDescription = \"" + address_book_usage_descriptions[lang].operator String() + "\";"); - } - if (calendar_usage_descriptions.has(lang)) { - f->store_line("NSCalendarsUsageDescription = \"" + calendar_usage_descriptions[lang].operator String() + "\";"); - } - if (photos_library_usage_descriptions.has(lang)) { - f->store_line("NSPhotoLibraryUsageDescription = \"" + photos_library_usage_descriptions[lang].operator String() + "\";"); - } - if (desktop_folder_usage_descriptions.has(lang)) { - f->store_line("NSDesktopFolderUsageDescription = \"" + desktop_folder_usage_descriptions[lang].operator String() + "\";"); - } - if (documents_folder_usage_descriptions.has(lang)) { - f->store_line("NSDocumentsFolderUsageDescription = \"" + documents_folder_usage_descriptions[lang].operator String() + "\";"); - } - if (downloads_folder_usage_descriptions.has(lang)) { - f->store_line("NSDownloadsFolderUsageDescription = \"" + downloads_folder_usage_descriptions[lang].operator String() + "\";"); - } - if (network_volumes_usage_descriptions.has(lang)) { - f->store_line("NSNetworkVolumesUsageDescription = \"" + network_volumes_usage_descriptions[lang].operator String() + "\";"); - } - if (removable_volumes_usage_descriptions.has(lang)) { - f->store_line("NSRemovableVolumesUsageDescription = \"" + removable_volumes_usage_descriptions[lang].operator String() + "\";"); - } - if (copyrights.has(lang)) { - f->store_line("NSHumanReadableCopyright = \"" + copyrights[lang].operator String() + "\";"); - } + if (tr.is_valid() && tr->get_locale() != "en") { + languages.insert(tr->get_locale()); + } + } + + for (const String &lang : languages) { + String fname = tmp_app_path_name + "/Contents/Resources/" + lang + ".lproj"; + tmp_app_dir->make_dir_recursive(fname); + Ref<FileAccess> f = FileAccess::open(fname + "/InfoPlist.strings", FileAccess::WRITE); + f->store_line("/* Localized versions of Info.plist keys */"); + f->store_line(""); + if (appnames.has(lang)) { + f->store_line("CFBundleDisplayName = \"" + appnames[lang].operator String() + "\";"); + } + if (microphone_usage_descriptions.has(lang)) { + f->store_line("NSMicrophoneUsageDescription = \"" + microphone_usage_descriptions[lang].operator String() + "\";"); + } + if (camera_usage_descriptions.has(lang)) { + f->store_line("NSCameraUsageDescription = \"" + camera_usage_descriptions[lang].operator String() + "\";"); + } + if (location_usage_descriptions.has(lang)) { + f->store_line("NSLocationUsageDescription = \"" + location_usage_descriptions[lang].operator String() + "\";"); + } + if (address_book_usage_descriptions.has(lang)) { + f->store_line("NSContactsUsageDescription = \"" + address_book_usage_descriptions[lang].operator String() + "\";"); + } + if (calendar_usage_descriptions.has(lang)) { + f->store_line("NSCalendarsUsageDescription = \"" + calendar_usage_descriptions[lang].operator String() + "\";"); + } + if (photos_library_usage_descriptions.has(lang)) { + f->store_line("NSPhotoLibraryUsageDescription = \"" + photos_library_usage_descriptions[lang].operator String() + "\";"); + } + if (desktop_folder_usage_descriptions.has(lang)) { + f->store_line("NSDesktopFolderUsageDescription = \"" + desktop_folder_usage_descriptions[lang].operator String() + "\";"); + } + if (documents_folder_usage_descriptions.has(lang)) { + f->store_line("NSDocumentsFolderUsageDescription = \"" + documents_folder_usage_descriptions[lang].operator String() + "\";"); + } + if (downloads_folder_usage_descriptions.has(lang)) { + f->store_line("NSDownloadsFolderUsageDescription = \"" + downloads_folder_usage_descriptions[lang].operator String() + "\";"); + } + if (network_volumes_usage_descriptions.has(lang)) { + f->store_line("NSNetworkVolumesUsageDescription = \"" + network_volumes_usage_descriptions[lang].operator String() + "\";"); + } + if (removable_volumes_usage_descriptions.has(lang)) { + f->store_line("NSRemovableVolumesUsageDescription = \"" + removable_volumes_usage_descriptions[lang].operator String() + "\";"); + } + if (copyrights.has(lang)) { + f->store_line("NSHumanReadableCopyright = \"" + copyrights[lang].operator String() + "\";"); } } } @@ -984,14 +1182,14 @@ Error EditorExportPlatformOSX::export_project(const Ref<EditorExportPreset> &p_p unzCloseCurrentFile(src_pkg_zip); // Write. - file = file.replace_first("osx_template.app/", ""); + file = file.replace_first("macos_template.app/", ""); if (((info.external_fa >> 16L) & 0120000) == 0120000) { #ifndef UNIX_ENABLED add_message(EXPORT_MESSAGE_INFO, TTR("Export"), TTR("Relative symlinks are not supported on this OS, the exported project might be broken!")); #endif // Handle symlinks in the archive. - file = tmp_app_path_name.plus_file(file); + file = tmp_app_path_name.path_join(file); if (err == OK) { err = tmp_app_dir->make_dir_recursive(file.get_base_dir()); if (err != OK) { @@ -1053,19 +1251,19 @@ Error EditorExportPlatformOSX::export_project(const Ref<EditorExportPreset> &p_p } if (data.size() > 0) { - if (file.find("/data.mono.osx.64.release_debug/") != -1) { + if (file.find("/data.mono.macos.release_debug." + architecture + "/") != -1) { if (!p_debug) { ret = unzGoToNextFile(src_pkg_zip); continue; // skip } - file = file.replace("/data.mono.osx.64.release_debug/", "/GodotSharp/"); + file = file.replace("/data.mono.macos.release_debug." + architecture + "/", "/GodotSharp/"); } - if (file.find("/data.mono.osx.64.release/") != -1) { + if (file.find("/data.mono.macos.release." + architecture + "/") != -1) { if (p_debug) { ret = unzGoToNextFile(src_pkg_zip); continue; // skip } - file = file.replace("/data.mono.osx.64.release/", "/GodotSharp/"); + file = file.replace("/data.mono.macos.release." + architecture + "/", "/GodotSharp/"); } if (file.ends_with(".dylib")) { @@ -1075,7 +1273,7 @@ Error EditorExportPlatformOSX::export_project(const Ref<EditorExportPreset> &p_p print_verbose("ADDING: " + file + " size: " + itos(data.size())); // Write it into our application bundle. - file = tmp_app_path_name.plus_file(file); + file = tmp_app_path_name.path_join(file); if (err == OK) { err = tmp_app_dir->make_dir_recursive(file.get_base_dir()); if (err != OK) { @@ -1131,12 +1329,12 @@ Error EditorExportPlatformOSX::export_project(const Ref<EditorExportPreset> &p_p err = save_pack(p_preset, p_debug, pack_path, &shared_objects); // See if we can code sign our new package. - bool sign_enabled = p_preset->get("codesign/enable"); + bool sign_enabled = (p_preset->get("codesign/codesign").operator int() > 0); String ent_path = p_preset->get("codesign/entitlements/custom_file"); - String hlp_ent_path = EditorPaths::get_singleton()->get_cache_dir().plus_file(pkg_name + "_helper.entitlements"); + String hlp_ent_path = EditorPaths::get_singleton()->get_cache_dir().path_join(pkg_name + "_helper.entitlements"); if (sign_enabled && (ent_path.is_empty())) { - ent_path = EditorPaths::get_singleton()->get_cache_dir().plus_file(pkg_name + ".entitlements"); + ent_path = EditorPaths::get_singleton()->get_cache_dir().path_join(pkg_name + ".entitlements"); Ref<FileAccess> ent_f = FileAccess::open(ent_path, FileAccess::WRITE); if (ent_f.is_valid()) { @@ -1297,14 +1495,25 @@ Error EditorExportPlatformOSX::export_project(const Ref<EditorExportPreset> &p_p } } - bool ad_hoc = true; - if (err == OK) { -#ifdef OSX_ENABLED - String sign_identity = p_preset->get("codesign/identity"); -#else - String sign_identity = "-"; + bool ad_hoc = false; + int codesign_tool = p_preset->get("codesign/codesign"); + switch (codesign_tool) { + case 1: { // built-in ad-hoc + ad_hoc = true; + } break; + case 2: { // "rcodesign" + ad_hoc = p_preset->get("codesign/certificate_file").operator String().is_empty() || p_preset->get("codesign/certificate_password").operator String().is_empty(); + } break; +#ifdef MACOS_ENABLED + case 3: { // "codesign" + ad_hoc = (p_preset->get("codesign/identity") == "" || p_preset->get("codesign/identity") == "-"); + } break; #endif - ad_hoc = (sign_identity == "" || sign_identity == "-"); + default: { + }; + } + + if (err == OK) { bool lib_validation = p_preset->get("codesign/entitlements/disable_library_validation"); if ((!dylibs_found.is_empty() || !shared_objects.is_empty()) && sign_enabled && ad_hoc && !lib_validation) { add_message(EXPORT_MESSAGE_ERROR, TTR("Code Signing"), TTR("Ad-hoc signed applications require the 'Disable Library Validation' entitlement to load dynamic libraries.")); @@ -1320,7 +1529,7 @@ Error EditorExportPlatformOSX::export_project(const Ref<EditorExportPreset> &p_p 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); } else { - String path_in_app = tmp_app_path_name.plus_file(shared_objects[i].target).plus_file(src_path.get_file()); + String path_in_app = tmp_app_path_name.path_join(shared_objects[i].target).path_join(src_path.get_file()); err = _copy_and_sign_files(da, src_path, path_in_app, sign_enabled, p_preset, ent_path, false); } if (err != OK) { @@ -1330,7 +1539,7 @@ Error EditorExportPlatformOSX::export_project(const Ref<EditorExportPreset> &p_p Vector<Ref<EditorExportPlugin>> export_plugins{ EditorExport::get_singleton()->get_export_plugins() }; for (int i = 0; i < export_plugins.size(); ++i) { - err = _export_osx_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); if (err != OK) { break; } @@ -1387,8 +1596,7 @@ Error EditorExportPlatformOSX::export_project(const Ref<EditorExportPreset> &p_p } } -#ifdef OSX_ENABLED - bool noto_enabled = p_preset->get("notarization/enable"); + bool noto_enabled = (p_preset->get("notarization/notarization").operator int() > 0); if (err == OK && noto_enabled) { if (export_format == "app") { add_message(EXPORT_MESSAGE_INFO, TTR("Notarization"), TTR("Notarization requires the app to be archived first, select the DMG or ZIP export format instead.")); @@ -1399,10 +1607,11 @@ Error EditorExportPlatformOSX::export_project(const Ref<EditorExportPreset> &p_p err = _notarize(p_preset, p_path); } } -#endif // Clean up temporary entitlements files. - DirAccess::remove_file_or_error(hlp_ent_path); + if (FileAccess::exists(hlp_ent_path)) { + DirAccess::remove_file_or_error(hlp_ent_path); + } // Clean up temporary .app dir and generated entitlements. if ((String)(p_preset->get("codesign/entitlements/custom_file")) == "") { @@ -1420,8 +1629,8 @@ Error EditorExportPlatformOSX::export_project(const Ref<EditorExportPreset> &p_p return err; } -void EditorExportPlatformOSX::_zip_folder_recursive(zipFile &p_zip, const String &p_root_path, const String &p_folder, const String &p_pkg_name) { - String dir = p_folder.is_empty() ? p_root_path : p_root_path.plus_file(p_folder); +void EditorExportPlatformMacOS::_zip_folder_recursive(zipFile &p_zip, const String &p_root_path, const String &p_folder, const String &p_pkg_name) { + String dir = p_folder.is_empty() ? p_root_path : p_root_path.path_join(p_folder); Ref<DirAccess> da = DirAccess::open(dir); da->list_dir_begin(); @@ -1432,16 +1641,15 @@ void EditorExportPlatformOSX::_zip_folder_recursive(zipFile &p_zip, const String continue; } if (da->is_link(f)) { - OS::Time time = OS::get_singleton()->get_time(); - OS::Date date = OS::get_singleton()->get_date(); + OS::DateTime dt = OS::get_singleton()->get_datetime(); zip_fileinfo zipfi; - zipfi.tmz_date.tm_hour = time.hour; - zipfi.tmz_date.tm_mday = date.day; - zipfi.tmz_date.tm_min = time.minute; - zipfi.tmz_date.tm_mon = date.month - 1; // Note: "tm" month range - 0..11, Godot month range - 1..12, https://www.cplusplus.com/reference/ctime/tm/ - zipfi.tmz_date.tm_sec = time.second; - zipfi.tmz_date.tm_year = date.year; + zipfi.tmz_date.tm_year = dt.year; + zipfi.tmz_date.tm_mon = dt.month - 1; // Note: "tm" month range - 0..11, Godot month range - 1..12, https://www.cplusplus.com/reference/ctime/tm/ + zipfi.tmz_date.tm_mday = dt.day; + zipfi.tmz_date.tm_hour = dt.hour; + zipfi.tmz_date.tm_min = dt.minute; + zipfi.tmz_date.tm_sec = dt.second; zipfi.dosDate = 0; // 0120000: symbolic link type // 0000755: permissions rwxr-xr-x @@ -1451,7 +1659,7 @@ void EditorExportPlatformOSX::_zip_folder_recursive(zipFile &p_zip, const String zipfi.internal_fa = 0; zipOpenNewFileInZip4(p_zip, - p_folder.plus_file(f).utf8().get_data(), + p_folder.path_join(f).utf8().get_data(), &zipfi, nullptr, 0, @@ -1473,20 +1681,19 @@ void EditorExportPlatformOSX::_zip_folder_recursive(zipFile &p_zip, const String zipWriteInFileInZip(p_zip, target.utf8().get_data(), target.utf8().size()); zipCloseFileInZip(p_zip); } else if (da->current_is_dir()) { - _zip_folder_recursive(p_zip, p_root_path, p_folder.plus_file(f), p_pkg_name); + _zip_folder_recursive(p_zip, p_root_path, p_folder.path_join(f), p_pkg_name); } else { bool is_executable = (p_folder.ends_with("MacOS") && (f == p_pkg_name)) || p_folder.ends_with("Helpers") || f.ends_with(".command"); - OS::Time time = OS::get_singleton()->get_time(); - OS::Date date = OS::get_singleton()->get_date(); + OS::DateTime dt = OS::get_singleton()->get_datetime(); zip_fileinfo zipfi; - zipfi.tmz_date.tm_hour = time.hour; - zipfi.tmz_date.tm_mday = date.day; - zipfi.tmz_date.tm_min = time.minute; - zipfi.tmz_date.tm_mon = date.month - 1; // Note: "tm" month range - 0..11, Godot month range - 1..12, https://www.cplusplus.com/reference/ctime/tm/ - zipfi.tmz_date.tm_sec = time.second; - zipfi.tmz_date.tm_year = date.year; + zipfi.tmz_date.tm_year = dt.year; + zipfi.tmz_date.tm_mon = dt.month - 1; // Note: "tm" month range - 0..11, Godot month range - 1..12, https://www.cplusplus.com/reference/ctime/tm/ + zipfi.tmz_date.tm_mday = dt.day; + zipfi.tmz_date.tm_hour = dt.hour; + zipfi.tmz_date.tm_min = dt.minute; + zipfi.tmz_date.tm_sec = dt.second; zipfi.dosDate = 0; // 0100000: regular file type // 0000755: permissions rwxr-xr-x @@ -1496,7 +1703,7 @@ void EditorExportPlatformOSX::_zip_folder_recursive(zipFile &p_zip, const String zipfi.internal_fa = 0; zipOpenNewFileInZip4(p_zip, - p_folder.plus_file(f).utf8().get_data(), + p_folder.path_join(f).utf8().get_data(), &zipfi, nullptr, 0, @@ -1514,9 +1721,9 @@ void EditorExportPlatformOSX::_zip_folder_recursive(zipFile &p_zip, const String 0x0314, // "version made by", 0x03 - Unix, 0x14 - ZIP specification version 2.0, required to store Unix file permissions 0); - Ref<FileAccess> fa = FileAccess::open(dir.plus_file(f), FileAccess::READ); + Ref<FileAccess> fa = FileAccess::open(dir.path_join(f), FileAccess::READ); if (fa.is_null()) { - add_message(EXPORT_MESSAGE_ERROR, TTR("ZIP Creation"), vformat(TTR("Could not open file to read from path \"%s\"."), dir.plus_file(f))); + add_message(EXPORT_MESSAGE_ERROR, TTR("ZIP Creation"), vformat(TTR("Could not open file to read from path \"%s\"."), dir.path_join(f))); return; } const int bufsize = 16384; @@ -1537,7 +1744,7 @@ void EditorExportPlatformOSX::_zip_folder_recursive(zipFile &p_zip, const String da->list_dir_end(); } -bool EditorExportPlatformOSX::can_export(const Ref<EditorExportPreset> &p_preset, String &r_error, bool &r_missing_templates) const { +bool EditorExportPlatformMacOS::has_valid_export_configuration(const Ref<EditorExportPreset> &p_preset, String &r_error, bool &r_missing_templates) const { String err; bool valid = false; @@ -1560,13 +1767,24 @@ bool EditorExportPlatformOSX::can_export(const Ref<EditorExportPreset> &p_preset // Look for export templates (official templates, check only is custom templates are not set). if (!dvalid || !rvalid) { - dvalid = exists_export_template("osx.zip", &err); + dvalid = exists_export_template("macos.zip", &err); rvalid = dvalid; // Both in the same ZIP. } valid = dvalid || rvalid; r_missing_templates = !valid; + if (!err.is_empty()) { + r_error = err; + } + + return valid; +} + +bool EditorExportPlatformMacOS::has_valid_project_configuration(const Ref<EditorExportPreset> &p_preset, String &r_error) const { + String err; + bool valid = true; + String identifier = p_preset->get("application/bundle_identifier"); String pn_err; if (!is_package_name_valid(identifier, &pn_err)) { @@ -1574,65 +1792,98 @@ bool EditorExportPlatformOSX::can_export(const Ref<EditorExportPreset> &p_preset valid = false; } - bool sign_enabled = p_preset->get("codesign/enable"); - -#ifdef OSX_ENABLED - bool noto_enabled = p_preset->get("notarization/enable"); - bool ad_hoc = ((p_preset->get("codesign/identity") == "") || (p_preset->get("codesign/identity") == "-")); - - if (!ad_hoc && (bool)EditorSettings::get_singleton()->get("export/macos/force_builtin_codesign")) { - err += TTR("Warning: Built-in \"codesign\" is selected in the Editor Settings. Code signing is limited to ad-hoc signature only.") + "\n"; - } - if (!ad_hoc && !FileAccess::exists("/usr/bin/codesign") && !FileAccess::exists("/bin/codesign")) { - err += TTR("Warning: Xcode command line tools are not installed, using built-in \"codesign\". Code signing is limited to ad-hoc signature only.") + "\n"; + bool ad_hoc = false; + int codesign_tool = p_preset->get("codesign/codesign"); + switch (codesign_tool) { + case 1: { // built-in ad-hoc + ad_hoc = true; + } break; + case 2: { // "rcodesign" + ad_hoc = p_preset->get("codesign/certificate_file").operator String().is_empty() || p_preset->get("codesign/certificate_password").operator String().is_empty(); + } break; +#ifdef MACOS_ENABLED + case 3: { // "codesign" + ad_hoc = (p_preset->get("codesign/identity") == "" || p_preset->get("codesign/identity") == "-"); + } break; +#endif + default: { + }; } + int notary_tool = p_preset->get("notarization/notarization"); - if (noto_enabled) { + if (notary_tool > 0) { if (ad_hoc) { err += TTR("Notarization: Notarization with an ad-hoc signature is not supported.") + "\n"; valid = false; } - if (!sign_enabled) { + if (codesign_tool == 0) { err += TTR("Notarization: Code signing is required for notarization.") + "\n"; valid = false; } - if (!(bool)p_preset->get("codesign/hardened_runtime")) { - err += TTR("Notarization: Hardened runtime is required for notarization.") + "\n"; - valid = false; - } - if (!(bool)p_preset->get("codesign/timestamp")) { - err += TTR("Notarization: Timestamping is required for notarization.") + "\n"; - valid = false; - } - if (p_preset->get("notarization/apple_id_name") == "") { - err += TTR("Notarization: Apple ID name not specified.") + "\n"; - valid = false; - } - if (p_preset->get("notarization/apple_id_password") == "") { - err += TTR("Notarization: Apple ID password not specified.") + "\n"; - valid = false; + if (notary_tool == 2) { + if (!FileAccess::exists("/usr/bin/xcrun") && !FileAccess::exists("/bin/xcrun")) { + err += TTR("Notarization: Xcode command line tools are not installed.") + "\n"; + valid = false; + } + if (p_preset->get("notarization/apple_id_name") == "" && p_preset->get("notarization/api_uuid") == "") { + err += TTR("Notarization: Neither Apple ID name nor App Store Connect issuer ID name not specified.") + "\n"; + valid = false; + } else if (p_preset->get("notarization/apple_id_name") != "" && p_preset->get("notarization/api_uuid") != "") { + err += TTR("Notarization: Both Apple ID name and App Store Connect issuer ID name are specified, only one should be set at the same time.") + "\n"; + valid = false; + } else { + if (p_preset->get("notarization/apple_id_name") != "") { + if (p_preset->get("notarization/apple_id_password") == "") { + err += TTR("Notarization: Apple ID password not specified.") + "\n"; + } + valid = false; + } + if (p_preset->get("notarization/api_uuid") != "") { + if (p_preset->get("notarization/api_key") == "") { + err += TTR("Notarization: App Store Connect API key ID not specified.") + "\n"; + valid = false; + } + } + } + } else if (notary_tool == 1) { + if (p_preset->get("notarization/api_uuid") == "") { + err += TTR("Notarization: App Store Connect issuer ID name not specified.") + "\n"; + valid = false; + } + if (p_preset->get("notarization/api_key") == "") { + err += TTR("Notarization: App Store Connect API key ID not specified.") + "\n"; + valid = false; + } + + String rcodesign = EditorSettings::get_singleton()->get("export/macos/rcodesign").operator String(); + if (rcodesign.is_empty()) { + err += TTR("Notarization: rcodesign path is not set. Configure rcodesign path in the Editor Settings (Export > macOS > rcodesign).") + "\n"; + valid = false; + } } } else { err += TTR("Warning: Notarization is disabled. The exported project will be blocked by Gatekeeper if it's downloaded from an unknown source.") + "\n"; - if (!sign_enabled) { + if (codesign_tool == 0) { err += TTR("Code signing is disabled. The exported project will not run on Macs with enabled Gatekeeper and Apple Silicon powered Macs.") + "\n"; - } else { - if ((bool)p_preset->get("codesign/hardened_runtime") && ad_hoc) { - err += TTR("Hardened Runtime is not compatible with ad-hoc signature, and will be disabled!") + "\n"; - } - if ((bool)p_preset->get("codesign/timestamp") && ad_hoc) { - err += TTR("Timestamping is not compatible with ad-hoc signature, and will be disabled!") + "\n"; - } } } -#else - err += TTR("Warning: Notarization is not supported from this OS. The exported project will be blocked by Gatekeeper if it's downloaded from an unknown source.") + "\n"; - if (!sign_enabled) { - err += TTR("Code signing is disabled. The exported project will not run on Macs with enabled Gatekeeper and Apple Silicon powered Macs.") + "\n"; - } -#endif - if (sign_enabled) { + if (codesign_tool > 0) { + if (ad_hoc) { + err += TTR("Code signing: Using ad-hoc signature. The exported project will be blocked by Gatekeeper") + "\n"; + } + if (codesign_tool == 3) { + if (!FileAccess::exists("/usr/bin/codesign") && !FileAccess::exists("/bin/codesign")) { + err += TTR("Code signing: Xcode command line tools are not installed.") + "\n"; + valid = false; + } + } else if (codesign_tool == 2) { + String rcodesign = EditorSettings::get_singleton()->get("export/macos/rcodesign").operator String(); + if (rcodesign.is_empty()) { + err += TTR("Code signing: rcodesign path is not set. Configure rcodesign path in the Editor Settings (Export > macOS > rcodesign).") + "\n"; + valid = false; + } + } if ((bool)p_preset->get("codesign/entitlements/audio_input") && ((String)p_preset->get("privacy/microphone_usage_description")).is_empty()) { err += TTR("Privacy: Microphone access is enabled, but usage description is not specified.") + "\n"; valid = false; @@ -1665,9 +1916,9 @@ bool EditorExportPlatformOSX::can_export(const Ref<EditorExportPreset> &p_preset return valid; } -EditorExportPlatformOSX::EditorExportPlatformOSX() { - logo = ImageTexture::create_from_image(memnew(Image(_osx_logo))); +EditorExportPlatformMacOS::EditorExportPlatformMacOS() { + logo = ImageTexture::create_from_image(memnew(Image(_macos_logo))); } -EditorExportPlatformOSX::~EditorExportPlatformOSX() { +EditorExportPlatformMacOS::~EditorExportPlatformMacOS() { } diff --git a/platform/osx/export/export_plugin.h b/platform/macos/export/export_plugin.h index ec97d4139f..87790129d3 100644 --- a/platform/osx/export/export_plugin.h +++ b/platform/macos/export/export_plugin.h @@ -28,8 +28,8 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ -#ifndef OSX_EXPORT_PLUGIN_H -#define OSX_EXPORT_PLUGIN_H +#ifndef MACOS_EXPORT_PLUGIN_H +#define MACOS_EXPORT_PLUGIN_H #include "core/config/project_settings.h" #include "core/io/dir_access.h" @@ -39,14 +39,14 @@ #include "core/io/zip_io.h" #include "core/os/os.h" #include "core/version.h" -#include "editor/editor_export.h" #include "editor/editor_settings.h" -#include "platform/osx/logo.gen.h" +#include "editor/export/editor_export.h" +#include "platform/macos/logo.gen.h" #include <sys/stat.h> -class EditorExportPlatformOSX : public EditorExportPlatform { - GDCLASS(EditorExportPlatformOSX, EditorExportPlatform); +class EditorExportPlatformMacOS : public EditorExportPlatform { + GDCLASS(EditorExportPlatformMacOS, EditorExportPlatform); int version_code = 0; @@ -61,7 +61,7 @@ class EditorExportPlatformOSX : public EditorExportPlatform { 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_should_error_on_non_code_sign); - Error _export_osx_plugins_for(Ref<EditorExportPlugin> p_editor_export_plugin, const String &p_app_path_name, + 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); Error _create_dmg(const String &p_dmg_path, const String &p_pkg_name, const String &p_app_path_name); @@ -69,7 +69,7 @@ class EditorExportPlatformOSX : public EditorExportPlatform { Error _export_debug_script(const Ref<EditorExportPreset> &p_preset, const String &p_app_name, const String &p_pkg_name, const String &p_path); bool use_codesign() const { return true; } -#ifdef OSX_ENABLED +#ifdef MACOS_ENABLED bool use_dmg() const { return true; } #else bool use_dmg() const { return false; } @@ -99,9 +99,9 @@ class EditorExportPlatformOSX : public EditorExportPlatform { } protected: - virtual void get_preset_features(const Ref<EditorExportPreset> &p_preset, List<String> *r_features) override; + virtual void get_preset_features(const Ref<EditorExportPreset> &p_preset, List<String> *r_features) const override; virtual void get_export_options(List<ExportOption> *r_options) override; - virtual bool get_export_option_visibility(const String &p_option, const HashMap<StringName, Variant> &p_options) const override; + virtual bool get_export_option_visibility(const EditorExportPreset *p_preset, const String &p_option, const HashMap<StringName, Variant> &p_options) const override; public: virtual String get_name() const override { return "macOS"; } @@ -119,9 +119,10 @@ public: } virtual Error export_project(const Ref<EditorExportPreset> &p_preset, bool p_debug, const String &p_path, int p_flags = 0) override; - virtual bool can_export(const Ref<EditorExportPreset> &p_preset, String &r_error, bool &r_missing_templates) const override; + virtual bool has_valid_export_configuration(const Ref<EditorExportPreset> &p_preset, String &r_error, bool &r_missing_templates) const override; + virtual bool has_valid_project_configuration(const Ref<EditorExportPreset> &p_preset, String &r_error) const override; - virtual void get_platform_features(List<String> *r_features) override { + virtual void get_platform_features(List<String> *r_features) const override { r_features->push_back("pc"); r_features->push_back("s3tc"); r_features->push_back("macos"); @@ -130,8 +131,8 @@ public: virtual void resolve_platform_feature_priorities(const Ref<EditorExportPreset> &p_preset, HashSet<String> &p_features) override { } - EditorExportPlatformOSX(); - ~EditorExportPlatformOSX(); + EditorExportPlatformMacOS(); + ~EditorExportPlatformMacOS(); }; -#endif +#endif // MACOS_EXPORT_PLUGIN_H diff --git a/platform/osx/export/lipo.cpp b/platform/macos/export/lipo.cpp index 82baf18c52..82baf18c52 100644 --- a/platform/osx/export/lipo.cpp +++ b/platform/macos/export/lipo.cpp diff --git a/platform/osx/export/lipo.h b/platform/macos/export/lipo.h index 0e419be17e..516ef99860 100644 --- a/platform/osx/export/lipo.h +++ b/platform/macos/export/lipo.h @@ -30,8 +30,8 @@ // Universal / Universal 2 fat binary file creator and extractor. -#ifndef LIPO_H -#define LIPO_H +#ifndef MACOS_LIPO_H +#define MACOS_LIPO_H #include "core/io/file_access.h" #include "core/object/ref_counted.h" @@ -73,4 +73,4 @@ public: #endif // MODULE_REGEX_ENABLED -#endif // LIPO_H +#endif // MACOS_LIPO_H diff --git a/platform/osx/export/macho.cpp b/platform/macos/export/macho.cpp index e6e67eff06..e6e67eff06 100644 --- a/platform/osx/export/macho.cpp +++ b/platform/macos/export/macho.cpp diff --git a/platform/osx/export/macho.h b/platform/macos/export/macho.h index 6cfc3c44f5..7ef0d9067e 100644 --- a/platform/osx/export/macho.h +++ b/platform/macos/export/macho.h @@ -30,8 +30,8 @@ // Mach-O binary object file format parser and editor. -#ifndef MACHO_H -#define MACHO_H +#ifndef MACOS_MACHO_H +#define MACOS_MACHO_H #include "core/crypto/crypto.h" #include "core/crypto/crypto_core.h" @@ -212,4 +212,4 @@ public: #endif // MODULE_REGEX_ENABLED -#endif // MACHO_H +#endif // MACOS_MACHO_H diff --git a/platform/osx/export/plist.cpp b/platform/macos/export/plist.cpp index 36de9dd34b..36de9dd34b 100644 --- a/platform/osx/export/plist.cpp +++ b/platform/macos/export/plist.cpp diff --git a/platform/osx/export/plist.h b/platform/macos/export/plist.h index ba9eaec196..79cb928d0a 100644 --- a/platform/osx/export/plist.h +++ b/platform/macos/export/plist.h @@ -30,8 +30,8 @@ // Property list file format (application/x-plist) parser, property list ASN-1 serialization. -#ifndef PLIST_H -#define PLIST_H +#ifndef MACOS_PLIST_H +#define MACOS_PLIST_H #include "core/crypto/crypto_core.h" #include "core/io/file_access.h" @@ -113,4 +113,4 @@ public: #endif // MODULE_REGEX_ENABLED -#endif // PLIST_H +#endif // MACOS_PLIST_H diff --git a/platform/osx/gl_manager_osx_legacy.h b/platform/macos/gl_manager_macos_legacy.h index 2d4913a7a6..8752086551 100644 --- a/platform/osx/gl_manager_osx_legacy.h +++ b/platform/macos/gl_manager_macos_legacy.h @@ -1,5 +1,5 @@ /*************************************************************************/ -/* gl_manager_osx_legacy.h */ +/* gl_manager_macos_legacy.h */ /*************************************************************************/ /* This file is part of: */ /* GODOT ENGINE */ @@ -28,10 +28,10 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ -#ifndef GL_MANAGER_OSX_LEGACY_H -#define GL_MANAGER_OSX_LEGACY_H +#ifndef GL_MANAGER_MACOS_LEGACY_H +#define GL_MANAGER_MACOS_LEGACY_H -#if defined(OSX_ENABLED) && defined(GLES3_ENABLED) +#if defined(MACOS_ENABLED) && defined(GLES3_ENABLED) #include "core/error/error_list.h" #include "core/os/os.h" @@ -42,7 +42,7 @@ #import <ApplicationServices/ApplicationServices.h> #import <CoreVideo/CoreVideo.h> -class GLManager_OSX { +class GLManager_MacOS { public: enum ContextType { GLES_3_0_COMPATIBLE, @@ -89,9 +89,10 @@ public: void set_use_vsync(bool p_use); bool is_using_vsync() const; - GLManager_OSX(ContextType p_context_type); - ~GLManager_OSX(); + GLManager_MacOS(ContextType p_context_type); + ~GLManager_MacOS(); }; -#endif // OSX_ENABLED && GLES3_ENABLED -#endif // GL_MANAGER_OSX_LEGACY_H +#endif // MACOS_ENABLED && GLES3_ENABLED + +#endif // GL_MANAGER_MACOS_LEGACY_H diff --git a/platform/osx/gl_manager_osx_legacy.mm b/platform/macos/gl_manager_macos_legacy.mm index c769d7f5c5..dec4821b86 100644 --- a/platform/osx/gl_manager_osx_legacy.mm +++ b/platform/macos/gl_manager_macos_legacy.mm @@ -1,5 +1,5 @@ /*************************************************************************/ -/* gl_manager_osx_legacy.mm */ +/* gl_manager_macos_legacy.mm */ /*************************************************************************/ /* This file is part of: */ /* GODOT ENGINE */ @@ -28,15 +28,15 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ -#include "gl_manager_osx_legacy.h" +#include "gl_manager_macos_legacy.h" -#ifdef OSX_ENABLED +#ifdef MACOS_ENABLED #ifdef GLES3_ENABLED #include <stdio.h> #include <stdlib.h> -Error GLManager_OSX::create_context(GLWindow &win) { +Error GLManager_MacOS::create_context(GLWindow &win) { NSOpenGLPixelFormatAttribute attributes[] = { NSOpenGLPFADoubleBuffer, NSOpenGLPFAClosestPolicy, @@ -62,7 +62,7 @@ Error GLManager_OSX::create_context(GLWindow &win) { return OK; } -Error GLManager_OSX::window_create(DisplayServer::WindowID p_window_id, id p_view, int p_width, int p_height) { +Error GLManager_MacOS::window_create(DisplayServer::WindowID p_window_id, id p_view, int p_width, int p_height) { GLWindow win; win.width = p_width; win.height = p_height; @@ -78,7 +78,7 @@ Error GLManager_OSX::window_create(DisplayServer::WindowID p_window_id, id p_vie return OK; } -void GLManager_OSX::window_resize(DisplayServer::WindowID p_window_id, int p_width, int p_height) { +void GLManager_MacOS::window_resize(DisplayServer::WindowID p_window_id, int p_width, int p_height) { if (!windows.has(p_window_id)) { return; } @@ -102,7 +102,7 @@ void GLManager_OSX::window_resize(DisplayServer::WindowID p_window_id, int p_wid [win.context update]; } -int GLManager_OSX::window_get_width(DisplayServer::WindowID p_window_id) { +int GLManager_MacOS::window_get_width(DisplayServer::WindowID p_window_id) { if (!windows.has(p_window_id)) { return 0; } @@ -111,7 +111,7 @@ int GLManager_OSX::window_get_width(DisplayServer::WindowID p_window_id) { return win.width; } -int GLManager_OSX::window_get_height(DisplayServer::WindowID p_window_id) { +int GLManager_MacOS::window_get_height(DisplayServer::WindowID p_window_id) { if (!windows.has(p_window_id)) { return 0; } @@ -120,7 +120,7 @@ int GLManager_OSX::window_get_height(DisplayServer::WindowID p_window_id) { return win.height; } -void GLManager_OSX::window_destroy(DisplayServer::WindowID p_window_id) { +void GLManager_MacOS::window_destroy(DisplayServer::WindowID p_window_id) { if (!windows.has(p_window_id)) { return; } @@ -132,7 +132,7 @@ void GLManager_OSX::window_destroy(DisplayServer::WindowID p_window_id) { windows.erase(p_window_id); } -void GLManager_OSX::release_current() { +void GLManager_MacOS::release_current() { if (current_window == DisplayServer::INVALID_WINDOW_ID) { return; } @@ -140,7 +140,7 @@ void GLManager_OSX::release_current() { [NSOpenGLContext clearCurrentContext]; } -void GLManager_OSX::window_make_current(DisplayServer::WindowID p_window_id) { +void GLManager_MacOS::window_make_current(DisplayServer::WindowID p_window_id) { if (current_window == p_window_id) { return; } @@ -154,7 +154,7 @@ void GLManager_OSX::window_make_current(DisplayServer::WindowID p_window_id) { current_window = p_window_id; } -void GLManager_OSX::make_current() { +void GLManager_MacOS::make_current() { if (current_window == DisplayServer::INVALID_WINDOW_ID) { return; } @@ -166,13 +166,12 @@ void GLManager_OSX::make_current() { [win.context makeCurrentContext]; } -void GLManager_OSX::swap_buffers() { - for (const KeyValue<DisplayServer::WindowID, GLWindow> &E : windows) { - [E.value.context flushBuffer]; - } +void GLManager_MacOS::swap_buffers() { + GLWindow &win = windows[current_window]; + [win.context flushBuffer]; } -void GLManager_OSX::window_update(DisplayServer::WindowID p_window_id) { +void GLManager_MacOS::window_update(DisplayServer::WindowID p_window_id) { if (!windows.has(p_window_id)) { return; } @@ -181,7 +180,7 @@ void GLManager_OSX::window_update(DisplayServer::WindowID p_window_id) { [win.context update]; } -void GLManager_OSX::window_set_per_pixel_transparency_enabled(DisplayServer::WindowID p_window_id, bool p_enabled) { +void GLManager_MacOS::window_set_per_pixel_transparency_enabled(DisplayServer::WindowID p_window_id, bool p_enabled) { if (!windows.has(p_window_id)) { return; } @@ -197,11 +196,11 @@ void GLManager_OSX::window_set_per_pixel_transparency_enabled(DisplayServer::Win [win.context update]; } -Error GLManager_OSX::initialize() { +Error GLManager_MacOS::initialize() { return OK; } -void GLManager_OSX::set_use_vsync(bool p_use) { +void GLManager_MacOS::set_use_vsync(bool p_use) { use_vsync = p_use; CGLContextObj ctx = CGLGetCurrentContext(); @@ -212,17 +211,17 @@ void GLManager_OSX::set_use_vsync(bool p_use) { } } -bool GLManager_OSX::is_using_vsync() const { +bool GLManager_MacOS::is_using_vsync() const { return use_vsync; } -GLManager_OSX::GLManager_OSX(ContextType p_context_type) { +GLManager_MacOS::GLManager_MacOS(ContextType p_context_type) { context_type = p_context_type; } -GLManager_OSX::~GLManager_OSX() { +GLManager_MacOS::~GLManager_MacOS() { release_current(); } #endif // GLES3_ENABLED -#endif // OSX +#endif // MACOS_ENABLED diff --git a/platform/osx/godot_application.h b/platform/macos/godot_application.h index 8d48a659f3..8d48a659f3 100644 --- a/platform/osx/godot_application.h +++ b/platform/macos/godot_application.h diff --git a/platform/osx/godot_application.mm b/platform/macos/godot_application.mm index 13313a025a..3f71c77fd1 100644 --- a/platform/osx/godot_application.mm +++ b/platform/macos/godot_application.mm @@ -30,12 +30,12 @@ #include "godot_application.h" -#include "display_server_osx.h" +#include "display_server_macos.h" @implementation GodotApplication - (void)sendEvent:(NSEvent *)event { - DisplayServerOSX *ds = (DisplayServerOSX *)DisplayServer::get_singleton(); + DisplayServerMacOS *ds = (DisplayServerMacOS *)DisplayServer::get_singleton(); if (ds) { if ([event type] == NSEventTypeLeftMouseDown || [event type] == NSEventTypeRightMouseDown || [event type] == NSEventTypeOtherMouseDown) { if (ds->mouse_process_popups()) { diff --git a/platform/osx/godot_application_delegate.h b/platform/macos/godot_application_delegate.h index f5b67b580f..f5b67b580f 100644 --- a/platform/osx/godot_application_delegate.h +++ b/platform/macos/godot_application_delegate.h diff --git a/platform/osx/godot_application_delegate.mm b/platform/macos/godot_application_delegate.mm index 4d3558b273..bacdcc2bc4 100644 --- a/platform/osx/godot_application_delegate.mm +++ b/platform/macos/godot_application_delegate.mm @@ -30,8 +30,8 @@ #include "godot_application_delegate.h" -#include "display_server_osx.h" -#include "os_osx.h" +#include "display_server_macos.h" +#include "os_macos.h" @implementation GodotApplicationDelegate @@ -78,7 +78,7 @@ } - (void)handleAppleEvent:(NSAppleEventDescriptor *)event withReplyEvent:(NSAppleEventDescriptor *)replyEvent { - OS_OSX *os = (OS_OSX *)OS::get_singleton(); + OS_MacOS *os = (OS_MacOS *)OS::get_singleton(); if (!event || !os) { return; } @@ -114,7 +114,7 @@ } - (void)applicationDidResignActive:(NSNotification *)notification { - DisplayServerOSX *ds = (DisplayServerOSX *)DisplayServer::get_singleton(); + DisplayServerMacOS *ds = (DisplayServerMacOS *)DisplayServer::get_singleton(); if (ds) { ds->mouse_process_popups(true); } @@ -130,14 +130,14 @@ } - (void)globalMenuCallback:(id)sender { - DisplayServerOSX *ds = (DisplayServerOSX *)DisplayServer::get_singleton(); + DisplayServerMacOS *ds = (DisplayServerMacOS *)DisplayServer::get_singleton(); if (ds) { return ds->menu_callback(sender); } } - (NSMenu *)applicationDockMenu:(NSApplication *)sender { - DisplayServerOSX *ds = (DisplayServerOSX *)DisplayServer::get_singleton(); + DisplayServerMacOS *ds = (DisplayServerMacOS *)DisplayServer::get_singleton(); if (ds) { return ds->get_dock_menu(); } else { @@ -146,15 +146,15 @@ } - (NSApplicationTerminateReply)applicationShouldTerminate:(NSApplication *)sender { - DisplayServerOSX *ds = (DisplayServerOSX *)DisplayServer::get_singleton(); + DisplayServerMacOS *ds = (DisplayServerMacOS *)DisplayServer::get_singleton(); if (ds) { - ds->send_window_event(ds->get_window(DisplayServerOSX::MAIN_WINDOW_ID), DisplayServerOSX::WINDOW_EVENT_CLOSE_REQUEST); + ds->send_window_event(ds->get_window(DisplayServerMacOS::MAIN_WINDOW_ID), DisplayServerMacOS::WINDOW_EVENT_CLOSE_REQUEST); } return NSTerminateCancel; } - (void)showAbout:(id)sender { - OS_OSX *os = (OS_OSX *)OS::get_singleton(); + OS_MacOS *os = (OS_MacOS *)OS::get_singleton(); if (os && os->get_main_loop()) { os->get_main_loop()->notification(MainLoop::NOTIFICATION_WM_ABOUT); } diff --git a/platform/osx/godot_content_view.h b/platform/macos/godot_content_view.h index 353305aec1..a6318ab903 100644 --- a/platform/osx/godot_content_view.h +++ b/platform/macos/godot_content_view.h @@ -45,6 +45,14 @@ #import <QuartzCore/CAMetalLayer.h> +@interface GodotContentLayerDelegate : NSObject <CALayerDelegate> { + DisplayServer::WindowID window_id; +} + +- (void)setWindowID:(DisplayServer::WindowID)wid; + +@end + @interface GodotContentView : RootView <NSTextInputClient> { DisplayServer::WindowID window_id; NSTrackingArea *tracking_area; @@ -53,12 +61,14 @@ bool mouse_down_control; bool ignore_momentum_scroll; bool last_pen_inverted; + id layer_delegate; } - (void)processScrollEvent:(NSEvent *)event button:(MouseButton)button factor:(double)factor; - (void)processPanEvent:(NSEvent *)event dx:(double)dx dy:(double)dy; - (void)processMouseEvent:(NSEvent *)event index:(MouseButton)index mask:(MouseButton)mask pressed:(bool)pressed; - (void)setWindowID:(DisplayServer::WindowID)wid; +- (void)updateLayerDelegate; - (void)cancelComposition; @end diff --git a/platform/osx/godot_content_view.mm b/platform/macos/godot_content_view.mm index 018b90e629..f93ef48f6c 100644 --- a/platform/osx/godot_content_view.mm +++ b/platform/macos/godot_content_view.mm @@ -30,13 +30,50 @@ #include "godot_content_view.h" -#include "display_server_osx.h" -#include "key_mapping_osx.h" +#include "display_server_macos.h" +#include "key_mapping_macos.h" +#include "main/main.h" + +@implementation GodotContentLayerDelegate + +- (id)init { + self = [super init]; + window_id = DisplayServer::INVALID_WINDOW_ID; + return self; +} + +- (void)setWindowID:(DisplayServerMacOS::WindowID)wid { + window_id = wid; +} + +- (void)displayLayer:(CALayer *)layer { + DisplayServerMacOS *ds = (DisplayServerMacOS *)DisplayServer::get_singleton(); + if (OS::get_singleton()->get_main_loop() && ds->get_is_resizing()) { + Main::force_redraw(); + if (!Main::is_iterating()) { // Avoid cyclic loop. + Main::iteration(); + } + } +} + +@end @implementation GodotContentView +- (void)setFrameSize:(NSSize)newSize { + [super setFrameSize:newSize]; + [self.layer setNeedsDisplay]; // Force "drawRect" call. +} + +- (void)updateLayerDelegate { + self.layer.delegate = layer_delegate; + self.layer.autoresizingMask = kCALayerHeightSizable | kCALayerWidthSizable; + self.layer.needsDisplayOnBoundsChange = YES; +} + - (id)init { self = [super init]; + layer_delegate = [[GodotContentLayerDelegate alloc] init]; window_id = DisplayServer::INVALID_WINDOW_ID; tracking_area = nil; ime_input_event_in_progress = false; @@ -45,6 +82,9 @@ last_pen_inverted = false; [self updateTrackingAreas]; + self.layerContentsRedrawPolicy = NSViewLayerContentsRedrawDuringViewResize; + self.layerContentsPlacement = NSViewLayerContentsPlacementTopLeft; + if (@available(macOS 10.13, *)) { [self registerForDraggedTypes:[NSArray arrayWithObject:NSPasteboardTypeFileURL]]; #if !defined(__aarch64__) // Do not build deprectead 10.13 code on ARM. @@ -56,8 +96,9 @@ return self; } -- (void)setWindowID:(DisplayServerOSX::WindowID)wid { +- (void)setWindowID:(DisplayServerMacOS::WindowID)wid { window_id = wid; + [layer_delegate setWindowID:window_id]; } // MARK: Backing Layer @@ -67,7 +108,7 @@ } - (void)updateLayer { - DisplayServerOSX *ds = (DisplayServerOSX *)DisplayServer::get_singleton(); + DisplayServerMacOS *ds = (DisplayServerMacOS *)DisplayServer::get_singleton(); ds->window_update(window_id); [super updateLayer]; } @@ -106,12 +147,12 @@ return; } - DisplayServerOSX *ds = (DisplayServerOSX *)DisplayServer::get_singleton(); + DisplayServerMacOS *ds = (DisplayServerMacOS *)DisplayServer::get_singleton(); if (!ds || !ds->has_window(window_id)) { return; } - DisplayServerOSX::WindowData &wd = ds->get_window(window_id); + DisplayServerMacOS::WindowData &wd = ds->get_window(window_id); if (wd.im_active) { ime_input_event_in_progress = true; ds->update_im_text(Point2i(selectedRange.location, selectedRange.length), String::utf8([[marked_text mutableString] UTF8String])); @@ -126,12 +167,12 @@ ime_input_event_in_progress = false; [[marked_text mutableString] setString:@""]; - DisplayServerOSX *ds = (DisplayServerOSX *)DisplayServer::get_singleton(); + DisplayServerMacOS *ds = (DisplayServerMacOS *)DisplayServer::get_singleton(); if (!ds || !ds->has_window(window_id)) { return; } - DisplayServerOSX::WindowData &wd = ds->get_window(window_id); + DisplayServerMacOS::WindowData &wd = ds->get_window(window_id); if (wd.im_active) { ds->update_im_text(Point2i(), String()); } @@ -150,12 +191,12 @@ } - (NSRect)firstRectForCharacterRange:(NSRange)aRange actualRange:(NSRangePointer)actualRange { - DisplayServerOSX *ds = (DisplayServerOSX *)DisplayServer::get_singleton(); + DisplayServerMacOS *ds = (DisplayServerMacOS *)DisplayServer::get_singleton(); if (!ds || !ds->has_window(window_id)) { return NSMakeRect(0, 0, 0, 0); } - DisplayServerOSX::WindowData &wd = ds->get_window(window_id); + DisplayServerMacOS::WindowData &wd = ds->get_window(window_id); const NSRect content_rect = [wd.window_view frame]; const float scale = ds->screen_get_max_scale(); NSRect point_in_window_rect = NSMakeRect(wd.im_position.x / scale, content_rect.size.height - (wd.im_position.y / scale) - 1, 0, 0); @@ -191,7 +232,7 @@ return; } - DisplayServerOSX *ds = (DisplayServerOSX *)DisplayServer::get_singleton(); + DisplayServerMacOS *ds = (DisplayServerMacOS *)DisplayServer::get_singleton(); if (!ds || !ds->has_window(window_id)) { [self cancelComposition]; return; @@ -210,10 +251,10 @@ continue; } - DisplayServerOSX::KeyEvent ke; + DisplayServerMacOS::KeyEvent ke; ke.window_id = window_id; - ke.osx_state = [event modifierFlags]; + ke.macos_state = [event modifierFlags]; ke.pressed = true; ke.echo = false; ke.raw = false; // IME input event. @@ -237,12 +278,12 @@ } - (BOOL)performDragOperation:(id<NSDraggingInfo>)sender { - DisplayServerOSX *ds = (DisplayServerOSX *)DisplayServer::get_singleton(); + DisplayServerMacOS *ds = (DisplayServerMacOS *)DisplayServer::get_singleton(); if (!ds || !ds->has_window(window_id)) { return NO; } - DisplayServerOSX::WindowData &wd = ds->get_window(window_id); + DisplayServerMacOS::WindowData &wd = ds->get_window(window_id); if (!wd.drop_files_callback.is_null()) { Vector<String> files; NSPasteboard *pboard = [sender draggingPasteboard]; @@ -267,7 +308,7 @@ Variant *vp = &v; Variant ret; Callable::CallError ce; - wd.drop_files_callback.call((const Variant **)&vp, 1, ret, ce); + wd.drop_files_callback.callp((const Variant **)&vp, 1, ret, ce); } return NO; @@ -276,12 +317,12 @@ // MARK: Focus - (BOOL)canBecomeKeyView { - DisplayServerOSX *ds = (DisplayServerOSX *)DisplayServer::get_singleton(); + DisplayServerMacOS *ds = (DisplayServerMacOS *)DisplayServer::get_singleton(); if (!ds || !ds->has_window(window_id)) { return YES; } - DisplayServerOSX::WindowData &wd = ds->get_window(window_id); + DisplayServerMacOS::WindowData &wd = ds->get_window(window_id); return !wd.no_focus && !wd.is_popup; } @@ -292,7 +333,7 @@ // MARK: Mouse - (void)cursorUpdate:(NSEvent *)event { - DisplayServerOSX *ds = (DisplayServerOSX *)DisplayServer::get_singleton(); + DisplayServerMacOS *ds = (DisplayServerMacOS *)DisplayServer::get_singleton(); if (!ds) { return; } @@ -301,12 +342,12 @@ } - (void)processMouseEvent:(NSEvent *)event index:(MouseButton)index mask:(MouseButton)mask pressed:(bool)pressed { - DisplayServerOSX *ds = (DisplayServerOSX *)DisplayServer::get_singleton(); + DisplayServerMacOS *ds = (DisplayServerMacOS *)DisplayServer::get_singleton(); if (!ds || !ds->has_window(window_id)) { return; } - DisplayServerOSX::WindowData &wd = ds->get_window(window_id); + DisplayServerMacOS::WindowData &wd = ds->get_window(window_id); MouseButton last_button_state = ds->mouse_get_button_state(); if (pressed) { @@ -356,12 +397,12 @@ } - (void)mouseMoved:(NSEvent *)event { - DisplayServerOSX *ds = (DisplayServerOSX *)DisplayServer::get_singleton(); + DisplayServerMacOS *ds = (DisplayServerMacOS *)DisplayServer::get_singleton(); if (!ds || !ds->has_window(window_id)) { return; } - DisplayServerOSX::WindowData &wd = ds->get_window(window_id); + DisplayServerMacOS::WindowData &wd = ds->get_window(window_id); NSPoint delta = NSMakePoint([event deltaX], [event deltaY]); NSPoint mpos = [event locationInWindow]; @@ -438,38 +479,38 @@ } - (void)mouseExited:(NSEvent *)event { - DisplayServerOSX *ds = (DisplayServerOSX *)DisplayServer::get_singleton(); + DisplayServerMacOS *ds = (DisplayServerMacOS *)DisplayServer::get_singleton(); if (!ds || !ds->has_window(window_id)) { return; } - DisplayServerOSX::WindowData &wd = ds->get_window(window_id); + DisplayServerMacOS::WindowData &wd = ds->get_window(window_id); if (ds->mouse_get_mode() != DisplayServer::MOUSE_MODE_CAPTURED) { - ds->send_window_event(wd, DisplayServerOSX::WINDOW_EVENT_MOUSE_EXIT); + ds->send_window_event(wd, DisplayServerMacOS::WINDOW_EVENT_MOUSE_EXIT); } } - (void)mouseEntered:(NSEvent *)event { - DisplayServerOSX *ds = (DisplayServerOSX *)DisplayServer::get_singleton(); + DisplayServerMacOS *ds = (DisplayServerMacOS *)DisplayServer::get_singleton(); if (!ds || !ds->has_window(window_id)) { return; } - DisplayServerOSX::WindowData &wd = ds->get_window(window_id); + DisplayServerMacOS::WindowData &wd = ds->get_window(window_id); if (ds->mouse_get_mode() != DisplayServer::MOUSE_MODE_CAPTURED) { - ds->send_window_event(wd, DisplayServerOSX::WINDOW_EVENT_MOUSE_ENTER); + ds->send_window_event(wd, DisplayServerMacOS::WINDOW_EVENT_MOUSE_ENTER); } ds->cursor_update_shape(); } - (void)magnifyWithEvent:(NSEvent *)event { - DisplayServerOSX *ds = (DisplayServerOSX *)DisplayServer::get_singleton(); + DisplayServerMacOS *ds = (DisplayServerMacOS *)DisplayServer::get_singleton(); if (!ds || !ds->has_window(window_id)) { return; } - DisplayServerOSX::WindowData &wd = ds->get_window(window_id); + DisplayServerMacOS::WindowData &wd = ds->get_window(window_id); Ref<InputEventMagnifyGesture> ev; ev.instantiate(); @@ -497,12 +538,12 @@ // MARK: Keyboard - (void)keyDown:(NSEvent *)event { - DisplayServerOSX *ds = (DisplayServerOSX *)DisplayServer::get_singleton(); + DisplayServerMacOS *ds = (DisplayServerMacOS *)DisplayServer::get_singleton(); if (!ds || !ds->has_window(window_id)) { return; } - DisplayServerOSX::WindowData &wd = ds->get_window(window_id); + DisplayServerMacOS::WindowData &wd = ds->get_window(window_id); ignore_momentum_scroll = true; @@ -511,7 +552,7 @@ NSString *characters = [event characters]; NSUInteger length = [characters length]; - if (!wd.im_active && length > 0 && keycode_has_unicode(KeyMappingOSX::remap_key([event keyCode], [event modifierFlags]))) { + if (!wd.im_active && length > 0 && keycode_has_unicode(KeyMappingMacOS::remap_key([event keyCode], [event modifierFlags]))) { // Fallback unicode character handler used if IME is not active. Char16String text; text.resize([characters length] + 1); @@ -523,28 +564,28 @@ for (int i = 0; i < u32text.length(); i++) { const char32_t codepoint = u32text[i]; - DisplayServerOSX::KeyEvent ke; + DisplayServerMacOS::KeyEvent ke; ke.window_id = window_id; - ke.osx_state = [event modifierFlags]; + ke.macos_state = [event modifierFlags]; ke.pressed = true; ke.echo = [event isARepeat]; - ke.keycode = KeyMappingOSX::remap_key([event keyCode], [event modifierFlags]); - ke.physical_keycode = KeyMappingOSX::translate_key([event keyCode]); + ke.keycode = KeyMappingMacOS::remap_key([event keyCode], [event modifierFlags]); + ke.physical_keycode = KeyMappingMacOS::translate_key([event keyCode]); ke.raw = true; ke.unicode = codepoint; ds->push_to_key_event_buffer(ke); } } else { - DisplayServerOSX::KeyEvent ke; + DisplayServerMacOS::KeyEvent ke; ke.window_id = window_id; - ke.osx_state = [event modifierFlags]; + ke.macos_state = [event modifierFlags]; ke.pressed = true; ke.echo = [event isARepeat]; - ke.keycode = KeyMappingOSX::remap_key([event keyCode], [event modifierFlags]); - ke.physical_keycode = KeyMappingOSX::translate_key([event keyCode]); + ke.keycode = KeyMappingMacOS::remap_key([event keyCode], [event modifierFlags]); + ke.physical_keycode = KeyMappingMacOS::translate_key([event keyCode]); ke.raw = false; ke.unicode = 0; @@ -559,7 +600,7 @@ } - (void)flagsChanged:(NSEvent *)event { - DisplayServerOSX *ds = (DisplayServerOSX *)DisplayServer::get_singleton(); + DisplayServerMacOS *ds = (DisplayServerMacOS *)DisplayServer::get_singleton(); if (!ds || !ds->has_window(window_id)) { return; } @@ -567,7 +608,7 @@ // Ignore all input if IME input is in progress if (!ime_input_event_in_progress) { - DisplayServerOSX::KeyEvent ke; + DisplayServerMacOS::KeyEvent ke; ke.window_id = window_id; ke.echo = false; @@ -608,9 +649,9 @@ return; } - ke.osx_state = mod; - ke.keycode = KeyMappingOSX::remap_key(key, mod); - ke.physical_keycode = KeyMappingOSX::translate_key(key); + ke.macos_state = mod; + ke.keycode = KeyMappingMacOS::remap_key(key, mod); + ke.physical_keycode = KeyMappingMacOS::translate_key(key); ke.unicode = 0; ds->push_to_key_event_buffer(ke); @@ -618,12 +659,12 @@ } - (void)keyUp:(NSEvent *)event { - DisplayServerOSX *ds = (DisplayServerOSX *)DisplayServer::get_singleton(); + DisplayServerMacOS *ds = (DisplayServerMacOS *)DisplayServer::get_singleton(); if (!ds || !ds->has_window(window_id)) { return; } - DisplayServerOSX::WindowData &wd = ds->get_window(window_id); + DisplayServerMacOS::WindowData &wd = ds->get_window(window_id); // Ignore all input if IME input is in progress. if (!ime_input_event_in_progress) { @@ -631,7 +672,7 @@ NSUInteger length = [characters length]; // Fallback unicode character handler used if IME is not active. - if (!wd.im_active && length > 0 && keycode_has_unicode(KeyMappingOSX::remap_key([event keyCode], [event modifierFlags]))) { + if (!wd.im_active && length > 0 && keycode_has_unicode(KeyMappingMacOS::remap_key([event keyCode], [event modifierFlags]))) { Char16String text; text.resize([characters length] + 1); [characters getCharacters:(unichar *)text.ptrw() range:NSMakeRange(0, [characters length])]; @@ -641,28 +682,28 @@ for (int i = 0; i < u32text.length(); i++) { const char32_t codepoint = u32text[i]; - DisplayServerOSX::KeyEvent ke; + DisplayServerMacOS::KeyEvent ke; ke.window_id = window_id; - ke.osx_state = [event modifierFlags]; + ke.macos_state = [event modifierFlags]; ke.pressed = false; ke.echo = [event isARepeat]; - ke.keycode = KeyMappingOSX::remap_key([event keyCode], [event modifierFlags]); - ke.physical_keycode = KeyMappingOSX::translate_key([event keyCode]); + ke.keycode = KeyMappingMacOS::remap_key([event keyCode], [event modifierFlags]); + ke.physical_keycode = KeyMappingMacOS::translate_key([event keyCode]); ke.raw = true; ke.unicode = codepoint; ds->push_to_key_event_buffer(ke); } } else { - DisplayServerOSX::KeyEvent ke; + DisplayServerMacOS::KeyEvent ke; ke.window_id = window_id; - ke.osx_state = [event modifierFlags]; + ke.macos_state = [event modifierFlags]; ke.pressed = false; ke.echo = [event isARepeat]; - ke.keycode = KeyMappingOSX::remap_key([event keyCode], [event modifierFlags]); - ke.physical_keycode = KeyMappingOSX::translate_key([event keyCode]); + ke.keycode = KeyMappingMacOS::remap_key([event keyCode], [event modifierFlags]); + ke.physical_keycode = KeyMappingMacOS::translate_key([event keyCode]); ke.raw = true; ke.unicode = 0; @@ -674,12 +715,12 @@ // MARK: Scroll and pan - (void)processScrollEvent:(NSEvent *)event button:(MouseButton)button factor:(double)factor { - DisplayServerOSX *ds = (DisplayServerOSX *)DisplayServer::get_singleton(); + DisplayServerMacOS *ds = (DisplayServerMacOS *)DisplayServer::get_singleton(); if (!ds || !ds->has_window(window_id)) { return; } - DisplayServerOSX::WindowData &wd = ds->get_window(window_id); + DisplayServerMacOS::WindowData &wd = ds->get_window(window_id); MouseButton mask = mouse_button_to_mask(button); Ref<InputEventMouseButton> sc; @@ -713,12 +754,12 @@ } - (void)processPanEvent:(NSEvent *)event dx:(double)dx dy:(double)dy { - DisplayServerOSX *ds = (DisplayServerOSX *)DisplayServer::get_singleton(); + DisplayServerMacOS *ds = (DisplayServerMacOS *)DisplayServer::get_singleton(); if (!ds || !ds->has_window(window_id)) { return; } - DisplayServerOSX::WindowData &wd = ds->get_window(window_id); + DisplayServerMacOS::WindowData &wd = ds->get_window(window_id); Ref<InputEventPanGesture> pg; pg.instantiate(); @@ -732,12 +773,12 @@ } - (void)scrollWheel:(NSEvent *)event { - DisplayServerOSX *ds = (DisplayServerOSX *)DisplayServer::get_singleton(); + DisplayServerMacOS *ds = (DisplayServerMacOS *)DisplayServer::get_singleton(); if (!ds || !ds->has_window(window_id)) { return; } - DisplayServerOSX::WindowData &wd = ds->get_window(window_id); + DisplayServerMacOS::WindowData &wd = ds->get_window(window_id); ds->update_mouse_pos(wd, [event locationInWindow]); double delta_x = [event scrollingDeltaX]; diff --git a/platform/osx/godot_main_osx.mm b/platform/macos/godot_main_macos.mm index 722928ad60..66071f1404 100644 --- a/platform/osx/godot_main_osx.mm +++ b/platform/macos/godot_main_macos.mm @@ -1,5 +1,5 @@ /*************************************************************************/ -/* godot_main_osx.mm */ +/* godot_main_macos.mm */ /*************************************************************************/ /* This file is part of: */ /* GODOT ENGINE */ @@ -30,7 +30,7 @@ #include "main/main.h" -#include "os_osx.h" +#include "os_macos.h" #include <string.h> #include <unistd.h> @@ -68,7 +68,7 @@ int main(int argc, char **argv) { printf("Current path: %s\n", cwd); #endif - OS_OSX os; + OS_MacOS os; Error err; // We must override main when testing is enabled. diff --git a/platform/macos/godot_menu_delegate.h b/platform/macos/godot_menu_delegate.h new file mode 100644 index 0000000000..805ac0c4a3 --- /dev/null +++ b/platform/macos/godot_menu_delegate.h @@ -0,0 +1,44 @@ +/*************************************************************************/ +/* godot_menu_delegate.h */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ + +#ifndef GODOT_MENU_DELEGATE_H +#define GODOT_MENU_DELEGATE_H + +#import <AppKit/AppKit.h> +#import <Foundation/Foundation.h> + +@interface GodotMenuDelegate : NSObject <NSMenuDelegate> { +} + +- (void)doNothing:(id)sender; + +@end + +#endif // GODOT_MENU_DELEGATE_H diff --git a/platform/macos/godot_menu_delegate.mm b/platform/macos/godot_menu_delegate.mm new file mode 100644 index 0000000000..376f28d1d0 --- /dev/null +++ b/platform/macos/godot_menu_delegate.mm @@ -0,0 +1,76 @@ +/*************************************************************************/ +/* godot_menu_delegate.mm */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ + +#include "godot_menu_delegate.h" + +#include "display_server_macos.h" +#include "godot_menu_item.h" +#include "key_mapping_macos.h" + +@implementation GodotMenuDelegate + +- (void)doNothing:(id)sender { +} + +- (BOOL)menuHasKeyEquivalent:(NSMenu *)menu forEvent:(NSEvent *)event target:(id *)target action:(SEL *)action { + NSString *ev_key = [[event charactersIgnoringModifiers] lowercaseString]; + NSUInteger ev_modifiers = [event modifierFlags] & NSDeviceIndependentModifierFlagsMask; + for (int i = 0; i < [menu numberOfItems]; i++) { + const NSMenuItem *menu_item = [menu itemAtIndex:i]; + if ([menu_item isEnabled] && [[menu_item keyEquivalent] compare:ev_key] == NSOrderedSame) { + NSUInteger item_modifiers = [menu_item keyEquivalentModifierMask]; + + if (ev_modifiers == item_modifiers) { + GodotMenuItem *value = [menu_item representedObject]; + if (value->key_callback != Callable()) { + // If custom callback is set, use it. + Variant tag = value->meta; + Variant *tagp = &tag; + Variant ret; + Callable::CallError ce; + value->key_callback.callp((const Variant **)&tagp, 1, ret, ce); + } else { + // Otherwise redirect event to the engine. + if (DisplayServer::get_singleton()) { + [[[NSApplication sharedApplication] keyWindow] sendEvent:event]; + } + } + + // Suppress default menu action. + *target = self; + *action = @selector(doNothing:); + return YES; + } + } + } + return NO; +} + +@end diff --git a/platform/osx/godot_menu_item.h b/platform/macos/godot_menu_item.h index 2c12897f10..e96f5dc1cf 100644 --- a/platform/osx/godot_menu_item.h +++ b/platform/macos/godot_menu_item.h @@ -45,8 +45,8 @@ enum GlobalMenuCheckType { @interface GodotMenuItem : NSObject { @public Callable callback; + Callable key_callback; Variant meta; - int id; GlobalMenuCheckType checkable_type; int max_states; int state; @@ -55,7 +55,4 @@ enum GlobalMenuCheckType { @end -@implementation GodotMenuItem -@end - #endif // GODOT_MENU_ITEM_H diff --git a/platform/macos/godot_menu_item.mm b/platform/macos/godot_menu_item.mm new file mode 100644 index 0000000000..ea35e35d19 --- /dev/null +++ b/platform/macos/godot_menu_item.mm @@ -0,0 +1,34 @@ +/*************************************************************************/ +/* godot_menu_item.mm */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ + +#include "godot_menu_item.h" + +@implementation GodotMenuItem +@end diff --git a/platform/osx/godot_window.h b/platform/macos/godot_window.h index 16ff101142..9fc5599e86 100644 --- a/platform/osx/godot_window.h +++ b/platform/macos/godot_window.h @@ -44,4 +44,4 @@ @end -#endif //GODOT_WINDOW_H +#endif // GODOT_WINDOW_H diff --git a/platform/osx/godot_window.mm b/platform/macos/godot_window.mm index d43853a94b..e205e7546d 100644 --- a/platform/osx/godot_window.mm +++ b/platform/macos/godot_window.mm @@ -30,7 +30,7 @@ #include "godot_window.h" -#include "display_server_osx.h" +#include "display_server_macos.h" @implementation GodotWindow @@ -40,29 +40,29 @@ return self; } -- (void)setWindowID:(DisplayServerOSX::WindowID)wid { +- (void)setWindowID:(DisplayServerMacOS::WindowID)wid { window_id = wid; } - (BOOL)canBecomeKeyWindow { // Required for NSWindowStyleMaskBorderless windows. - DisplayServerOSX *ds = (DisplayServerOSX *)DisplayServer::get_singleton(); + DisplayServerMacOS *ds = (DisplayServerMacOS *)DisplayServer::get_singleton(); if (!ds || !ds->has_window(window_id)) { return YES; } - DisplayServerOSX::WindowData &wd = ds->get_window(window_id); + DisplayServerMacOS::WindowData &wd = ds->get_window(window_id); return !wd.no_focus && !wd.is_popup; } - (BOOL)canBecomeMainWindow { // Required for NSWindowStyleMaskBorderless windows. - DisplayServerOSX *ds = (DisplayServerOSX *)DisplayServer::get_singleton(); + DisplayServerMacOS *ds = (DisplayServerMacOS *)DisplayServer::get_singleton(); if (!ds || !ds->has_window(window_id)) { return YES; } - DisplayServerOSX::WindowData &wd = ds->get_window(window_id); + DisplayServerMacOS::WindowData &wd = ds->get_window(window_id); return !wd.no_focus && !wd.is_popup; } diff --git a/platform/osx/godot_window_delegate.h b/platform/macos/godot_window_delegate.h index 8a1f681fcd..98c226aa2f 100644 --- a/platform/osx/godot_window_delegate.h +++ b/platform/macos/godot_window_delegate.h @@ -44,4 +44,4 @@ @end -#endif //GODOT_WINDOW_DELEGATE_H +#endif // GODOT_WINDOW_DELEGATE_H diff --git a/platform/osx/godot_window_delegate.mm b/platform/macos/godot_window_delegate.mm index 521127f01b..2d9329ab3c 100644 --- a/platform/osx/godot_window_delegate.mm +++ b/platform/macos/godot_window_delegate.mm @@ -30,7 +30,7 @@ #include "godot_window_delegate.h" -#include "display_server_osx.h" +#include "display_server_macos.h" @implementation GodotWindowDelegate @@ -39,42 +39,42 @@ } - (BOOL)windowShouldClose:(id)sender { - DisplayServerOSX *ds = (DisplayServerOSX *)DisplayServer::get_singleton(); + DisplayServerMacOS *ds = (DisplayServerMacOS *)DisplayServer::get_singleton(); if (!ds || !ds->has_window(window_id)) { return YES; } - ds->send_window_event(ds->get_window(window_id), DisplayServerOSX::WINDOW_EVENT_CLOSE_REQUEST); + ds->send_window_event(ds->get_window(window_id), DisplayServerMacOS::WINDOW_EVENT_CLOSE_REQUEST); return NO; } - (void)windowWillClose:(NSNotification *)notification { - DisplayServerOSX *ds = (DisplayServerOSX *)DisplayServer::get_singleton(); + DisplayServerMacOS *ds = (DisplayServerMacOS *)DisplayServer::get_singleton(); if (!ds || !ds->has_window(window_id)) { return; } ds->popup_close(window_id); - DisplayServerOSX::WindowData &wd = ds->get_window(window_id); + DisplayServerMacOS::WindowData &wd = ds->get_window(window_id); while (wd.transient_children.size()) { - ds->window_set_transient(*wd.transient_children.begin(), DisplayServerOSX::INVALID_WINDOW_ID); + ds->window_set_transient(*wd.transient_children.begin(), DisplayServerMacOS::INVALID_WINDOW_ID); } - if (wd.transient_parent != DisplayServerOSX::INVALID_WINDOW_ID) { - ds->window_set_transient(window_id, DisplayServerOSX::INVALID_WINDOW_ID); + if (wd.transient_parent != DisplayServerMacOS::INVALID_WINDOW_ID) { + ds->window_set_transient(window_id, DisplayServerMacOS::INVALID_WINDOW_ID); } ds->window_destroy(window_id); } - (void)windowDidEnterFullScreen:(NSNotification *)notification { - DisplayServerOSX *ds = (DisplayServerOSX *)DisplayServer::get_singleton(); + DisplayServerMacOS *ds = (DisplayServerMacOS *)DisplayServer::get_singleton(); if (!ds || !ds->has_window(window_id)) { return; } - DisplayServerOSX::WindowData &wd = ds->get_window(window_id); + DisplayServerMacOS::WindowData &wd = ds->get_window(window_id); wd.fullscreen = true; // Reset window size limits. [wd.window_object setContentMinSize:NSMakeSize(0, 0)]; @@ -85,12 +85,12 @@ } - (void)windowDidExitFullScreen:(NSNotification *)notification { - DisplayServerOSX *ds = (DisplayServerOSX *)DisplayServer::get_singleton(); + DisplayServerMacOS *ds = (DisplayServerMacOS *)DisplayServer::get_singleton(); if (!ds || !ds->has_window(window_id)) { return; } - DisplayServerOSX::WindowData &wd = ds->get_window(window_id); + DisplayServerMacOS::WindowData &wd = ds->get_window(window_id); wd.fullscreen = false; // Set window size limits. @@ -119,12 +119,12 @@ } - (void)windowDidChangeBackingProperties:(NSNotification *)notification { - DisplayServerOSX *ds = (DisplayServerOSX *)DisplayServer::get_singleton(); + DisplayServerMacOS *ds = (DisplayServerMacOS *)DisplayServer::get_singleton(); if (!ds || !ds->has_window(window_id)) { return; } - DisplayServerOSX::WindowData &wd = ds->get_window(window_id); + DisplayServerMacOS::WindowData &wd = ds->get_window(window_id); CGFloat new_scale_factor = [wd.window_object backingScaleFactor]; CGFloat old_scale_factor = [[[notification userInfo] objectForKey:@"NSBackingPropertyOldScaleFactorKey"] doubleValue]; @@ -137,7 +137,7 @@ wd.size.width = content_rect.size.width * scale; wd.size.height = content_rect.size.height * scale; - ds->send_window_event(wd, DisplayServerOSX::WINDOW_EVENT_DPI_CHANGE); + ds->send_window_event(wd, DisplayServerMacOS::WINDOW_EVENT_DPI_CHANGE); CALayer *layer = [wd.window_view layer]; if (layer) { @@ -150,26 +150,26 @@ } - (void)windowWillStartLiveResize:(NSNotification *)notification { - DisplayServerOSX *ds = (DisplayServerOSX *)DisplayServer::get_singleton(); + DisplayServerMacOS *ds = (DisplayServerMacOS *)DisplayServer::get_singleton(); if (ds) { ds->set_is_resizing(true); } } - (void)windowDidEndLiveResize:(NSNotification *)notification { - DisplayServerOSX *ds = (DisplayServerOSX *)DisplayServer::get_singleton(); + DisplayServerMacOS *ds = (DisplayServerMacOS *)DisplayServer::get_singleton(); if (ds) { ds->set_is_resizing(false); } } - (void)windowDidResize:(NSNotification *)notification { - DisplayServerOSX *ds = (DisplayServerOSX *)DisplayServer::get_singleton(); + DisplayServerMacOS *ds = (DisplayServerMacOS *)DisplayServer::get_singleton(); if (!ds || !ds->has_window(window_id)) { return; } - DisplayServerOSX::WindowData &wd = ds->get_window(window_id); + DisplayServerMacOS::WindowData &wd = ds->get_window(window_id); const NSRect content_rect = [wd.window_view frame]; const float scale = ds->screen_get_max_scale(); wd.size.width = content_rect.size.width * scale; @@ -187,17 +187,17 @@ Variant *sizep = &size; Variant ret; Callable::CallError ce; - wd.rect_changed_callback.call((const Variant **)&sizep, 1, ret, ce); + wd.rect_changed_callback.callp((const Variant **)&sizep, 1, ret, ce); } } - (void)windowDidMove:(NSNotification *)notification { - DisplayServerOSX *ds = (DisplayServerOSX *)DisplayServer::get_singleton(); + DisplayServerMacOS *ds = (DisplayServerMacOS *)DisplayServer::get_singleton(); if (!ds || !ds->has_window(window_id)) { return; } - DisplayServerOSX::WindowData &wd = ds->get_window(window_id); + DisplayServerMacOS::WindowData &wd = ds->get_window(window_id); ds->release_pressed_events(); if (!wd.rect_changed_callback.is_null()) { @@ -205,17 +205,17 @@ Variant *sizep = &size; Variant ret; Callable::CallError ce; - wd.rect_changed_callback.call((const Variant **)&sizep, 1, ret, ce); + wd.rect_changed_callback.callp((const Variant **)&sizep, 1, ret, ce); } } - (void)windowDidBecomeKey:(NSNotification *)notification { - DisplayServerOSX *ds = (DisplayServerOSX *)DisplayServer::get_singleton(); + DisplayServerMacOS *ds = (DisplayServerMacOS *)DisplayServer::get_singleton(); if (!ds || !ds->has_window(window_id)) { return; } - DisplayServerOSX::WindowData &wd = ds->get_window(window_id); + DisplayServerMacOS::WindowData &wd = ds->get_window(window_id); if (ds->mouse_get_mode() == DisplayServer::MOUSE_MODE_CAPTURED) { const NSRect content_rect = [wd.window_view frame]; @@ -228,43 +228,43 @@ } ds->set_last_focused_window(window_id); - ds->send_window_event(wd, DisplayServerOSX::WINDOW_EVENT_FOCUS_IN); + ds->send_window_event(wd, DisplayServerMacOS::WINDOW_EVENT_FOCUS_IN); } - (void)windowDidResignKey:(NSNotification *)notification { - DisplayServerOSX *ds = (DisplayServerOSX *)DisplayServer::get_singleton(); + DisplayServerMacOS *ds = (DisplayServerMacOS *)DisplayServer::get_singleton(); if (!ds || !ds->has_window(window_id)) { return; } - DisplayServerOSX::WindowData &wd = ds->get_window(window_id); + DisplayServerMacOS::WindowData &wd = ds->get_window(window_id); ds->release_pressed_events(); - ds->send_window_event(wd, DisplayServerOSX::WINDOW_EVENT_FOCUS_OUT); + ds->send_window_event(wd, DisplayServerMacOS::WINDOW_EVENT_FOCUS_OUT); } - (void)windowDidMiniaturize:(NSNotification *)notification { - DisplayServerOSX *ds = (DisplayServerOSX *)DisplayServer::get_singleton(); + DisplayServerMacOS *ds = (DisplayServerMacOS *)DisplayServer::get_singleton(); if (!ds || !ds->has_window(window_id)) { return; } - DisplayServerOSX::WindowData &wd = ds->get_window(window_id); + DisplayServerMacOS::WindowData &wd = ds->get_window(window_id); ds->release_pressed_events(); - ds->send_window_event(wd, DisplayServerOSX::WINDOW_EVENT_FOCUS_OUT); + ds->send_window_event(wd, DisplayServerMacOS::WINDOW_EVENT_FOCUS_OUT); } - (void)windowDidDeminiaturize:(NSNotification *)notification { - DisplayServerOSX *ds = (DisplayServerOSX *)DisplayServer::get_singleton(); + DisplayServerMacOS *ds = (DisplayServerMacOS *)DisplayServer::get_singleton(); if (!ds || !ds->has_window(window_id)) { return; } - DisplayServerOSX::WindowData &wd = ds->get_window(window_id); + DisplayServerMacOS::WindowData &wd = ds->get_window(window_id); ds->set_last_focused_window(window_id); - ds->send_window_event(wd, DisplayServerOSX::WINDOW_EVENT_FOCUS_IN); + ds->send_window_event(wd, DisplayServerMacOS::WINDOW_EVENT_FOCUS_IN); } @end diff --git a/platform/osx/joypad_osx.cpp b/platform/macos/joypad_macos.cpp index be9567e17c..1ddcfec1b5 100644 --- a/platform/osx/joypad_osx.cpp +++ b/platform/macos/joypad_macos.cpp @@ -1,5 +1,5 @@ /*************************************************************************/ -/* joypad_osx.cpp */ +/* joypad_macos.cpp */ /*************************************************************************/ /* This file is part of: */ /* GODOT ENGINE */ @@ -28,13 +28,13 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ -#include "joypad_osx.h" +#include "joypad_macos.h" #include <machine/endian.h> #define GODOT_JOY_LOOP_RUN_MODE CFSTR("GodotJoypad") -static JoypadOSX *self = nullptr; +static JoypadMacOS *self = nullptr; joypad::joypad() { ff_constant_force.lMagnitude = 10000; @@ -235,7 +235,7 @@ static bool is_joypad(IOHIDDeviceRef p_device_ref) { return true; } -void JoypadOSX::_device_added(IOReturn p_res, IOHIDDeviceRef p_device) { +void JoypadMacOS::_device_added(IOReturn p_res, IOHIDDeviceRef p_device) { if (p_res != kIOReturnSuccess || have_device(p_device)) { return; } @@ -258,7 +258,7 @@ void JoypadOSX::_device_added(IOReturn p_res, IOHIDDeviceRef p_device) { IOHIDDeviceScheduleWithRunLoop(p_device, CFRunLoopGetCurrent(), GODOT_JOY_LOOP_RUN_MODE); } -void JoypadOSX::_device_removed(IOReturn p_res, IOHIDDeviceRef p_device) { +void JoypadMacOS::_device_removed(IOReturn p_res, IOHIDDeviceRef p_device) { int device = get_joy_ref(p_device); ERR_FAIL_COND(device == -1); @@ -278,7 +278,7 @@ static String _hex_str(uint8_t p_byte) { return ret; } -bool JoypadOSX::configure_joypad(IOHIDDeviceRef p_device_ref, joypad *p_joy) { +bool JoypadMacOS::configure_joypad(IOHIDDeviceRef p_device_ref, joypad *p_joy) { p_joy->device_ref = p_device_ref; // Get device name. String name; @@ -445,7 +445,7 @@ static HatMask process_hat_value(int p_min, int p_max, int p_value, bool p_offse return hat_value; } -void JoypadOSX::poll_joypads() const { +void JoypadMacOS::poll_joypads() const { while (CFRunLoopRunInMode(GODOT_JOY_LOOP_RUN_MODE, 0, TRUE) == kCFRunLoopRunHandledSource) { // No-op. Pending callbacks will fire. } @@ -456,7 +456,7 @@ static float axis_correct(int p_value, int p_min, int p_max) { return 2.0f * (p_value - p_min) / (p_max - p_min) - 1.0f; } -void JoypadOSX::process_joypads() { +void JoypadMacOS::process_joypads() { poll_joypads(); for (int i = 0; i < device_list.size(); i++) { @@ -494,7 +494,7 @@ void JoypadOSX::process_joypads() { } } -void JoypadOSX::joypad_vibration_start(int p_id, float p_magnitude, float p_duration, uint64_t p_timestamp) { +void JoypadMacOS::joypad_vibration_start(int p_id, float p_magnitude, float p_duration, uint64_t p_timestamp) { joypad *joy = &device_list.write[get_joy_index(p_id)]; joy->ff_timestamp = p_timestamp; joy->ff_effect.dwDuration = p_duration * FF_SECONDS; @@ -503,13 +503,13 @@ void JoypadOSX::joypad_vibration_start(int p_id, float p_magnitude, float p_dura FFEffectStart(joy->ff_object, 1, 0); } -void JoypadOSX::joypad_vibration_stop(int p_id, uint64_t p_timestamp) { +void JoypadMacOS::joypad_vibration_stop(int p_id, uint64_t p_timestamp) { joypad *joy = &device_list.write[get_joy_index(p_id)]; joy->ff_timestamp = p_timestamp; FFEffectStop(joy->ff_object); } -int JoypadOSX::get_joy_index(int p_id) const { +int JoypadMacOS::get_joy_index(int p_id) const { for (int i = 0; i < device_list.size(); i++) { if (device_list[i].id == p_id) { return i; @@ -518,7 +518,7 @@ int JoypadOSX::get_joy_index(int p_id) const { return -1; } -int JoypadOSX::get_joy_ref(IOHIDDeviceRef p_device) const { +int JoypadMacOS::get_joy_ref(IOHIDDeviceRef p_device) const { for (int i = 0; i < device_list.size(); i++) { if (device_list[i].device_ref == p_device) { return i; @@ -527,7 +527,7 @@ int JoypadOSX::get_joy_ref(IOHIDDeviceRef p_device) const { return -1; } -bool JoypadOSX::have_device(IOHIDDeviceRef p_device) const { +bool JoypadMacOS::have_device(IOHIDDeviceRef p_device) const { for (int i = 0; i < device_list.size(); i++) { if (device_list[i].device_ref == p_device) { return true; @@ -561,7 +561,7 @@ static CFDictionaryRef create_match_dictionary(const UInt32 page, const UInt32 u return retval; } -void JoypadOSX::config_hid_manager(CFArrayRef p_matching_array) const { +void JoypadMacOS::config_hid_manager(CFArrayRef p_matching_array) const { CFRunLoopRef runloop = CFRunLoopGetCurrent(); IOReturn ret = IOHIDManagerOpen(hid_manager, kIOHIDOptionsTypeNone); ERR_FAIL_COND(ret != kIOReturnSuccess); @@ -576,7 +576,7 @@ void JoypadOSX::config_hid_manager(CFArrayRef p_matching_array) const { } } -JoypadOSX::JoypadOSX(Input *in) { +JoypadMacOS::JoypadMacOS(Input *in) { self = this; input = in; @@ -604,7 +604,7 @@ JoypadOSX::JoypadOSX(Input *in) { } } -JoypadOSX::~JoypadOSX() { +JoypadMacOS::~JoypadMacOS() { for (int i = 0; i < device_list.size(); i++) { device_list.write[i].free(); } diff --git a/platform/osx/joypad_osx.h b/platform/macos/joypad_macos.h index 3f89048ce6..4b14fed6d5 100644 --- a/platform/osx/joypad_osx.h +++ b/platform/macos/joypad_macos.h @@ -1,5 +1,5 @@ /*************************************************************************/ -/* joypad_osx.h */ +/* joypad_macos.h */ /*************************************************************************/ /* This file is part of: */ /* GODOT ENGINE */ @@ -28,8 +28,8 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ -#ifndef JOYPADOSX_H -#define JOYPADOSX_H +#ifndef JOYPAD_MACOS_H +#define JOYPAD_MACOS_H #ifdef MACOS_10_0_4 #import <IOKit/hidsystem/IOHIDUsageTables.h> @@ -88,7 +88,7 @@ struct joypad { joypad(); }; -class JoypadOSX { +class JoypadMacOS { enum { JOYPADS_MAX = 16, }; @@ -117,8 +117,8 @@ public: void _device_added(IOReturn p_res, IOHIDDeviceRef p_device); void _device_removed(IOReturn p_res, IOHIDDeviceRef p_device); - JoypadOSX(Input *in); - ~JoypadOSX(); + JoypadMacOS(Input *in); + ~JoypadMacOS(); }; -#endif // JOYPADOSX_H +#endif // JOYPAD_MACOS_H diff --git a/platform/osx/key_mapping_osx.h b/platform/macos/key_mapping_macos.h index 252cc907bb..fc5b791e44 100644 --- a/platform/osx/key_mapping_osx.h +++ b/platform/macos/key_mapping_macos.h @@ -1,5 +1,5 @@ /*************************************************************************/ -/* key_mapping_osx.h */ +/* key_mapping_macos.h */ /*************************************************************************/ /* This file is part of: */ /* GODOT ENGINE */ @@ -28,13 +28,13 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ -#ifndef KEY_MAPPING_OSX_H -#define KEY_MAPPING_OSX_H +#ifndef KEY_MAPPING_MACOS_H +#define KEY_MAPPING_MACOS_H #include "core/os/keyboard.h" -class KeyMappingOSX { - KeyMappingOSX() {} +class KeyMappingMacOS { + KeyMappingMacOS() {} static bool is_numpad_key(unsigned int key); @@ -49,4 +49,4 @@ public: static unsigned int keycode_get_native_mask(Key p_keycode); }; -#endif // KEY_MAPPING_OSX_H +#endif // KEY_MAPPING_MACOS_H diff --git a/platform/osx/key_mapping_osx.mm b/platform/macos/key_mapping_macos.mm index 0bf6bc7d1c..f6cff7124b 100644 --- a/platform/osx/key_mapping_osx.mm +++ b/platform/macos/key_mapping_macos.mm @@ -1,5 +1,5 @@ /*************************************************************************/ -/* key_mapping_osx.mm */ +/* key_mapping_macos.mm */ /*************************************************************************/ /* This file is part of: */ /* GODOT ENGINE */ @@ -28,12 +28,12 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ -#include "key_mapping_osx.h" +#include "key_mapping_macos.h" #import <Carbon/Carbon.h> #import <Cocoa/Cocoa.h> -bool KeyMappingOSX::is_numpad_key(unsigned int key) { +bool KeyMappingMacOS::is_numpad_key(unsigned int key) { static const unsigned int table[] = { 0x41, /* kVK_ANSI_KeypadDecimal */ 0x43, /* kVK_ANSI_KeypadMultiply */ @@ -65,7 +65,7 @@ bool KeyMappingOSX::is_numpad_key(unsigned int key) { } // Keyboard symbol translation table. -static const Key _osx_to_godot_table[128] = { +static const Key _macos_to_godot_table[128] = { /* 00 */ Key::A, /* 01 */ Key::S, /* 02 */ Key::D, @@ -197,18 +197,18 @@ static const Key _osx_to_godot_table[128] = { }; // Translates a OS X keycode to a Godot keycode. -Key KeyMappingOSX::translate_key(unsigned int key) { +Key KeyMappingMacOS::translate_key(unsigned int key) { if (key >= 128) { return Key::UNKNOWN; } - return _osx_to_godot_table[key]; + return _macos_to_godot_table[key]; } -// Translates a Godot keycode back to a OSX keycode. -unsigned int KeyMappingOSX::unmap_key(Key key) { +// Translates a Godot keycode back to a macOS keycode. +unsigned int KeyMappingMacOS::unmap_key(Key key) { for (int i = 0; i <= 126; i++) { - if (_osx_to_godot_table[i] == key) { + if (_macos_to_godot_table[i] == key) { return i; } } @@ -279,7 +279,7 @@ static const _KeyCodeMap _keycodes[55] = { }; // Remap key according to current keyboard layout. -Key KeyMappingOSX::remap_key(unsigned int key, unsigned int state) { +Key KeyMappingMacOS::remap_key(unsigned int key, unsigned int state) { if (is_numpad_key(key)) { return translate_key(key); } @@ -463,7 +463,7 @@ static const _KeyCodeText _native_keycodes[] = { /* clang-format on */ }; -String KeyMappingOSX::keycode_get_native_string(Key p_keycode) { +String KeyMappingMacOS::keycode_get_native_string(Key p_keycode) { const _KeyCodeText *kct = &_native_keycodes[0]; while (kct->text) { @@ -475,7 +475,7 @@ String KeyMappingOSX::keycode_get_native_string(Key p_keycode) { return String(); } -unsigned int KeyMappingOSX::keycode_get_native_mask(Key p_keycode) { +unsigned int KeyMappingMacOS::keycode_get_native_mask(Key p_keycode) { unsigned int mask = 0; if ((p_keycode & KeyModifierMask::CTRL) != Key::NONE) { mask |= NSEventModifierFlagControl; diff --git a/platform/osx/logo.png b/platform/macos/logo.png Binary files differindex b5a660b165..b5a660b165 100644 --- a/platform/osx/logo.png +++ b/platform/macos/logo.png diff --git a/platform/osx/osx_terminal_logger.h b/platform/macos/macos_terminal_logger.h index 8413509c4b..a811a5cbaf 100644 --- a/platform/osx/osx_terminal_logger.h +++ b/platform/macos/macos_terminal_logger.h @@ -1,5 +1,5 @@ /*************************************************************************/ -/* osx_terminal_logger.h */ +/* macos_terminal_logger.h */ /*************************************************************************/ /* This file is part of: */ /* GODOT ENGINE */ @@ -28,17 +28,18 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ -#ifndef OSX_TERMINAL_LOGGER_H -#define OSX_TERMINAL_LOGGER_H +#ifndef MACOS_TERMINAL_LOGGER_H +#define MACOS_TERMINAL_LOGGER_H -#ifdef OSX_ENABLED +#ifdef MACOS_ENABLED #include "core/io/logger.h" -class OSXTerminalLogger : public StdLogger { +class MacOSTerminalLogger : public StdLogger { public: virtual void log_error(const char *p_function, const char *p_file, int p_line, const char *p_code, const char *p_rationale, bool p_editor_notify = false, ErrorType p_type = ERR_ERROR) override; }; -#endif // OSX_ENABLED -#endif // OSX_TERMINAL_LOGGER_H +#endif // MACOS_ENABLED + +#endif // MACOS_TERMINAL_LOGGER_H diff --git a/platform/osx/osx_terminal_logger.mm b/platform/macos/macos_terminal_logger.mm index 48e26f42bf..b5ea2938ee 100644 --- a/platform/osx/osx_terminal_logger.mm +++ b/platform/macos/macos_terminal_logger.mm @@ -1,5 +1,5 @@ /*************************************************************************/ -/* osx_terminal_logger.mm */ +/* macos_terminal_logger.mm */ /*************************************************************************/ /* This file is part of: */ /* GODOT ENGINE */ @@ -28,13 +28,13 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ -#include "osx_terminal_logger.h" +#include "macos_terminal_logger.h" -#ifdef OSX_ENABLED +#ifdef MACOS_ENABLED #include <os/log.h> -void OSXTerminalLogger::log_error(const char *p_function, const char *p_file, int p_line, const char *p_code, const char *p_rationale, bool p_editor_notify, ErrorType p_type) { +void MacOSTerminalLogger::log_error(const char *p_function, const char *p_file, int p_line, const char *p_code, const char *p_rationale, bool p_editor_notify, ErrorType p_type) { if (!should_log(true)) { return; } @@ -79,4 +79,4 @@ void OSXTerminalLogger::log_error(const char *p_function, const char *p_file, in } } -#endif // OSX_ENABLED +#endif // MACOS_ENABLED diff --git a/platform/osx/os_osx.h b/platform/macos/os_macos.h index b105be4a06..61db99689c 100644 --- a/platform/osx/os_osx.h +++ b/platform/macos/os_macos.h @@ -1,5 +1,5 @@ /*************************************************************************/ -/* os_osx.h */ +/* os_macos.h */ /*************************************************************************/ /* This file is part of: */ /* GODOT ENGINE */ @@ -28,21 +28,19 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ -#ifndef OS_OSX_H -#define OS_OSX_H +#ifndef OS_MACOS_H +#define OS_MACOS_H #include "core/input/input.h" -#include "crash_handler_osx.h" +#include "crash_handler_macos.h" #include "drivers/coreaudio/audio_driver_coreaudio.h" #include "drivers/coremidi/midi_driver_coremidi.h" #include "drivers/unix/os_unix.h" -#include "joypad_osx.h" +#include "joypad_macos.h" #include "servers/audio_server.h" -class OS_OSX : public OS_Unix { - bool force_quit = false; - - JoypadOSX *joypad_osx = nullptr; +class OS_MacOS : public OS_Unix { + JoypadMacOS *joypad_macos = nullptr; #ifdef COREAUDIO_ENABLED AudioDriverCoreAudio audio_driver; @@ -97,6 +95,8 @@ public: virtual String get_locale() const override; + virtual Vector<String> get_system_fonts() const override; + virtual String get_system_font_path(const String &p_font_name, bool p_bold = false, bool p_italic = false) const override; virtual String get_executable_path() const override; virtual Error create_process(const String &p_path, const List<String> &p_arguments, ProcessID *r_child_id = nullptr, bool p_open_console = false) override; virtual Error create_instance(const List<String> &p_arguments, ProcessID *r_child_id = nullptr) override; @@ -113,8 +113,8 @@ public: void run(); - OS_OSX(); - ~OS_OSX(); + OS_MacOS(); + ~OS_MacOS(); }; -#endif +#endif // OS_MACOS_H diff --git a/platform/osx/os_osx.mm b/platform/macos/os_macos.mm index 5230ed4155..c250a9d71a 100644 --- a/platform/osx/os_osx.mm +++ b/platform/macos/os_macos.mm @@ -1,5 +1,5 @@ /*************************************************************************/ -/* os_osx.mm */ +/* os_macos.mm */ /*************************************************************************/ /* This file is part of: */ /* GODOT ENGINE */ @@ -28,16 +28,16 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ -#include "os_osx.h" +#include "os_macos.h" #include "core/version_generated.gen.h" #include "main/main.h" -#include "dir_access_osx.h" -#include "display_server_osx.h" +#include "dir_access_macos.h" +#include "display_server_macos.h" #include "godot_application.h" #include "godot_application_delegate.h" -#include "osx_terminal_logger.h" +#include "macos_terminal_logger.h" #include <dlfcn.h> #include <libproc.h> @@ -45,21 +45,22 @@ #include <os/log.h> #include <sys/sysctl.h> -_FORCE_INLINE_ String OS_OSX::get_framework_executable(const String &p_path) { +_FORCE_INLINE_ String OS_MacOS::get_framework_executable(const String &p_path) { // Append framework executable name, or return as is if p_path is not a framework. Ref<DirAccess> da = DirAccess::create(DirAccess::ACCESS_FILESYSTEM); - if (da->dir_exists(p_path) && da->file_exists(p_path.plus_file(p_path.get_file().get_basename()))) { - return p_path.plus_file(p_path.get_file().get_basename()); + if (da->dir_exists(p_path) && da->file_exists(p_path.path_join(p_path.get_file().get_basename()))) { + return p_path.path_join(p_path.get_file().get_basename()); } else { return p_path; } } -void OS_OSX::pre_wait_observer_cb(CFRunLoopObserverRef p_observer, CFRunLoopActivity p_activiy, void *p_context) { - // Prevent main loop from sleeping and redraw window during resize / modal popups. +void OS_MacOS::pre_wait_observer_cb(CFRunLoopObserverRef p_observer, CFRunLoopActivity p_activiy, void *p_context) { + // Prevent main loop from sleeping and redraw window during modal popup display. + // Do not redraw when rendering is done from the separate thread, it will conflict with the OpenGL context updates. - DisplayServerOSX *ds = (DisplayServerOSX *)DisplayServer::get_singleton(); - if (get_singleton()->get_main_loop() && ds && (get_singleton()->get_render_thread_mode() != RENDER_SEPARATE_THREAD || !ds->get_is_resizing())) { + DisplayServerMacOS *ds = (DisplayServerMacOS *)DisplayServer::get_singleton(); + if (get_singleton()->get_main_loop() && ds && (get_singleton()->get_render_thread_mode() != RENDER_SEPARATE_THREAD) && !ds->get_is_resizing()) { Main::force_redraw(); if (!Main::is_iterating()) { // Avoid cyclic loop. Main::iteration(); @@ -69,13 +70,13 @@ void OS_OSX::pre_wait_observer_cb(CFRunLoopObserverRef p_observer, CFRunLoopActi CFRunLoopWakeUp(CFRunLoopGetCurrent()); // Prevent main loop from sleeping. } -void OS_OSX::initialize() { +void OS_MacOS::initialize() { crash_handler.initialize(); initialize_core(); } -String OS_OSX::get_processor_name() const { +String OS_MacOS::get_processor_name() const { char buffer[256]; size_t buffer_len = 256; if (sysctlbyname("machdep.cpu.brand_string", &buffer, &buffer_len, NULL, 0) == 0) { @@ -84,35 +85,35 @@ String OS_OSX::get_processor_name() const { ERR_FAIL_V_MSG("", String("Couldn't get the CPU model name. Returning an empty string.")); } -void OS_OSX::initialize_core() { +void OS_MacOS::initialize_core() { OS_Unix::initialize_core(); - DirAccess::make_default<DirAccessOSX>(DirAccess::ACCESS_RESOURCES); - DirAccess::make_default<DirAccessOSX>(DirAccess::ACCESS_USERDATA); - DirAccess::make_default<DirAccessOSX>(DirAccess::ACCESS_FILESYSTEM); + DirAccess::make_default<DirAccessMacOS>(DirAccess::ACCESS_RESOURCES); + DirAccess::make_default<DirAccessMacOS>(DirAccess::ACCESS_USERDATA); + DirAccess::make_default<DirAccessMacOS>(DirAccess::ACCESS_FILESYSTEM); } -void OS_OSX::finalize() { +void OS_MacOS::finalize() { #ifdef COREMIDI_ENABLED midi_driver.close(); #endif delete_main_loop(); - if (joypad_osx) { - memdelete(joypad_osx); + if (joypad_macos) { + memdelete(joypad_macos); } } -void OS_OSX::initialize_joypads() { - joypad_osx = memnew(JoypadOSX(Input::get_singleton())); +void OS_MacOS::initialize_joypads() { + joypad_macos = memnew(JoypadMacOS(Input::get_singleton())); } -void OS_OSX::set_main_loop(MainLoop *p_main_loop) { +void OS_MacOS::set_main_loop(MainLoop *p_main_loop) { main_loop = p_main_loop; } -void OS_OSX::delete_main_loop() { +void OS_MacOS::delete_main_loop() { if (!main_loop) { return; } @@ -121,19 +122,19 @@ void OS_OSX::delete_main_loop() { main_loop = nullptr; } -void OS_OSX::set_cmdline_platform_args(const List<String> &p_args) { +void OS_MacOS::set_cmdline_platform_args(const List<String> &p_args) { launch_service_args = p_args; } -List<String> OS_OSX::get_cmdline_platform_args() const { +List<String> OS_MacOS::get_cmdline_platform_args() const { return launch_service_args; } -String OS_OSX::get_name() const { +String OS_MacOS::get_name() const { return "macOS"; } -void OS_OSX::alert(const String &p_alert, const String &p_title) { +void OS_MacOS::alert(const String &p_alert, const String &p_title) { NSAlert *window = [[NSAlert alloc] init]; NSString *ns_title = [NSString stringWithUTF8String:p_title.utf8().get_data()]; NSString *ns_alert = [NSString stringWithUTF8String:p_alert.utf8().get_data()]; @@ -150,17 +151,17 @@ void OS_OSX::alert(const String &p_alert, const String &p_title) { } } -Error OS_OSX::open_dynamic_library(const String p_path, void *&p_library_handle, bool p_also_set_library_path, String *r_resolved_path) { +Error OS_MacOS::open_dynamic_library(const String p_path, void *&p_library_handle, bool p_also_set_library_path, String *r_resolved_path) { String path = get_framework_executable(p_path); if (!FileAccess::exists(path)) { // Load .dylib or framework from within the executable path. - path = get_framework_executable(get_executable_path().get_base_dir().plus_file(p_path.get_file())); + path = get_framework_executable(get_executable_path().get_base_dir().path_join(p_path.get_file())); } if (!FileAccess::exists(path)) { // Load .dylib or framework from a standard macOS location. - path = get_framework_executable(get_executable_path().get_base_dir().plus_file("../Frameworks").plus_file(p_path.get_file())); + path = get_framework_executable(get_executable_path().get_base_dir().path_join("../Frameworks").path_join(p_path.get_file())); } p_library_handle = dlopen(path.utf8().get_data(), RTLD_NOW); @@ -173,11 +174,11 @@ Error OS_OSX::open_dynamic_library(const String p_path, void *&p_library_handle, return OK; } -MainLoop *OS_OSX::get_main_loop() const { +MainLoop *OS_MacOS::get_main_loop() const { return main_loop; } -String OS_OSX::get_config_path() const { +String OS_MacOS::get_config_path() const { // The XDG Base Directory specification technically only applies on Linux/*BSD, but it doesn't hurt to support it on macOS as well. if (has_environment("XDG_CONFIG_HOME")) { if (get_environment("XDG_CONFIG_HOME").is_absolute_path()) { @@ -187,12 +188,12 @@ String OS_OSX::get_config_path() const { } } if (has_environment("HOME")) { - return get_environment("HOME").plus_file("Library/Application Support"); + return get_environment("HOME").path_join("Library/Application Support"); } return "."; } -String OS_OSX::get_data_path() const { +String OS_MacOS::get_data_path() const { // The XDG Base Directory specification technically only applies on Linux/*BSD, but it doesn't hurt to support it on macOS as well. if (has_environment("XDG_DATA_HOME")) { if (get_environment("XDG_DATA_HOME").is_absolute_path()) { @@ -204,7 +205,7 @@ String OS_OSX::get_data_path() const { return get_config_path(); } -String OS_OSX::get_cache_path() const { +String OS_MacOS::get_cache_path() const { // The XDG Base Directory specification technically only applies on Linux/*BSD, but it doesn't hurt to support it on macOS as well. if (has_environment("XDG_CACHE_HOME")) { if (get_environment("XDG_CACHE_HOME").is_absolute_path()) { @@ -214,12 +215,12 @@ String OS_OSX::get_cache_path() const { } } if (has_environment("HOME")) { - return get_environment("HOME").plus_file("Library/Caches"); + return get_environment("HOME").path_join("Library/Caches"); } return get_config_path(); } -String OS_OSX::get_bundle_resource_dir() const { +String OS_MacOS::get_bundle_resource_dir() const { String ret; NSBundle *main = [NSBundle mainBundle]; @@ -230,7 +231,7 @@ String OS_OSX::get_bundle_resource_dir() const { return ret; } -String OS_OSX::get_bundle_icon_path() const { +String OS_MacOS::get_bundle_icon_path() const { String ret; NSBundle *main = [NSBundle mainBundle]; @@ -244,11 +245,11 @@ String OS_OSX::get_bundle_icon_path() const { } // Get properly capitalized engine name for system paths -String OS_OSX::get_godot_dir_name() const { +String OS_MacOS::get_godot_dir_name() const { return String(VERSION_SHORT_NAME).capitalize(); } -String OS_OSX::get_system_dir(SystemDir p_dir, bool p_shared_storage) const { +String OS_MacOS::get_system_dir(SystemDir p_dir, bool p_shared_storage) const { NSSearchPathDirectory id; bool found = true; @@ -287,7 +288,7 @@ String OS_OSX::get_system_dir(SystemDir p_dir, bool p_shared_storage) const { return ret; } -Error OS_OSX::shell_open(String p_uri) { +Error OS_MacOS::shell_open(String p_uri) { NSString *string = [NSString stringWithUTF8String:p_uri.utf8().get_data()]; NSURL *uri = [[NSURL alloc] initWithString:string]; // Escape special characters in filenames @@ -298,12 +299,86 @@ Error OS_OSX::shell_open(String p_uri) { return OK; } -String OS_OSX::get_locale() const { +String OS_MacOS::get_locale() const { NSString *locale_code = [[NSLocale preferredLanguages] objectAtIndex:0]; return String([locale_code UTF8String]).replace("-", "_"); } -String OS_OSX::get_executable_path() const { +Vector<String> OS_MacOS::get_system_fonts() const { + HashSet<String> font_names; + CFArrayRef fonts = CTFontManagerCopyAvailableFontFamilyNames(); + if (fonts) { + for (CFIndex i = 0; i < CFArrayGetCount(fonts); i++) { + CFStringRef cf_name = (CFStringRef)CFArrayGetValueAtIndex(fonts, i); + if (cf_name && (CFStringGetLength(cf_name) > 0) && (CFStringCompare(cf_name, CFSTR("LastResort"), kCFCompareCaseInsensitive) != kCFCompareEqualTo) && (CFStringGetCharacterAtIndex(cf_name, 0) != '.')) { + NSString *ns_name = (__bridge NSString *)cf_name; + font_names.insert(String::utf8([ns_name UTF8String])); + } + } + CFRelease(fonts); + } + + Vector<String> ret; + for (const String &E : font_names) { + ret.push_back(E); + } + return ret; +} + +String OS_MacOS::get_system_font_path(const String &p_font_name, bool p_bold, bool p_italic) const { + String ret; + + String font_name = p_font_name; + if (font_name.to_lower() == "sans-serif") { + font_name = "Helvetica"; + } else if (font_name.to_lower() == "serif") { + font_name = "Times"; + } else if (font_name.to_lower() == "monospace") { + font_name = "Courier"; + } else if (font_name.to_lower() == "fantasy") { + font_name = "Papyrus"; + } else if (font_name.to_lower() == "cursive") { + font_name = "Apple Chancery"; + }; + + CFStringRef name = CFStringCreateWithCString(kCFAllocatorDefault, font_name.utf8().get_data(), kCFStringEncodingUTF8); + + CTFontSymbolicTraits traits = 0; + if (p_bold) { + traits |= kCTFontBoldTrait; + } + if (p_italic) { + traits |= kCTFontItalicTrait; + } + + CFNumberRef sym_traits = CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt32Type, &traits); + CFMutableDictionaryRef traits_dict = CFDictionaryCreateMutable(kCFAllocatorDefault, 0, nullptr, nullptr); + CFDictionaryAddValue(traits_dict, kCTFontSymbolicTrait, sym_traits); + + CFMutableDictionaryRef attributes = CFDictionaryCreateMutable(kCFAllocatorDefault, 0, nullptr, nullptr); + CFDictionaryAddValue(attributes, kCTFontFamilyNameAttribute, name); + CFDictionaryAddValue(attributes, kCTFontTraitsAttribute, traits_dict); + + CTFontDescriptorRef font = CTFontDescriptorCreateWithAttributes(attributes); + if (font) { + CFURLRef url = (CFURLRef)CTFontDescriptorCopyAttribute(font, kCTFontURLAttribute); + if (url) { + NSString *font_path = [NSString stringWithString:[(__bridge NSURL *)url path]]; + ret = String::utf8([font_path UTF8String]); + CFRelease(url); + } + CFRelease(font); + } + + CFRelease(attributes); + CFRelease(traits_dict); + CFRelease(sym_traits); + CFRelease(name); + + return ret; +} + +String OS_MacOS::get_executable_path() const { char pathbuf[PROC_PIDPATHINFO_MAXSIZE]; int pid = getpid(); pid_t ret = proc_pidpath(pid, pathbuf, sizeof(pathbuf)); @@ -317,7 +392,7 @@ String OS_OSX::get_executable_path() const { } } -Error OS_OSX::create_process(const String &p_path, const List<String> &p_arguments, ProcessID *r_child_id, bool p_open_console) { +Error OS_MacOS::create_process(const String &p_path, const List<String> &p_arguments, ProcessID *r_child_id, bool p_open_console) { // Use NSWorkspace if path is an .app bundle. NSURL *url = [NSURL fileURLWithPath:@(p_path.utf8().get_data())]; NSBundle *bundle = [NSBundle bundleWithURL:url]; @@ -375,7 +450,7 @@ Error OS_OSX::create_process(const String &p_path, const List<String> &p_argumen } } -Error OS_OSX::create_instance(const List<String> &p_arguments, ProcessID *r_child_id) { +Error OS_MacOS::create_instance(const List<String> &p_arguments, ProcessID *r_child_id) { // If executable is bundled, always execute editor instances as an app bundle to ensure app window is registered and activated correctly. NSString *nsappname = [[[NSBundle mainBundle] infoDictionary] objectForKey:@"CFBundleName"]; if (nsappname != nil) { @@ -387,7 +462,7 @@ Error OS_OSX::create_instance(const List<String> &p_arguments, ProcessID *r_chil } } -String OS_OSX::get_unique_id() const { +String OS_MacOS::get_unique_id() const { static String serial_number; if (serial_number.is_empty()) { @@ -412,19 +487,19 @@ String OS_OSX::get_unique_id() const { return serial_number; } -bool OS_OSX::_check_internal_feature_support(const String &p_feature) { +bool OS_MacOS::_check_internal_feature_support(const String &p_feature) { return p_feature == "pc"; } -void OS_OSX::disable_crash_handler() { +void OS_MacOS::disable_crash_handler() { crash_handler.disable(); } -bool OS_OSX::is_disable_crash_handler() const { +bool OS_MacOS::is_disable_crash_handler() const { return crash_handler.is_disabled(); } -Error OS_OSX::move_to_trash(const String &p_path) { +Error OS_MacOS::move_to_trash(const String &p_path) { NSFileManager *fm = [NSFileManager defaultManager]; NSURL *url = [NSURL fileURLWithPath:@(p_path.utf8().get_data())]; NSError *err; @@ -437,9 +512,7 @@ Error OS_OSX::move_to_trash(const String &p_path) { return OK; } -void OS_OSX::run() { - force_quit = false; - +void OS_MacOS::run() { if (!main_loop) { return; } @@ -447,12 +520,12 @@ void OS_OSX::run() { main_loop->initialize(); bool quit = false; - while (!force_quit && !quit) { + while (!quit) { @try { if (DisplayServer::get_singleton()) { DisplayServer::get_singleton()->process_events(); // Get rid of pending events. } - joypad_osx->process_joypads(); + joypad_macos->process_joypads(); if (Main::iteration()) { quit = true; @@ -465,19 +538,18 @@ void OS_OSX::run() { main_loop->finalize(); } -OS_OSX::OS_OSX() { +OS_MacOS::OS_MacOS() { main_loop = nullptr; - force_quit = false; Vector<Logger *> loggers; - loggers.push_back(memnew(OSXTerminalLogger)); + loggers.push_back(memnew(MacOSTerminalLogger)); _set_logger(memnew(CompositeLogger(loggers))); #ifdef COREAUDIO_ENABLED AudioDriverManager::add_driver(&audio_driver); #endif - DisplayServerOSX::register_osx_driver(); + DisplayServerMacOS::register_macos_driver(); // Implicitly create shared NSApplication instance. [GodotApplication sharedApplication]; @@ -518,7 +590,7 @@ OS_OSX::OS_OSX() { [NSApp activateIgnoringOtherApps:YES]; } -OS_OSX::~OS_OSX() { +OS_MacOS::~OS_MacOS() { CFRunLoopRemoveObserver(CFRunLoopGetCurrent(), pre_wait_observer, kCFRunLoopCommonModes); CFRelease(pre_wait_observer); } diff --git a/platform/osx/platform_config.h b/platform/macos/platform_config.h index e114606b82..e114606b82 100644 --- a/platform/osx/platform_config.h +++ b/platform/macos/platform_config.h diff --git a/platform/osx/platform_osx_builders.py b/platform/macos/platform_macos_builders.py index 953ed479db..3a1cc92bd2 100644 --- a/platform/osx/platform_osx_builders.py +++ b/platform/macos/platform_macos_builders.py @@ -7,7 +7,7 @@ import os from platform_methods import subprocess_main -def make_debug_osx(target, source, env): +def make_debug_macos(target, source, env): if env["macports_clang"] != "no": mpprefix = os.environ.get("MACPORTS_PREFIX", "/opt/local") mpclangver = env["macports_clang"] diff --git a/platform/osx/tts_osx.h b/platform/macos/tts_macos.h index 449418e48f..344676868a 100644 --- a/platform/osx/tts_osx.h +++ b/platform/macos/tts_macos.h @@ -1,5 +1,5 @@ /*************************************************************************/ -/* tts_osx.h */ +/* tts_macos.h */ /*************************************************************************/ /* This file is part of: */ /* GODOT ENGINE */ @@ -28,8 +28,8 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ -#ifndef TTS_OSX_H -#define TTS_OSX_H +#ifndef TTS_MACOS_H +#define TTS_MACOS_H #include "core/string/ustring.h" #include "core/templates/list.h" @@ -45,7 +45,7 @@ #import <AVFoundation/AVFoundation.h> #endif -@interface TTS_OSX : NSObject <AVSpeechSynthesizerDelegate> { +@interface TTS_MacOS : NSObject <AVSpeechSynthesizerDelegate> { // AVSpeechSynthesizer bool speaking; HashMap<id, int> ids; @@ -68,4 +68,4 @@ - (Array)getVoices; @end -#endif // TTS_OSX_H +#endif // TTS_MACOS_H diff --git a/platform/osx/tts_osx.mm b/platform/macos/tts_macos.mm index e6a5236cd9..56e15979c4 100644 --- a/platform/osx/tts_osx.mm +++ b/platform/macos/tts_macos.mm @@ -1,5 +1,5 @@ /*************************************************************************/ -/* tts_osx.mm */ +/* tts_macos.mm */ /*************************************************************************/ /* This file is part of: */ /* GODOT ENGINE */ @@ -28,9 +28,9 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ -#include "tts_osx.h" +#include "tts_macos.h" -@implementation TTS_OSX +@implementation TTS_MacOS - (id)init { self = [super init]; @@ -126,12 +126,12 @@ AVSpeechUtterance *new_utterance = [[AVSpeechUtterance alloc] initWithString:[NSString stringWithUTF8String:message.text.utf8().get_data()]]; [new_utterance setVoice:[AVSpeechSynthesisVoice voiceWithIdentifier:[NSString stringWithUTF8String:message.voice.utf8().get_data()]]]; if (message.rate > 1.f) { - [new_utterance setRate:Math::range_lerp(message.rate, 1.f, 10.f, AVSpeechUtteranceDefaultSpeechRate, AVSpeechUtteranceMaximumSpeechRate)]; + [new_utterance setRate:Math::remap(message.rate, 1.f, 10.f, AVSpeechUtteranceDefaultSpeechRate, AVSpeechUtteranceMaximumSpeechRate)]; } else if (message.rate < 1.f) { - [new_utterance setRate:Math::range_lerp(message.rate, 0.1f, 1.f, AVSpeechUtteranceMinimumSpeechRate, AVSpeechUtteranceDefaultSpeechRate)]; + [new_utterance setRate:Math::remap(message.rate, 0.1f, 1.f, AVSpeechUtteranceMinimumSpeechRate, AVSpeechUtteranceDefaultSpeechRate)]; } [new_utterance setPitchMultiplier:message.pitch]; - [new_utterance setVolume:(Math::range_lerp(message.volume, 0.f, 100.f, 0.f, 1.f))]; + [new_utterance setVolume:(Math::remap(message.volume, 0.f, 100.f, 0.f, 1.f))]; ids[new_utterance] = message.id; [av_synth speakUtterance:new_utterance]; @@ -141,7 +141,7 @@ [ns_synth setVoice:[NSString stringWithUTF8String:message.voice.utf8().get_data()]]; int base_pitch = [[ns_synth objectForProperty:NSSpeechPitchBaseProperty error:nil] intValue]; [ns_synth setObject:[NSNumber numberWithInt:(base_pitch * (message.pitch / 2.f + 0.5f))] forProperty:NSSpeechPitchBaseProperty error:nullptr]; - [ns_synth setVolume:(Math::range_lerp(message.volume, 0.f, 100.f, 0.f, 1.f))]; + [ns_synth setVolume:(Math::remap(message.volume, 0.f, 100.f, 0.f, 1.f))]; [ns_synth setRate:(message.rate * 200)]; last_utterance = message.id; diff --git a/platform/osx/vulkan_context_osx.h b/platform/macos/vulkan_context_macos.h index ade0f4a4c9..579c42b042 100644 --- a/platform/osx/vulkan_context_osx.h +++ b/platform/macos/vulkan_context_macos.h @@ -1,5 +1,5 @@ /*************************************************************************/ -/* vulkan_context_osx.h */ +/* vulkan_context_macos.h */ /*************************************************************************/ /* This file is part of: */ /* GODOT ENGINE */ @@ -28,20 +28,20 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ -#ifndef VULKAN_DEVICE_OSX_H -#define VULKAN_DEVICE_OSX_H +#ifndef VULKAN_CONTEXT_MACOS_H +#define VULKAN_CONTEXT_MACOS_H #include "drivers/vulkan/vulkan_context.h" #import <AppKit/AppKit.h> -class VulkanContextOSX : public VulkanContext { +class VulkanContextMacOS : public VulkanContext { virtual const char *_get_platform_surface_extension() const; public: Error window_create(DisplayServer::WindowID p_window_id, DisplayServer::VSyncMode p_vsync_mode, id p_window, int p_width, int p_height); - VulkanContextOSX(); - ~VulkanContextOSX(); + VulkanContextMacOS(); + ~VulkanContextMacOS(); }; -#endif // VULKAN_DEVICE_OSX_H +#endif // VULKAN_CONTEXT_MACOS_H diff --git a/platform/osx/vulkan_context_osx.mm b/platform/macos/vulkan_context_macos.mm index bdabc24c28..cf317f3c68 100644 --- a/platform/osx/vulkan_context_osx.mm +++ b/platform/macos/vulkan_context_macos.mm @@ -1,5 +1,5 @@ /*************************************************************************/ -/* vulkan_context_osx.mm */ +/* vulkan_context_macos.mm */ /*************************************************************************/ /* This file is part of: */ /* GODOT ENGINE */ @@ -28,18 +28,18 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ -#include "vulkan_context_osx.h" +#include "vulkan_context_macos.h" #ifdef USE_VOLK #include <volk.h> #else #include <vulkan/vulkan.h> #endif -const char *VulkanContextOSX::_get_platform_surface_extension() const { +const char *VulkanContextMacOS::_get_platform_surface_extension() const { return VK_MVK_MACOS_SURFACE_EXTENSION_NAME; } -Error VulkanContextOSX::window_create(DisplayServer::WindowID p_window_id, DisplayServer::VSyncMode p_vsync_mode, id p_window, int p_width, int p_height) { +Error VulkanContextMacOS::window_create(DisplayServer::WindowID p_window_id, DisplayServer::VSyncMode p_vsync_mode, id p_window, int p_width, int p_height) { VkMacOSSurfaceCreateInfoMVK createInfo; createInfo.sType = VK_STRUCTURE_TYPE_MACOS_SURFACE_CREATE_INFO_MVK; createInfo.pNext = nullptr; @@ -52,8 +52,8 @@ Error VulkanContextOSX::window_create(DisplayServer::WindowID p_window_id, Displ return _window_create(p_window_id, p_vsync_mode, surface, p_width, p_height); } -VulkanContextOSX::VulkanContextOSX() { +VulkanContextMacOS::VulkanContextMacOS() { } -VulkanContextOSX::~VulkanContextOSX() { +VulkanContextMacOS::~VulkanContextMacOS() { } diff --git a/platform/osx/SCsub b/platform/osx/SCsub deleted file mode 100644 index 3a4c95613d..0000000000 --- a/platform/osx/SCsub +++ /dev/null @@ -1,30 +0,0 @@ -#!/usr/bin/env python - -Import("env") - -from platform_methods import run_in_subprocess -import platform_osx_builders - -files = [ - "os_osx.mm", - "godot_application.mm", - "godot_application_delegate.mm", - "crash_handler_osx.mm", - "osx_terminal_logger.mm", - "display_server_osx.mm", - "godot_content_view.mm", - "godot_window_delegate.mm", - "godot_window.mm", - "key_mapping_osx.mm", - "godot_main_osx.mm", - "dir_access_osx.mm", - "tts_osx.mm", - "joypad_osx.cpp", - "vulkan_context_osx.mm", - "gl_manager_osx_legacy.mm", -] - -prog = env.add_program("#bin/godot", files) - -if env["debug_symbols"] and env["separate_debug_symbols"]: - env.AddPostAction(prog, run_in_subprocess(platform_osx_builders.make_debug_osx)) diff --git a/platform/register_platform_apis.h b/platform/register_platform_apis.h index 8b6d23a7a4..9dd90d9b20 100644 --- a/platform/register_platform_apis.h +++ b/platform/register_platform_apis.h @@ -28,10 +28,10 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ -#ifndef REGISTER_APIS_H -#define REGISTER_APIS_H +#ifndef REGISTER_PLATFORM_APIS_H +#define REGISTER_PLATFORM_APIS_H void register_platform_apis(); void unregister_platform_apis(); -#endif +#endif // REGISTER_PLATFORM_APIS_H diff --git a/platform/uwp/README.md b/platform/uwp/README.md new file mode 100644 index 0000000000..575f90e3c7 --- /dev/null +++ b/platform/uwp/README.md @@ -0,0 +1,20 @@ +# UWP platform port + +> **Warning** +> +> The UWP platform port is not currently in a working state for the `master` +> branch, and may be dropped in the future. + +This folder contains the C++ code for the Universal Windows Platform (UWP) +platform port. **This is not to be confused with the "standard" Win32 port**, +which is available in [`platform/windows`](/platform/windows). + +See also [`misc/dist/uwp_template`](/misc/dist/uwp_template) folder for the UWP +project template used for packaging the UWP export templates. + +## Documentation + +- [Compiling for Universal Windows Platform](https://docs.godotengine.org/en/latest/development/compiling/compiling_for_uwp.html) + - Instructions on building this platform port from source. +- [Exporting for Universal Windows Platform](https://docs.godotengine.org/en/latest/tutorials/export/exporting_for_uwp.html) + - Instructions on using the compiled export templates to export a project. diff --git a/platform/uwp/app_uwp.h b/platform/uwp/app_uwp.h index 9aadcfac75..82ad3ca01a 100644 --- a/platform/uwp/app_uwp.h +++ b/platform/uwp/app_uwp.h @@ -112,4 +112,5 @@ namespace GodotUWP } /* clang-format on */ + #endif // APP_UWP_H diff --git a/platform/uwp/detect.py b/platform/uwp/detect.py index 9c91378b22..2c5746cb06 100644 --- a/platform/uwp/detect.py +++ b/platform/uwp/detect.py @@ -1,6 +1,7 @@ import methods import os import sys +from platform_methods import detect_arch def is_active(): @@ -31,6 +32,7 @@ def get_opts(): def get_flags(): return [ + ("arch", detect_arch()), ("tools", False), ("xaudio2", True), ("builtin_pcre2_with_jit", False), @@ -38,19 +40,17 @@ def get_flags(): def configure(env): - env.msvc = True - - if env["bits"] != "default": - print("Error: bits argument is disabled for MSVC") + # Validate arch. + supported_arches = ["x86_32", "x86_64", "arm32"] + if env["arch"] not in supported_arches: print( - """ - Bits argument is not supported for MSVC compilation. Architecture depends on the Native/Cross Compile Tools Prompt/Developer Console - (or Visual Studio settings) that is being used to run SCons. As a consequence, bits argument is disabled. Run scons again without bits - argument (example: scons p=uwp) and SCons will attempt to detect what MSVC compiler will be executed and inform you. - """ + 'Unsupported CPU architecture "%s" for UWP. Supported architectures are: %s.' + % (env["arch"], ", ".join(supported_arches)) ) sys.exit() + env.msvc = True + ## Build type if env["target"] == "release": @@ -101,11 +101,10 @@ def configure(env): arch = "" if str(os.getenv("Platform")).lower() == "arm": - - print("Compiled program architecture will be an ARM executable. (forcing bits=32).") + print("Compiled program architecture will be an ARM executable (forcing arch=arm32).") arch = "arm" - env["bits"] = "32" + env["arch"] = "arm32" env.Append(LINKFLAGS=["/MACHINE:ARM"]) env.Append(LIBPATH=[vc_base_path + "lib/store/arm"]) @@ -117,20 +116,20 @@ def configure(env): compiler_version_str = methods.detect_visual_c_compiler_version(env["ENV"]) if compiler_version_str == "amd64" or compiler_version_str == "x86_amd64": - env["bits"] = "64" - print("Compiled program architecture will be a x64 executable (forcing bits=64).") + env["arch"] = "x86_64" + print("Compiled program architecture will be a x64 executable (forcing arch=x86_64).") elif compiler_version_str == "x86" or compiler_version_str == "amd64_x86": - env["bits"] = "32" - print("Compiled program architecture will be a x86 executable. (forcing bits=32).") + env["arch"] = "x86_32" + print("Compiled program architecture will be a x86 executable (forcing arch=x86_32).") else: print( - "Failed to detect MSVC compiler architecture version... Defaulting to 32-bit executable settings" - " (forcing bits=32). Compilation attempt will continue, but SCons can not detect for what architecture" + "Failed to detect MSVC compiler architecture version... Defaulting to x86 32-bit executable settings" + " (forcing arch=x86_32). Compilation attempt will continue, but SCons can not detect for what architecture" " this build is compiled for. You should check your settings/compilation setup." ) - env["bits"] = "32" + env["arch"] = "x86_32" - if env["bits"] == "32": + if env["arch"] == "x86_32": arch = "x86" angle_build_cmd += "Win32" diff --git a/platform/uwp/export/app_packager.cpp b/platform/uwp/export/app_packager.cpp index 09717b9d69..87224d38b8 100644 --- a/platform/uwp/export/app_packager.cpp +++ b/platform/uwp/export/app_packager.cpp @@ -408,7 +408,7 @@ void AppxPackager::finish() { // Create and add block map file EditorNode::progress_task_step("export", "Creating block map...", 4); - const String &tmp_blockmap_file_path = EditorPaths::get_singleton()->get_cache_dir().plus_file("tmpblockmap.xml"); + const String &tmp_blockmap_file_path = EditorPaths::get_singleton()->get_cache_dir().path_join("tmpblockmap.xml"); make_block_map(tmp_blockmap_file_path); { @@ -425,7 +425,7 @@ void AppxPackager::finish() { EditorNode::progress_task_step("export", "Setting content types...", 5); - const String &tmp_content_types_file_path = EditorPaths::get_singleton()->get_cache_dir().plus_file("tmpcontenttypes.xml"); + const String &tmp_content_types_file_path = EditorPaths::get_singleton()->get_cache_dir().path_join("tmpcontenttypes.xml"); make_content_types(tmp_content_types_file_path); { diff --git a/platform/uwp/export/app_packager.h b/platform/uwp/export/app_packager.h index dc5a5259ec..18db3eb806 100644 --- a/platform/uwp/export/app_packager.h +++ b/platform/uwp/export/app_packager.h @@ -40,7 +40,7 @@ #include "core/io/zip_io.h" #include "core/object/class_db.h" #include "core/version.h" -#include "editor/editor_export.h" +#include "editor/export/editor_export_platform.h" #include "thirdparty/minizip/unzip.h" #include "thirdparty/minizip/zip.h" @@ -146,4 +146,4 @@ public: ~AppxPackager(); }; -#endif +#endif // UWP_APP_PACKAGER_H diff --git a/platform/uwp/export/export.cpp b/platform/uwp/export/export.cpp index efba006985..31105824a5 100644 --- a/platform/uwp/export/export.cpp +++ b/platform/uwp/export/export.cpp @@ -30,6 +30,7 @@ #include "export.h" +#include "editor/editor_settings.h" #include "export_plugin.h" void register_uwp_exporter() { diff --git a/platform/uwp/export/export_plugin.cpp b/platform/uwp/export/export_plugin.cpp index 19b43d50be..4e4afb9704 100644 --- a/platform/uwp/export/export_plugin.cpp +++ b/platform/uwp/export/export_plugin.cpp @@ -30,6 +30,7 @@ #include "export_plugin.h" +#include "editor/editor_settings.h" #include "platform/uwp/logo.gen.h" String EditorExportPlatformUWP::get_name() const { @@ -49,27 +50,17 @@ Ref<Texture2D> EditorExportPlatformUWP::get_logo() const { return logo; } -void EditorExportPlatformUWP::get_preset_features(const Ref<EditorExportPreset> &p_preset, List<String> *r_features) { +void EditorExportPlatformUWP::get_preset_features(const Ref<EditorExportPreset> &p_preset, List<String> *r_features) const { r_features->push_back("s3tc"); r_features->push_back("etc"); - switch ((int)p_preset->get("architecture/target")) { - case EditorExportPlatformUWP::ARM: { - r_features->push_back("arm"); - } break; - case EditorExportPlatformUWP::X86: { - r_features->push_back("32"); - } break; - case EditorExportPlatformUWP::X64: { - r_features->push_back("64"); - } break; - } + r_features->push_back(p_preset->get("binary_format/architecture")); } void EditorExportPlatformUWP::get_export_options(List<ExportOption> *r_options) { r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "custom_template/debug", PROPERTY_HINT_GLOBAL_FILE, "*.zip"), "")); r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "custom_template/release", PROPERTY_HINT_GLOBAL_FILE, "*.zip"), "")); - r_options->push_back(ExportOption(PropertyInfo(Variant::INT, "architecture/target", PROPERTY_HINT_ENUM, "arm,x86,x64"), 1)); + r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "binary_format/architecture", PROPERTY_HINT_ENUM, "x86_64,x86_32,arm32"), "x86_64")); r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "command_line/extra_args"), "")); @@ -130,7 +121,7 @@ void EditorExportPlatformUWP::get_export_options(List<ExportOption> *r_options) } } -bool EditorExportPlatformUWP::can_export(const Ref<EditorExportPreset> &p_preset, String &r_error, bool &r_missing_templates) const { +bool EditorExportPlatformUWP::has_valid_export_configuration(const Ref<EditorExportPreset> &p_preset, String &r_error, bool &r_missing_templates) const { #ifndef DEV_ENABLED // We don't provide export templates for the UWP platform currently as it // has not been ported for Godot 4.0. This is skipped in DEV_ENABLED so that @@ -143,23 +134,18 @@ bool EditorExportPlatformUWP::can_export(const Ref<EditorExportPreset> &p_preset bool valid = false; // Look for export templates (first official, and if defined custom templates). - - Platform arch = (Platform)(int)(p_preset->get("architecture/target")); - String platform_infix; - switch (arch) { - case EditorExportPlatformUWP::ARM: { - platform_infix = "arm"; - } break; - case EditorExportPlatformUWP::X86: { - platform_infix = "x86"; - } break; - case EditorExportPlatformUWP::X64: { - platform_infix = "x64"; - } break; + String arch = p_preset->get("binary_format/architecture"); + String arch_infix; + if (arch == "arm32") { + arch_infix = "arm"; + } else if (arch == "x86_32") { + arch_infix = "x86"; + } else if (arch == "x86_64") { + arch_infix = "x64"; } - bool dvalid = exists_export_template("uwp_" + platform_infix + "_debug.zip", &err); - bool rvalid = exists_export_template("uwp_" + platform_infix + "_release.zip", &err); + bool dvalid = exists_export_template("uwp_" + arch_infix + "_debug.zip", &err); + bool rvalid = exists_export_template("uwp_" + arch_infix + "_release.zip", &err); if (p_preset->get("custom_template/debug") != "") { dvalid = FileAccess::exists(p_preset->get("custom_template/debug")); @@ -177,7 +163,26 @@ bool EditorExportPlatformUWP::can_export(const Ref<EditorExportPreset> &p_preset valid = dvalid || rvalid; r_missing_templates = !valid; - // Validate the rest of the configuration. + if (!err.is_empty()) { + r_error = err; + } + + return valid; +} + +bool EditorExportPlatformUWP::has_valid_project_configuration(const Ref<EditorExportPreset> &p_preset, String &r_error) const { +#ifndef DEV_ENABLED + // We don't provide export templates for the UWP platform currently as it + // has not been ported for Godot 4.0. This is skipped in DEV_ENABLED so that + // contributors can still test the pipeline if/when we can build it again. + r_error = "The UWP platform is currently not supported in Godot 4.0.\n"; + return false; +#endif + + String err; + bool valid = true; + + // Validate the project configuration. if (!_valid_resource_name(p_preset->get("package/short_name"))) { valid = false; @@ -263,25 +268,21 @@ Error EditorExportPlatformUWP::export_project(const Ref<EditorExportPreset> &p_p src_appx = src_appx.strip_edges(); - Platform arch = (Platform)(int)p_preset->get("architecture/target"); + String arch = p_preset->get("binary_format/architecture"); if (src_appx.is_empty()) { - String err, infix; - switch (arch) { - case ARM: { - infix = "_arm_"; - } break; - case X86: { - infix = "_x86_"; - } break; - case X64: { - infix = "_x64_"; - } break; + String err, arch_infix; + if (arch == "arm32") { + arch_infix = "arm"; + } else if (arch == "x86_32") { + arch_infix = "x86"; + } else if (arch == "x86_64") { + arch_infix = "x64"; } if (p_debug) { - src_appx = find_export_template("uwp" + infix + "debug.zip", &err); + src_appx = find_export_template("uwp_" + arch_infix + "_debug.zip", &err); } else { - src_appx = find_export_template("uwp" + infix + "release.zip", &err); + src_appx = find_export_template("uwp_" + arch_infix + "_release.zip", &err); } if (src_appx.is_empty()) { EditorNode::add_io_error(err); @@ -494,7 +495,7 @@ Error EditorExportPlatformUWP::export_project(const Ref<EditorExportPreset> &p_p return OK; } -void EditorExportPlatformUWP::get_platform_features(List<String> *r_features) { +void EditorExportPlatformUWP::get_platform_features(List<String> *r_features) const { r_features->push_back("pc"); r_features->push_back("uwp"); } diff --git a/platform/uwp/export/export_plugin.h b/platform/uwp/export/export_plugin.h index d92687075c..b0427d1a65 100644 --- a/platform/uwp/export/export_plugin.h +++ b/platform/uwp/export/export_plugin.h @@ -39,9 +39,9 @@ #include "core/io/zip_io.h" #include "core/object/class_db.h" #include "core/version.h" -#include "editor/editor_export.h" #include "editor/editor_node.h" #include "editor/editor_paths.h" +#include "editor/export/editor_export_platform.h" #include "thirdparty/minizip/unzip.h" #include "thirdparty/minizip/zip.h" @@ -90,12 +90,6 @@ class EditorExportPlatformUWP : public EditorExportPlatform { Ref<ImageTexture> logo; - enum Platform { - ARM, - X86, - X64 - }; - bool _valid_resource_name(const String &p_name) const { if (p_name.is_empty()) { return false; @@ -215,8 +209,8 @@ class EditorExportPlatformUWP : public EditorExportPlatform { String version = itos(p_preset->get("version/major")) + "." + itos(p_preset->get("version/minor")) + "." + itos(p_preset->get("version/build")) + "." + itos(p_preset->get("version/revision")); result = result.replace("$version_string$", version); - Platform arch = (Platform)(int)p_preset->get("architecture/target"); - String architecture = arch == ARM ? "arm" : (arch == X86 ? "x86" : "x64"); + String arch = p_preset->get("binary_format/architecture"); + String architecture = arch == "arm32" ? "arm" : (arch == "x86_32" ? "x86" : "x64"); result = result.replace("$architecture$", architecture); result = result.replace("$display_name$", String(p_preset->get("package/display_name")).is_empty() ? (String)ProjectSettings::get_singleton()->get("application/config/name") : String(p_preset->get("package/display_name"))); @@ -335,7 +329,7 @@ class EditorExportPlatformUWP : public EditorExportPlatform { return data; } - String tmp_path = EditorPaths::get_singleton()->get_cache_dir().plus_file("uwp_tmp_logo.png"); + String tmp_path = EditorPaths::get_singleton()->get_cache_dir().path_join("uwp_tmp_logo.png"); Error err = texture->get_image()->save_png(tmp_path); @@ -431,19 +425,20 @@ public: virtual Ref<Texture2D> get_logo() const override; - virtual void get_preset_features(const Ref<EditorExportPreset> &p_preset, List<String> *r_features) override; + virtual void get_preset_features(const Ref<EditorExportPreset> &p_preset, List<String> *r_features) const override; virtual void get_export_options(List<ExportOption> *r_options) override; - virtual bool can_export(const Ref<EditorExportPreset> &p_preset, String &r_error, bool &r_missing_templates) const override; + virtual bool has_valid_export_configuration(const Ref<EditorExportPreset> &p_preset, String &r_error, bool &r_missing_templates) const override; + virtual bool has_valid_project_configuration(const Ref<EditorExportPreset> &p_preset, String &r_error) const override; virtual Error export_project(const Ref<EditorExportPreset> &p_preset, bool p_debug, const String &p_path, int p_flags = 0) override; - virtual void get_platform_features(List<String> *r_features) override; + virtual void get_platform_features(List<String> *r_features) const override; virtual void resolve_platform_feature_priorities(const Ref<EditorExportPreset> &p_preset, HashSet<String> &p_features) override; EditorExportPlatformUWP(); }; -#endif +#endif // UWP_EXPORT_PLUGIN_H diff --git a/platform/uwp/joypad_uwp.h b/platform/uwp/joypad_uwp.h index 0869f1961d..81f84152b9 100644 --- a/platform/uwp/joypad_uwp.h +++ b/platform/uwp/joypad_uwp.h @@ -78,4 +78,4 @@ private: void joypad_vibration_stop(int p_device, uint64_t p_timestamp); }; -#endif +#endif // JOYPAD_UWP_H diff --git a/platform/uwp/os_uwp.cpp b/platform/uwp/os_uwp.cpp index 1614bfdcc3..791328964b 100644 --- a/platform/uwp/os_uwp.cpp +++ b/platform/uwp/os_uwp.cpp @@ -275,7 +275,7 @@ Error OS_UWP::initialize(const VideoMode &p_desired, int p_video_driver, int p_a display_request->RequestActive(); } - set_keep_screen_on(GLOBAL_DEF("display/window/energy_saving/keep_screen_on", true)); + set_keep_screen_on(GLOBAL_GET("display/window/energy_saving/keep_screen_on")); return OK; } @@ -444,7 +444,7 @@ String OS_UWP::get_name() const { return "UWP"; } -OS::Date OS_UWP::get_date(bool p_utc) const { +OS::DateTime OS_UWP::get_datetime(bool p_utc) const { SYSTEMTIME systemtime; if (p_utc) { GetSystemTime(&systemtime); @@ -452,28 +452,23 @@ OS::Date OS_UWP::get_date(bool p_utc) const { GetLocalTime(&systemtime); } - Date date; - date.day = systemtime.wDay; - date.month = Month(systemtime.wMonth); - date.weekday = Weekday(systemtime.wDayOfWeek); - date.year = systemtime.wYear; - date.dst = false; - return date; -} - -OS::Time OS_UWP::get_time(bool p_utc) const { - SYSTEMTIME systemtime; - if (p_utc) { - GetSystemTime(&systemtime); - } else { - GetLocalTime(&systemtime); + //Get DST information from Windows, but only if p_utc is false. + TIME_ZONE_INFORMATION info; + bool daylight = false; + if (!p_utc && GetTimeZoneInformation(&info) == TIME_ZONE_ID_DAYLIGHT) { + daylight = true; } - Time time; - time.hour = systemtime.wHour; - time.min = systemtime.wMinute; - time.sec = systemtime.wSecond; - return time; + DateTime dt; + dt.year = systemtime.wYear; + dt.month = Month(systemtime.wMonth); + dt.day = systemtime.wDay; + dt.weekday = Weekday(systemtime.wDayOfWeek); + dt.hour = systemtime.wHour; + dt.minute = systemtime.wMinute; + dt.second = systemtime.wSecond; + dt.dst = daylight; + return dt; } OS::TimeZoneInfo OS_UWP::get_time_zone_info() const { @@ -557,6 +552,7 @@ uint64_t OS_UWP::get_ticks_usec() const { void OS_UWP::process_events() { joypad->process_controllers(); process_key_events(); + input->flush_buffered_events(); } void OS_UWP::process_key_events() { @@ -715,7 +711,7 @@ bool OS_UWP::has_virtual_keyboard() const { return UIViewSettings::GetForCurrentView()->UserInteractionMode == UserInteractionMode::Touch; } -void OS_UWP::show_virtual_keyboard(const String &p_existing_text, const Rect2 &p_screen_rect, bool p_multiline, int p_max_input_length, int p_cursor_start, int p_cursor_end) { +void OS_UWP::show_virtual_keyboard(const String &p_existing_text, const Rect2 &p_screen_rect, VirtualKeyboardType p_type, int p_max_input_length, int p_cursor_start, int p_cursor_end) { InputPane ^ pane = InputPane::GetForCurrentView(); pane->TryShow(); } @@ -780,7 +776,7 @@ void OS_UWP::run() { int frames = 0; uint64_t frame = 0; - while (!force_quit) { + while (true) { CoreWindow::GetForCurrentThread()->Dispatcher->ProcessEvents(CoreProcessEventsOption::ProcessAllIfPresent); if (managed_object->alert_close_handle) { continue; @@ -810,7 +806,6 @@ bool OS_UWP::_check_internal_feature_support(const String &p_feature) { OS_UWP::OS_UWP() { key_event_pos = 0; - force_quit = false; alt_mem = false; gr_mem = false; shift_mem = false; diff --git a/platform/uwp/os_uwp.h b/platform/uwp/os_uwp.h index bddf63ff18..7d4224cf74 100644 --- a/platform/uwp/os_uwp.h +++ b/platform/uwp/os_uwp.h @@ -106,7 +106,6 @@ private: bool shift_mem; bool control_mem; bool meta_mem; - bool force_quit; MouseButton last_button_state = MouseButton::NONE; CursorShape cursor_shape; @@ -185,8 +184,7 @@ public: virtual String get_name() const; - virtual Date get_date(bool p_utc) const; - virtual Time get_time(bool p_utc) const; + virtual DateTime get_datetime(bool p_utc) const; virtual TimeZoneInfo get_time_zone_info() const; virtual uint64_t get_unix_time() const; @@ -231,7 +229,7 @@ public: virtual bool has_touchscreen_ui_hint() const; virtual bool has_virtual_keyboard() const; - virtual void show_virtual_keyboard(const String &p_existing_text, const Rect2 &p_screen_rect = Rect2(), bool p_multiline = false, int p_max_input_length = -1, int p_cursor_start = -1, int p_cursor_end = -1); + virtual void show_virtual_keyboard(const String &p_existing_text, const Rect2 &p_screen_rect = Rect2(), VirtualKeyboardType p_type = KEYBOARD_TYPE_DEFAULT, int p_max_input_length = -1, int p_cursor_start = -1, int p_cursor_end = -1); virtual void hide_virtual_keyboard(); virtual Error open_dynamic_library(const String p_path, void *&p_library_handle, bool p_also_set_library_path = false, String *r_resolved_path = nullptr); @@ -252,4 +250,4 @@ public: ~OS_UWP(); }; -#endif +#endif // OS_UWP_H diff --git a/platform/javascript/.eslintrc.engine.js b/platform/web/.eslintrc.engine.js index 78df6d41d9..78df6d41d9 100644 --- a/platform/javascript/.eslintrc.engine.js +++ b/platform/web/.eslintrc.engine.js diff --git a/platform/javascript/.eslintrc.js b/platform/web/.eslintrc.js index 2c81f1f02d..2c81f1f02d 100644 --- a/platform/javascript/.eslintrc.js +++ b/platform/web/.eslintrc.js diff --git a/platform/javascript/.eslintrc.libs.js b/platform/web/.eslintrc.libs.js index 8e579fd462..8e579fd462 100644 --- a/platform/javascript/.eslintrc.libs.js +++ b/platform/web/.eslintrc.libs.js diff --git a/platform/web/README.md b/platform/web/README.md new file mode 100644 index 0000000000..1265ca09df --- /dev/null +++ b/platform/web/README.md @@ -0,0 +1,22 @@ +# Web platform port + +This folder contains the C++ and JavaScript code for the Web platform port, +compiled using [Emscripten](https://emscripten.org/). + +It also contains a ESLint linting setup (see [`package.json`](package.json)). + +See also [`misc/dist/html`](/misc/dist/html) folder for additional files used by +this platform such as the html shell (web page). + +## Documentation + +- [Compiling for the Web](https://docs.godotengine.org/en/latest/development/compiling/compiling_for_web.html) + - Instructions on building this platform port from source. +- [Exporting for the Web](https://docs.godotengine.org/en/latest/tutorials/export/exporting_for_web.html) + - Instructions on using the compiled export templates to export a project. + +## Artwork license + +[`logo.png`](logo.png) and [`run_icon.png`](run_icon.png) are licensed under +[Creative Commons Attribution 3.0 Unported](https://www.w3.org/html/logo/faq.html#how-licenced) +per the HTML5 logo usage guidelines. diff --git a/platform/javascript/SCsub b/platform/web/SCsub index 4827dc4627..e8d0181ede 100644 --- a/platform/javascript/SCsub +++ b/platform/web/SCsub @@ -2,14 +2,14 @@ Import("env") -javascript_files = [ - "audio_driver_javascript.cpp", - "display_server_javascript.cpp", - "http_client_javascript.cpp", - "javascript_singleton.cpp", - "javascript_main.cpp", - "os_javascript.cpp", - "api/javascript_tools_editor_plugin.cpp", +web_files = [ + "audio_driver_web.cpp", + "display_server_web.cpp", + "http_client_web.cpp", + "javascript_bridge_singleton.cpp", + "web_main.cpp", + "os_web.cpp", + "api/web_tools_editor_plugin.cpp", ] sys_env = env.Clone() @@ -35,39 +35,31 @@ for ext in env["JS_EXTERNS"]: sys_env["ENV"]["EMCC_CLOSURE_ARGS"] += " --externs " + ext.abspath build = [] -if env["gdnative_enabled"]: - build_targets = ["#bin/godot${PROGSUFFIX}.js", "#bin/godot${PROGSUFFIX}.wasm"] - if env["threads_enabled"]: - build_targets.append("#bin/godot${PROGSUFFIX}.worker.js") +build_targets = ["#bin/godot${PROGSUFFIX}.js", "#bin/godot${PROGSUFFIX}.wasm", "#bin/godot${PROGSUFFIX}.worker.js"] +if env["dlink_enabled"]: # Reset libraries. The main runtime will only link emscripten libraries, not godot ones. sys_env["LIBS"] = [] # We use IDBFS. Since Emscripten 1.39.1 it needs to be linked explicitly. sys_env.Append(LIBS=["idbfs.js"]) # Configure it as a main module (dynamic linking support). + sys_env["CCFLAGS"].remove("SIDE_MODULE=2") + sys_env["LINKFLAGS"].remove("SIDE_MODULE=2") sys_env.Append(CCFLAGS=["-s", "MAIN_MODULE=1"]) sys_env.Append(LINKFLAGS=["-s", "MAIN_MODULE=1"]) - sys_env.Append(CCFLAGS=["-s", "EXPORT_ALL=1"]) sys_env.Append(LINKFLAGS=["-s", "EXPORT_ALL=1"]) sys_env.Append(LINKFLAGS=["-s", "WARN_ON_UNDEFINED_SYMBOLS=0"]) # Force exporting the standard library (printf, malloc, etc.) sys_env["ENV"]["EMCC_FORCE_STDLIBS"] = "libc,libc++,libc++abi" # The main emscripten runtime, with exported standard libraries. - sys = sys_env.Program(build_targets, ["javascript_runtime.cpp"]) + sys = sys_env.Program(build_targets, ["web_runtime.cpp"]) # The side library, containing all Godot code. - wasm_env = env.Clone() - wasm_env.Append(CPPDEFINES=["WASM_GDNATIVE"]) # So that OS knows it can run GDNative libraries. - wasm_env.Append(CCFLAGS=["-s", "SIDE_MODULE=2"]) - wasm_env.Append(LINKFLAGS=["-s", "SIDE_MODULE=2"]) - wasm = wasm_env.add_program("#bin/godot.side${PROGSUFFIX}.wasm", javascript_files) + wasm = env.add_program("#bin/godot.side${PROGSUFFIX}.wasm", web_files) build = sys + [wasm[0]] else: - build_targets = ["#bin/godot${PROGSUFFIX}.js", "#bin/godot${PROGSUFFIX}.wasm"] - if env["threads_enabled"]: - build_targets.append("#bin/godot${PROGSUFFIX}.worker.js") # We use IDBFS. Since Emscripten 1.39.1 it needs to be linked explicitly. sys_env.Append(LIBS=["idbfs.js"]) - build = sys_env.Program(build_targets, javascript_files + ["javascript_runtime.cpp"]) + build = sys_env.Program(build_targets, web_files + ["web_runtime.cpp"]) sys_env.Depends(build[0], sys_env["JS_LIBS"]) sys_env.Depends(build[0], sys_env["JS_PRE"]) @@ -78,7 +70,7 @@ engine = [ "js/engine/config.js", "js/engine/engine.js", ] -externs = [env.File("#platform/javascript/js/engine/engine.externs.js")] +externs = [env.File("#platform/web/js/engine/engine.externs.js")] js_engine = env.CreateEngineFile("#bin/godot${PROGSUFFIX}.engine.js", engine, externs) env.Depends(js_engine, externs) @@ -88,6 +80,8 @@ wrap_list = [ ] js_wrapped = env.Textfile("#bin/godot", [env.File(f) for f in wrap_list], TEXTFILESUFFIX="${PROGSUFFIX}.wrapped.js") -# Extra will be the thread worker, or the GDNative side, or None -extra = build[2:] if len(build) > 2 else None -env.CreateTemplateZip(js_wrapped, build[1], extra) +# 0 - unwrapped js file (use wrapped one instead) +# 1 - wasm file +# 2 - worker file +# 3 - wasm side (when dlink is enabled). +env.CreateTemplateZip(js_wrapped, build[1], build[2], build[3] if len(build) > 3 else None) diff --git a/platform/javascript/api/api.cpp b/platform/web/api/api.cpp index 46a0a816bf..e637f2aef2 100644 --- a/platform/javascript/api/api.cpp +++ b/platform/web/api/api.cpp @@ -30,66 +30,66 @@ #include "api.h" #include "core/config/engine.h" -#include "javascript_singleton.h" -#include "javascript_tools_editor_plugin.h" +#include "javascript_bridge_singleton.h" +#include "web_tools_editor_plugin.h" -static JavaScript *javascript_eval; +static JavaScriptBridge *javascript_bridge_singleton; -void register_javascript_api() { - JavaScriptToolsEditorPlugin::initialize(); +void register_web_api() { + WebToolsEditorPlugin::initialize(); GDREGISTER_ABSTRACT_CLASS(JavaScriptObject); - GDREGISTER_ABSTRACT_CLASS(JavaScript); - javascript_eval = memnew(JavaScript); - Engine::get_singleton()->add_singleton(Engine::Singleton("JavaScript", javascript_eval)); + GDREGISTER_ABSTRACT_CLASS(JavaScriptBridge); + javascript_bridge_singleton = memnew(JavaScriptBridge); + Engine::get_singleton()->add_singleton(Engine::Singleton("JavaScriptBridge", javascript_bridge_singleton)); } -void unregister_javascript_api() { - memdelete(javascript_eval); +void unregister_web_api() { + memdelete(javascript_bridge_singleton); } -JavaScript *JavaScript::singleton = nullptr; +JavaScriptBridge *JavaScriptBridge::singleton = nullptr; -JavaScript *JavaScript::get_singleton() { +JavaScriptBridge *JavaScriptBridge::get_singleton() { return singleton; } -JavaScript::JavaScript() { - ERR_FAIL_COND_MSG(singleton != nullptr, "JavaScript singleton already exist."); +JavaScriptBridge::JavaScriptBridge() { + ERR_FAIL_COND_MSG(singleton != nullptr, "JavaScriptBridge singleton already exist."); singleton = this; } -JavaScript::~JavaScript() {} +JavaScriptBridge::~JavaScriptBridge() {} -void JavaScript::_bind_methods() { - ClassDB::bind_method(D_METHOD("eval", "code", "use_global_execution_context"), &JavaScript::eval, DEFVAL(false)); - ClassDB::bind_method(D_METHOD("get_interface", "interface"), &JavaScript::get_interface); - ClassDB::bind_method(D_METHOD("create_callback", "callable"), &JavaScript::create_callback); +void JavaScriptBridge::_bind_methods() { + ClassDB::bind_method(D_METHOD("eval", "code", "use_global_execution_context"), &JavaScriptBridge::eval, DEFVAL(false)); + ClassDB::bind_method(D_METHOD("get_interface", "interface"), &JavaScriptBridge::get_interface); + ClassDB::bind_method(D_METHOD("create_callback", "callable"), &JavaScriptBridge::create_callback); { MethodInfo mi; mi.name = "create_object"; mi.arguments.push_back(PropertyInfo(Variant::STRING, "object")); - ClassDB::bind_vararg_method(METHOD_FLAGS_DEFAULT, "create_object", &JavaScript::_create_object_bind, mi); + ClassDB::bind_vararg_method(METHOD_FLAGS_DEFAULT, "create_object", &JavaScriptBridge::_create_object_bind, mi); } - ClassDB::bind_method(D_METHOD("download_buffer", "buffer", "name", "mime"), &JavaScript::download_buffer, DEFVAL("application/octet-stream")); - ClassDB::bind_method(D_METHOD("pwa_needs_update"), &JavaScript::pwa_needs_update); - ClassDB::bind_method(D_METHOD("pwa_update"), &JavaScript::pwa_update); + ClassDB::bind_method(D_METHOD("download_buffer", "buffer", "name", "mime"), &JavaScriptBridge::download_buffer, DEFVAL("application/octet-stream")); + ClassDB::bind_method(D_METHOD("pwa_needs_update"), &JavaScriptBridge::pwa_needs_update); + ClassDB::bind_method(D_METHOD("pwa_update"), &JavaScriptBridge::pwa_update); ADD_SIGNAL(MethodInfo("pwa_update_available")); } -#if !defined(JAVASCRIPT_ENABLED) || !defined(JAVASCRIPT_EVAL_ENABLED) -Variant JavaScript::eval(const String &p_code, bool p_use_global_exec_context) { +#if !defined(WEB_ENABLED) || !defined(JAVASCRIPT_EVAL_ENABLED) +Variant JavaScriptBridge::eval(const String &p_code, bool p_use_global_exec_context) { return Variant(); } -Ref<JavaScriptObject> JavaScript::get_interface(const String &p_interface) { +Ref<JavaScriptObject> JavaScriptBridge::get_interface(const String &p_interface) { return Ref<JavaScriptObject>(); } -Ref<JavaScriptObject> JavaScript::create_callback(const Callable &p_callable) { +Ref<JavaScriptObject> JavaScriptBridge::create_callback(const Callable &p_callable) { return Ref<JavaScriptObject>(); } -Variant JavaScript::_create_object_bind(const Variant **p_args, int p_argcount, Callable::CallError &r_error) { +Variant JavaScriptBridge::_create_object_bind(const Variant **p_args, int p_argcount, Callable::CallError &r_error) { if (p_argcount < 1) { r_error.error = Callable::CallError::CALL_ERROR_TOO_FEW_ARGUMENTS; r_error.argument = 0; @@ -104,13 +104,13 @@ Variant JavaScript::_create_object_bind(const Variant **p_args, int p_argcount, return Ref<JavaScriptObject>(); } #endif -#if !defined(JAVASCRIPT_ENABLED) -bool JavaScript::pwa_needs_update() const { +#if !defined(WEB_ENABLED) +bool JavaScriptBridge::pwa_needs_update() const { return false; } -Error JavaScript::pwa_update() { +Error JavaScriptBridge::pwa_update() { return ERR_UNAVAILABLE; } -void JavaScript::download_buffer(Vector<uint8_t> p_arr, const String &p_name, const String &p_mime) { +void JavaScriptBridge::download_buffer(Vector<uint8_t> p_arr, const String &p_name, const String &p_mime) { } #endif diff --git a/platform/javascript/api/api.h b/platform/web/api/api.h index 97e06c8577..f073e817d1 100644 --- a/platform/javascript/api/api.h +++ b/platform/web/api/api.h @@ -28,10 +28,10 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ -#ifndef JAVASCRIPT_API_H -#define JAVASCRIPT_API_H +#ifndef WEB_API_H +#define WEB_API_H -void register_javascript_api(); -void unregister_javascript_api(); +void register_web_api(); +void unregister_web_api(); -#endif // JAVASCRIPT_API_H +#endif // WEB_API_H diff --git a/platform/javascript/api/javascript_singleton.h b/platform/web/api/javascript_bridge_singleton.h index e93b0a18a1..1e7b5a1699 100644 --- a/platform/javascript/api/javascript_singleton.h +++ b/platform/web/api/javascript_bridge_singleton.h @@ -1,5 +1,5 @@ /*************************************************************************/ -/* javascript_singleton.h */ +/* javascript_bridge_singleton.h */ /*************************************************************************/ /* This file is part of: */ /* GODOT ENGINE */ @@ -28,8 +28,8 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ -#ifndef JAVASCRIPT_SINGLETON_H -#define JAVASCRIPT_SINGLETON_H +#ifndef JAVASCRIPT_BRIDGE_SINGLETON_H +#define JAVASCRIPT_BRIDGE_SINGLETON_H #include "core/object/class_db.h" #include "core/object/ref_counted.h" @@ -44,11 +44,11 @@ protected: virtual void _get_property_list(List<PropertyInfo> *p_list) const {} }; -class JavaScript : public Object { +class JavaScriptBridge : public Object { private: - GDCLASS(JavaScript, Object); + GDCLASS(JavaScriptBridge, Object); - static JavaScript *singleton; + static JavaScriptBridge *singleton; protected: static void _bind_methods(); @@ -62,9 +62,9 @@ public: bool pwa_needs_update() const; Error pwa_update(); - static JavaScript *get_singleton(); - JavaScript(); - ~JavaScript(); + static JavaScriptBridge *get_singleton(); + JavaScriptBridge(); + ~JavaScriptBridge(); }; -#endif // JAVASCRIPT_SINGLETON_H +#endif // JAVASCRIPT_BRIDGE_SINGLETON_H diff --git a/platform/javascript/api/javascript_tools_editor_plugin.cpp b/platform/web/api/web_tools_editor_plugin.cpp index 1507f32375..46fcb2d452 100644 --- a/platform/javascript/api/javascript_tools_editor_plugin.cpp +++ b/platform/web/api/web_tools_editor_plugin.cpp @@ -1,5 +1,5 @@ /*************************************************************************/ -/* javascript_tools_editor_plugin.cpp */ +/* web_tools_editor_plugin.cpp */ /*************************************************************************/ /* This file is part of: */ /* GODOT ENGINE */ @@ -28,8 +28,8 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ -#if defined(TOOLS_ENABLED) && defined(JAVASCRIPT_ENABLED) -#include "javascript_tools_editor_plugin.h" +#if defined(TOOLS_ENABLED) && defined(WEB_ENABLED) +#include "web_tools_editor_plugin.h" #include "core/config/engine.h" #include "core/config/project_settings.h" @@ -40,24 +40,24 @@ #include <emscripten/emscripten.h> -// JavaScript functions defined in library_godot_editor_tools.js +// Web functions defined in library_godot_editor_tools.js extern "C" { extern void godot_js_os_download_buffer(const uint8_t *p_buf, int p_buf_size, const char *p_name, const char *p_mime); } -static void _javascript_editor_init_callback() { - EditorNode::get_singleton()->add_editor_plugin(memnew(JavaScriptToolsEditorPlugin)); +static void _web_editor_init_callback() { + EditorNode::get_singleton()->add_editor_plugin(memnew(WebToolsEditorPlugin)); } -void JavaScriptToolsEditorPlugin::initialize() { - EditorNode::add_init_callback(_javascript_editor_init_callback); +void WebToolsEditorPlugin::initialize() { + EditorNode::add_init_callback(_web_editor_init_callback); } -JavaScriptToolsEditorPlugin::JavaScriptToolsEditorPlugin() { - add_tool_menu_item("Download Project Source", callable_mp(this, &JavaScriptToolsEditorPlugin::_download_zip)); +WebToolsEditorPlugin::WebToolsEditorPlugin() { + add_tool_menu_item("Download Project Source", callable_mp(this, &WebToolsEditorPlugin::_download_zip)); } -void JavaScriptToolsEditorPlugin::_download_zip(Variant p_v) { +void WebToolsEditorPlugin::_download_zip(Variant p_v) { if (!Engine::get_singleton() || !Engine::get_singleton()->is_editor_hint()) { ERR_PRINT("Downloading the project as a ZIP archive is only available in Editor mode."); return; @@ -76,7 +76,7 @@ void JavaScriptToolsEditorPlugin::_download_zip(Variant p_v) { const String datetime_safe = Time::get_singleton()->get_datetime_string_from_system(false, true).replace(" ", "_"); const String output_name = OS::get_singleton()->get_safe_dir_name(vformat("%s_%s.zip")); - const String output_path = String("/tmp").plus_file(output_name); + const String output_path = String("/tmp").path_join(output_name); zipFile zip = zipOpen2(output_path.utf8().get_data(), APPEND_STATUS_CREATE, nullptr, &io); const String base_path = resource_path.substr(0, resource_path.rfind("/")) + "/"; @@ -95,7 +95,7 @@ void JavaScriptToolsEditorPlugin::_download_zip(Variant p_v) { DirAccess::remove_file_or_error(output_path); } -void JavaScriptToolsEditorPlugin::_zip_file(String p_path, String p_base_path, zipFile p_zip) { +void WebToolsEditorPlugin::_zip_file(String p_path, String p_base_path, zipFile p_zip) { Ref<FileAccess> f = FileAccess::open(p_path, FileAccess::READ); if (f.is_null()) { WARN_PRINT("Unable to open file for zipping: " + p_path); @@ -121,7 +121,7 @@ void JavaScriptToolsEditorPlugin::_zip_file(String p_path, String p_base_path, z zipCloseFileInZip(p_zip); } -void JavaScriptToolsEditorPlugin::_zip_recursive(String p_path, String p_base_path, zipFile p_zip) { +void WebToolsEditorPlugin::_zip_recursive(String p_path, String p_base_path, zipFile p_zip) { Ref<DirAccess> dir = DirAccess::open(p_path); if (dir.is_null()) { WARN_PRINT("Unable to open directory for zipping: " + p_path); @@ -131,7 +131,7 @@ void JavaScriptToolsEditorPlugin::_zip_recursive(String p_path, String p_base_pa String cur = dir->get_next(); String project_data_dir_name = ProjectSettings::get_singleton()->get_project_data_dir_name(); while (!cur.is_empty()) { - String cs = p_path.plus_file(cur); + String cs = p_path.path_join(cur); if (cur == "." || cur == ".." || cur == project_data_dir_name) { // Skip } else if (dir->current_is_dir()) { diff --git a/platform/javascript/api/javascript_tools_editor_plugin.h b/platform/web/api/web_tools_editor_plugin.h index cbf5f49497..6af1dec3fb 100644 --- a/platform/javascript/api/javascript_tools_editor_plugin.h +++ b/platform/web/api/web_tools_editor_plugin.h @@ -1,5 +1,5 @@ /*************************************************************************/ -/* javascript_tools_editor_plugin.h */ +/* web_tools_editor_plugin.h */ /*************************************************************************/ /* This file is part of: */ /* GODOT ENGINE */ @@ -28,15 +28,15 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ -#ifndef JAVASCRIPT_TOOLS_EDITOR_PLUGIN_H -#define JAVASCRIPT_TOOLS_EDITOR_PLUGIN_H +#ifndef WEB_TOOLS_EDITOR_PLUGIN_H +#define WEB_TOOLS_EDITOR_PLUGIN_H -#if defined(TOOLS_ENABLED) && defined(JAVASCRIPT_ENABLED) +#if defined(TOOLS_ENABLED) && defined(WEB_ENABLED) #include "core/io/zip_io.h" #include "editor/editor_plugin.h" -class JavaScriptToolsEditorPlugin : public EditorPlugin { - GDCLASS(JavaScriptToolsEditorPlugin, EditorPlugin); +class WebToolsEditorPlugin : public EditorPlugin { + GDCLASS(WebToolsEditorPlugin, EditorPlugin); private: void _zip_file(String p_path, String p_base_path, zipFile p_zip); @@ -46,13 +46,13 @@ private: public: static void initialize(); - JavaScriptToolsEditorPlugin(); + WebToolsEditorPlugin(); }; #else -class JavaScriptToolsEditorPlugin { +class WebToolsEditorPlugin { public: static void initialize() {} }; #endif -#endif // JAVASCRIPT_TOOLS_EDITOR_PLUGIN_H +#endif // WEB_TOOLS_EDITOR_PLUGIN_H diff --git a/platform/javascript/audio_driver_javascript.cpp b/platform/web/audio_driver_web.cpp index d45885b8e8..0e37afc2cc 100644 --- a/platform/javascript/audio_driver_javascript.cpp +++ b/platform/web/audio_driver_web.cpp @@ -1,5 +1,5 @@ /*************************************************************************/ -/* audio_driver_javascript.cpp */ +/* audio_driver_web.cpp */ /*************************************************************************/ /* This file is part of: */ /* GODOT ENGINE */ @@ -28,27 +28,27 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ -#include "audio_driver_javascript.h" +#include "audio_driver_web.h" #include "core/config/project_settings.h" #include <emscripten.h> -AudioDriverJavaScript::AudioContext AudioDriverJavaScript::audio_context; +AudioDriverWeb::AudioContext AudioDriverWeb::audio_context; -bool AudioDriverJavaScript::is_available() { +bool AudioDriverWeb::is_available() { return godot_audio_is_available() != 0; } -void AudioDriverJavaScript::_state_change_callback(int p_state) { - AudioDriverJavaScript::audio_context.state = p_state; +void AudioDriverWeb::_state_change_callback(int p_state) { + AudioDriverWeb::audio_context.state = p_state; } -void AudioDriverJavaScript::_latency_update_callback(float p_latency) { - AudioDriverJavaScript::audio_context.output_latency = p_latency; +void AudioDriverWeb::_latency_update_callback(float p_latency) { + AudioDriverWeb::audio_context.output_latency = p_latency; } -void AudioDriverJavaScript::_audio_driver_process(int p_from, int p_samples) { +void AudioDriverWeb::_audio_driver_process(int p_from, int p_samples) { int32_t *stream_buffer = reinterpret_cast<int32_t *>(output_rb); const int max_samples = memarr_len(output_rb); @@ -74,7 +74,7 @@ void AudioDriverJavaScript::_audio_driver_process(int p_from, int p_samples) { } } -void AudioDriverJavaScript::_audio_driver_capture(int p_from, int p_samples) { +void AudioDriverWeb::_audio_driver_capture(int p_from, int p_samples) { if (get_input_buffer().size() == 0) { return; // Input capture stopped. } @@ -100,7 +100,7 @@ void AudioDriverJavaScript::_audio_driver_capture(int p_from, int p_samples) { } } -Error AudioDriverJavaScript::init() { +Error AudioDriverWeb::init() { int latency = GLOBAL_GET("audio/driver/output_latency"); if (!audio_context.inited) { audio_context.mix_rate = GLOBAL_GET("audio/driver/mix_rate"); @@ -132,29 +132,29 @@ Error AudioDriverJavaScript::init() { return OK; } -void AudioDriverJavaScript::start() { +void AudioDriverWeb::start() { start(output_rb, memarr_len(output_rb), input_rb, memarr_len(input_rb)); } -void AudioDriverJavaScript::resume() { +void AudioDriverWeb::resume() { if (audio_context.state == 0) { // 'suspended' godot_audio_resume(); } } -float AudioDriverJavaScript::get_latency() { +float AudioDriverWeb::get_latency() { return audio_context.output_latency + (float(buffer_length) / mix_rate); } -int AudioDriverJavaScript::get_mix_rate() const { +int AudioDriverWeb::get_mix_rate() const { return mix_rate; } -AudioDriver::SpeakerMode AudioDriverJavaScript::get_speaker_mode() const { +AudioDriver::SpeakerMode AudioDriverWeb::get_speaker_mode() const { return get_speaker_mode_by_total_channels(channel_count); } -void AudioDriverJavaScript::finish() { +void AudioDriverWeb::finish() { finish_driver(); if (output_rb) { memdelete_arr(output_rb); @@ -166,7 +166,7 @@ void AudioDriverJavaScript::finish() { } } -Error AudioDriverJavaScript::capture_start() { +Error AudioDriverWeb::capture_start() { lock(); input_buffer_init(buffer_length); unlock(); @@ -176,7 +176,7 @@ Error AudioDriverJavaScript::capture_start() { return OK; } -Error AudioDriverJavaScript::capture_stop() { +Error AudioDriverWeb::capture_stop() { godot_audio_capture_stop(); lock(); input_buffer.clear(); diff --git a/platform/javascript/audio_driver_javascript.h b/platform/web/audio_driver_web.h index b7b0b3ac96..dfce277c0c 100644 --- a/platform/javascript/audio_driver_javascript.h +++ b/platform/web/audio_driver_web.h @@ -1,5 +1,5 @@ /*************************************************************************/ -/* audio_driver_javascript.h */ +/* audio_driver_web.h */ /*************************************************************************/ /* This file is part of: */ /* GODOT ENGINE */ @@ -28,8 +28,8 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ -#ifndef AUDIO_DRIVER_JAVASCRIPT_H -#define AUDIO_DRIVER_JAVASCRIPT_H +#ifndef AUDIO_DRIVER_WEB_H +#define AUDIO_DRIVER_WEB_H #include "core/os/mutex.h" #include "core/os/thread.h" @@ -37,7 +37,7 @@ #include "godot_audio.h" -class AudioDriverJavaScript : public AudioDriver { +class AudioDriverWeb : public AudioDriver { private: struct AudioContext { bool inited = false; @@ -58,7 +58,7 @@ private: static void _state_change_callback(int p_state); static void _latency_update_callback(float p_latency); - static AudioDriverJavaScript *singleton; + static AudioDriverWeb *singleton; protected: void _audio_driver_process(int p_from = 0, int p_samples = 0); @@ -86,11 +86,11 @@ public: static void resume(); - AudioDriverJavaScript() {} + AudioDriverWeb() {} }; #ifdef NO_THREADS -class AudioDriverScriptProcessor : public AudioDriverJavaScript { +class AudioDriverScriptProcessor : public AudioDriverWeb { private: static void _process_callback(); @@ -109,7 +109,7 @@ public: AudioDriverScriptProcessor() { singleton = this; } }; -class AudioDriverWorklet : public AudioDriverJavaScript { +class AudioDriverWorklet : public AudioDriverWeb { private: static void _process_callback(int p_pos, int p_samples); static void _capture_callback(int p_pos, int p_samples); @@ -129,7 +129,7 @@ public: AudioDriverWorklet() { singleton = this; } }; #else -class AudioDriverWorklet : public AudioDriverJavaScript { +class AudioDriverWorklet : public AudioDriverWeb { private: enum { STATE_LOCK, @@ -158,4 +158,4 @@ public: }; #endif -#endif +#endif // AUDIO_DRIVER_WEB_H diff --git a/platform/javascript/detect.py b/platform/web/detect.py index a769260f01..08f964db92 100644 --- a/platform/javascript/detect.py +++ b/platform/web/detect.py @@ -18,7 +18,7 @@ def is_active(): def get_name(): - return "JavaScript" + return "Web" def can_build(): @@ -31,28 +31,45 @@ def get_opts(): return [ ("initial_memory", "Initial WASM memory (in MiB)", 32), BoolVariable("use_assertions", "Use Emscripten runtime assertions", False), - BoolVariable("use_thinlto", "Use ThinLTO", False), BoolVariable("use_ubsan", "Use Emscripten undefined behavior sanitizer (UBSAN)", False), BoolVariable("use_asan", "Use Emscripten address sanitizer (ASAN)", False), BoolVariable("use_lsan", "Use Emscripten leak sanitizer (LSAN)", False), BoolVariable("use_safe_heap", "Use Emscripten SAFE_HEAP sanitizer", False), # eval() can be a security concern, so it can be disabled. BoolVariable("javascript_eval", "Enable JavaScript eval interface", True), - BoolVariable("threads_enabled", "Enable WebAssembly Threads support (limited browser support)", True), - BoolVariable("gdnative_enabled", "Enable WebAssembly GDNative support (produces bigger binaries)", False), + BoolVariable( + "dlink_enabled", "Enable WebAssembly dynamic linking (GDExtension support). Produces bigger binaries", False + ), BoolVariable("use_closure_compiler", "Use closure compiler to minimize JavaScript code", False), ] def get_flags(): return [ + ("arch", "wasm32"), ("tools", False), ("builtin_pcre2_with_jit", False), ("vulkan", False), + # Use -Os to prioritize optimizing for reduced file size. This is + # particularly valuable for the web platform because it directly + # decreases download time. + # -Os reduces file size by around 5 MiB over -O3. -Oz only saves about + # 100 KiB over -Os, which does not justify the negative impact on + # run-time performance. + ("optimize", "size"), ] def configure(env): + # Validate arch. + supported_arches = ["wasm32"] + if env["arch"] not in supported_arches: + print( + 'Unsupported CPU architecture "%s" for iOS. Supported architectures are: %s.' + % (env["arch"], ", ".join(supported_arches)) + ) + sys.exit() + try: env["initial_memory"] = int(env["initial_memory"]) except Exception: @@ -61,15 +78,12 @@ def configure(env): ## Build type if env["target"].startswith("release"): - # Use -Os to prioritize optimizing for reduced file size. This is - # particularly valuable for the web platform because it directly - # decreases download time. - # -Os reduces file size by around 5 MiB over -O3. -Oz only saves about - # 100 KiB over -Os, which does not justify the negative impact on - # run-time performance. - if env["optimize"] != "none": + if env["optimize"] == "size": env.Append(CCFLAGS=["-Os"]) env.Append(LINKFLAGS=["-Os"]) + elif env["optimize"] == "speed": + env.Append(CCFLAGS=["-O3"]) + env.Append(LINKFLAGS=["-O3"]) if env["target"] == "release_debug": # Retain function names for backtraces at the cost of file size. @@ -83,21 +97,11 @@ def configure(env): env.Append(LINKFLAGS=["-s", "ASSERTIONS=1"]) if env["tools"]: - if not env["threads_enabled"]: - print('Note: Forcing "threads_enabled=yes" as it is required for the web editor.') - env["threads_enabled"] = "yes" if env["initial_memory"] < 64: print('Note: Forcing "initial_memory=64" as it is required for the web editor.') env["initial_memory"] = 64 - env.Append(CCFLAGS=["-frtti"]) - elif env["builtin_icu"]: - env.Append(CCFLAGS=["-fno-exceptions", "-frtti"]) else: - # Disable exceptions and rtti on non-tools (template) builds - # These flags help keep the file size down. - env.Append(CCFLAGS=["-fno-exceptions", "-fno-rtti"]) - # Don't use dynamic_cast, necessary with no-rtti. - env.Append(CPPDEFINES=["NO_SAFE_CAST"]) + env.Append(CPPFLAGS=["-fno-exceptions"]) env.Append(LINKFLAGS=["-s", "INITIAL_MEMORY=%sMB" % env["initial_memory"]]) @@ -105,12 +109,13 @@ def configure(env): env["ENV"] = os.environ # LTO - if env["use_thinlto"]: - env.Append(CCFLAGS=["-flto=thin"]) - env.Append(LINKFLAGS=["-flto=thin"]) - elif env["use_lto"]: - env.Append(CCFLAGS=["-flto=full"]) - env.Append(LINKFLAGS=["-flto=full"]) + if env["lto"] != "none": + if env["lto"] == "thin": + env.Append(CCFLAGS=["-flto=thin"]) + env.Append(LINKFLAGS=["-flto=thin"]) + else: + env.Append(CCFLAGS=["-flto"]) + env.Append(LINKFLAGS=["-flto"]) # Sanitizers if env["use_ubsan"]: @@ -161,9 +166,9 @@ def configure(env): env["ARCOM_POSIX"] = env["ARCOM"].replace("$TARGET", "$TARGET.posix").replace("$SOURCES", "$SOURCES.posix") env["ARCOM"] = "${TEMPFILE(ARCOM_POSIX)}" - # All intermediate files are just LLVM bitcode. + # All intermediate files are just object files. env["OBJPREFIX"] = "" - env["OBJSUFFIX"] = ".bc" + env["OBJSUFFIX"] = ".o" env["PROGPREFIX"] = "" # Program() output consists of multiple files, so specify suffixes manually at builder. env["PROGSUFFIX"] = "" @@ -172,8 +177,8 @@ def configure(env): env["LIBPREFIXES"] = ["$LIBPREFIX"] env["LIBSUFFIXES"] = ["$LIBSUFFIX"] - env.Prepend(CPPPATH=["#platform/javascript"]) - env.Append(CPPDEFINES=["JAVASCRIPT_ENABLED", "UNIX_ENABLED"]) + env.Prepend(CPPPATH=["#platform/web"]) + env.Append(CPPDEFINES=["WEB_ENABLED", "UNIX_ENABLED"]) if env["opengl3"]: env.AppendUnique(CPPDEFINES=["GLES3_ENABLED"]) @@ -186,31 +191,22 @@ def configure(env): env.Append(CPPDEFINES=["JAVASCRIPT_EVAL_ENABLED"]) # Thread support (via SharedArrayBuffer). - if env["threads_enabled"]: - env.Append(CPPDEFINES=["PTHREAD_NO_RENAME"]) - env.Append(CCFLAGS=["-s", "USE_PTHREADS=1"]) - env.Append(LINKFLAGS=["-s", "USE_PTHREADS=1"]) - env.Append(LINKFLAGS=["-s", "PTHREAD_POOL_SIZE=8"]) - env.Append(LINKFLAGS=["-s", "WASM_MEM_MAX=2048MB"]) - env.extra_suffix = ".threads" + env.extra_suffix - else: - env.Append(CPPDEFINES=["NO_THREADS"]) + env.Append(CPPDEFINES=["PTHREAD_NO_RENAME"]) + env.Append(CCFLAGS=["-s", "USE_PTHREADS=1"]) + env.Append(LINKFLAGS=["-s", "USE_PTHREADS=1"]) + env.Append(LINKFLAGS=["-s", "PTHREAD_POOL_SIZE=8"]) + env.Append(LINKFLAGS=["-s", "WASM_MEM_MAX=2048MB"]) - if env["gdnative_enabled"]: + if env["dlink_enabled"]: cc_version = get_compiler_version(env) cc_semver = (int(cc_version["major"]), int(cc_version["minor"]), int(cc_version["patch"])) - if cc_semver < (2, 0, 10): - print("GDNative support requires emscripten >= 2.0.10, detected: %s.%s.%s" % cc_semver) + if cc_semver < (3, 1, 14): + print("GDExtension support requires emscripten >= 3.1.14, detected: %s.%s.%s" % cc_semver) sys.exit(255) - if env["threads_enabled"] and cc_semver < (3, 1, 14): - print("Threads and GDNative requires emscripten >= 3.1.14, detected: %s.%s.%s" % cc_semver) - sys.exit(255) - env.Append(CCFLAGS=["-s", "RELOCATABLE=1"]) - env.Append(LINKFLAGS=["-s", "RELOCATABLE=1"]) - # Weak symbols are broken upstream: https://github.com/emscripten-core/emscripten/issues/12819 - env.Append(CPPDEFINES=["ZSTD_HAVE_WEAK_SYMBOLS=0"]) - env.extra_suffix = ".gdnative" + env.extra_suffix + env.Append(CCFLAGS=["-s", "SIDE_MODULE=2"]) + env.Append(LINKFLAGS=["-s", "SIDE_MODULE=2"]) + env.extra_suffix = ".dlink" + env.extra_suffix # Reduce code size by generating less support code (e.g. skip NodeJS support). env.Append(LINKFLAGS=["-s", "ENVIRONMENT=web,worker"]) @@ -231,3 +227,7 @@ def configure(env): # Add code that allow exiting runtime. env.Append(LINKFLAGS=["-s", "EXIT_RUNTIME=1"]) + + # This workaround creates a closure that prevents the garbage collector from freeing the WebGL context. + # We also only use WebGL2, and changing context version is not widely supported anyway. + env.Append(LINKFLAGS=["-s", "GL_WORKAROUND_SAFARI_GETCONTEXT_BUG=0"]) diff --git a/platform/javascript/display_server_javascript.cpp b/platform/web/display_server_web.cpp index 4edd6c793a..f6a61b18e4 100644 --- a/platform/javascript/display_server_javascript.cpp +++ b/platform/web/display_server_web.cpp @@ -1,5 +1,5 @@ /*************************************************************************/ -/* display_server_javascript.cpp */ +/* display_server_web.cpp */ /*************************************************************************/ /* This file is part of: */ /* GODOT ENGINE */ @@ -28,12 +28,12 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ -#include "display_server_javascript.h" +#include "display_server_web.h" #ifdef GLES3_ENABLED #include "drivers/gles3/rasterizer_gles3.h" #endif -#include "platform/javascript/os_javascript.h" +#include "platform/web/os_web.h" #include "servers/rendering/dummy/rasterizer_dummy.h" #include <emscripten.h> @@ -48,17 +48,17 @@ #define DOM_BUTTON_XBUTTON1 3 #define DOM_BUTTON_XBUTTON2 4 -DisplayServerJavaScript *DisplayServerJavaScript::get_singleton() { - return static_cast<DisplayServerJavaScript *>(DisplayServer::get_singleton()); +DisplayServerWeb *DisplayServerWeb::get_singleton() { + return static_cast<DisplayServerWeb *>(DisplayServer::get_singleton()); } // Window (canvas) -bool DisplayServerJavaScript::check_size_force_redraw() { +bool DisplayServerWeb::check_size_force_redraw() { return godot_js_display_size_update() != 0; } -void DisplayServerJavaScript::fullscreen_change_callback(int p_fullscreen) { - DisplayServerJavaScript *display = get_singleton(); +void DisplayServerWeb::fullscreen_change_callback(int p_fullscreen) { + DisplayServerWeb *display = get_singleton(); if (p_fullscreen) { display->window_mode = WINDOW_MODE_FULLSCREEN; } else { @@ -67,8 +67,8 @@ void DisplayServerJavaScript::fullscreen_change_callback(int p_fullscreen) { } // Drag and drop callback. -void DisplayServerJavaScript::drop_files_js_callback(char **p_filev, int p_filec) { - DisplayServerJavaScript *ds = get_singleton(); +void DisplayServerWeb::drop_files_js_callback(char **p_filev, int p_filec) { + DisplayServerWeb *ds = get_singleton(); if (!ds) { ERR_FAIL_MSG("Unable to drop files because the DisplayServer is not active"); } @@ -83,35 +83,35 @@ void DisplayServerJavaScript::drop_files_js_callback(char **p_filev, int p_filec Variant *vp = &v; Variant ret; Callable::CallError ce; - ds->drop_files_callback.call((const Variant **)&vp, 1, ret, ce); + ds->drop_files_callback.callp((const Variant **)&vp, 1, ret, ce); } -// JavaScript quit request callback. -void DisplayServerJavaScript::request_quit_callback() { - DisplayServerJavaScript *ds = get_singleton(); +// Web quit request callback. +void DisplayServerWeb::request_quit_callback() { + DisplayServerWeb *ds = get_singleton(); if (ds && !ds->window_event_callback.is_null()) { Variant event = int(DisplayServer::WINDOW_EVENT_CLOSE_REQUEST); Variant *eventp = &event; Variant ret; Callable::CallError ce; - ds->window_event_callback.call((const Variant **)&eventp, 1, ret, ce); + ds->window_event_callback.callp((const Variant **)&eventp, 1, ret, ce); } } // Keys -void DisplayServerJavaScript::dom2godot_mod(Ref<InputEventWithModifiers> ev, int p_mod) { +void DisplayServerWeb::dom2godot_mod(Ref<InputEventWithModifiers> ev, int p_mod) { ev->set_shift_pressed(p_mod & 1); ev->set_alt_pressed(p_mod & 2); ev->set_ctrl_pressed(p_mod & 4); ev->set_meta_pressed(p_mod & 8); } -void DisplayServerJavaScript::key_callback(int p_pressed, int p_repeat, int p_modifiers) { - DisplayServerJavaScript *ds = get_singleton(); +void DisplayServerWeb::key_callback(int p_pressed, int p_repeat, int p_modifiers) { + DisplayServerWeb *ds = get_singleton(); JSKeyEvent &key_event = ds->key_event; // Resume audio context after input in case autoplay was denied. - OS_JavaScript::get_singleton()->resume_audio(); + OS_Web::get_singleton()->resume_audio(); Ref<InputEventKey> ev; ev.instantiate(); @@ -133,8 +133,8 @@ void DisplayServerJavaScript::key_callback(int p_pressed, int p_repeat, int p_mo // Mouse -int DisplayServerJavaScript::mouse_button_callback(int p_pressed, int p_button, double p_x, double p_y, int p_modifiers) { - DisplayServerJavaScript *ds = get_singleton(); +int DisplayServerWeb::mouse_button_callback(int p_pressed, int p_button, double p_x, double p_y, int p_modifiers) { + DisplayServerWeb *ds = get_singleton(); Point2 pos(p_x, p_y); Ref<InputEventMouseButton> ev; @@ -199,7 +199,7 @@ int DisplayServerJavaScript::mouse_button_callback(int p_pressed, int p_button, Input::get_singleton()->parse_input_event(ev); // Resume audio context after input in case autoplay was denied. - OS_JavaScript::get_singleton()->resume_audio(); + OS_Web::get_singleton()->resume_audio(); // Make sure to flush all events so we can call restricted APIs inside the event. Input::get_singleton()->flush_buffered_events(); @@ -209,7 +209,7 @@ int DisplayServerJavaScript::mouse_button_callback(int p_pressed, int p_button, return true; } -void DisplayServerJavaScript::mouse_move_callback(double p_x, double p_y, double p_rel_x, double p_rel_y, int p_modifiers) { +void DisplayServerWeb::mouse_move_callback(double p_x, double p_y, double p_rel_x, double p_rel_y, int p_modifiers) { MouseButton input_mask = Input::get_singleton()->get_mouse_button_mask(); // For motion outside the canvas, only read mouse movement if dragging // started inside the canvas; imitating desktop app behaviour. @@ -233,7 +233,7 @@ void DisplayServerJavaScript::mouse_move_callback(double p_x, double p_y, double } // Cursor -const char *DisplayServerJavaScript::godot2dom_cursor(DisplayServer::CursorShape p_shape) { +const char *DisplayServerWeb::godot2dom_cursor(DisplayServer::CursorShape p_shape) { switch (p_shape) { case DisplayServer::CURSOR_ARROW: return "default"; @@ -274,15 +274,15 @@ const char *DisplayServerJavaScript::godot2dom_cursor(DisplayServer::CursorShape } } -bool DisplayServerJavaScript::tts_is_speaking() const { +bool DisplayServerWeb::tts_is_speaking() const { return godot_js_tts_is_speaking(); } -bool DisplayServerJavaScript::tts_is_paused() const { +bool DisplayServerWeb::tts_is_paused() const { return godot_js_tts_is_paused(); } -void DisplayServerJavaScript::update_voices_callback(int p_size, const char **p_voice) { +void DisplayServerWeb::update_voices_callback(int p_size, const char **p_voice) { get_singleton()->voices.clear(); for (int i = 0; i < p_size; i++) { Vector<String> tokens = String::utf8(p_voice[i]).split(";", true, 2); @@ -296,12 +296,12 @@ void DisplayServerJavaScript::update_voices_callback(int p_size, const char **p_ } } -Array DisplayServerJavaScript::tts_get_voices() const { +TypedArray<Dictionary> DisplayServerWeb::tts_get_voices() const { godot_js_tts_get_voices(update_voices_callback); return voices; } -void DisplayServerJavaScript::tts_speak(const String &p_text, const String &p_voice, int p_volume, float p_pitch, float p_rate, int p_utterance_id, bool p_interrupt) { +void DisplayServerWeb::tts_speak(const String &p_text, const String &p_voice, int p_volume, float p_pitch, float p_rate, int p_utterance_id, bool p_interrupt) { if (p_interrupt) { tts_stop(); } @@ -314,18 +314,18 @@ void DisplayServerJavaScript::tts_speak(const String &p_text, const String &p_vo CharString string = p_text.utf8(); utterance_ids[p_utterance_id] = string; - godot_js_tts_speak(string.get_data(), p_voice.utf8().get_data(), CLAMP(p_volume, 0, 100), CLAMP(p_pitch, 0.f, 2.f), CLAMP(p_rate, 0.1f, 10.f), p_utterance_id, DisplayServerJavaScript::_js_utterance_callback); + godot_js_tts_speak(string.get_data(), p_voice.utf8().get_data(), CLAMP(p_volume, 0, 100), CLAMP(p_pitch, 0.f, 2.f), CLAMP(p_rate, 0.1f, 10.f), p_utterance_id, DisplayServerWeb::_js_utterance_callback); } -void DisplayServerJavaScript::tts_pause() { +void DisplayServerWeb::tts_pause() { godot_js_tts_pause(); } -void DisplayServerJavaScript::tts_resume() { +void DisplayServerWeb::tts_resume() { godot_js_tts_resume(); } -void DisplayServerJavaScript::tts_stop() { +void DisplayServerWeb::tts_stop() { for (const KeyValue<int, CharString> &E : utterance_ids) { tts_post_utterance_event(DisplayServer::TTS_UTTERANCE_CANCELED, E.key); } @@ -333,8 +333,8 @@ void DisplayServerJavaScript::tts_stop() { godot_js_tts_stop(); } -void DisplayServerJavaScript::_js_utterance_callback(int p_event, int p_id, int p_pos) { - DisplayServerJavaScript *ds = (DisplayServerJavaScript *)DisplayServer::get_singleton(); +void DisplayServerWeb::_js_utterance_callback(int p_event, int p_id, int p_pos) { + DisplayServerWeb *ds = (DisplayServerWeb *)DisplayServer::get_singleton(); if (ds->utterance_ids.has(p_id)) { int pos = 0; if ((TTSUtteranceEvent)p_event == DisplayServer::TTS_UTTERANCE_BOUNDARY) { @@ -358,7 +358,7 @@ void DisplayServerJavaScript::_js_utterance_callback(int p_event, int p_id, int } } -void DisplayServerJavaScript::cursor_set_shape(CursorShape p_shape) { +void DisplayServerWeb::cursor_set_shape(CursorShape p_shape) { ERR_FAIL_INDEX(p_shape, CURSOR_MAX); if (cursor_shape == p_shape) { return; @@ -367,11 +367,11 @@ void DisplayServerJavaScript::cursor_set_shape(CursorShape p_shape) { godot_js_display_cursor_set_shape(godot2dom_cursor(cursor_shape)); } -DisplayServer::CursorShape DisplayServerJavaScript::cursor_get_shape() const { +DisplayServer::CursorShape DisplayServerWeb::cursor_get_shape() const { return cursor_shape; } -void DisplayServerJavaScript::cursor_set_custom_image(const Ref<Resource> &p_cursor, CursorShape p_shape, const Vector2 &p_hotspot) { +void DisplayServerWeb::cursor_set_custom_image(const Ref<Resource> &p_cursor, CursorShape p_shape, const Vector2 &p_hotspot) { if (p_cursor.is_valid()) { Ref<Texture2D> texture = p_cursor; Ref<AtlasTexture> atlas_texture = p_cursor; @@ -446,8 +446,8 @@ void DisplayServerJavaScript::cursor_set_custom_image(const Ref<Resource> &p_cur } // Mouse mode -void DisplayServerJavaScript::mouse_set_mode(MouseMode p_mode) { - ERR_FAIL_COND_MSG(p_mode == MOUSE_MODE_CONFINED || p_mode == MOUSE_MODE_CONFINED_HIDDEN, "MOUSE_MODE_CONFINED is not supported for the HTML5 platform."); +void DisplayServerWeb::mouse_set_mode(MouseMode p_mode) { + ERR_FAIL_COND_MSG(p_mode == MOUSE_MODE_CONFINED || p_mode == MOUSE_MODE_CONFINED_HIDDEN, "MOUSE_MODE_CONFINED is not supported for the Web platform."); if (p_mode == mouse_get_mode()) { return; } @@ -466,7 +466,7 @@ void DisplayServerJavaScript::mouse_set_mode(MouseMode p_mode) { } } -DisplayServer::MouseMode DisplayServerJavaScript::mouse_get_mode() const { +DisplayServer::MouseMode DisplayServerWeb::mouse_get_mode() const { if (godot_js_display_cursor_is_hidden()) { return MOUSE_MODE_HIDDEN; } @@ -477,12 +477,12 @@ DisplayServer::MouseMode DisplayServerJavaScript::mouse_get_mode() const { return MOUSE_MODE_VISIBLE; } -Point2i DisplayServerJavaScript::mouse_get_position() const { +Point2i DisplayServerWeb::mouse_get_position() const { return Input::get_singleton()->get_mouse_position(); } // Wheel -int DisplayServerJavaScript::mouse_wheel_callback(double p_delta_x, double p_delta_y) { +int DisplayServerWeb::mouse_wheel_callback(double p_delta_x, double p_delta_y) { if (!godot_js_display_canvas_is_focused()) { if (get_singleton()->cursor_inside_canvas) { godot_js_display_canvas_focus(); @@ -532,8 +532,8 @@ int DisplayServerJavaScript::mouse_wheel_callback(double p_delta_x, double p_del } // Touch -void DisplayServerJavaScript::touch_callback(int p_type, int p_count) { - DisplayServerJavaScript *ds = get_singleton(); +void DisplayServerWeb::touch_callback(int p_type, int p_count) { + DisplayServerWeb *ds = get_singleton(); const JSTouchEvent &touch_event = ds->touch_event; for (int i = 0; i < p_count; i++) { @@ -555,7 +555,7 @@ void DisplayServerJavaScript::touch_callback(int p_type, int p_count) { Ref<InputEventScreenTouch> ev; // Resume audio context after input in case autoplay was denied. - OS_JavaScript::get_singleton()->resume_audio(); + OS_Web::get_singleton()->resume_audio(); ev.instantiate(); ev->set_index(touch_event.identifier[i]); @@ -571,13 +571,13 @@ void DisplayServerJavaScript::touch_callback(int p_type, int p_count) { } } -bool DisplayServerJavaScript::screen_is_touchscreen(int p_screen) const { +bool DisplayServerWeb::screen_is_touchscreen(int p_screen) const { return godot_js_display_touchscreen_is_available(); } // Virtual Keyboard -void DisplayServerJavaScript::vk_input_text_callback(const char *p_text, int p_cursor) { - DisplayServerJavaScript *ds = DisplayServerJavaScript::get_singleton(); +void DisplayServerWeb::vk_input_text_callback(const char *p_text, int p_cursor) { + DisplayServerWeb *ds = DisplayServerWeb::get_singleton(); if (!ds || ds->input_text_callback.is_null()) { return; } @@ -586,7 +586,7 @@ void DisplayServerJavaScript::vk_input_text_callback(const char *p_text, int p_c Variant *eventp = &event; Variant ret; Callable::CallError ce; - ds->input_text_callback.call((const Variant **)&eventp, 1, ret, ce); + ds->input_text_callback.callp((const Variant **)&eventp, 1, ret, ce); // Insert key right to reach position. Input *input = Input::get_singleton(); Ref<InputEventKey> k; @@ -604,20 +604,20 @@ void DisplayServerJavaScript::vk_input_text_callback(const char *p_text, int p_c } } -void DisplayServerJavaScript::virtual_keyboard_show(const String &p_existing_text, const Rect2 &p_screen_rect, bool p_multiline, int p_max_input_length, int p_cursor_start, int p_cursor_end) { - godot_js_display_vk_show(p_existing_text.utf8().get_data(), p_multiline, p_cursor_start, p_cursor_end); +void DisplayServerWeb::virtual_keyboard_show(const String &p_existing_text, const Rect2 &p_screen_rect, VirtualKeyboardType p_type, int p_max_input_length, int p_cursor_start, int p_cursor_end) { + godot_js_display_vk_show(p_existing_text.utf8().get_data(), p_type, p_cursor_start, p_cursor_end); } -void DisplayServerJavaScript::virtual_keyboard_hide() { +void DisplayServerWeb::virtual_keyboard_hide() { godot_js_display_vk_hide(); } -void DisplayServerJavaScript::window_blur_callback() { +void DisplayServerWeb::window_blur_callback() { Input::get_singleton()->release_pressed_events(); } // Gamepad -void DisplayServerJavaScript::gamepad_callback(int p_index, int p_connected, const char *p_id, const char *p_guid) { +void DisplayServerWeb::gamepad_callback(int p_index, int p_connected, const char *p_id, const char *p_guid) { Input *input = Input::get_singleton(); if (p_connected) { input->joy_connection_changed(p_index, true, String::utf8(p_id), String::utf8(p_guid)); @@ -626,7 +626,7 @@ void DisplayServerJavaScript::gamepad_callback(int p_index, int p_connected, con } } -void DisplayServerJavaScript::process_joypads() { +void DisplayServerWeb::process_joypads() { Input *input = Input::get_singleton(); int32_t pads = godot_js_input_gamepad_sample_count(); int32_t s_btns_num = 0; @@ -654,7 +654,7 @@ void DisplayServerJavaScript::process_joypads() { } } -Vector<String> DisplayServerJavaScript::get_rendering_drivers_func() { +Vector<String> DisplayServerWeb::get_rendering_drivers_func() { Vector<String> drivers; #ifdef GLES3_ENABLED drivers.push_back("opengl3"); @@ -663,23 +663,23 @@ Vector<String> DisplayServerJavaScript::get_rendering_drivers_func() { } // Clipboard -void DisplayServerJavaScript::update_clipboard_callback(const char *p_text) { +void DisplayServerWeb::update_clipboard_callback(const char *p_text) { get_singleton()->clipboard = String::utf8(p_text); } -void DisplayServerJavaScript::clipboard_set(const String &p_text) { +void DisplayServerWeb::clipboard_set(const String &p_text) { clipboard = p_text; int err = godot_js_display_clipboard_set(p_text.utf8().get_data()); ERR_FAIL_COND_MSG(err, "Clipboard API is not supported."); } -String DisplayServerJavaScript::clipboard_get() const { +String DisplayServerWeb::clipboard_get() const { godot_js_display_clipboard_get(update_clipboard_callback); return clipboard; } -void DisplayServerJavaScript::send_window_event_callback(int p_notification) { - DisplayServerJavaScript *ds = get_singleton(); +void DisplayServerWeb::send_window_event_callback(int p_notification) { + DisplayServerWeb *ds = get_singleton(); if (!ds) { return; } @@ -691,11 +691,11 @@ void DisplayServerJavaScript::send_window_event_callback(int p_notification) { Variant *eventp = &event; Variant ret; Callable::CallError ce; - ds->window_event_callback.call((const Variant **)&eventp, 1, ret, ce); + ds->window_event_callback.callp((const Variant **)&eventp, 1, ret, ce); } } -void DisplayServerJavaScript::set_icon(const Ref<Image> &p_icon) { +void DisplayServerWeb::set_icon(const Ref<Image> &p_icon) { ERR_FAIL_COND(p_icon.is_null()); Ref<Image> icon = p_icon; if (icon->is_compressed()) { @@ -727,22 +727,22 @@ void DisplayServerJavaScript::set_icon(const Ref<Image> &p_icon) { godot_js_display_window_icon_set(png.ptr(), len); } -void DisplayServerJavaScript::_dispatch_input_event(const Ref<InputEvent> &p_event) { +void DisplayServerWeb::_dispatch_input_event(const Ref<InputEvent> &p_event) { Callable cb = get_singleton()->input_event_callback; if (!cb.is_null()) { Variant ev = p_event; Variant *evp = &ev; Variant ret; Callable::CallError ce; - cb.call((const Variant **)&evp, 1, ret, ce); + cb.callp((const Variant **)&evp, 1, ret, ce); } } -DisplayServer *DisplayServerJavaScript::create_func(const String &p_rendering_driver, WindowMode p_window_mode, VSyncMode p_vsync_mode, uint32_t p_flags, const Size2i &p_resolution, Error &r_error) { - return memnew(DisplayServerJavaScript(p_rendering_driver, p_window_mode, p_vsync_mode, p_flags, p_resolution, r_error)); +DisplayServer *DisplayServerWeb::create_func(const String &p_rendering_driver, WindowMode p_window_mode, VSyncMode p_vsync_mode, uint32_t p_flags, const Size2i &p_resolution, Error &r_error) { + return memnew(DisplayServerWeb(p_rendering_driver, p_window_mode, p_vsync_mode, p_flags, p_resolution, r_error)); } -DisplayServerJavaScript::DisplayServerJavaScript(const String &p_rendering_driver, WindowMode p_window_mode, VSyncMode p_vsync_mode, uint32_t p_flags, const Size2i &p_resolution, Error &r_error) { +DisplayServerWeb::DisplayServerWeb(const String &p_rendering_driver, WindowMode p_window_mode, VSyncMode p_vsync_mode, uint32_t p_flags, const Size2i &p_resolution, Error &r_error) { r_error = OK; // Always succeeds for now. // Ensure the canvas ID. @@ -764,10 +764,10 @@ DisplayServerJavaScript::DisplayServerJavaScript(const String &p_rendering_drive if (wants_webgl2 && !webgl2_init_failed) { EmscriptenWebGLContextAttributes attributes; emscripten_webgl_init_context_attributes(&attributes); - //attributes.alpha = GLOBAL_GET("display/window/per_pixel_transparency/allowed"); - attributes.alpha = true; + attributes.alpha = OS::get_singleton()->is_layered_allowed(); attributes.antialias = false; attributes.majorVersion = 2; + attributes.explicitSwapControl = true; webgl_ctx = emscripten_webgl_create_context(canvas_id, &attributes); if (emscripten_webgl_make_context_current(webgl_ctx) != EMSCRIPTEN_RESULT_SUCCESS) { @@ -788,17 +788,17 @@ DisplayServerJavaScript::DisplayServerJavaScript(const String &p_rendering_drive #endif // JS Input interface (js/libs/library_godot_input.js) - godot_js_input_mouse_button_cb(&DisplayServerJavaScript::mouse_button_callback); - godot_js_input_mouse_move_cb(&DisplayServerJavaScript::mouse_move_callback); - godot_js_input_mouse_wheel_cb(&DisplayServerJavaScript::mouse_wheel_callback); - godot_js_input_touch_cb(&DisplayServerJavaScript::touch_callback, touch_event.identifier, touch_event.coords); - godot_js_input_key_cb(&DisplayServerJavaScript::key_callback, key_event.code, key_event.key); + godot_js_input_mouse_button_cb(&DisplayServerWeb::mouse_button_callback); + godot_js_input_mouse_move_cb(&DisplayServerWeb::mouse_move_callback); + godot_js_input_mouse_wheel_cb(&DisplayServerWeb::mouse_wheel_callback); + godot_js_input_touch_cb(&DisplayServerWeb::touch_callback, touch_event.identifier, touch_event.coords); + godot_js_input_key_cb(&DisplayServerWeb::key_callback, key_event.code, key_event.key); godot_js_input_paste_cb(update_clipboard_callback); godot_js_input_drop_files_cb(drop_files_js_callback); - godot_js_input_gamepad_cb(&DisplayServerJavaScript::gamepad_callback); + godot_js_input_gamepad_cb(&DisplayServerWeb::gamepad_callback); // JS Display interface (js/libs/library_godot_display.js) - godot_js_display_fullscreen_cb(&DisplayServerJavaScript::fullscreen_change_callback); + godot_js_display_fullscreen_cb(&DisplayServerWeb::fullscreen_change_callback); godot_js_display_window_blur_cb(&window_blur_callback); godot_js_display_notification_cb(&send_window_event_callback, WINDOW_EVENT_MOUSE_ENTER, @@ -810,7 +810,7 @@ DisplayServerJavaScript::DisplayServerJavaScript(const String &p_rendering_drive Input::get_singleton()->set_event_dispatch_function(_dispatch_input_event); } -DisplayServerJavaScript::~DisplayServerJavaScript() { +DisplayServerWeb::~DisplayServerWeb() { #ifdef GLES3_ENABLED if (webgl_ctx) { emscripten_webgl_commit_frame(); @@ -819,7 +819,7 @@ DisplayServerJavaScript::~DisplayServerJavaScript() { #endif } -bool DisplayServerJavaScript::has_feature(Feature p_feature) const { +bool DisplayServerWeb::has_feature(Feature p_feature) const { switch (p_feature) { //case FEATURE_GLOBAL_MENU: //case FEATURE_HIDPI: @@ -846,139 +846,139 @@ bool DisplayServerJavaScript::has_feature(Feature p_feature) const { } } -void DisplayServerJavaScript::register_javascript_driver() { - register_create_function("javascript", create_func, get_rendering_drivers_func); +void DisplayServerWeb::register_web_driver() { + register_create_function("web", create_func, get_rendering_drivers_func); } -String DisplayServerJavaScript::get_name() const { - return "javascript"; +String DisplayServerWeb::get_name() const { + return "web"; } -int DisplayServerJavaScript::get_screen_count() const { +int DisplayServerWeb::get_screen_count() const { return 1; } -Point2i DisplayServerJavaScript::screen_get_position(int p_screen) const { +Point2i DisplayServerWeb::screen_get_position(int p_screen) const { return Point2i(); // TODO offsetX/Y? } -Size2i DisplayServerJavaScript::screen_get_size(int p_screen) const { +Size2i DisplayServerWeb::screen_get_size(int p_screen) const { int size[2]; godot_js_display_screen_size_get(size, size + 1); return Size2(size[0], size[1]); } -Rect2i DisplayServerJavaScript::screen_get_usable_rect(int p_screen) const { +Rect2i DisplayServerWeb::screen_get_usable_rect(int p_screen) const { int size[2]; godot_js_display_window_size_get(size, size + 1); return Rect2i(0, 0, size[0], size[1]); } -int DisplayServerJavaScript::screen_get_dpi(int p_screen) const { +int DisplayServerWeb::screen_get_dpi(int p_screen) const { return godot_js_display_screen_dpi_get(); } -float DisplayServerJavaScript::screen_get_scale(int p_screen) const { +float DisplayServerWeb::screen_get_scale(int p_screen) const { return godot_js_display_pixel_ratio_get(); } -float DisplayServerJavaScript::screen_get_refresh_rate(int p_screen) const { - return SCREEN_REFRESH_RATE_FALLBACK; // Javascript doesn't have much of a need for the screen refresh rate, and there's no native way to do so. +float DisplayServerWeb::screen_get_refresh_rate(int p_screen) const { + return SCREEN_REFRESH_RATE_FALLBACK; // Web doesn't have much of a need for the screen refresh rate, and there's no native way to do so. } -Vector<DisplayServer::WindowID> DisplayServerJavaScript::get_window_list() const { +Vector<DisplayServer::WindowID> DisplayServerWeb::get_window_list() const { Vector<WindowID> ret; ret.push_back(MAIN_WINDOW_ID); return ret; } -DisplayServerJavaScript::WindowID DisplayServerJavaScript::get_window_at_screen_position(const Point2i &p_position) const { +DisplayServerWeb::WindowID DisplayServerWeb::get_window_at_screen_position(const Point2i &p_position) const { return MAIN_WINDOW_ID; } -void DisplayServerJavaScript::window_attach_instance_id(ObjectID p_instance, WindowID p_window) { +void DisplayServerWeb::window_attach_instance_id(ObjectID p_instance, WindowID p_window) { window_attached_instance_id = p_instance; } -ObjectID DisplayServerJavaScript::window_get_attached_instance_id(WindowID p_window) const { +ObjectID DisplayServerWeb::window_get_attached_instance_id(WindowID p_window) const { return window_attached_instance_id; } -void DisplayServerJavaScript::window_set_rect_changed_callback(const Callable &p_callable, WindowID p_window) { +void DisplayServerWeb::window_set_rect_changed_callback(const Callable &p_callable, WindowID p_window) { // Not supported. } -void DisplayServerJavaScript::window_set_window_event_callback(const Callable &p_callable, WindowID p_window) { +void DisplayServerWeb::window_set_window_event_callback(const Callable &p_callable, WindowID p_window) { window_event_callback = p_callable; } -void DisplayServerJavaScript::window_set_input_event_callback(const Callable &p_callable, WindowID p_window) { +void DisplayServerWeb::window_set_input_event_callback(const Callable &p_callable, WindowID p_window) { input_event_callback = p_callable; } -void DisplayServerJavaScript::window_set_input_text_callback(const Callable &p_callable, WindowID p_window) { +void DisplayServerWeb::window_set_input_text_callback(const Callable &p_callable, WindowID p_window) { input_text_callback = p_callable; } -void DisplayServerJavaScript::window_set_drop_files_callback(const Callable &p_callable, WindowID p_window) { +void DisplayServerWeb::window_set_drop_files_callback(const Callable &p_callable, WindowID p_window) { drop_files_callback = p_callable; } -void DisplayServerJavaScript::window_set_title(const String &p_title, WindowID p_window) { +void DisplayServerWeb::window_set_title(const String &p_title, WindowID p_window) { godot_js_display_window_title_set(p_title.utf8().get_data()); } -int DisplayServerJavaScript::window_get_current_screen(WindowID p_window) const { +int DisplayServerWeb::window_get_current_screen(WindowID p_window) const { return 1; } -void DisplayServerJavaScript::window_set_current_screen(int p_screen, WindowID p_window) { +void DisplayServerWeb::window_set_current_screen(int p_screen, WindowID p_window) { // Not implemented. } -Point2i DisplayServerJavaScript::window_get_position(WindowID p_window) const { +Point2i DisplayServerWeb::window_get_position(WindowID p_window) const { return Point2i(); // TODO Does this need implementation? } -void DisplayServerJavaScript::window_set_position(const Point2i &p_position, WindowID p_window) { +void DisplayServerWeb::window_set_position(const Point2i &p_position, WindowID p_window) { // Not supported. } -void DisplayServerJavaScript::window_set_transient(WindowID p_window, WindowID p_parent) { +void DisplayServerWeb::window_set_transient(WindowID p_window, WindowID p_parent) { // Not supported. } -void DisplayServerJavaScript::window_set_max_size(const Size2i p_size, WindowID p_window) { +void DisplayServerWeb::window_set_max_size(const Size2i p_size, WindowID p_window) { // Not supported. } -Size2i DisplayServerJavaScript::window_get_max_size(WindowID p_window) const { +Size2i DisplayServerWeb::window_get_max_size(WindowID p_window) const { return Size2i(); } -void DisplayServerJavaScript::window_set_min_size(const Size2i p_size, WindowID p_window) { +void DisplayServerWeb::window_set_min_size(const Size2i p_size, WindowID p_window) { // Not supported. } -Size2i DisplayServerJavaScript::window_get_min_size(WindowID p_window) const { +Size2i DisplayServerWeb::window_get_min_size(WindowID p_window) const { return Size2i(); } -void DisplayServerJavaScript::window_set_size(const Size2i p_size, WindowID p_window) { +void DisplayServerWeb::window_set_size(const Size2i p_size, WindowID p_window) { godot_js_display_desired_size_set(p_size.x, p_size.y); } -Size2i DisplayServerJavaScript::window_get_size(WindowID p_window) const { +Size2i DisplayServerWeb::window_get_size(WindowID p_window) const { int size[2]; godot_js_display_window_size_get(size, size + 1); return Size2i(size[0], size[1]); } -Size2i DisplayServerJavaScript::window_get_real_size(WindowID p_window) const { +Size2i DisplayServerWeb::window_get_real_size(WindowID p_window) const { return window_get_size(p_window); } -void DisplayServerJavaScript::window_set_mode(WindowMode p_mode, WindowID p_window) { +void DisplayServerWeb::window_set_mode(WindowMode p_mode, WindowID p_window) { if (window_mode == p_mode) { return; } @@ -993,65 +993,65 @@ void DisplayServerJavaScript::window_set_mode(WindowMode p_mode, WindowID p_wind case WINDOW_MODE_EXCLUSIVE_FULLSCREEN: case WINDOW_MODE_FULLSCREEN: { int result = godot_js_display_fullscreen_request(); - ERR_FAIL_COND_MSG(result, "The request was denied. Remember that enabling fullscreen is only possible from an input callback for the HTML5 platform."); + ERR_FAIL_COND_MSG(result, "The request was denied. Remember that enabling fullscreen is only possible from an input callback for the Web platform."); } break; case WINDOW_MODE_MAXIMIZED: case WINDOW_MODE_MINIMIZED: - WARN_PRINT("WindowMode MAXIMIZED and MINIMIZED are not supported in HTML5 platform."); + // WindowMode MAXIMIZED and MINIMIZED are not supported in Web platform. break; default: break; } } -DisplayServerJavaScript::WindowMode DisplayServerJavaScript::window_get_mode(WindowID p_window) const { +DisplayServerWeb::WindowMode DisplayServerWeb::window_get_mode(WindowID p_window) const { return window_mode; } -bool DisplayServerJavaScript::window_is_maximize_allowed(WindowID p_window) const { +bool DisplayServerWeb::window_is_maximize_allowed(WindowID p_window) const { return false; } -void DisplayServerJavaScript::window_set_flag(WindowFlags p_flag, bool p_enabled, WindowID p_window) { +void DisplayServerWeb::window_set_flag(WindowFlags p_flag, bool p_enabled, WindowID p_window) { // Not supported. } -bool DisplayServerJavaScript::window_get_flag(WindowFlags p_flag, WindowID p_window) const { +bool DisplayServerWeb::window_get_flag(WindowFlags p_flag, WindowID p_window) const { return false; } -void DisplayServerJavaScript::window_request_attention(WindowID p_window) { +void DisplayServerWeb::window_request_attention(WindowID p_window) { // Not supported. } -void DisplayServerJavaScript::window_move_to_foreground(WindowID p_window) { +void DisplayServerWeb::window_move_to_foreground(WindowID p_window) { // Not supported. } -bool DisplayServerJavaScript::window_can_draw(WindowID p_window) const { +bool DisplayServerWeb::window_can_draw(WindowID p_window) const { return true; } -bool DisplayServerJavaScript::can_any_window_draw() const { +bool DisplayServerWeb::can_any_window_draw() const { return true; } -void DisplayServerJavaScript::process_events() { +void DisplayServerWeb::process_events() { Input::get_singleton()->flush_buffered_events(); if (godot_js_input_gamepad_sample() == OK) { process_joypads(); } } -int DisplayServerJavaScript::get_current_video_driver() const { +int DisplayServerWeb::get_current_video_driver() const { return 1; } -bool DisplayServerJavaScript::get_swap_cancel_ok() { +bool DisplayServerWeb::get_swap_cancel_ok() { return swap_cancel_ok; } -void DisplayServerJavaScript::swap_buffers() { +void DisplayServerWeb::swap_buffers() { #ifdef GLES3_ENABLED if (webgl_ctx) { emscripten_webgl_commit_frame(); diff --git a/platform/javascript/display_server_javascript.h b/platform/web/display_server_web.h index 79b0fbb652..85076b906f 100644 --- a/platform/javascript/display_server_javascript.h +++ b/platform/web/display_server_web.h @@ -1,5 +1,5 @@ /*************************************************************************/ -/* display_server_javascript.h */ +/* display_server_web.h */ /*************************************************************************/ /* This file is part of: */ /* GODOT ENGINE */ @@ -28,15 +28,15 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ -#ifndef DISPLAY_SERVER_JAVASCRIPT_H -#define DISPLAY_SERVER_JAVASCRIPT_H +#ifndef DISPLAY_SERVER_WEB_H +#define DISPLAY_SERVER_WEB_H #include "servers/display_server.h" #include <emscripten.h> #include <emscripten/html5.h> -class DisplayServerJavaScript : public DisplayServer { +class DisplayServerWeb : public DisplayServer { private: struct JSTouchEvent { uint32_t identifier[32] = { 0 }; @@ -112,7 +112,7 @@ protected: public: // Override return type to make writing static callbacks less tedious. - static DisplayServerJavaScript *get_singleton(); + static DisplayServerWeb *get_singleton(); // utilities bool check_size_force_redraw(); @@ -124,7 +124,7 @@ public: // tts virtual bool tts_is_speaking() const override; virtual bool tts_is_paused() const override; - virtual Array tts_get_voices() const override; + virtual TypedArray<Dictionary> tts_get_voices() const override; virtual void tts_speak(const String &p_text, const String &p_voice, int p_volume = 50, float p_pitch = 1.f, float p_rate = 1.f, int p_utterance_id = 0, bool p_interrupt = false) override; virtual void tts_pause() override; @@ -157,7 +157,7 @@ public: virtual float screen_get_scale(int p_screen = SCREEN_OF_MAIN_WINDOW) const override; virtual float screen_get_refresh_rate(int p_screen = SCREEN_OF_MAIN_WINDOW) const override; - virtual void virtual_keyboard_show(const String &p_existing_text, const Rect2 &p_screen_rect = Rect2(), bool p_multiline = false, int p_max_input_length = -1, int p_cursor_start = -1, int p_cursor_end = -1) override; + virtual void virtual_keyboard_show(const String &p_existing_text, const Rect2 &p_screen_rect = Rect2(), VirtualKeyboardType p_type = KEYBOARD_TYPE_DEFAULT, int p_max_input_length = -1, int p_cursor_start = -1, int p_cursor_end = -1) override; virtual void virtual_keyboard_hide() override; // windows @@ -220,9 +220,9 @@ public: virtual bool get_swap_cancel_ok() override; virtual void swap_buffers() override; - static void register_javascript_driver(); - DisplayServerJavaScript(const String &p_rendering_driver, WindowMode p_window_mode, VSyncMode p_vsync_mode, uint32_t p_flags, const Size2i &p_resolution, Error &r_error); - ~DisplayServerJavaScript(); + static void register_web_driver(); + DisplayServerWeb(const String &p_rendering_driver, WindowMode p_window_mode, VSyncMode p_vsync_mode, uint32_t p_flags, const Size2i &p_resolution, Error &r_error); + ~DisplayServerWeb(); }; -#endif // DISPLAY_SERVER_JAVASCRIPT_H +#endif // DISPLAY_SERVER_WEB_H diff --git a/platform/javascript/dom_keys.inc b/platform/web/dom_keys.inc index 115b5479e4..115b5479e4 100644 --- a/platform/javascript/dom_keys.inc +++ b/platform/web/dom_keys.inc diff --git a/platform/javascript/emscripten_helpers.py b/platform/web/emscripten_helpers.py index 3cb1d75e52..6045bc6fbd 100644 --- a/platform/javascript/emscripten_helpers.py +++ b/platform/web/emscripten_helpers.py @@ -37,26 +37,25 @@ def create_engine_file(env, target, source, externs): return env.Textfile(target, [env.File(s) for s in source]) -def create_template_zip(env, js, wasm, extra): +def create_template_zip(env, js, wasm, worker, side): binary_name = "godot.tools" if env["tools"] else "godot" - zip_dir = env.Dir("#bin/.javascript_zip") + zip_dir = env.Dir("#bin/.web_zip") in_files = [ js, wasm, - "#platform/javascript/js/libs/audio.worklet.js", + worker, + "#platform/web/js/libs/audio.worklet.js", ] out_files = [ zip_dir.File(binary_name + ".js"), zip_dir.File(binary_name + ".wasm"), + zip_dir.File(binary_name + ".worker.js"), zip_dir.File(binary_name + ".audio.worklet.js"), ] - # GDNative/Threads specific - if env["gdnative_enabled"]: - in_files.append(extra.pop()) # Runtime + # Dynamic linking (extensions) specific. + if env["dlink_enabled"]: + in_files.append(side) # Side wasm (contains the actual Godot code). out_files.append(zip_dir.File(binary_name + ".side.wasm")) - if env["threads_enabled"]: - in_files.append(extra.pop()) # Worker - out_files.append(zip_dir.File(binary_name + ".worker.js")) service_worker = "#misc/dist/html/service-worker.js" if env["tools"]: diff --git a/platform/javascript/export/export_server.h b/platform/web/export/editor_http_server.h index a831b76076..fa0010ec8d 100644 --- a/platform/javascript/export/export_server.h +++ b/platform/web/export/editor_http_server.h @@ -1,5 +1,5 @@ /*************************************************************************/ -/* export_server.h */ +/* editor_http_server.h */ /*************************************************************************/ /* This file is part of: */ /* GODOT ENGINE */ @@ -28,14 +28,13 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ -#ifndef JAVASCRIPT_EXPORT_SERVER_H -#define JAVASCRIPT_EXPORT_SERVER_H +#ifndef WEB_EDITOR_HTTP_SERVER_H +#define WEB_EDITOR_HTTP_SERVER_H #include "core/io/image_loader.h" -#include "core/io/stream_peer_ssl.h" +#include "core/io/stream_peer_tls.h" #include "core/io/tcp_server.h" #include "core/io/zip_io.h" -#include "editor/editor_export.h" #include "editor/editor_paths.h" class EditorHTTPServer : public RefCounted { @@ -43,18 +42,18 @@ private: Ref<TCPServer> server; HashMap<String, String> mimes; Ref<StreamPeerTCP> tcp; - Ref<StreamPeerSSL> ssl; + Ref<StreamPeerTLS> tls; Ref<StreamPeer> peer; Ref<CryptoKey> key; Ref<X509Certificate> cert; - bool use_ssl = false; + bool use_tls = false; uint64_t time = 0; uint8_t req_buf[4096]; int req_pos = 0; void _clear_client() { peer = Ref<StreamPeer>(); - ssl = Ref<StreamPeerSSL>(); + tls = Ref<StreamPeerTLS>(); tcp = Ref<StreamPeerTCP>(); memset(req_buf, 0, sizeof(req_buf)); time = 0; @@ -63,8 +62,8 @@ private: void _set_internal_certs(Ref<Crypto> p_crypto) { const String cache_path = EditorPaths::get_singleton()->get_cache_dir(); - const String key_path = cache_path.plus_file("html5_server.key"); - const String crt_path = cache_path.plus_file("html5_server.crt"); + const String key_path = cache_path.path_join("html5_server.key"); + const String crt_path = cache_path.path_join("html5_server.crt"); bool regen = !FileAccess::exists(key_path) || !FileAccess::exists(crt_path); if (!regen) { key = Ref<CryptoKey>(CryptoKey::create()); @@ -99,19 +98,19 @@ public: _clear_client(); } - Error listen(int p_port, IPAddress p_address, bool p_use_ssl, String p_ssl_key, String p_ssl_cert) { - use_ssl = p_use_ssl; - if (use_ssl) { + Error listen(int p_port, IPAddress p_address, bool p_use_tls, String p_tls_key, String p_tls_cert) { + use_tls = p_use_tls; + if (use_tls) { Ref<Crypto> crypto = Crypto::create(); if (crypto.is_null()) { return ERR_UNAVAILABLE; } - if (!p_ssl_key.is_empty() && !p_ssl_cert.is_empty()) { + if (!p_tls_key.is_empty() && !p_tls_cert.is_empty()) { key = Ref<CryptoKey>(CryptoKey::create()); - Error err = key->load(p_ssl_key); + Error err = key->load(p_tls_key); ERR_FAIL_COND_V(err != OK, err); cert = Ref<X509Certificate>(X509Certificate::create()); - err = cert->load(p_ssl_cert); + err = cert->load(p_tls_cert); ERR_FAIL_COND_V(err != OK, err); } else { _set_internal_certs(crypto); @@ -140,8 +139,8 @@ public: const String req_file = path.get_file(); const String req_ext = path.get_extension(); - const String cache_path = EditorPaths::get_singleton()->get_cache_dir().plus_file("web"); - const String filepath = cache_path.plus_file(req_file); + const String cache_path = EditorPaths::get_singleton()->get_cache_dir().path_join("web"); + const String filepath = cache_path.path_join(req_file); if (!mimes.has(req_ext) || !FileAccess::exists(filepath)) { String s = "HTTP/1.1 404 Not Found\r\n"; @@ -202,22 +201,22 @@ public: return; } - if (use_ssl) { - if (ssl.is_null()) { - ssl = Ref<StreamPeerSSL>(StreamPeerSSL::create()); - peer = ssl; - ssl->set_blocking_handshake_enabled(false); - if (ssl->accept_stream(tcp, key, cert) != OK) { + if (use_tls) { + if (tls.is_null()) { + tls = Ref<StreamPeerTLS>(StreamPeerTLS::create()); + peer = tls; + tls->set_blocking_handshake_enabled(false); + if (tls->accept_stream(tcp, key, cert) != OK) { _clear_client(); return; } } - ssl->poll(); - if (ssl->get_status() == StreamPeerSSL::STATUS_HANDSHAKING) { + tls->poll(); + if (tls->get_status() == StreamPeerTLS::STATUS_HANDSHAKING) { // Still handshaking, keep waiting. return; } - if (ssl->get_status() != StreamPeerSSL::STATUS_CONNECTED) { + if (tls->get_status() != StreamPeerTLS::STATUS_CONNECTED) { _clear_client(); return; } @@ -248,4 +247,4 @@ public: } }; -#endif +#endif // WEB_EDITOR_HTTP_SERVER_H diff --git a/platform/javascript/export/export.cpp b/platform/web/export/export.cpp index 825c1b6638..4b4e8b2705 100644 --- a/platform/javascript/export/export.cpp +++ b/platform/web/export/export.cpp @@ -30,19 +30,22 @@ #include "export.h" +#include "editor/editor_settings.h" #include "export_plugin.h" -void register_javascript_exporter() { +void register_web_exporter() { +#ifndef ANDROID_ENABLED EDITOR_DEF("export/web/http_host", "localhost"); EDITOR_DEF("export/web/http_port", 8060); - EDITOR_DEF("export/web/use_ssl", false); - EDITOR_DEF("export/web/ssl_key", ""); - EDITOR_DEF("export/web/ssl_certificate", ""); + EDITOR_DEF("export/web/use_tls", false); + EDITOR_DEF("export/web/tls_key", ""); + EDITOR_DEF("export/web/tls_certificate", ""); EditorSettings::get_singleton()->add_property_hint(PropertyInfo(Variant::INT, "export/web/http_port", PROPERTY_HINT_RANGE, "1,65535,1")); - EditorSettings::get_singleton()->add_property_hint(PropertyInfo(Variant::STRING, "export/web/ssl_key", PROPERTY_HINT_GLOBAL_FILE, "*.key")); - EditorSettings::get_singleton()->add_property_hint(PropertyInfo(Variant::STRING, "export/web/ssl_certificate", PROPERTY_HINT_GLOBAL_FILE, "*.crt,*.pem")); + EditorSettings::get_singleton()->add_property_hint(PropertyInfo(Variant::STRING, "export/web/tls_key", PROPERTY_HINT_GLOBAL_FILE, "*.key")); + EditorSettings::get_singleton()->add_property_hint(PropertyInfo(Variant::STRING, "export/web/tls_certificate", PROPERTY_HINT_GLOBAL_FILE, "*.crt,*.pem")); +#endif - Ref<EditorExportPlatformJavaScript> platform; + Ref<EditorExportPlatformWeb> platform; platform.instantiate(); EditorExport::get_singleton()->add_export_platform(platform); } diff --git a/platform/javascript/export/export.h b/platform/web/export/export.h index 41cc66cfb8..7947f292a4 100644 --- a/platform/javascript/export/export.h +++ b/platform/web/export/export.h @@ -28,9 +28,9 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ -#ifndef JAVASCRIPT_EXPORT_H -#define JAVASCRIPT_EXPORT_H +#ifndef WEB_EXPORT_H +#define WEB_EXPORT_H -void register_javascript_exporter(); +void register_web_exporter(); -#endif +#endif // WEB_EXPORT_H diff --git a/platform/javascript/export/export_plugin.cpp b/platform/web/export/export_plugin.cpp index e2ae45627e..306453c1eb 100644 --- a/platform/javascript/export/export_plugin.cpp +++ b/platform/web/export/export_plugin.cpp @@ -31,8 +31,9 @@ #include "export_plugin.h" #include "core/config/project_settings.h" +#include "editor/editor_settings.h" -Error EditorExportPlatformJavaScript::_extract_template(const String &p_template, const String &p_dir, const String &p_name, bool pwa) { +Error EditorExportPlatformWeb::_extract_template(const String &p_template, const String &p_dir, const String &p_name, bool pwa) { Ref<FileAccess> io_fa; zlib_filefunc_def io = zipio_create_io(&io_fa); unzFile pkg = unzOpen2(p_template.utf8().get_data(), &io); @@ -74,7 +75,7 @@ Error EditorExportPlatformJavaScript::_extract_template(const String &p_template unzCloseCurrentFile(pkg); //write - String dst = p_dir.plus_file(file.replace("godot", p_name)); + String dst = p_dir.path_join(file.replace("godot", p_name)); Ref<FileAccess> f = FileAccess::open(dst, FileAccess::WRITE); if (f.is_null()) { add_message(EXPORT_MESSAGE_ERROR, TTR("Prepare Templates"), vformat(TTR("Could not write file: \"%s\"."), dst)); @@ -88,7 +89,7 @@ Error EditorExportPlatformJavaScript::_extract_template(const String &p_template return OK; } -Error EditorExportPlatformJavaScript::_write_or_error(const uint8_t *p_content, int p_size, String p_path) { +Error EditorExportPlatformWeb::_write_or_error(const uint8_t *p_content, int p_size, String p_path) { Ref<FileAccess> f = FileAccess::open(p_path, FileAccess::WRITE); if (f.is_null()) { add_message(EXPORT_MESSAGE_ERROR, TTR("Export"), vformat(TTR("Could not write file: \"%s\"."), p_path)); @@ -98,7 +99,7 @@ Error EditorExportPlatformJavaScript::_write_or_error(const uint8_t *p_content, return OK; } -void EditorExportPlatformJavaScript::_replace_strings(HashMap<String, String> p_replaces, Vector<uint8_t> &r_template) { +void EditorExportPlatformWeb::_replace_strings(HashMap<String, String> p_replaces, Vector<uint8_t> &r_template) { String str_template = String::utf8(reinterpret_cast<const char *>(r_template.ptr()), r_template.size()); String out; Vector<String> lines = str_template.split("\n"); @@ -116,7 +117,7 @@ void EditorExportPlatformJavaScript::_replace_strings(HashMap<String, String> p_ } } -void EditorExportPlatformJavaScript::_fix_html(Vector<uint8_t> &p_html, const Ref<EditorExportPreset> &p_preset, const String &p_name, bool p_debug, int p_flags, const Vector<SharedObject> p_shared_objects, const Dictionary &p_file_sizes) { +void EditorExportPlatformWeb::_fix_html(Vector<uint8_t> &p_html, const Ref<EditorExportPreset> &p_preset, const String &p_name, bool p_debug, int p_flags, const Vector<SharedObject> p_shared_objects, const Dictionary &p_file_sizes) { // Engine.js config Dictionary config; Array libs; @@ -158,10 +159,10 @@ void EditorExportPlatformJavaScript::_fix_html(Vector<uint8_t> &p_html, const Re _replace_strings(replaces, p_html); } -Error EditorExportPlatformJavaScript::_add_manifest_icon(const String &p_path, const String &p_icon, int p_size, Array &r_arr) { +Error EditorExportPlatformWeb::_add_manifest_icon(const String &p_path, const String &p_icon, int p_size, Array &r_arr) { const String name = p_path.get_file().get_basename(); const String icon_name = vformat("%s.%dx%d.png", name, p_size, p_size); - const String icon_dest = p_path.get_base_dir().plus_file(icon_name); + const String icon_dest = p_path.get_base_dir().path_join(icon_name); Ref<Image> icon; if (!p_icon.is_empty()) { @@ -191,7 +192,7 @@ Error EditorExportPlatformJavaScript::_add_manifest_icon(const String &p_path, c return err; } -Error EditorExportPlatformJavaScript::_build_pwa(const Ref<EditorExportPreset> &p_preset, const String p_path, const Vector<SharedObject> &p_shared_objects) { +Error EditorExportPlatformWeb::_build_pwa(const Ref<EditorExportPreset> &p_preset, const String p_path, const Vector<SharedObject> &p_shared_objects) { String proj_name = ProjectSettings::get_singleton()->get_setting("application/config/name"); if (proj_name.is_empty()) { proj_name = "Godot Game"; @@ -200,7 +201,7 @@ Error EditorExportPlatformJavaScript::_build_pwa(const Ref<EditorExportPreset> & // Service worker const String dir = p_path.get_base_dir(); const String name = p_path.get_file().get_basename(); - const ExportMode mode = (ExportMode)(int)p_preset->get("variant/export_type"); + bool extensions = (bool)p_preset->get("variant/extensions_support"); HashMap<String, String> replaces; replaces["@GODOT_VERSION@"] = String::num_int64(OS::get_singleton()->get_unix_time()) + "|" + String::num_int64(OS::get_singleton()->get_ticks_usec()); replaces["@GODOT_NAME@"] = proj_name.substr(0, 16); @@ -215,17 +216,15 @@ Error EditorExportPlatformJavaScript::_build_pwa(const Ref<EditorExportPreset> & cache_files.push_back(name + ".icon.png"); cache_files.push_back(name + ".apple-touch-icon.png"); } - if (mode & EXPORT_MODE_THREADS) { - cache_files.push_back(name + ".worker.js"); - cache_files.push_back(name + ".audio.worklet.js"); - } + cache_files.push_back(name + ".worker.js"); + cache_files.push_back(name + ".audio.worklet.js"); replaces["@GODOT_CACHE@"] = Variant(cache_files).to_json_string(); // Heavy files that are cached on demand. Array opt_cache_files; opt_cache_files.push_back(name + ".wasm"); opt_cache_files.push_back(name + ".pck"); - if (mode & EXPORT_MODE_GDNATIVE) { + if (extensions) { opt_cache_files.push_back(name + ".side.wasm"); for (int i = 0; i < p_shared_objects.size(); i++) { opt_cache_files.push_back(p_shared_objects[i].path.get_file()); @@ -233,7 +232,7 @@ Error EditorExportPlatformJavaScript::_build_pwa(const Ref<EditorExportPreset> & } replaces["@GODOT_OPT_CACHE@"] = Variant(opt_cache_files).to_json_string(); - const String sw_path = dir.plus_file(name + ".service.worker.js"); + const String sw_path = dir.path_join(name + ".service.worker.js"); Vector<uint8_t> sw; { Ref<FileAccess> f = FileAccess::open(sw_path, FileAccess::READ); @@ -245,7 +244,7 @@ Error EditorExportPlatformJavaScript::_build_pwa(const Ref<EditorExportPreset> & f->get_buffer(sw.ptrw(), sw.size()); } _replace_strings(replaces, sw); - Error err = _write_or_error(sw.ptr(), sw.size(), dir.plus_file(name + ".service.worker.js")); + Error err = _write_or_error(sw.ptr(), sw.size(), dir.path_join(name + ".service.worker.js")); if (err != OK) { return err; } @@ -254,7 +253,7 @@ Error EditorExportPlatformJavaScript::_build_pwa(const Ref<EditorExportPreset> & const String offline_page = p_preset->get("progressive_web_app/offline_page"); if (!offline_page.is_empty()) { Ref<DirAccess> da = DirAccess::create(DirAccess::ACCESS_FILESYSTEM); - const String offline_dest = dir.plus_file(name + ".offline.html"); + const String offline_dest = dir.path_join(name + ".offline.html"); err = da->copy(ProjectSettings::get_singleton()->globalize_path(offline_page), offline_dest); if (err != OK) { add_message(EXPORT_MESSAGE_ERROR, TTR("PWA"), vformat(TTR("Could not read file: \"%s\"."), offline_dest)); @@ -294,7 +293,7 @@ Error EditorExportPlatformJavaScript::_build_pwa(const Ref<EditorExportPreset> & manifest["icons"] = icons_arr; CharString cs = Variant(manifest).to_json_string().utf8(); - err = _write_or_error((const uint8_t *)cs.get_data(), cs.length(), dir.plus_file(name + ".manifest.json")); + err = _write_or_error((const uint8_t *)cs.get_data(), cs.length(), dir.path_join(name + ".manifest.json")); if (err != OK) { return err; } @@ -302,7 +301,7 @@ Error EditorExportPlatformJavaScript::_build_pwa(const Ref<EditorExportPreset> & return OK; } -void EditorExportPlatformJavaScript::get_preset_features(const Ref<EditorExportPreset> &p_preset, List<String> *r_features) { +void EditorExportPlatformWeb::get_preset_features(const Ref<EditorExportPreset> &p_preset, List<String> *r_features) const { if (p_preset->get("vram_texture_compression/for_desktop")) { r_features->push_back("s3tc"); } @@ -316,20 +315,14 @@ void EditorExportPlatformJavaScript::get_preset_features(const Ref<EditorExportP r_features->push_back("etc2"); } } - ExportMode mode = (ExportMode)(int)p_preset->get("variant/export_type"); - if (mode & EXPORT_MODE_THREADS) { - r_features->push_back("threads"); - } - if (mode & EXPORT_MODE_GDNATIVE) { - r_features->push_back("wasm32"); - } + r_features->push_back("wasm32"); } -void EditorExportPlatformJavaScript::get_export_options(List<ExportOption> *r_options) { +void EditorExportPlatformWeb::get_export_options(List<ExportOption> *r_options) { r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "custom_template/debug", PROPERTY_HINT_GLOBAL_FILE, "*.zip"), "")); r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "custom_template/release", PROPERTY_HINT_GLOBAL_FILE, "*.zip"), "")); - r_options->push_back(ExportOption(PropertyInfo(Variant::INT, "variant/export_type", PROPERTY_HINT_ENUM, "Regular,Threads,GDNative"), 0)); // Export type. + r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "variant/extensions_support"), false)); // Export type. r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "vram_texture_compression/for_desktop"), true)); // S3TC r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "vram_texture_compression/for_mobile"), false)); // ETC or ETC2, depending on renderer @@ -349,35 +342,26 @@ void EditorExportPlatformJavaScript::get_export_options(List<ExportOption> *r_op r_options->push_back(ExportOption(PropertyInfo(Variant::COLOR, "progressive_web_app/background_color", PROPERTY_HINT_COLOR_NO_ALPHA), Color())); } -String EditorExportPlatformJavaScript::get_name() const { - return "HTML5"; +String EditorExportPlatformWeb::get_name() const { + return "Web"; } -String EditorExportPlatformJavaScript::get_os_name() const { - return "HTML5"; +String EditorExportPlatformWeb::get_os_name() const { + return "Web"; } -Ref<Texture2D> EditorExportPlatformJavaScript::get_logo() const { +Ref<Texture2D> EditorExportPlatformWeb::get_logo() const { return logo; } -bool EditorExportPlatformJavaScript::can_export(const Ref<EditorExportPreset> &p_preset, String &r_error, bool &r_missing_templates) const { -#ifndef DEV_ENABLED - // We don't provide export templates for the HTML5 platform currently as there - // is no suitable renderer to use with them. So we forbid exporting and tell - // users why. This is skipped in DEV_ENABLED so that contributors can still test - // the pipeline once we start having WebGL or WebGPU support. - r_error = "The HTML5 platform is currently not supported in Godot 4.0, as there is no suitable renderer for it.\n"; - return false; -#endif - +bool EditorExportPlatformWeb::has_valid_export_configuration(const Ref<EditorExportPreset> &p_preset, String &r_error, bool &r_missing_templates) const { String err; bool valid = false; - ExportMode mode = (ExportMode)(int)p_preset->get("variant/export_type"); + bool extensions = (bool)p_preset->get("variant/extensions_support"); // Look for export templates (first official, and if defined custom templates). - bool dvalid = exists_export_template(_get_template_name(mode, true), &err); - bool rvalid = exists_export_template(_get_template_name(mode, false), &err); + bool dvalid = exists_export_template(_get_template_name(extensions, true), &err); + bool rvalid = exists_export_template(_get_template_name(extensions, false), &err); if (p_preset->get("custom_template/debug") != "") { dvalid = FileAccess::exists(p_preset->get("custom_template/debug")); @@ -395,7 +379,18 @@ bool EditorExportPlatformJavaScript::can_export(const Ref<EditorExportPreset> &p valid = dvalid || rvalid; r_missing_templates = !valid; - // Validate the rest of the configuration. + if (!err.is_empty()) { + r_error = err; + } + + return valid; +} + +bool EditorExportPlatformWeb::has_valid_project_configuration(const Ref<EditorExportPreset> &p_preset, String &r_error) const { + String err; + bool valid = true; + + // Validate the project configuration. if (p_preset->get("vram_texture_compression/for_mobile")) { String etc_error = test_etc2(); @@ -412,13 +407,13 @@ bool EditorExportPlatformJavaScript::can_export(const Ref<EditorExportPreset> &p return valid; } -List<String> EditorExportPlatformJavaScript::get_binary_extensions(const Ref<EditorExportPreset> &p_preset) const { +List<String> EditorExportPlatformWeb::get_binary_extensions(const Ref<EditorExportPreset> &p_preset) const { List<String> list; list.push_back("html"); return list; } -Error EditorExportPlatformJavaScript::export_project(const Ref<EditorExportPreset> &p_preset, bool p_debug, const String &p_path, int p_flags) { +Error EditorExportPlatformWeb::export_project(const Ref<EditorExportPreset> &p_preset, bool p_debug, const String &p_path, int p_flags) { ExportNotifier notifier(*this, p_preset, p_debug, p_path, p_flags); const String custom_debug = p_preset->get("custom_template/debug"); @@ -435,8 +430,8 @@ Error EditorExportPlatformJavaScript::export_project(const Ref<EditorExportPrese String template_path = p_debug ? custom_debug : custom_release; template_path = template_path.strip_edges(); if (template_path.is_empty()) { - ExportMode mode = (ExportMode)(int)p_preset->get("variant/export_type"); - template_path = find_export_template(_get_template_name(mode, p_debug)); + bool extensions = (bool)p_preset->get("variant/extensions_support"); + template_path = find_export_template(_get_template_name(extensions, p_debug)); } if (!DirAccess::exists(base_dir)) { @@ -460,7 +455,7 @@ Error EditorExportPlatformJavaScript::export_project(const Ref<EditorExportPrese { Ref<DirAccess> da = DirAccess::create(DirAccess::ACCESS_FILESYSTEM); for (int i = 0; i < shared_objects.size(); i++) { - String dst = base_dir.plus_file(shared_objects[i].path.get_file()); + String dst = base_dir.path_join(shared_objects[i].path.get_file()); error = da->copy(shared_objects[i].path, dst); if (error != OK) { add_message(EXPORT_MESSAGE_ERROR, TTR("Export"), vformat(TTR("Could not write file: \"%s\"."), shared_objects[i].path.get_file())); @@ -541,7 +536,7 @@ Error EditorExportPlatformJavaScript::export_project(const Ref<EditorExportPrese return OK; } -bool EditorExportPlatformJavaScript::poll_export() { +bool EditorExportPlatformWeb::poll_export() { Ref<EditorExportPreset> preset; for (int i = 0; i < EditorExport::get_singleton()->get_export_preset_count(); i++) { @@ -565,22 +560,22 @@ bool EditorExportPlatformJavaScript::poll_export() { return menu_options != prev; } -Ref<ImageTexture> EditorExportPlatformJavaScript::get_option_icon(int p_index) const { +Ref<ImageTexture> EditorExportPlatformWeb::get_option_icon(int p_index) const { return p_index == 1 ? stop_icon : EditorExportPlatform::get_option_icon(p_index); } -int EditorExportPlatformJavaScript::get_options_count() const { +int EditorExportPlatformWeb::get_options_count() const { return menu_options; } -Error EditorExportPlatformJavaScript::run(const Ref<EditorExportPreset> &p_preset, int p_option, int p_debug_flags) { +Error EditorExportPlatformWeb::run(const Ref<EditorExportPreset> &p_preset, int p_option, int p_debug_flags) { if (p_option == 1) { MutexLock lock(server_lock); server->stop(); return OK; } - const String dest = EditorPaths::get_singleton()->get_cache_dir().plus_file("web"); + const String dest = EditorPaths::get_singleton()->get_cache_dir().path_join("web"); Ref<DirAccess> da = DirAccess::create(DirAccess::ACCESS_FILESYSTEM); if (!da->dir_exists(dest)) { Error err = da->make_dir_recursive(dest); @@ -590,7 +585,7 @@ Error EditorExportPlatformJavaScript::run(const Ref<EditorExportPreset> &p_prese } } - const String basepath = dest.plus_file("tmp_js_export"); + const String basepath = dest.path_join("tmp_js_export"); Error err = export_project(p_preset, true, basepath + ".html", p_debug_flags); if (err != OK) { // Export generates several files, clean them up on failure. @@ -620,34 +615,34 @@ Error EditorExportPlatformJavaScript::run(const Ref<EditorExportPreset> &p_prese } ERR_FAIL_COND_V_MSG(!bind_ip.is_valid(), ERR_INVALID_PARAMETER, "Invalid editor setting 'export/web/http_host': '" + bind_host + "'. Try using '127.0.0.1'."); - const bool use_ssl = EDITOR_GET("export/web/use_ssl"); - const String ssl_key = EDITOR_GET("export/web/ssl_key"); - const String ssl_cert = EDITOR_GET("export/web/ssl_certificate"); + const bool use_tls = EDITOR_GET("export/web/use_tls"); + const String tls_key = EDITOR_GET("export/web/tls_key"); + const String tls_cert = EDITOR_GET("export/web/tls_certificate"); // Restart server. { MutexLock lock(server_lock); server->stop(); - err = server->listen(bind_port, bind_ip, use_ssl, ssl_key, ssl_cert); + err = server->listen(bind_port, bind_ip, use_tls, tls_key, tls_cert); } if (err != OK) { add_message(EXPORT_MESSAGE_ERROR, TTR("Run"), vformat(TTR("Error starting HTTP server: %d."), err)); return err; } - OS::get_singleton()->shell_open(String((use_ssl ? "https://" : "http://") + bind_host + ":" + itos(bind_port) + "/tmp_js_export.html")); + OS::get_singleton()->shell_open(String((use_tls ? "https://" : "http://") + bind_host + ":" + itos(bind_port) + "/tmp_js_export.html")); // FIXME: Find out how to clean up export files after running the successfully // exported game. Might not be trivial. return OK; } -Ref<Texture2D> EditorExportPlatformJavaScript::get_run_icon() const { +Ref<Texture2D> EditorExportPlatformWeb::get_run_icon() const { return run_icon; } -void EditorExportPlatformJavaScript::_server_thread_poll(void *data) { - EditorExportPlatformJavaScript *ej = static_cast<EditorExportPlatformJavaScript *>(data); +void EditorExportPlatformWeb::_server_thread_poll(void *data) { + EditorExportPlatformWeb *ej = static_cast<EditorExportPlatformWeb *>(data); while (!ej->server_quit) { OS::get_singleton()->delay_usec(6900); { @@ -657,12 +652,12 @@ void EditorExportPlatformJavaScript::_server_thread_poll(void *data) { } } -EditorExportPlatformJavaScript::EditorExportPlatformJavaScript() { +EditorExportPlatformWeb::EditorExportPlatformWeb() { server.instantiate(); server_thread.start(_server_thread_poll, this); - logo = ImageTexture::create_from_image(memnew(Image(_javascript_logo))); - run_icon = ImageTexture::create_from_image(memnew(Image(_javascript_run_icon))); + logo = ImageTexture::create_from_image(memnew(Image(_web_logo))); + run_icon = ImageTexture::create_from_image(memnew(Image(_web_run_icon))); Ref<Theme> theme = EditorNode::get_singleton()->get_editor_theme(); if (theme.is_valid()) { @@ -672,7 +667,7 @@ EditorExportPlatformJavaScript::EditorExportPlatformJavaScript() { } } -EditorExportPlatformJavaScript::~EditorExportPlatformJavaScript() { +EditorExportPlatformWeb::~EditorExportPlatformWeb() { server->stop(); server_quit = true; server_thread.wait_to_finish(); diff --git a/platform/javascript/export/export_plugin.h b/platform/web/export/export_plugin.h index 1aaec5454d..f11e38df09 100644 --- a/platform/javascript/export/export_plugin.h +++ b/platform/web/export/export_plugin.h @@ -28,24 +28,24 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ -#ifndef JAVASCRIPT_EXPORT_PLUGIN_H -#define JAVASCRIPT_EXPORT_PLUGIN_H +#ifndef WEB_EXPORT_PLUGIN_H +#define WEB_EXPORT_PLUGIN_H #include "core/config/project_settings.h" #include "core/io/image_loader.h" -#include "core/io/stream_peer_ssl.h" +#include "core/io/stream_peer_tls.h" #include "core/io/tcp_server.h" #include "core/io/zip_io.h" -#include "editor/editor_export.h" #include "editor/editor_node.h" +#include "editor/export/editor_export_platform.h" #include "main/splash.gen.h" -#include "platform/javascript/logo.gen.h" -#include "platform/javascript/run_icon.gen.h" +#include "platform/web/logo.gen.h" +#include "platform/web/run_icon.gen.h" -#include "export_server.h" +#include "editor_http_server.h" -class EditorExportPlatformJavaScript : public EditorExportPlatform { - GDCLASS(EditorExportPlatformJavaScript, EditorExportPlatform); +class EditorExportPlatformWeb : public EditorExportPlatform { + GDCLASS(EditorExportPlatformWeb, EditorExportPlatform); Ref<ImageTexture> logo; Ref<ImageTexture> run_icon; @@ -57,20 +57,10 @@ class EditorExportPlatformJavaScript : public EditorExportPlatform { Mutex server_lock; Thread server_thread; - enum ExportMode { - EXPORT_MODE_NORMAL = 0, - EXPORT_MODE_THREADS = 1, - EXPORT_MODE_GDNATIVE = 2, - EXPORT_MODE_THREADS_GDNATIVE = 3, - }; - - String _get_template_name(ExportMode p_mode, bool p_debug) const { - String name = "webassembly"; - if (p_mode & EXPORT_MODE_GDNATIVE) { - name += "_gdnative"; - } - if (p_mode & EXPORT_MODE_THREADS) { - name += "_threads"; + String _get_template_name(bool p_extension, bool p_debug) const { + String name = "web"; + if (p_extension) { + name += "_dlink"; } if (p_debug) { name += "_debug.zip"; @@ -110,7 +100,7 @@ class EditorExportPlatformJavaScript : public EditorExportPlatform { static void _server_thread_poll(void *data); public: - virtual void get_preset_features(const Ref<EditorExportPreset> &p_preset, List<String> *r_features) override; + virtual void get_preset_features(const Ref<EditorExportPreset> &p_preset, List<String> *r_features) const override; virtual void get_export_options(List<ExportOption> *r_options) override; @@ -118,7 +108,8 @@ public: virtual String get_os_name() const override; virtual Ref<Texture2D> get_logo() const override; - virtual bool can_export(const Ref<EditorExportPreset> &p_preset, String &r_error, bool &r_missing_templates) const override; + virtual bool has_valid_export_configuration(const Ref<EditorExportPreset> &p_preset, String &r_error, bool &r_missing_templates) const override; + virtual bool has_valid_project_configuration(const Ref<EditorExportPreset> &p_preset, String &r_error) const override; virtual List<String> get_binary_extensions(const Ref<EditorExportPreset> &p_preset) const override; virtual Error export_project(const Ref<EditorExportPreset> &p_preset, bool p_debug, const String &p_path, int p_flags = 0) override; @@ -130,7 +121,7 @@ public: virtual Error run(const Ref<EditorExportPreset> &p_preset, int p_option, int p_debug_flags) override; virtual Ref<Texture2D> get_run_icon() const override; - virtual void get_platform_features(List<String> *r_features) override { + virtual void get_platform_features(List<String> *r_features) const override { r_features->push_back("web"); r_features->push_back(get_os_name().to_lower()); } @@ -140,8 +131,8 @@ public: String get_debug_protocol() const override { return "ws://"; } - EditorExportPlatformJavaScript(); - ~EditorExportPlatformJavaScript(); + EditorExportPlatformWeb(); + ~EditorExportPlatformWeb(); }; -#endif +#endif // WEB_EXPORT_PLUGIN_H diff --git a/platform/javascript/godot_audio.h b/platform/web/godot_audio.h index 012f8daeb7..3855b7301e 100644 --- a/platform/javascript/godot_audio.h +++ b/platform/web/godot_audio.h @@ -63,4 +63,4 @@ extern void godot_audio_script_start(float *p_in_buf, int p_in_size, float *p_ou } #endif -#endif /* GODOT_AUDIO_H */ +#endif // GODOT_AUDIO_H diff --git a/platform/javascript/godot_js.h b/platform/web/godot_js.h index 1a383c9799..a323f2d157 100644 --- a/platform/javascript/godot_js.h +++ b/platform/web/godot_js.h @@ -58,6 +58,7 @@ extern void godot_js_input_mouse_move_cb(void (*p_callback)(double p_x, double p extern void godot_js_input_mouse_wheel_cb(int (*p_callback)(double p_delta_x, double p_delta_y)); extern void godot_js_input_touch_cb(void (*p_callback)(int p_type, int p_count), uint32_t *r_identifiers, double *r_coords); extern void godot_js_input_key_cb(void (*p_callback)(int p_type, int p_repeat, int p_modifiers), char r_code[32], char r_key[32]); +extern void godot_js_input_vibrate_handheld(int p_duration_ms); // Input gamepad extern void godot_js_input_gamepad_cb(void (*p_on_change)(int p_index, int p_connected, const char *p_id, const char *p_guid)); @@ -120,11 +121,11 @@ extern void godot_js_display_notification_cb(void (*p_callback)(int p_notificati extern int godot_js_display_vk_available(); extern int godot_js_display_tts_available(); extern void godot_js_display_vk_cb(void (*p_input)(const char *p_text, int p_cursor)); -extern void godot_js_display_vk_show(const char *p_text, int p_multiline, int p_start, int p_end); +extern void godot_js_display_vk_show(const char *p_text, int p_type, int p_start, int p_end); extern void godot_js_display_vk_hide(); #ifdef __cplusplus } #endif -#endif /* GODOT_JS_H */ +#endif // GODOT_JS_H diff --git a/platform/javascript/godot_webgl2.h b/platform/web/godot_webgl2.h index 7c357ff66d..968b70f84b 100644 --- a/platform/javascript/godot_webgl2.h +++ b/platform/web/godot_webgl2.h @@ -34,4 +34,4 @@ #include "GLES3/gl3.h" #include "webgl/webgl2.h" -#endif +#endif // GODOT_WEBGL2_H diff --git a/platform/javascript/http_client_javascript.cpp b/platform/web/http_client_web.cpp index 32bdfed4c7..d045275826 100644 --- a/platform/javascript/http_client_javascript.cpp +++ b/platform/web/http_client_web.cpp @@ -1,5 +1,5 @@ /*************************************************************************/ -/* http_client_javascript.cpp */ +/* http_client_web.cpp */ /*************************************************************************/ /* This file is part of: */ /* GODOT ENGINE */ @@ -28,23 +28,23 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ -#include "http_client_javascript.h" +#include "http_client_web.h" -void HTTPClientJavaScript::_parse_headers(int p_len, const char **p_headers, void *p_ref) { - HTTPClientJavaScript *client = static_cast<HTTPClientJavaScript *>(p_ref); +void HTTPClientWeb::_parse_headers(int p_len, const char **p_headers, void *p_ref) { + HTTPClientWeb *client = static_cast<HTTPClientWeb *>(p_ref); for (int i = 0; i < p_len; i++) { client->response_headers.push_back(String::utf8(p_headers[i])); } } -Error HTTPClientJavaScript::connect_to_host(const String &p_host, int p_port, bool p_ssl, bool p_verify_host) { +Error HTTPClientWeb::connect_to_host(const String &p_host, int p_port, bool p_tls, bool p_verify_host) { close(); - if (p_ssl && !p_verify_host) { - WARN_PRINT("Disabling HTTPClientJavaScript's host verification is not supported for the HTML5 platform, host will be verified"); + if (p_tls && !p_verify_host) { + WARN_PRINT("Disabling HTTPClientWeb's host verification is not supported for the Web platform, host will be verified"); } port = p_port; - use_tls = p_ssl; + use_tls = p_tls; host = p_host; @@ -71,17 +71,17 @@ Error HTTPClientJavaScript::connect_to_host(const String &p_host, int p_port, bo return OK; } -void HTTPClientJavaScript::set_connection(const Ref<StreamPeer> &p_connection) { - ERR_FAIL_MSG("Accessing an HTTPClientJavaScript's StreamPeer is not supported for the HTML5 platform."); +void HTTPClientWeb::set_connection(const Ref<StreamPeer> &p_connection) { + ERR_FAIL_MSG("Accessing an HTTPClientWeb's StreamPeer is not supported for the Web platform."); } -Ref<StreamPeer> HTTPClientJavaScript::get_connection() const { - ERR_FAIL_V_MSG(Ref<RefCounted>(), "Accessing an HTTPClientJavaScript's StreamPeer is not supported for the HTML5 platform."); +Ref<StreamPeer> HTTPClientWeb::get_connection() const { + ERR_FAIL_V_MSG(Ref<RefCounted>(), "Accessing an HTTPClientWeb's StreamPeer is not supported for the Web platform."); } -Error HTTPClientJavaScript::request(Method p_method, const String &p_url, const Vector<String> &p_headers, const uint8_t *p_body, int p_body_len) { +Error HTTPClientWeb::request(Method p_method, const String &p_url, const Vector<String> &p_headers, const uint8_t *p_body, int p_body_len) { ERR_FAIL_INDEX_V(p_method, METHOD_MAX, ERR_INVALID_PARAMETER); - ERR_FAIL_COND_V_MSG(p_method == METHOD_TRACE || p_method == METHOD_CONNECT, ERR_UNAVAILABLE, "HTTP methods TRACE and CONNECT are not supported for the HTML5 platform."); + ERR_FAIL_COND_V_MSG(p_method == METHOD_TRACE || p_method == METHOD_CONNECT, ERR_UNAVAILABLE, "HTTP methods TRACE and CONNECT are not supported for the Web platform."); ERR_FAIL_COND_V(status != STATUS_CONNECTED, ERR_INVALID_PARAMETER); ERR_FAIL_COND_V(host.is_empty(), ERR_UNCONFIGURED); ERR_FAIL_COND_V(port < 0, ERR_UNCONFIGURED); @@ -107,7 +107,7 @@ Error HTTPClientJavaScript::request(Method p_method, const String &p_url, const return OK; } -void HTTPClientJavaScript::close() { +void HTTPClientWeb::close() { host = ""; port = -1; use_tls = false; @@ -121,23 +121,23 @@ void HTTPClientJavaScript::close() { } } -HTTPClientJavaScript::Status HTTPClientJavaScript::get_status() const { +HTTPClientWeb::Status HTTPClientWeb::get_status() const { return status; } -bool HTTPClientJavaScript::has_response() const { +bool HTTPClientWeb::has_response() const { return response_headers.size() > 0; } -bool HTTPClientJavaScript::is_response_chunked() const { +bool HTTPClientWeb::is_response_chunked() const { return godot_js_fetch_is_chunked(js_id); } -int HTTPClientJavaScript::get_response_code() const { +int HTTPClientWeb::get_response_code() const { return polled_response_code; } -Error HTTPClientJavaScript::get_response_headers(List<String> *r_response) { +Error HTTPClientWeb::get_response_headers(List<String> *r_response) { if (!response_headers.size()) { return ERR_INVALID_PARAMETER; } @@ -148,11 +148,11 @@ Error HTTPClientJavaScript::get_response_headers(List<String> *r_response) { return OK; } -int64_t HTTPClientJavaScript::get_response_body_length() const { +int64_t HTTPClientWeb::get_response_body_length() const { return godot_js_fetch_body_length_get(js_id); } -PackedByteArray HTTPClientJavaScript::read_response_body_chunk() { +PackedByteArray HTTPClientWeb::read_response_body_chunk() { ERR_FAIL_COND_V(status != STATUS_BODY, PackedByteArray()); if (response_buffer.size() != read_limit) { @@ -177,23 +177,23 @@ PackedByteArray HTTPClientJavaScript::read_response_body_chunk() { return chunk; } -void HTTPClientJavaScript::set_blocking_mode(bool p_enable) { - ERR_FAIL_COND_MSG(p_enable, "HTTPClientJavaScript blocking mode is not supported for the HTML5 platform."); +void HTTPClientWeb::set_blocking_mode(bool p_enable) { + ERR_FAIL_COND_MSG(p_enable, "HTTPClientWeb blocking mode is not supported for the Web platform."); } -bool HTTPClientJavaScript::is_blocking_mode_enabled() const { +bool HTTPClientWeb::is_blocking_mode_enabled() const { return false; } -void HTTPClientJavaScript::set_read_chunk_size(int p_size) { +void HTTPClientWeb::set_read_chunk_size(int p_size) { read_limit = p_size; } -int HTTPClientJavaScript::get_read_chunk_size() const { +int HTTPClientWeb::get_read_chunk_size() const { return read_limit; } -Error HTTPClientJavaScript::poll() { +Error HTTPClientWeb::poll() { switch (status) { case STATUS_DISCONNECTED: return ERR_UNCONFIGURED; @@ -227,9 +227,9 @@ Error HTTPClientJavaScript::poll() { #ifdef DEBUG_ENABLED // forcing synchronous requests is not possible on the web if (last_polling_frame == Engine::get_singleton()->get_process_frames()) { - WARN_PRINT("HTTPClientJavaScript polled multiple times in one frame, " + WARN_PRINT("HTTPClientWeb polled multiple times in one frame, " "but request cannot progress more than once per " - "frame on the HTML5 platform."); + "frame on the Web platform."); } last_polling_frame = Engine::get_singleton()->get_process_frames(); #endif @@ -258,15 +258,15 @@ Error HTTPClientJavaScript::poll() { return OK; } -HTTPClient *HTTPClientJavaScript::_create_func() { - return memnew(HTTPClientJavaScript); +HTTPClient *HTTPClientWeb::_create_func() { + return memnew(HTTPClientWeb); } -HTTPClient *(*HTTPClient::_create)() = HTTPClientJavaScript::_create_func; +HTTPClient *(*HTTPClient::_create)() = HTTPClientWeb::_create_func; -HTTPClientJavaScript::HTTPClientJavaScript() { +HTTPClientWeb::HTTPClientWeb() { } -HTTPClientJavaScript::~HTTPClientJavaScript() { +HTTPClientWeb::~HTTPClientWeb() { close(); } diff --git a/platform/javascript/http_client_javascript.h b/platform/web/http_client_web.h index 096aa6a153..5059b4693e 100644 --- a/platform/javascript/http_client_javascript.h +++ b/platform/web/http_client_web.h @@ -1,5 +1,5 @@ /*************************************************************************/ -/* http_client_javascript.h */ +/* http_client_web.h */ /*************************************************************************/ /* This file is part of: */ /* GODOT ENGINE */ @@ -28,8 +28,8 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ -#ifndef HTTP_CLIENT_JAVASCRIPT_H -#define HTTP_CLIENT_JAVASCRIPT_H +#ifndef HTTP_CLIENT_WEB_H +#define HTTP_CLIENT_WEB_H #include "core/io/http_client.h" @@ -59,7 +59,7 @@ extern int godot_js_fetch_is_chunked(int p_id); } #endif -class HTTPClientJavaScript : public HTTPClient { +class HTTPClientWeb : public HTTPClient { private: int js_id = 0; Status status = STATUS_DISCONNECTED; @@ -86,7 +86,7 @@ public: Error request(Method p_method, const String &p_url, const Vector<String> &p_headers, const uint8_t *p_body, int p_body_size) override; - Error connect_to_host(const String &p_host, int p_port = -1, bool p_ssl = false, bool p_verify_host = true) override; + Error connect_to_host(const String &p_host, int p_port = -1, bool p_tls = false, bool p_verify_host = true) override; void set_connection(const Ref<StreamPeer> &p_connection) override; Ref<StreamPeer> get_connection() const override; void close() override; @@ -102,7 +102,8 @@ public: void set_read_chunk_size(int p_size) override; int get_read_chunk_size() const override; Error poll() override; - HTTPClientJavaScript(); - ~HTTPClientJavaScript(); + HTTPClientWeb(); + ~HTTPClientWeb(); }; -#endif // HTTP_CLIENT_JAVASCRIPT_H + +#endif // HTTP_CLIENT_WEB_H diff --git a/platform/javascript/javascript_singleton.cpp b/platform/web/javascript_bridge_singleton.cpp index 8dc7aba5f8..69cd0cece1 100644 --- a/platform/javascript/javascript_singleton.cpp +++ b/platform/web/javascript_bridge_singleton.cpp @@ -1,5 +1,5 @@ /*************************************************************************/ -/* javascript_singleton.cpp */ +/* javascript_bridge_singleton.cpp */ /*************************************************************************/ /* This file is part of: */ /* GODOT ENGINE */ @@ -28,10 +28,10 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ -#include "api/javascript_singleton.h" +#include "api/javascript_bridge_singleton.h" #include "emscripten.h" -#include "os_javascript.h" +#include "os_web.h" extern "C" { extern void godot_js_os_download_buffer(const uint8_t *p_buf, int p_buf_size, const char *p_name, const char *p_mime); @@ -62,7 +62,7 @@ extern int godot_js_wrapper_create_object(const char *p_method, void **p_args, i class JavaScriptObjectImpl : public JavaScriptObject { private: - friend class JavaScript; + friend class JavaScriptBridge; int _js_id = 0; Callable _callable; @@ -259,7 +259,7 @@ void JavaScriptObjectImpl::_callback(void *p_ref, int p_args_id, int p_argc) { const Variant *argv[1] = { &arg }; Callable::CallError err; Variant ret; - obj->_callable.call(argv, 1, ret, err); + obj->_callable.callp(argv, 1, ret, err); // Set return value godot_js_wrapper_ex exchange; @@ -272,20 +272,20 @@ void JavaScriptObjectImpl::_callback(void *p_ref, int p_args_id, int p_argc) { } } -Ref<JavaScriptObject> JavaScript::create_callback(const Callable &p_callable) { +Ref<JavaScriptObject> JavaScriptBridge::create_callback(const Callable &p_callable) { Ref<JavaScriptObjectImpl> out = memnew(JavaScriptObjectImpl); out->_callable = p_callable; out->_js_id = godot_js_wrapper_create_cb(out.ptr(), JavaScriptObjectImpl::_callback); return out; } -Ref<JavaScriptObject> JavaScript::get_interface(const String &p_interface) { +Ref<JavaScriptObject> JavaScriptBridge::get_interface(const String &p_interface) { int js_id = godot_js_wrapper_interface_get(p_interface.utf8().get_data()); ERR_FAIL_COND_V_MSG(!js_id, Ref<JavaScriptObject>(), "No interface '" + p_interface + "' registered."); return Ref<JavaScriptObject>(memnew(JavaScriptObjectImpl(js_id))); } -Variant JavaScript::_create_object_bind(const Variant **p_args, int p_argcount, Callable::CallError &r_error) { +Variant JavaScriptBridge::_create_object_bind(const Variant **p_args, int p_argcount, Callable::CallError &r_error) { if (p_argcount < 1) { r_error.error = Callable::CallError::CALL_ERROR_TOO_FEW_ARGUMENTS; r_error.argument = 0; @@ -328,7 +328,7 @@ void *resize_PackedByteArray_and_open_write(void *p_arr, void *r_write, int p_le return arr->ptrw(); } -Variant JavaScript::eval(const String &p_code, bool p_use_global_exec_context) { +Variant JavaScriptBridge::eval(const String &p_code, bool p_use_global_exec_context) { union js_eval_ret js_data; PackedByteArray arr; VectorWriteProxy<uint8_t> arr_write; @@ -354,13 +354,13 @@ Variant JavaScript::eval(const String &p_code, bool p_use_global_exec_context) { } #endif // JAVASCRIPT_EVAL_ENABLED -void JavaScript::download_buffer(Vector<uint8_t> p_arr, const String &p_name, const String &p_mime) { +void JavaScriptBridge::download_buffer(Vector<uint8_t> p_arr, const String &p_name, const String &p_mime) { godot_js_os_download_buffer(p_arr.ptr(), p_arr.size(), p_name.utf8().get_data(), p_mime.utf8().get_data()); } -bool JavaScript::pwa_needs_update() const { - return OS_JavaScript::get_singleton()->pwa_needs_update(); +bool JavaScriptBridge::pwa_needs_update() const { + return OS_Web::get_singleton()->pwa_needs_update(); } -Error JavaScript::pwa_update() { - return OS_JavaScript::get_singleton()->pwa_update(); +Error JavaScriptBridge::pwa_update() { + return OS_Web::get_singleton()->pwa_update(); } diff --git a/platform/javascript/js/engine/config.js b/platform/web/js/engine/config.js index 2e5e1ed0d1..41be7b2512 100644 --- a/platform/javascript/js/engine/config.js +++ b/platform/web/js/engine/config.js @@ -317,7 +317,8 @@ const InternalConfig = function (initConfig) { // eslint-disable-line no-unused- if (!(this.canvas instanceof HTMLCanvasElement)) { const nodes = document.getElementsByTagName('canvas'); if (nodes.length && nodes[0] instanceof HTMLCanvasElement) { - this.canvas = nodes[0]; + const first = nodes[0]; + this.canvas = /** @type {!HTMLCanvasElement} */ (first); } if (!this.canvas) { throw new Error('No canvas found in page'); @@ -334,6 +335,7 @@ const InternalConfig = function (initConfig) { // eslint-disable-line no-unused- locale = navigator.languages ? navigator.languages[0] : navigator.language; locale = locale.split('.')[0]; } + locale = locale.replace('-', '_'); const onExit = this.onExit; // Godot configuration. diff --git a/platform/javascript/js/engine/engine.externs.js b/platform/web/js/engine/engine.externs.js index 35a66a93ae..35a66a93ae 100644 --- a/platform/javascript/js/engine/engine.externs.js +++ b/platform/web/js/engine/engine.externs.js diff --git a/platform/javascript/js/engine/engine.js b/platform/web/js/engine/engine.js index d2ba595083..6f0d51b2be 100644 --- a/platform/javascript/js/engine/engine.js +++ b/platform/web/js/engine/engine.js @@ -6,7 +6,7 @@ * of `Promises <https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Using_promises>`__. * * @module Engine - * @header HTML5 shell class reference + * @header Web export JavaScript reference */ const Engine = (function () { const preloader = new Preloader(); diff --git a/platform/javascript/js/engine/preloader.js b/platform/web/js/engine/preloader.js index 564c68d264..564c68d264 100644 --- a/platform/javascript/js/engine/preloader.js +++ b/platform/web/js/engine/preloader.js diff --git a/platform/javascript/js/jsdoc2rst/publish.js b/platform/web/js/jsdoc2rst/publish.js index ad9c0fbaaa..ad9c0fbaaa 100644 --- a/platform/javascript/js/jsdoc2rst/publish.js +++ b/platform/web/js/jsdoc2rst/publish.js diff --git a/platform/javascript/js/libs/audio.worklet.js b/platform/web/js/libs/audio.worklet.js index ea4d8cb221..daf5c9ef12 100644 --- a/platform/javascript/js/libs/audio.worklet.js +++ b/platform/web/js/libs/audio.worklet.js @@ -133,6 +133,8 @@ class GodotProcessor extends AudioWorkletProcessor { this.running = false; this.output = null; this.input = null; + this.lock = null; + this.notifier = null; } else if (p_cmd === 'start_nothreads') { this.output = new RingBuffer(p_data[0], p_data[0].length, false); } else if (p_cmd === 'chunk') { diff --git a/platform/javascript/js/libs/library_godot_audio.js b/platform/web/js/libs/library_godot_audio.js index 756c1ac595..68e100cca0 100644 --- a/platform/javascript/js/libs/library_godot_audio.js +++ b/platform/web/js/libs/library_godot_audio.js @@ -339,16 +339,21 @@ const GodotAudioWorklet = { if (GodotAudioWorklet.promise === null) { return; } - GodotAudioWorklet.promise.then(function () { + const p = GodotAudioWorklet.promise; + p.then(function () { GodotAudioWorklet.worklet.port.postMessage({ 'cmd': 'stop', 'data': null, }); GodotAudioWorklet.worklet.disconnect(); + GodotAudioWorklet.worklet.port.onmessage = null; GodotAudioWorklet.worklet = null; GodotAudioWorklet.promise = null; resolve(); - }).catch(function (err) { /* aborted? */ }); + }).catch(function (err) { + // Aborted? + GodotRuntime.error(err); + }); }); }, }, diff --git a/platform/javascript/js/libs/library_godot_display.js b/platform/web/js/libs/library_godot_display.js index 5997631bf8..91cb8e728a 100644 --- a/platform/javascript/js/libs/library_godot_display.js +++ b/platform/web/js/libs/library_godot_display.js @@ -73,7 +73,7 @@ const GodotDisplayVK = { GodotDisplayVK.textarea = create('textarea'); GodotDisplayVK.updateSize(); }, - show: function (text, multiline, start, end) { + show: function (text, type, start, end) { if (!GodotDisplayVK.textinput || !GodotDisplayVK.textarea) { return; } @@ -81,7 +81,46 @@ const GodotDisplayVK = { GodotDisplayVK.hide(); } GodotDisplayVK.updateSize(); - const elem = multiline ? GodotDisplayVK.textarea : GodotDisplayVK.textinput; + + let elem = GodotDisplayVK.textinput; + switch (type) { + case 0: // KEYBOARD_TYPE_DEFAULT + elem.type = 'text'; + elem.inputmode = ''; + break; + case 1: // KEYBOARD_TYPE_MULTILINE + elem = GodotDisplayVK.textarea; + break; + case 2: // KEYBOARD_TYPE_NUMBER + elem.type = 'text'; + elem.inputmode = 'numeric'; + break; + case 3: // KEYBOARD_TYPE_NUMBER_DECIMAL + elem.type = 'text'; + elem.inputmode = 'decimal'; + break; + case 4: // KEYBOARD_TYPE_PHONE + elem.type = 'tel'; + elem.inputmode = ''; + break; + case 5: // KEYBOARD_TYPE_EMAIL_ADDRESS + elem.type = 'email'; + elem.inputmode = ''; + break; + case 6: // KEYBOARD_TYPE_PASSWORD + elem.type = 'password'; + elem.inputmode = ''; + break; + case 7: // KEYBOARD_TYPE_URL + elem.type = 'url'; + elem.inputmode = ''; + break; + default: + elem.type = 'text'; + elem.inputmode = ''; + break; + } + elem.readonly = false; elem.disabled = false; elem.value = text; @@ -297,26 +336,12 @@ const GodotDisplay = { $GodotDisplay__deps: ['$GodotConfig', '$GodotRuntime', '$GodotDisplayCursor', '$GodotEventListeners', '$GodotDisplayScreen', '$GodotDisplayVK'], $GodotDisplay: { window_icon: '', - findDPI: function () { - function testDPI(dpi) { - return window.matchMedia(`(max-resolution: ${dpi}dpi)`).matches; - } - function bisect(low, high, func) { - const mid = parseInt(((high - low) / 2) + low, 10); - if (high - low <= 1) { - return func(high) ? high : low; - } - if (func(mid)) { - return bisect(low, mid, func); - } - return bisect(mid, high, func); - } - try { - const dpi = bisect(0, 800, testDPI); - return dpi >= 96 ? dpi : 96; - } catch (e) { - return 96; - } + getDPI: function () { + // devicePixelRatio is given in dppx + // https://drafts.csswg.org/css-values/#resolution + // > due to the 1:96 fixed ratio of CSS *in* to CSS *px*, 1dppx is equivalent to 96dpi. + const dpi = Math.round(window.devicePixelRatio * 96); + return dpi >= 96 ? dpi : 96; }, }, @@ -422,7 +447,7 @@ const GodotDisplay = { godot_js_display_screen_dpi_get__sig: 'i', godot_js_display_screen_dpi_get: function () { - return GodotDisplay.findDPI(); + return GodotDisplay.getDPI(); }, godot_js_display_pixel_ratio_get__sig: 'f', @@ -511,7 +536,7 @@ const GodotDisplay = { } navigator.clipboard.writeText(text).catch(function (e) { // Setting OS clipboard is only possible from an input callback. - GodotRuntime.error('Setting OS clipboard is only possible from an input callback for the HTML5 plafrom. Exception:', e); + GodotRuntime.error('Setting OS clipboard is only possible from an input callback for the Web plafrom. Exception:', e); }); return 0; }, @@ -694,11 +719,11 @@ const GodotDisplay = { * Virtual Keyboard */ godot_js_display_vk_show__sig: 'viiii', - godot_js_display_vk_show: function (p_text, p_multiline, p_start, p_end) { + godot_js_display_vk_show: function (p_text, p_type, p_start, p_end) { const text = GodotRuntime.parseString(p_text); const start = p_start > 0 ? p_start : 0; const end = p_end > 0 ? p_end : start; - GodotDisplayVK.show(text, p_multiline, start, end); + GodotDisplayVK.show(text, p_type, start, end); }, godot_js_display_vk_hide__sig: 'v', diff --git a/platform/javascript/js/libs/library_godot_fetch.js b/platform/web/js/libs/library_godot_fetch.js index 285e50a035..285e50a035 100644 --- a/platform/javascript/js/libs/library_godot_fetch.js +++ b/platform/web/js/libs/library_godot_fetch.js diff --git a/platform/javascript/js/libs/library_godot_input.js b/platform/web/js/libs/library_godot_input.js index 1e64c260f8..51571d64a2 100644 --- a/platform/javascript/js/libs/library_godot_input.js +++ b/platform/web/js/libs/library_godot_input.js @@ -534,6 +534,15 @@ const GodotInput = { GodotRuntime.free(ptr); }, false); }, + + godot_js_input_vibrate_handheld__sig: 'vi', + godot_js_input_vibrate_handheld: function (p_duration_ms) { + if (typeof navigator.vibrate !== 'function') { + GodotRuntime.print('This browser does not support vibration.'); + } else { + navigator.vibrate(p_duration_ms); + } + }, }; autoAddDeps(GodotInput, '$GodotInput'); diff --git a/platform/javascript/js/libs/library_godot_javascript_singleton.js b/platform/web/js/libs/library_godot_javascript_singleton.js index 692f27676a..692f27676a 100644 --- a/platform/javascript/js/libs/library_godot_javascript_singleton.js +++ b/platform/web/js/libs/library_godot_javascript_singleton.js diff --git a/platform/javascript/js/libs/library_godot_os.js b/platform/web/js/libs/library_godot_os.js index 377eec3234..ce64fb98c0 100644 --- a/platform/javascript/js/libs/library_godot_os.js +++ b/platform/web/js/libs/library_godot_os.js @@ -106,12 +106,14 @@ autoAddDeps(GodotConfig, '$GodotConfig'); mergeInto(LibraryManager.library, GodotConfig); const GodotFS = { - $GodotFS__deps: ['$ERRNO_CODES', '$FS', '$IDBFS', '$GodotRuntime'], + $GodotFS__deps: ['$FS', '$IDBFS', '$GodotRuntime'], $GodotFS__postset: [ 'Module["initFS"] = GodotFS.init;', 'Module["copyToFS"] = GodotFS.copy_to_fs;', ].join(''), $GodotFS: { + // ERRNO_CODES works every odd version of emscripten, but this will break too eventually. + ENOENT: 44, _idbfs: false, _syncing: false, _mount_points: [], @@ -138,8 +140,9 @@ const GodotFS = { try { FS.stat(dir); } catch (e) { - if (e.errno !== ERRNO_CODES.ENOENT) { - throw e; + if (e.errno !== GodotFS.ENOENT) { + // Let mkdirTree throw in case, we cannot trust the above check. + GodotRuntime.error(e); } FS.mkdirTree(dir); } @@ -208,8 +211,9 @@ const GodotFS = { try { FS.stat(dir); } catch (e) { - if (e.errno !== ERRNO_CODES.ENOENT) { - throw e; + if (e.errno !== GodotFS.ENOENT) { + // Let mkdirTree throw in case, we cannot trust the above check. + GodotRuntime.error(e); } FS.mkdirTree(dir); } diff --git a/platform/javascript/js/libs/library_godot_runtime.js b/platform/web/js/libs/library_godot_runtime.js index e2f7c8dca6..e2f7c8dca6 100644 --- a/platform/javascript/js/libs/library_godot_runtime.js +++ b/platform/web/js/libs/library_godot_runtime.js diff --git a/platform/javascript/logo.png b/platform/web/logo.png Binary files differindex c046d87dc4..c046d87dc4 100644 --- a/platform/javascript/logo.png +++ b/platform/web/logo.png diff --git a/platform/javascript/os_javascript.cpp b/platform/web/os_web.cpp index 1686353229..ebe56924df 100644 --- a/platform/javascript/os_javascript.cpp +++ b/platform/web/os_web.cpp @@ -1,5 +1,5 @@ /*************************************************************************/ -/* os_javascript.cpp */ +/* os_web.cpp */ /*************************************************************************/ /* This file is part of: */ /* GODOT ENGINE */ @@ -28,13 +28,13 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ -#include "os_javascript.h" +#include "os_web.h" #include "core/debugger/engine_debugger.h" #include "drivers/unix/dir_access_unix.h" #include "drivers/unix/file_access_unix.h" #include "main/main.h" -#include "platform/javascript/display_server_javascript.h" +#include "platform/web/display_server_web.h" #include "modules/modules_enabled.gen.h" // For websocket. #ifdef MODULE_WEBSOCKET_ENABLED @@ -45,17 +45,17 @@ #include <emscripten.h> #include <stdlib.h> -#include "api/javascript_singleton.h" +#include "api/javascript_bridge_singleton.h" #include "godot_js.h" -void OS_JavaScript::alert(const String &p_alert, const String &p_title) { +void OS_Web::alert(const String &p_alert, const String &p_title) { godot_js_display_alert(p_alert.utf8().get_data()); } // Lifecycle -void OS_JavaScript::initialize() { +void OS_Web::initialize() { OS_Unix::initialize_core(); - DisplayServerJavaScript::register_javascript_driver(); + DisplayServerWeb::register_web_driver(); #ifdef MODULE_WEBSOCKET_ENABLED EngineDebugger::register_uri_handler("ws://", RemoteDebuggerPeerWebSocket::create); @@ -63,23 +63,23 @@ void OS_JavaScript::initialize() { #endif } -void OS_JavaScript::resume_audio() { - AudioDriverJavaScript::resume(); +void OS_Web::resume_audio() { + AudioDriverWeb::resume(); } -void OS_JavaScript::set_main_loop(MainLoop *p_main_loop) { +void OS_Web::set_main_loop(MainLoop *p_main_loop) { main_loop = p_main_loop; } -MainLoop *OS_JavaScript::get_main_loop() const { +MainLoop *OS_Web::get_main_loop() const { return main_loop; } -void OS_JavaScript::fs_sync_callback() { +void OS_Web::fs_sync_callback() { get_singleton()->idb_is_syncing = false; } -bool OS_JavaScript::main_loop_iterate() { +bool OS_Web::main_loop_iterate() { if (is_userfs_persistent() && idb_needs_sync && !idb_is_syncing) { idb_is_syncing = true; idb_needs_sync = false; @@ -91,16 +91,16 @@ bool OS_JavaScript::main_loop_iterate() { return Main::iteration(); } -void OS_JavaScript::delete_main_loop() { +void OS_Web::delete_main_loop() { if (main_loop) { memdelete(main_loop); } main_loop = nullptr; } -void OS_JavaScript::finalize() { +void OS_Web::finalize() { delete_main_loop(); - for (AudioDriverJavaScript *driver : audio_drivers) { + for (AudioDriverWeb *driver : audio_drivers) { memdelete(driver); } audio_drivers.clear(); @@ -108,93 +108,80 @@ void OS_JavaScript::finalize() { // Miscellaneous -Error OS_JavaScript::execute(const String &p_path, const List<String> &p_arguments, String *r_pipe, int *r_exitcode, bool read_stderr, Mutex *p_pipe_mutex, bool p_open_console) { +Error OS_Web::execute(const String &p_path, const List<String> &p_arguments, String *r_pipe, int *r_exitcode, bool read_stderr, Mutex *p_pipe_mutex, bool p_open_console) { return create_process(p_path, p_arguments); } -Error OS_JavaScript::create_process(const String &p_path, const List<String> &p_arguments, ProcessID *r_child_id, bool p_open_console) { +Error OS_Web::create_process(const String &p_path, const List<String> &p_arguments, ProcessID *r_child_id, bool p_open_console) { Array args; for (const String &E : p_arguments) { args.push_back(E); } String json_args = Variant(args).to_json_string(); int failed = godot_js_os_execute(json_args.utf8().get_data()); - ERR_FAIL_COND_V_MSG(failed, ERR_UNAVAILABLE, "OS::execute() or create_process() must be implemented in JavaScript via 'engine.setOnExecute' if required."); + ERR_FAIL_COND_V_MSG(failed, ERR_UNAVAILABLE, "OS::execute() or create_process() must be implemented in Web via 'engine.setOnExecute' if required."); return OK; } -Error OS_JavaScript::kill(const ProcessID &p_pid) { - ERR_FAIL_V_MSG(ERR_UNAVAILABLE, "OS::kill() is not available on the HTML5 platform."); +Error OS_Web::kill(const ProcessID &p_pid) { + ERR_FAIL_V_MSG(ERR_UNAVAILABLE, "OS::kill() is not available on the Web platform."); } -int OS_JavaScript::get_process_id() const { - ERR_FAIL_V_MSG(0, "OS::get_process_id() is not available on the HTML5 platform."); +int OS_Web::get_process_id() const { + ERR_FAIL_V_MSG(0, "OS::get_process_id() is not available on the Web platform."); } -bool OS_JavaScript::is_process_running(const ProcessID &p_pid) const { +bool OS_Web::is_process_running(const ProcessID &p_pid) const { return false; } -int OS_JavaScript::get_processor_count() const { +int OS_Web::get_processor_count() const { return godot_js_os_hw_concurrency_get(); } -bool OS_JavaScript::_check_internal_feature_support(const String &p_feature) { - if (p_feature == "html5" || p_feature == "web") { +bool OS_Web::_check_internal_feature_support(const String &p_feature) { + if (p_feature == "web") { return true; } - -#ifdef JAVASCRIPT_EVAL_ENABLED - if (p_feature == "javascript") { - return true; - } -#endif -#ifndef NO_THREADS - if (p_feature == "threads") { - return true; - } -#endif -#if WASM_GDNATIVE - if (p_feature == "wasm32") { - return true; - } -#endif - return false; } -String OS_JavaScript::get_executable_path() const { +String OS_Web::get_executable_path() const { return OS::get_executable_path(); } -Error OS_JavaScript::shell_open(String p_uri) { +Error OS_Web::shell_open(String p_uri) { // Open URI in a new tab, browser will deal with it by protocol. godot_js_os_shell_open(p_uri.utf8().get_data()); return OK; } -String OS_JavaScript::get_name() const { - return "HTML5"; +String OS_Web::get_name() const { + return "Web"; +} + +void OS_Web::vibrate_handheld(int p_duration_ms) { + godot_js_input_vibrate_handheld(p_duration_ms); } -String OS_JavaScript::get_user_data_dir() const { +String OS_Web::get_user_data_dir() const { return "/userfs"; } -String OS_JavaScript::get_cache_path() const { +String OS_Web::get_cache_path() const { return "/home/web_user/.cache"; } -String OS_JavaScript::get_config_path() const { +String OS_Web::get_config_path() const { return "/home/web_user/.config"; } -String OS_JavaScript::get_data_path() const { +String OS_Web::get_data_path() const { return "/home/web_user/.local/share"; } -void OS_JavaScript::file_access_close_callback(const String &p_file, int p_flags) { - OS_JavaScript *os = OS_JavaScript::get_singleton(); +void OS_Web::file_access_close_callback(const String &p_file, int p_flags) { + OS_Web *os = OS_Web::get_singleton(); if (!(os->is_userfs_persistent() && (p_flags & FileAccess::WRITE))) { return; // FS persistence is not working or we are not writing. } @@ -208,24 +195,24 @@ void OS_JavaScript::file_access_close_callback(const String &p_file, int p_flags } } -void OS_JavaScript::update_pwa_state_callback() { - if (OS_JavaScript::get_singleton()) { - OS_JavaScript::get_singleton()->pwa_is_waiting = true; +void OS_Web::update_pwa_state_callback() { + if (OS_Web::get_singleton()) { + OS_Web::get_singleton()->pwa_is_waiting = true; } - if (JavaScript::get_singleton()) { - JavaScript::get_singleton()->emit_signal("pwa_update_available"); + if (JavaScriptBridge::get_singleton()) { + JavaScriptBridge::get_singleton()->emit_signal("pwa_update_available"); } } -Error OS_JavaScript::pwa_update() { +Error OS_Web::pwa_update() { return godot_js_pwa_update() ? FAILED : OK; } -bool OS_JavaScript::is_userfs_persistent() const { +bool OS_Web::is_userfs_persistent() const { return idb_available; } -Error OS_JavaScript::open_dynamic_library(const String p_path, void *&p_library_handle, bool p_also_set_library_path, String *r_resolved_path) { +Error OS_Web::open_dynamic_library(const String p_path, void *&p_library_handle, bool p_also_set_library_path, String *r_resolved_path) { String path = p_path.get_file(); p_library_handle = dlopen(path.utf8().get_data(), RTLD_NOW); ERR_FAIL_COND_V_MSG(!p_library_handle, ERR_CANT_OPEN, "Can't open dynamic library: " + p_path + ". Error: " + dlerror()); @@ -237,21 +224,21 @@ Error OS_JavaScript::open_dynamic_library(const String p_path, void *&p_library_ return OK; } -OS_JavaScript *OS_JavaScript::get_singleton() { - return static_cast<OS_JavaScript *>(OS::get_singleton()); +OS_Web *OS_Web::get_singleton() { + return static_cast<OS_Web *>(OS::get_singleton()); } -void OS_JavaScript::initialize_joypads() { +void OS_Web::initialize_joypads() { } -OS_JavaScript::OS_JavaScript() { +OS_Web::OS_Web() { char locale_ptr[16]; godot_js_config_locale_get(locale_ptr, 16); setenv("LANG", locale_ptr, true); - godot_js_pwa_cb(&OS_JavaScript::update_pwa_state_callback); + godot_js_pwa_cb(&OS_Web::update_pwa_state_callback); - if (AudioDriverJavaScript::is_available()) { + if (AudioDriverWeb::is_available()) { #ifdef NO_THREADS audio_drivers.push_back(memnew(AudioDriverScriptProcessor)); #endif diff --git a/platform/javascript/os_javascript.h b/platform/web/os_web.h index 0c672111cc..64f3a4d133 100644 --- a/platform/javascript/os_javascript.h +++ b/platform/web/os_web.h @@ -1,5 +1,5 @@ /*************************************************************************/ -/* os_javascript.h */ +/* os_web.h */ /*************************************************************************/ /* This file is part of: */ /* GODOT ENGINE */ @@ -28,19 +28,19 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ -#ifndef OS_JAVASCRIPT_H -#define OS_JAVASCRIPT_H +#ifndef OS_WEB_H +#define OS_WEB_H -#include "audio_driver_javascript.h" +#include "audio_driver_web.h" #include "core/input/input.h" #include "drivers/unix/os_unix.h" #include "servers/audio_server.h" #include <emscripten/html5.h> -class OS_JavaScript : public OS_Unix { +class OS_Web : public OS_Unix { MainLoop *main_loop = nullptr; - List<AudioDriverJavaScript *> audio_drivers; + List<AudioDriverWeb *> audio_drivers; bool idb_is_syncing = false; bool idb_available = false; @@ -65,7 +65,7 @@ protected: public: // Override return type to make writing static callbacks less tedious. - static OS_JavaScript *get_singleton(); + static OS_Web *get_singleton(); bool pwa_needs_update() const { return pwa_is_waiting; } Error pwa_update(); @@ -87,16 +87,17 @@ public: Error shell_open(String p_uri) override; String get_name() const override; // Override default OS implementation which would block the main thread with delay_usec. - // Implemented in javascript_main.cpp loop callback instead. + // Implemented in web_main.cpp loop callback instead. void add_frame_delay(bool p_can_draw) override {} + void vibrate_handheld(int p_duration_ms) override; + String get_cache_path() const override; String get_config_path() const override; String get_data_path() const override; String get_user_data_dir() const override; bool is_userfs_persistent() const override; - bool is_single_window() const override { return true; } void alert(const String &p_alert, const String &p_title = "ALERT!") override; @@ -104,7 +105,7 @@ public: void resume_audio(); - OS_JavaScript(); + OS_Web(); }; -#endif +#endif // OS_WEB_H diff --git a/platform/javascript/package-lock.json b/platform/web/package-lock.json index f8c67b206f..f8c67b206f 100644 --- a/platform/javascript/package-lock.json +++ b/platform/web/package-lock.json diff --git a/platform/javascript/package.json b/platform/web/package.json index 8c38bc89e8..a57205415a 100644 --- a/platform/javascript/package.json +++ b/platform/web/package.json @@ -2,7 +2,7 @@ "name": "godot", "private": true, "version": "1.0.0", - "description": "Development and linting setup for Godot's HTML5 platform code", + "description": "Development and linting setup for Godot's Web platform code", "scripts": { "docs": "jsdoc --template js/jsdoc2rst/ js/engine/engine.js js/engine/config.js --destination ''", "lint": "npm run lint:engine && npm run lint:libs && npm run lint:modules && npm run lint:tools", diff --git a/platform/javascript/platform_config.h b/platform/web/platform_config.h index 1970fe0fa0..5e48992af8 100644 --- a/platform/javascript/platform_config.h +++ b/platform/web/platform_config.h @@ -30,4 +30,4 @@ #include <alloca.h> -#define OPENGL_INCLUDE_H "platform/javascript/godot_webgl2.h" +#define OPENGL_INCLUDE_H "platform/web/godot_webgl2.h" diff --git a/platform/javascript/run_icon.png b/platform/web/run_icon.png Binary files differindex 574abb0150..574abb0150 100644 --- a/platform/javascript/run_icon.png +++ b/platform/web/run_icon.png diff --git a/platform/javascript/serve.json b/platform/web/serve.json index f2ef24751f..f2ef24751f 100644 --- a/platform/javascript/serve.json +++ b/platform/web/serve.json diff --git a/platform/javascript/javascript_main.cpp b/platform/web/web_main.cpp index 307a80feea..287fe48c4d 100644 --- a/platform/javascript/javascript_main.cpp +++ b/platform/web/web_main.cpp @@ -1,5 +1,5 @@ /*************************************************************************/ -/* javascript_main.cpp */ +/* web_main.cpp */ /*************************************************************************/ /* This file is part of: */ /* GODOT ENGINE */ @@ -31,21 +31,21 @@ #include "core/config/engine.h" #include "core/io/resource_loader.h" #include "main/main.h" -#include "platform/javascript/display_server_javascript.h" -#include "platform/javascript/os_javascript.h" +#include "platform/web/display_server_web.h" +#include "platform/web/os_web.h" #include <emscripten/emscripten.h> #include <stdlib.h> #include "godot_js.h" -static OS_JavaScript *os = nullptr; +static OS_Web *os = nullptr; static uint64_t target_ticks = 0; void exit_callback() { emscripten_cancel_main_loop(); // After this, we can exit! Main::cleanup(); - int exit_code = OS_JavaScript::get_singleton()->get_exit_code(); + int exit_code = OS_Web::get_singleton()->get_exit_code(); memdelete(os); os = nullptr; emscripten_force_exit(exit_code); // No matter that we call cancel_main_loop, regular "exit" will not work, forcing. @@ -55,10 +55,22 @@ void cleanup_after_sync() { emscripten_set_main_loop(exit_callback, -1, false); } +void early_cleanup() { + emscripten_cancel_main_loop(); // After this, we can exit! + int exit_code = OS_Web::get_singleton()->get_exit_code(); + memdelete(os); + os = nullptr; + emscripten_force_exit(exit_code); // No matter that we call cancel_main_loop, regular "exit" will not work, forcing. +} + +void early_cleanup_sync() { + emscripten_set_main_loop(early_cleanup, -1, false); +} + void main_loop_callback() { uint64_t current_ticks = os->get_ticks_usec(); - bool force_draw = DisplayServerJavaScript::get_singleton()->check_size_force_redraw(); + bool force_draw = DisplayServerWeb::get_singleton()->check_size_force_redraw(); if (force_draw) { Main::force_redraw(); } else if (current_ticks < target_ticks) { @@ -81,13 +93,25 @@ void main_loop_callback() { } /// When calling main, it is assumed FS is setup and synced. -extern EMSCRIPTEN_KEEPALIVE int godot_js_main(int argc, char *argv[]) { - os = new OS_JavaScript(); +extern EMSCRIPTEN_KEEPALIVE int godot_web_main(int argc, char *argv[]) { + os = new OS_Web(); // We must override main when testing is enabled TEST_MAIN_OVERRIDE - Main::setup(argv[0], argc - 1, &argv[1]); + Error err = Main::setup(argv[0], argc - 1, &argv[1]); + + // Proper shutdown in case of setup failure. + if (err != OK) { + int exit_code = (int)err; + if (err == ERR_HELP) { + exit_code = 0; // Called with --help. + } + os->set_exit_code(exit_code); + // Will only exit after sync. + godot_js_os_finish_async(early_cleanup_sync); + return exit_code; + } // Ease up compatibility. ResourceLoader::set_abort_on_missing_resources(false); diff --git a/platform/javascript/javascript_runtime.cpp b/platform/web/web_runtime.cpp index 932d0d5cb6..93a1745a83 100644 --- a/platform/javascript/javascript_runtime.cpp +++ b/platform/web/web_runtime.cpp @@ -1,5 +1,5 @@ /*************************************************************************/ -/* javascript_runtime.cpp */ +/* web_runtime.cpp */ /*************************************************************************/ /* This file is part of: */ /* GODOT ENGINE */ @@ -28,8 +28,8 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ -extern int godot_js_main(int argc, char *argv[]); +extern int godot_web_main(int argc, char *argv[]); int main(int argc, char *argv[]) { - return godot_js_main(argc, argv); + return godot_web_main(argc, argv); } diff --git a/platform/windows/README.md b/platform/windows/README.md new file mode 100644 index 0000000000..c04032ae1d --- /dev/null +++ b/platform/windows/README.md @@ -0,0 +1,15 @@ +# Windows platform port + +This folder contains the C++ code for the Windows platform port. + +See also [`misc/dist/windows`](/misc/dist/windows) folder for additional files +used by this platform. + +## Documentation + +- [Compiling for Windows](https://docs.godotengine.org/en/latest/development/compiling/compiling_for_windows.html) + - Instructions on building this platform port from source. +- [Exporting for Windows](https://docs.godotengine.org/en/latest/tutorials/export/exporting_for_windows.html) + - Instructions on using the compiled export templates to export a project. +- [Changing application icon for Windows](https://docs.godotengine.org/en/stable/tutorials/export/changing_application_icon_for_windows.html) + - Instructions on using a custom icon for the exported project executable. diff --git a/platform/windows/crash_handler_windows.cpp b/platform/windows/crash_handler_windows.cpp index 6ce10e6f0f..b501ee78db 100644 --- a/platform/windows/crash_handler_windows.cpp +++ b/platform/windows/crash_handler_windows.cpp @@ -173,10 +173,18 @@ DWORD CrashHandlerException(EXCEPTION_POINTERS *ep) { frame.AddrStack.Mode = AddrModeFlat; frame.AddrFrame.Mode = AddrModeFlat; -#ifdef _M_X64 +#if defined(_M_X64) frame.AddrPC.Offset = context->Rip; frame.AddrStack.Offset = context->Rsp; frame.AddrFrame.Offset = context->Rbp; +#elif defined(_M_ARM64) || defined(_M_ARM64EC) + frame.AddrPC.Offset = context->Pc; + frame.AddrStack.Offset = context->Sp; + frame.AddrFrame.Offset = context->Fp; +#elif defined(_M_ARM) + frame.AddrPC.Offset = context->Pc; + frame.AddrStack.Offset = context->Sp; + frame.AddrFrame.Offset = context->R11; #else frame.AddrPC.Offset = context->Eip; frame.AddrStack.Offset = context->Esp; diff --git a/platform/windows/detect.py b/platform/windows/detect.py index b82fe5e7ad..e6e1874fc0 100644 --- a/platform/windows/detect.py +++ b/platform/windows/detect.py @@ -1,5 +1,8 @@ import methods import os +import subprocess +import sys +from platform_methods import detect_arch # To match other platforms STACK_SIZE = 8388608 @@ -13,6 +16,38 @@ def get_name(): return "Windows" +def try_cmd(test, prefix, arch): + if arch: + try: + out = subprocess.Popen( + get_mingw_bin_prefix(prefix, arch) + test, + shell=True, + stderr=subprocess.PIPE, + stdout=subprocess.PIPE, + ) + out.communicate() + if out.returncode == 0: + return True + except Exception: + pass + else: + for a in ["x86_64", "x86_32", "arm64", "arm32"]: + try: + out = subprocess.Popen( + get_mingw_bin_prefix(prefix, a) + test, + shell=True, + stderr=subprocess.PIPE, + stdout=subprocess.PIPE, + ) + out.communicate() + if out.returncode == 0: + return True + except Exception: + pass + + return False + + def can_build(): if os.name == "nt": # Building natively on Windows @@ -20,7 +55,7 @@ def can_build(): if os.getenv("VCINSTALLDIR"): # MSVC, manual setup return True - # Otherwise, let SCons find MSVC if installed, or else Mingw. + # Otherwise, let SCons find MSVC if installed, or else MinGW. # Since we're just returning True here, if there's no compiler # installed, we'll get errors when it tries to build with the # null compiler. @@ -28,111 +63,197 @@ def can_build(): if os.name == "posix": # Cross-compiling with MinGW-w64 (old MinGW32 is not supported) - mingw32 = "i686-w64-mingw32-" - mingw64 = "x86_64-w64-mingw32-" + prefix = os.getenv("MINGW_PREFIX", "") - if os.getenv("MINGW32_PREFIX"): - mingw32 = os.getenv("MINGW32_PREFIX") - if os.getenv("MINGW64_PREFIX"): - mingw64 = os.getenv("MINGW64_PREFIX") - - test = "gcc --version > /dev/null 2>&1" - if os.system(mingw64 + test) == 0 or os.system(mingw32 + test) == 0: + if try_cmd("gcc --version", prefix, "") or try_cmd("clang --version", prefix, ""): return True return False +def get_mingw_bin_prefix(prefix, arch): + if not prefix: + mingw_bin_prefix = "" + elif prefix[-1] != "/": + mingw_bin_prefix = prefix + "/bin/" + else: + mingw_bin_prefix = prefix + "bin/" + + if arch == "x86_64": + mingw_bin_prefix += "x86_64-w64-mingw32-" + elif arch == "x86_32": + mingw_bin_prefix += "i686-w64-mingw32-" + elif arch == "arm32": + mingw_bin_prefix += "armv7-w64-mingw32-" + elif arch == "arm64": + mingw_bin_prefix += "aarch64-w64-mingw32-" + + return mingw_bin_prefix + + +def detect_build_env_arch(): + msvc_target_aliases = { + "amd64": "x86_64", + "i386": "x86_32", + "i486": "x86_32", + "i586": "x86_32", + "i686": "x86_32", + "x86": "x86_32", + "x64": "x86_64", + "x86_64": "x86_64", + "arm": "arm32", + "arm64": "arm64", + "aarch64": "arm64", + } + if os.getenv("VCINSTALLDIR") or os.getenv("VCTOOLSINSTALLDIR"): + if os.getenv("Platform"): + msvc_arch = os.getenv("Platform").lower() + if msvc_arch in msvc_target_aliases.keys(): + return msvc_target_aliases[msvc_arch] + + if os.getenv("VSCMD_ARG_TGT_ARCH"): + msvc_arch = os.getenv("VSCMD_ARG_TGT_ARCH").lower() + if msvc_arch in msvc_target_aliases.keys(): + return msvc_target_aliases[msvc_arch] + + # Pre VS 2017 checks. + if os.getenv("VCINSTALLDIR"): + PATH = os.getenv("PATH").upper() + VCINSTALLDIR = os.getenv("VCINSTALLDIR").upper() + path_arch = { + "BIN\\x86_ARM;": "arm32", + "BIN\\amd64_ARM;": "arm32", + "BIN\\x86_ARM64;": "arm64", + "BIN\\amd64_ARM64;": "arm64", + "BIN\\x86_amd64;": "a86_64", + "BIN\\amd64;": "x86_64", + "BIN\\amd64_x86;": "x86_32", + "BIN;": "x86_32", + } + for path, arch in path_arch.items(): + final_path = VCINSTALLDIR + path + if final_path in PATH: + return arch + + # VS 2017 and newer. + if os.getenv("VCTOOLSINSTALLDIR"): + host_path_index = os.getenv("PATH").upper().find(os.getenv("VCTOOLSINSTALLDIR").upper() + "BIN\\HOST") + if host_path_index > -1: + first_path_arch = os.getenv("PATH").split(";")[0].rsplit("\\", 1)[-1].lower() + return msvc_target_aliases[first_path_arch] + + msys_target_aliases = { + "mingw32": "x86_32", + "mingw64": "x86_64", + "ucrt64": "x86_64", + "clang64": "x86_64", + "clang32": "x86_32", + "clangarm64": "arm64", + } + if os.getenv("MSYSTEM"): + msys_arch = os.getenv("MSYSTEM").lower() + if msys_arch in msys_target_aliases.keys(): + return msys_target_aliases[msys_arch] + + return "" + + def get_opts(): from SCons.Variables import BoolVariable, EnumVariable - mingw32 = "" - mingw64 = "" - if os.name == "posix": - mingw32 = "i686-w64-mingw32-" - mingw64 = "x86_64-w64-mingw32-" - - if os.getenv("MINGW32_PREFIX"): - mingw32 = os.getenv("MINGW32_PREFIX") - if os.getenv("MINGW64_PREFIX"): - mingw64 = os.getenv("MINGW64_PREFIX") + mingw = os.getenv("MINGW_PREFIX", "") return [ - ("mingw_prefix_32", "MinGW prefix (Win32)", mingw32), - ("mingw_prefix_64", "MinGW prefix (Win64)", mingw64), + ("mingw_prefix", "MinGW prefix", mingw), # Targeted Windows version: 7 (and later), minimum supported version # XP support dropped after EOL due to missing API for IPv6 and other issues # Vista support dropped after EOL due to GH-10243 - ("target_win_version", "Targeted Windows version, >= 0x0601 (Windows 7)", "0x0601"), - BoolVariable("debug_symbols", "Add debugging symbols to release/release_debug builds", True), + ( + "target_win_version", + "Targeted Windows version, >= 0x0601 (Windows 7)", + "0x0601", + ), + BoolVariable( + "debug_symbols", + "Add debugging symbols to release/release_debug builds", + True, + ), EnumVariable("windows_subsystem", "Windows subsystem", "gui", ("gui", "console")), - BoolVariable("separate_debug_symbols", "Create a separate file containing debugging symbols", False), - ("msvc_version", "MSVC version to use. Ignored if VCINSTALLDIR is set in shell env.", None), + BoolVariable( + "separate_debug_symbols", + "Create a separate file containing debugging symbols", + False, + ), + ( + "msvc_version", + "MSVC version to use. Ignored if VCINSTALLDIR is set in shell env.", + None, + ), BoolVariable("use_mingw", "Use the Mingw compiler, even if MSVC is installed.", False), BoolVariable("use_llvm", "Use the LLVM compiler", False), - BoolVariable("use_thinlto", "Use ThinLTO", False), BoolVariable("use_static_cpp", "Link MinGW/MSVC C++ runtime libraries statically", True), BoolVariable("use_asan", "Use address sanitizer (ASAN)", False), ] def get_flags(): - return [] + arch = detect_build_env_arch() or detect_arch() + + return [ + ("arch", arch), + ] def build_res_file(target, source, env): - if env["bits"] == "32": - cmdbase = env["mingw_prefix_32"] - else: - cmdbase = env["mingw_prefix_64"] - cmdbase = cmdbase + "windres --include-dir . " - import subprocess + arch_aliases = { + "x86_32": "pe-i386", + "x86_64": "pe-x86-64", + "arm32": "armv7-w64-mingw32", + "arm64": "aarch64-w64-mingw32", + } + cmdbase = "windres --include-dir . --target=" + arch_aliases[env["arch"]] + + mingw_bin_prefix = get_mingw_bin_prefix(env["mingw_prefix"], env["arch"]) for x in range(len(source)): - cmd = cmdbase + "-i " + str(source[x]) + " -o " + str(target[x]) + ok = True + # Try prefixed executable (MinGW on Linux). + cmd = mingw_bin_prefix + cmdbase + " -i " + str(source[x]) + " -o " + str(target[x]) try: out = subprocess.Popen(cmd, shell=True, stderr=subprocess.PIPE).communicate() if len(out[1]): - return 1 + ok = False except Exception: - return 1 + ok = False + + # Try generic executable (MSYS2). + if not ok: + cmd = cmdbase + " -i " + str(source[x]) + " -o " + str(target[x]) + try: + out = subprocess.Popen(cmd, shell=True, stderr=subprocess.PIPE).communicate() + if len(out[1]): + return -1 + except Exception: + return -1 + return 0 def setup_msvc_manual(env): - """Set up env to use MSVC manually, using VCINSTALLDIR""" - if env["bits"] != "default": + """Running from VCVARS environment""" + + env_arch = detect_build_env_arch() + if env["arch"] != env_arch: print( """ - Bits argument is not supported for MSVC compilation. Architecture depends on the Native/Cross Compile Tools Prompt/Developer Console - (or Visual Studio settings) that is being used to run SCons. As a consequence, bits argument is disabled. Run scons again without bits - argument (example: scons p=windows) and SCons will attempt to detect what MSVC compiler will be executed and inform you. + 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. """ + % (env["arch"], env_arch) ) - raise SCons.Errors.UserError("Bits argument should not be used when using VCINSTALLDIR") - - # Force bits arg - # (Actually msys2 mingw can support 64-bit, we could detect that) - env["bits"] = "32" - env["x86_libtheora_opt_vc"] = True - - # find compiler manually - compiler_version_str = methods.detect_visual_c_compiler_version(env["ENV"]) - print("Found MSVC compiler: " + compiler_version_str) - - # If building for 64bit architecture, disable assembly optimisations for 32 bit builds (theora as of writing)... vc compiler for 64bit can not compile _asm - if compiler_version_str == "amd64" or compiler_version_str == "x86_amd64": - env["bits"] = "64" - env["x86_libtheora_opt_vc"] = False - print("Compiled program architecture will be a 64 bit executable (forcing bits=64).") - elif compiler_version_str == "x86" or compiler_version_str == "amd64_x86": - print("Compiled program architecture will be a 32 bit executable. (forcing bits=32).") - else: - print( - "Failed to manually detect MSVC compiler architecture version... Defaulting to 32bit executable settings" - " (forcing bits=32). Compilation attempt will continue, but SCons can not detect for what architecture this" - " build is compiled for. You should check your settings/compilation setup, or avoid setting VCINSTALLDIR." - ) + sys.exit(200) + + print("Found MSVC, arch %s" % (env_arch)) def setup_msvc_auto(env): @@ -141,6 +262,18 @@ def setup_msvc_auto(env): # If MSVC_VERSION is set by SCons, we know MSVC is installed. # But we may want a different version or target arch. + # Valid architectures for MSVC's TARGET_ARCH: + # ['amd64', 'emt64', 'i386', 'i486', 'i586', 'i686', 'ia64', 'itanium', 'x86', 'x86_64', 'arm', 'arm64', 'aarch64'] + # Our x86_64 and arm64 are the same, and we need to map the 32-bit + # architectures to other names since MSVC isn't as explicit. + # The rest we don't need to worry about because they are + # aliases or aren't supported by Godot (itanium & ia64). + msvc_arch_aliases = {"x86_32": "x86", "arm32": "arm"} + if env["arch"] in msvc_arch_aliases.keys(): + env["TARGET_ARCH"] = msvc_arch_aliases[env["arch"]] + else: + env["TARGET_ARCH"] = env["arch"] + # The env may have already been set up with default MSVC tools, so # reset a few things so we can set it up with the tools we want. # (Ideally we'd decide on the tool config before configuring any @@ -149,35 +282,55 @@ def setup_msvc_auto(env): env["MSVC_SETUP_RUN"] = False # Need to set this to re-run the tool env["MSVS_VERSION"] = None env["MSVC_VERSION"] = None - env["TARGET_ARCH"] = None - if env["bits"] != "default": - env["TARGET_ARCH"] = {"32": "x86", "64": "x86_64"}[env["bits"]] + if "msvc_version" in env: env["MSVC_VERSION"] = env["msvc_version"] env.Tool("msvc") 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 - # Get actual target arch into bits (it may be "default" at this point): - if env["TARGET_ARCH"] in ("amd64", "x86_64"): - env["bits"] = "64" - else: - env["bits"] = "32" - print("Found MSVC version %s, arch %s, bits=%s" % (env["MSVC_VERSION"], env["TARGET_ARCH"], env["bits"])) - if env["TARGET_ARCH"] in ("amd64", "x86_64"): - env["x86_libtheora_opt_vc"] = False + print("Found MSVC version %s, arch %s" % (env["MSVC_VERSION"], env["arch"])) def setup_mingw(env): """Set up env for use with mingw""" - # Nothing to do here - print("Using MinGW") + 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). + """ + ) + sys.exit(201) -def configure_msvc(env, manual_msvc_config): + 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. + """ + % (env["arch"], env_arch) + ) + sys.exit(202) + + 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("Using MinGW, arch %s" % (env["arch"])) + + +def configure_msvc(env, vcvars_msvc_config): """Configure env to work with MSVC""" # Build type - if env["target"] == "release": if env["optimize"] == "speed": # optimize for speed (default) env.Append(CCFLAGS=["/O2"]) @@ -198,7 +351,6 @@ def configure_msvc(env, manual_msvc_config): elif env["target"] == "debug": env.AppendUnique(CCFLAGS=["/Zi", "/FS", "/Od", "/EHsc"]) # Allow big objects. Only needed for debug, see MinGW branch for rationale. - env.AppendUnique(CCFLAGS=["/bigobj"]) env.Append(LINKFLAGS=["/DEBUG"]) if env["debug_symbols"]: @@ -218,11 +370,18 @@ def configure_msvc(env, manual_msvc_config): else: env.AppendUnique(CCFLAGS=["/MD"]) + if env["arch"] == "x86_32": + env["x86_libtheora_opt_vc"] = True + env.AppendUnique(CCFLAGS=["/Gd", "/GR", "/nologo"]) env.AppendUnique(CCFLAGS=["/utf-8"]) # Force to use Unicode encoding. env.AppendUnique(CXXFLAGS=["/TP"]) # assume all sources are C++ + # Once it was thought that only debug builds would be too large, + # but this has recently stopped being true. See the mingw function + # for notes on why this shouldn't be enabled for gcc + env.AppendUnique(CCFLAGS=["/bigobj"]) - if manual_msvc_config: # should be automatic if SCons found it + if vcvars_msvc_config: # should be automatic if SCons found it if os.getenv("WindowsSdkDir") is not None: env.Prepend(CPPPATH=[os.getenv("WindowsSdkDir") + "/Include"]) else: @@ -241,7 +400,7 @@ def configure_msvc(env, manual_msvc_config): ] ) env.AppendUnique(CPPDEFINES=["NOMINMAX"]) # disable bogus min/max WinDef.h macros - if env["bits"] == "64": + if env["arch"] == "x86_64": env.AppendUnique(CPPDEFINES=["_WIN64"]) ## Libs @@ -267,6 +426,7 @@ def configure_msvc(env, manual_msvc_config): "bcrypt", "Avrt", "dwmapi", + "dwrite", ] if env["vulkan"]: @@ -280,7 +440,7 @@ def configure_msvc(env, manual_msvc_config): env.Append(LINKFLAGS=[p + env["LIBSUFFIX"] for p in LIBS]) - if manual_msvc_config: + if vcvars_msvc_config: if os.getenv("WindowsSdkDir") is not None: env.Append(LIBPATH=[os.getenv("WindowsSdkDir") + "/Lib"]) else: @@ -288,7 +448,10 @@ def configure_msvc(env, manual_msvc_config): ## LTO - if env["use_lto"]: + if env["lto"] != "none": + if env["lto"] == "thin": + print("ThinLTO is only compatible with LLVM, use `use_llvm=yes` or `lto=full`.") + sys.exit(255) env.AppendUnique(CCFLAGS=["/GL"]) env.AppendUnique(ARFLAGS=["/LTCG"]) if env["progress"]: @@ -296,7 +459,7 @@ def configure_msvc(env, manual_msvc_config): else: env.AppendUnique(LINKFLAGS=["/LTCG"]) - if manual_msvc_config: + if vcvars_msvc_config: env.Prepend(CPPPATH=[p for p in os.getenv("INCLUDE").split(";")]) env.Append(LIBPATH=[p for p in os.getenv("LIB").split(";")]) @@ -320,14 +483,20 @@ def configure_mingw(env): ## Build type + if not env["use_llvm"] and not try_cmd("gcc --version", env["mingw_prefix"], env["arch"]): + env["use_llvm"] = True + + if env["use_llvm"] and not try_cmd("clang --version", env["mingw_prefix"], env["arch"]): + env["use_llvm"] = False + if env["target"] == "release": env.Append(CCFLAGS=["-msse2"]) if env["optimize"] == "speed": # optimize for speed (default) - if env["bits"] == "64": - env.Append(CCFLAGS=["-O3"]) - else: + if env["arch"] == "x86_32": env.Append(CCFLAGS=["-O2"]) + else: + env.Append(CCFLAGS=["-O3"]) else: # optimize for size env.Prepend(CCFLAGS=["-Os"]) @@ -361,60 +530,68 @@ def configure_mingw(env): if os.name != "nt": env["PROGSUFFIX"] = env["PROGSUFFIX"] + ".exe" # for linux cross-compilation - if env["bits"] == "default": - if os.name == "nt": - env["bits"] = "64" if "PROGRAMFILES(X86)" in os.environ else "32" - else: # default to 64-bit on Linux - env["bits"] = "64" - - mingw_prefix = "" - - if env["bits"] == "32": + if env["arch"] == "x86_32": if env["use_static_cpp"]: env.Append(LINKFLAGS=["-static"]) env.Append(LINKFLAGS=["-static-libgcc"]) env.Append(LINKFLAGS=["-static-libstdc++"]) - mingw_prefix = env["mingw_prefix_32"] else: if env["use_static_cpp"]: env.Append(LINKFLAGS=["-static"]) - mingw_prefix = env["mingw_prefix_64"] - if env["use_llvm"]: - env["CC"] = mingw_prefix + "clang" - env["CXX"] = mingw_prefix + "clang++" - env["AS"] = mingw_prefix + "as" - env["AR"] = mingw_prefix + "ar" - env["RANLIB"] = mingw_prefix + "ranlib" - else: - env["CC"] = mingw_prefix + "gcc" - env["CXX"] = mingw_prefix + "g++" - env["AS"] = mingw_prefix + "as" - env["AR"] = mingw_prefix + "gcc-ar" - env["RANLIB"] = mingw_prefix + "gcc-ranlib" + if env["arch"] in ["x86_32", "x86_64"]: + env["x86_libtheora_opt_gcc"] = True - env["x86_libtheora_opt_gcc"] = True + mingw_bin_prefix = get_mingw_bin_prefix(env["mingw_prefix"], env["arch"]) - if env["use_lto"]: - if not env["use_llvm"] and env.GetOption("num_jobs") > 1: + if env["use_llvm"]: + env["CC"] = mingw_bin_prefix + "clang" + env["CXX"] = mingw_bin_prefix + "clang++" + if try_cmd("as --version", env["mingw_prefix"], env["arch"]): + env["AS"] = mingw_bin_prefix + "as" + if try_cmd("ar --version", env["mingw_prefix"], env["arch"]): + env["AR"] = mingw_bin_prefix + "ar" + if try_cmd("ranlib --version", env["mingw_prefix"], env["arch"]): + env["RANLIB"] = mingw_bin_prefix + "ranlib" + env.extra_suffix = ".llvm" + env.extra_suffix + else: + env["CC"] = mingw_bin_prefix + "gcc" + env["CXX"] = mingw_bin_prefix + "g++" + if try_cmd("as --version", env["mingw_prefix"], env["arch"]): + env["AS"] = mingw_bin_prefix + "as" + if try_cmd("gcc-ar --version", env["mingw_prefix"], env["arch"]): + env["AR"] = mingw_bin_prefix + "gcc-ar" + if try_cmd("gcc-ranlib --version", env["mingw_prefix"], env["arch"]): + env["RANLIB"] = mingw_bin_prefix + "gcc-ranlib" + + 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`.") + sys.exit(255) + env.Append(CCFLAGS=["-flto=thin"]) + env.Append(LINKFLAGS=["-flto=thin"]) + elif not env["use_llvm"] and env.GetOption("num_jobs") > 1: env.Append(CCFLAGS=["-flto"]) env.Append(LINKFLAGS=["-flto=" + str(env.GetOption("num_jobs"))]) else: - if env["use_thinlto"]: - env.Append(CCFLAGS=["-flto=thin"]) - env.Append(LINKFLAGS=["-flto=thin"]) - else: - env.Append(CCFLAGS=["-flto"]) - env.Append(LINKFLAGS=["-flto"]) + env.Append(CCFLAGS=["-flto"]) + env.Append(LINKFLAGS=["-flto"]) env.Append(LINKFLAGS=["-Wl,--stack," + str(STACK_SIZE)]) ## Compile flags - env.Append(CCFLAGS=["-mwindows"]) + if not env["use_llvm"]: + env.Append(CCFLAGS=["-mwindows"]) env.Append(CPPDEFINES=["WINDOWS_ENABLED", "WASAPI_ENABLED", "WINMIDI_ENABLED"]) - env.Append(CPPDEFINES=[("WINVER", env["target_win_version"]), ("_WIN32_WINNT", env["target_win_version"])]) + env.Append( + CPPDEFINES=[ + ("WINVER", env["target_win_version"]), + ("_WIN32_WINNT", env["target_win_version"]), + ] + ) env.Append( LIBS=[ "mingw32", @@ -438,6 +615,7 @@ def configure_mingw(env): "avrt", "uuid", "dwmapi", + "dwrite", ] ) @@ -455,32 +633,38 @@ def configure_mingw(env): def configure(env): + # Validate arch. + supported_arches = ["x86_32", "x86_64", "arm32", "arm64"] + if env["arch"] not in supported_arches: + print( + 'Unsupported CPU architecture "%s" for Windows. Supported architectures are: %s.' + % (env["arch"], ", ".join(supported_arches)) + ) + sys.exit() + # At this point the env has been set up with basic tools/compilers. env.Prepend(CPPPATH=["#platform/windows"]) - print("Configuring for Windows: target=%s, bits=%s" % (env["target"], env["bits"])) - if os.name == "nt": env["ENV"] = os.environ # this makes build less repeatable, but simplifies some things env["ENV"]["TMP"] = os.environ["TMP"] # First figure out which compiler, version, and target arch we're using - if os.getenv("VCINSTALLDIR") and not env["use_mingw"]: - # Manual setup of MSVC + if os.getenv("VCINSTALLDIR") and detect_build_env_arch() and not env["use_mingw"]: setup_msvc_manual(env) env.msvc = True - manual_msvc_config = True + vcvars_msvc_config = True elif env.get("MSVC_VERSION", "") and not env["use_mingw"]: setup_msvc_auto(env) env.msvc = True - manual_msvc_config = False + vcvars_msvc_config = False else: setup_mingw(env) env.msvc = False # Now set compiler/linker flags if env.msvc: - configure_msvc(env, manual_msvc_config) + configure_msvc(env, vcvars_msvc_config) else: # MinGW configure_mingw(env) diff --git a/platform/windows/display_server_windows.cpp b/platform/windows/display_server_windows.cpp index e66fa142a7..237215c198 100644 --- a/platform/windows/display_server_windows.cpp +++ b/platform/windows/display_server_windows.cpp @@ -37,6 +37,11 @@ #include "scene/resources/texture.h" #include <avrt.h> +#include <dwmapi.h> + +#ifndef DWMWA_USE_IMMERSIVE_DARK_MODE +#define DWMWA_USE_IMMERSIVE_DARK_MODE 20 +#endif #if defined(GLES3_ENABLED) #include "drivers/gles3/rasterizer_gles3.h" @@ -144,8 +149,8 @@ bool DisplayServerWindows::tts_is_paused() const { return tts->is_paused(); } -Array DisplayServerWindows::tts_get_voices() const { - ERR_FAIL_COND_V(!tts, Array()); +TypedArray<Dictionary> DisplayServerWindows::tts_get_voices() const { + ERR_FAIL_COND_V(!tts, TypedArray<Dictionary>()); return tts->get_voices(); } @@ -531,10 +536,43 @@ DisplayServer::ScreenOrientation DisplayServerWindows::screen_get_orientation(in } void DisplayServerWindows::screen_set_keep_on(bool p_enable) { + if (keep_screen_on == p_enable) { + return; + } + + if (p_enable) { + const String reason = "Godot Engine running with display/window/energy_saving/keep_screen_on = true"; + Char16String reason_utf16 = reason.utf16(); + + REASON_CONTEXT context; + context.Version = POWER_REQUEST_CONTEXT_VERSION; + context.Flags = POWER_REQUEST_CONTEXT_SIMPLE_STRING; + context.Reason.SimpleReasonString = (LPWSTR)(reason_utf16.ptrw()); + power_request = PowerCreateRequest(&context); + if (power_request == INVALID_HANDLE_VALUE) { + print_error("Failed to enable screen_keep_on."); + return; + } + if (PowerSetRequest(power_request, POWER_REQUEST_TYPE::PowerRequestSystemRequired) == 0) { + print_error("Failed to request system sleep override."); + return; + } + if (PowerSetRequest(power_request, POWER_REQUEST_TYPE::PowerRequestDisplayRequired) == 0) { + print_error("Failed to request display timeout override."); + return; + } + } else { + PowerClearRequest(power_request, POWER_REQUEST_TYPE::PowerRequestSystemRequired); + PowerClearRequest(power_request, POWER_REQUEST_TYPE::PowerRequestDisplayRequired); + CloseHandle(power_request); + power_request = nullptr; + } + + keep_screen_on = p_enable; } bool DisplayServerWindows::screen_is_kept_on() const { - return false; + return keep_screen_on; } Vector<DisplayServer::WindowID> DisplayServerWindows::get_window_list() const { @@ -1274,7 +1312,28 @@ void DisplayServerWindows::window_set_flag(WindowFlags p_flag, bool p_enabled, W _update_window_style(p_window); } break; case WINDOW_FLAG_TRANSPARENT: { - // FIXME: Implement. + if (p_enabled) { + //enable per-pixel alpha + + DWM_BLURBEHIND bb = { 0 }; + HRGN hRgn = CreateRectRgn(0, 0, -1, -1); + bb.dwFlags = DWM_BB_ENABLE | DWM_BB_BLURREGION; + bb.hRgnBlur = hRgn; + bb.fEnable = TRUE; + DwmEnableBlurBehindWindow(wd.hWnd, &bb); + + wd.layered_window = true; + } else { + //disable per-pixel alpha + wd.layered_window = false; + + DWM_BLURBEHIND bb = { 0 }; + HRGN hRgn = CreateRectRgn(0, 0, -1, -1); + bb.dwFlags = DWM_BB_ENABLE | DWM_BB_BLURREGION; + bb.hRgnBlur = hRgn; + bb.fEnable = FALSE; + DwmEnableBlurBehindWindow(wd.hWnd, &bb); + } } break; case WINDOW_FLAG_NO_FOCUS: { wd.no_focus = p_enabled; @@ -1306,7 +1365,7 @@ bool DisplayServerWindows::window_get_flag(WindowFlags p_flag, WindowID p_window return wd.always_on_top; } break; case WINDOW_FLAG_TRANSPARENT: { - // FIXME: Implement. + return wd.layered_window; } break; case WINDOW_FLAG_NO_FOCUS: { return wd.no_focus; @@ -1437,7 +1496,7 @@ void DisplayServerWindows::cursor_set_shape(CursorShape p_shape) { IDC_HELP }; - if (cursors[p_shape] != nullptr) { + if (cursors_cache.has(p_shape)) { SetCursor(cursors[p_shape]); } else { SetCursor(LoadCursor(hInstance, win_cursors[p_shape])); @@ -1450,55 +1509,6 @@ DisplayServer::CursorShape DisplayServerWindows::cursor_get_shape() const { return cursor_shape; } -void DisplayServerWindows::GetMaskBitmaps(HBITMAP hSourceBitmap, COLORREF clrTransparent, OUT HBITMAP &hAndMaskBitmap, OUT HBITMAP &hXorMaskBitmap) { - // Get the system display DC. - HDC hDC = GetDC(nullptr); - - // Create helper DC. - HDC hMainDC = CreateCompatibleDC(hDC); - HDC hAndMaskDC = CreateCompatibleDC(hDC); - HDC hXorMaskDC = CreateCompatibleDC(hDC); - - // Get the dimensions of the source bitmap. - BITMAP bm; - GetObject(hSourceBitmap, sizeof(BITMAP), &bm); - - // Create the mask bitmaps. - hAndMaskBitmap = CreateCompatibleBitmap(hDC, bm.bmWidth, bm.bmHeight); // Color. - hXorMaskBitmap = CreateCompatibleBitmap(hDC, bm.bmWidth, bm.bmHeight); // Color. - - // Release the system display DC. - ReleaseDC(nullptr, hDC); - - // Select the bitmaps to helper DC. - HBITMAP hOldMainBitmap = (HBITMAP)SelectObject(hMainDC, hSourceBitmap); - HBITMAP hOldAndMaskBitmap = (HBITMAP)SelectObject(hAndMaskDC, hAndMaskBitmap); - HBITMAP hOldXorMaskBitmap = (HBITMAP)SelectObject(hXorMaskDC, hXorMaskBitmap); - - // Assign the monochrome AND mask bitmap pixels so that the pixels of the source bitmap - // with 'clrTransparent' will be white pixels of the monochrome bitmap. - SetBkColor(hMainDC, clrTransparent); - BitBlt(hAndMaskDC, 0, 0, bm.bmWidth, bm.bmHeight, hMainDC, 0, 0, SRCCOPY); - - // Assign the color XOR mask bitmap pixels so that the pixels of the source bitmap - // with 'clrTransparent' will be black and rest the pixels same as corresponding - // pixels of the source bitmap. - SetBkColor(hXorMaskDC, RGB(0, 0, 0)); - SetTextColor(hXorMaskDC, RGB(255, 255, 255)); - BitBlt(hXorMaskDC, 0, 0, bm.bmWidth, bm.bmHeight, hAndMaskDC, 0, 0, SRCCOPY); - BitBlt(hXorMaskDC, 0, 0, bm.bmWidth, bm.bmHeight, hMainDC, 0, 0, SRCAND); - - // Deselect bitmaps from the helper DC. - SelectObject(hMainDC, hOldMainBitmap); - SelectObject(hAndMaskDC, hOldAndMaskBitmap); - SelectObject(hXorMaskDC, hOldXorMaskBitmap); - - // Delete the helper DC. - DeleteDC(hXorMaskDC); - DeleteDC(hAndMaskDC); - DeleteDC(hMainDC); -} - void DisplayServerWindows::cursor_set_custom_image(const Ref<Resource> &p_cursor, CursorShape p_shape, const Vector2 &p_hotspot) { _THREAD_SAFE_METHOD_ @@ -1551,8 +1561,26 @@ void DisplayServerWindows::cursor_set_custom_image(const Ref<Resource> &p_cursor UINT image_size = texture_size.width * texture_size.height; // Create the BITMAP with alpha channel. - COLORREF *buffer = (COLORREF *)memalloc(sizeof(COLORREF) * image_size); - + COLORREF *buffer = nullptr; + + BITMAPV5HEADER bi; + ZeroMemory(&bi, sizeof(bi)); + bi.bV5Size = sizeof(bi); + bi.bV5Width = texture_size.width; + bi.bV5Height = -texture_size.height; + bi.bV5Planes = 1; + bi.bV5BitCount = 32; + bi.bV5Compression = BI_BITFIELDS; + bi.bV5RedMask = 0x00ff0000; + bi.bV5GreenMask = 0x0000ff00; + bi.bV5BlueMask = 0x000000ff; + bi.bV5AlphaMask = 0xff000000; + + HDC dc = GetDC(nullptr); + HBITMAP bitmap = CreateDIBSection(dc, reinterpret_cast<BITMAPINFO *>(&bi), DIB_RGB_COLORS, reinterpret_cast<void **>(&buffer), nullptr, 0); + HBITMAP mask = CreateBitmap(texture_size.width, texture_size.height, 1, 1, nullptr); + + bool fully_transparent = true; for (UINT index = 0; index < image_size; index++) { int row_index = floor(index / texture_size.width) + atlas_rect.position.y; int column_index = (index % int(texture_size.width)) + atlas_rect.position.x; @@ -1561,39 +1589,28 @@ void DisplayServerWindows::cursor_set_custom_image(const Ref<Resource> &p_cursor column_index = MIN(column_index, atlas_rect.size.width - 1); row_index = MIN(row_index, atlas_rect.size.height - 1); } + const Color &c = image->get_pixel(column_index, row_index); + fully_transparent = fully_transparent && (c.a == 0.f); - *(buffer + index) = image->get_pixel(column_index, row_index).to_argb32(); - } - - // Using 4 channels, so 4 * 8 bits. - HBITMAP bitmap = CreateBitmap(texture_size.width, texture_size.height, 1, 4 * 8, buffer); - COLORREF clrTransparent = -1; - - // Create the AND and XOR masks for the bitmap. - HBITMAP hAndMask = nullptr; - HBITMAP hXorMask = nullptr; - - GetMaskBitmaps(bitmap, clrTransparent, hAndMask, hXorMask); - - if (nullptr == hAndMask || nullptr == hXorMask) { - memfree(buffer); - DeleteObject(bitmap); - return; + *(buffer + index) = c.to_argb32(); } // Finally, create the icon. - ICONINFO iconinfo; - iconinfo.fIcon = FALSE; - iconinfo.xHotspot = p_hotspot.x; - iconinfo.yHotspot = p_hotspot.y; - iconinfo.hbmMask = hAndMask; - iconinfo.hbmColor = hXorMask; - if (cursors[p_shape]) { DestroyIcon(cursors[p_shape]); } - cursors[p_shape] = CreateIconIndirect(&iconinfo); + if (fully_transparent) { + cursors[p_shape] = nullptr; + } else { + ICONINFO iconinfo; + iconinfo.fIcon = FALSE; + iconinfo.xHotspot = p_hotspot.x; + iconinfo.yHotspot = p_hotspot.y; + iconinfo.hbmMask = mask; + iconinfo.hbmColor = bitmap; + cursors[p_shape] = CreateIconIndirect(&iconinfo); + } Vector<Variant> params; params.push_back(p_cursor); @@ -1606,17 +1623,15 @@ void DisplayServerWindows::cursor_set_custom_image(const Ref<Resource> &p_cursor } } - DeleteObject(hAndMask); - DeleteObject(hXorMask); - - memfree(buffer); + DeleteObject(mask); DeleteObject(bitmap); + ReleaseDC(nullptr, dc); } else { // Reset to default system cursor. if (cursors[p_shape]) { DestroyIcon(cursors[p_shape]); - cursors[p_shape] = nullptr; } + cursors[p_shape] = nullptr; CursorShape c = cursor_shape; cursor_shape = CURSOR_MAX; @@ -2035,7 +2050,7 @@ void DisplayServerWindows::_send_window_event(const WindowData &wd, WindowEvent Variant *eventp = &event; Variant ret; Callable::CallError ce; - wd.event_callback.call((const Variant **)&eventp, 1, ret, ce); + wd.event_callback.callp((const Variant **)&eventp, 1, ret, ce); } } @@ -2062,7 +2077,7 @@ void DisplayServerWindows::_dispatch_input_event(const Ref<InputEvent> &p_event) if (windows.has(E->get())) { Callable callable = windows[E->get()].input_event_callback; if (callable.is_valid()) { - callable.call((const Variant **)&evp, 1, ret, ce); + callable.callp((const Variant **)&evp, 1, ret, ce); } } in_dispatch_input_event = false; @@ -2076,7 +2091,7 @@ void DisplayServerWindows::_dispatch_input_event(const Ref<InputEvent> &p_event) if (windows.has(event_from_window->get_window_id())) { Callable callable = windows[event_from_window->get_window_id()].input_event_callback; if (callable.is_valid()) { - callable.call((const Variant **)&evp, 1, ret, ce); + callable.callp((const Variant **)&evp, 1, ret, ce); } } } else { @@ -2084,7 +2099,7 @@ void DisplayServerWindows::_dispatch_input_event(const Ref<InputEvent> &p_event) for (const KeyValue<WindowID, WindowData> &E : windows) { const Callable callable = E.value.input_event_callback; if (callable.is_valid()) { - callable.call((const Variant **)&evp, 1, ret, ce); + callable.callp((const Variant **)&evp, 1, ret, ce); } } } @@ -2358,6 +2373,20 @@ LRESULT DisplayServerWindows::WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARA case WM_PAINT: { Main::force_redraw(); } break; + case WM_SETTINGCHANGE: { + if (lParam && CompareStringOrdinal(reinterpret_cast<LPCWCH>(lParam), -1, L"ImmersiveColorSet", -1, true) == CSTR_EQUAL) { + if (is_dark_mode_supported() && dark_title_available) { + BOOL value = is_dark_mode(); + ::DwmSetWindowAttribute(windows[window_id].hWnd, DWMWA_USE_IMMERSIVE_DARK_MODE, &value, sizeof(value)); + } + } + } break; + case WM_THEMECHANGED: { + if (is_dark_mode_supported() && dark_title_available) { + BOOL value = is_dark_mode(); + ::DwmSetWindowAttribute(windows[window_id].hWnd, DWMWA_USE_IMMERSIVE_DARK_MODE, &value, sizeof(value)); + } + } break; case WM_SYSCOMMAND: // Intercept system commands. { switch (wParam) // Check system calls. @@ -2382,7 +2411,7 @@ LRESULT DisplayServerWindows::WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARA } case WM_MOUSELEAVE: { old_invalid = true; - outside = true; + windows[window_id].mouse_outside = true; _send_window_event(windows[window_id], WINDOW_EVENT_MOUSE_EXIT); @@ -2612,7 +2641,7 @@ LRESULT DisplayServerWindows::WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARA } } - if (outside) { + if (windows[window_id].mouse_outside) { // Mouse enter. if (mouse_mode != MOUSE_MODE_CAPTURED) { @@ -2622,7 +2651,7 @@ LRESULT DisplayServerWindows::WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARA CursorShape c = cursor_shape; cursor_shape = CURSOR_MAX; cursor_set_shape(c); - outside = false; + windows[window_id].mouse_outside = false; // Once-off notification, must call again. track_mouse_leave_event(hWnd); @@ -2713,7 +2742,7 @@ LRESULT DisplayServerWindows::WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARA } } - if (outside) { + if (windows[window_id].mouse_outside) { // Mouse enter. if (mouse_mode != MOUSE_MODE_CAPTURED) { @@ -2723,7 +2752,7 @@ LRESULT DisplayServerWindows::WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARA CursorShape c = cursor_shape; cursor_shape = CURSOR_MAX; cursor_set_shape(c); - outside = false; + windows[window_id].mouse_outside = false; // Once-off notification, must call again. track_mouse_leave_event(hWnd); @@ -3039,7 +3068,7 @@ LRESULT DisplayServerWindows::WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARA const Variant *args[] = { &size }; Variant ret; Callable::CallError ce; - window.rect_changed_callback.call(args, 1, ret, ce); + window.rect_changed_callback.callp(args, 1, ret, ce); } } @@ -3199,7 +3228,7 @@ LRESULT DisplayServerWindows::WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARA Variant *vp = &v; Variant ret; Callable::CallError ce; - windows[window_id].drop_files_callback.call((const Variant **)&vp, 1, ret, ce); + windows[window_id].drop_files_callback.callp((const Variant **)&vp, 1, ret, ce); } } break; default: { @@ -3458,10 +3487,21 @@ DisplayServer::WindowID DisplayServerWindows::_create_window(WindowMode p_mode, windows.erase(id); ERR_FAIL_V_MSG(INVALID_WINDOW_ID, "Failed to create Windows OS window."); } + if (p_mode == WINDOW_MODE_FULLSCREEN || p_mode == WINDOW_MODE_EXCLUSIVE_FULLSCREEN) { + wd.fullscreen = true; + if (p_mode == WINDOW_MODE_FULLSCREEN) { + wd.multiwindow_fs = true; + } + } if (p_mode != WINDOW_MODE_FULLSCREEN && p_mode != WINDOW_MODE_EXCLUSIVE_FULLSCREEN) { wd.pre_fs_valid = true; } + if (is_dark_mode_supported() && dark_title_available) { + BOOL value = is_dark_mode(); + ::DwmSetWindowAttribute(wd.hWnd, DWMWA_USE_IMMERSIVE_DARK_MODE, &value, sizeof(value)); + } + #ifdef VULKAN_ENABLED if (context_vulkan) { if (context_vulkan->window_create(id, p_vsync_mode, wd.hWnd, hInstance, WindowRect.right - WindowRect.left, WindowRect.bottom - WindowRect.top) == -1) { @@ -3548,6 +3588,15 @@ WTInfoPtr DisplayServerWindows::wintab_WTInfo = nullptr; WTPacketPtr DisplayServerWindows::wintab_WTPacket = nullptr; WTEnablePtr DisplayServerWindows::wintab_WTEnable = nullptr; +// UXTheme API. +bool DisplayServerWindows::dark_title_available = false; +bool DisplayServerWindows::ux_theme_available = false; +IsDarkModeAllowedForAppPtr DisplayServerWindows::IsDarkModeAllowedForApp = nullptr; +ShouldAppsUseDarkModePtr DisplayServerWindows::ShouldAppsUseDarkMode = nullptr; +GetImmersiveColorFromColorSetExPtr DisplayServerWindows::GetImmersiveColorFromColorSetEx = nullptr; +GetImmersiveColorTypeFromNamePtr DisplayServerWindows::GetImmersiveColorTypeFromName = nullptr; +GetImmersiveUserColorSetPreferencePtr DisplayServerWindows::GetImmersiveUserColorSetPreference = nullptr; + // Windows Ink API. bool DisplayServerWindows::winink_available = false; GetPointerTypePtr DisplayServerWindows::win8p_GetPointerType = nullptr; @@ -3559,6 +3608,23 @@ typedef enum _SHC_PROCESS_DPI_AWARENESS { SHC_PROCESS_PER_MONITOR_DPI_AWARE = 2 } SHC_PROCESS_DPI_AWARENESS; +bool DisplayServerWindows::is_dark_mode_supported() const { + return ux_theme_available && IsDarkModeAllowedForApp(); +} + +bool DisplayServerWindows::is_dark_mode() const { + return ux_theme_available && ShouldAppsUseDarkMode(); +} + +Color DisplayServerWindows::get_accent_color() const { + if (!ux_theme_available) { + return Color(0, 0, 0, 0); + } + + int argb = GetImmersiveColorFromColorSetEx((UINT)GetImmersiveUserColorSetPreference(false, false), GetImmersiveColorTypeFromName(L"ImmersiveSystemAccent"), false, 0); + return Color((argb & 0xFF) / 255.f, ((argb & 0xFF00) >> 8) / 255.f, ((argb & 0xFF0000) >> 16) / 255.f, ((argb & 0xFF000000) >> 24) / 255.f); +} + int DisplayServerWindows::tablet_get_driver_count() const { return tablet_drivers.size(); } @@ -3608,13 +3674,43 @@ DisplayServerWindows::DisplayServerWindows(const String &p_rendering_driver, Win old_invalid = true; mouse_mode = MOUSE_MODE_VISIBLE; - outside = true; - rendering_driver = p_rendering_driver; // Init TTS tts = memnew(TTS_Windows); + // Enforce default keep screen on value. + screen_set_keep_on(GLOBAL_GET("display/window/energy_saving/keep_screen_on")); + + // Load Windows version info. + OSVERSIONINFOW os_ver; + ZeroMemory(&os_ver, sizeof(OSVERSIONINFOW)); + os_ver.dwOSVersionInfoSize = sizeof(OSVERSIONINFOW); + + HMODULE nt_lib = LoadLibraryW(L"ntdll.dll"); + if (nt_lib) { + RtlGetVersionPtr RtlGetVersion = (RtlGetVersionPtr)GetProcAddress(nt_lib, "RtlGetVersion"); + if (RtlGetVersion) { + RtlGetVersion(&os_ver); + } + FreeLibrary(nt_lib); + } + + // Load UXTheme. + HMODULE ux_theme_lib = LoadLibraryW(L"uxtheme.dll"); + if (ux_theme_lib) { + IsDarkModeAllowedForApp = (IsDarkModeAllowedForAppPtr)GetProcAddress(ux_theme_lib, MAKEINTRESOURCEA(136)); + ShouldAppsUseDarkMode = (ShouldAppsUseDarkModePtr)GetProcAddress(ux_theme_lib, MAKEINTRESOURCEA(132)); + GetImmersiveColorFromColorSetEx = (GetImmersiveColorFromColorSetExPtr)GetProcAddress(ux_theme_lib, MAKEINTRESOURCEA(95)); + GetImmersiveColorTypeFromName = (GetImmersiveColorTypeFromNamePtr)GetProcAddress(ux_theme_lib, MAKEINTRESOURCEA(96)); + GetImmersiveUserColorSetPreference = (GetImmersiveUserColorSetPreferencePtr)GetProcAddress(ux_theme_lib, MAKEINTRESOURCEA(98)); + + ux_theme_available = IsDarkModeAllowedForApp && ShouldAppsUseDarkMode && GetImmersiveColorFromColorSetEx && GetImmersiveColorTypeFromName && GetImmersiveUserColorSetPreference; + if (os_ver.dwBuildNumber >= 22000) { + dark_title_available = true; + } + } + // Note: Wacom WinTab driver API for pen input, for devices incompatible with Windows Ink. HMODULE wintab_lib = LoadLibraryW(L"wintab32.dll"); if (wintab_lib) { @@ -3818,6 +3914,9 @@ DisplayServerWindows::~DisplayServerWindows() { SetWindowLongPtr(windows[MAIN_WINDOW_ID].hWnd, GWLP_WNDPROC, (LONG_PTR)user_proc); } + // Close power request handle. + screen_set_keep_on(false); + #ifdef GLES3_ENABLED // destroy windows .. NYI? // FIXME wglDeleteContext is never called diff --git a/platform/windows/display_server_windows.h b/platform/windows/display_server_windows.h index 0429bed3a0..fd64a02020 100644 --- a/platform/windows/display_server_windows.h +++ b/platform/windows/display_server_windows.h @@ -152,6 +152,13 @@ typedef UINT(WINAPI *WTInfoPtr)(UINT p_category, UINT p_index, LPVOID p_output); typedef BOOL(WINAPI *WTPacketPtr)(HANDLE p_ctx, UINT p_param, LPVOID p_packets); typedef BOOL(WINAPI *WTEnablePtr)(HANDLE p_ctx, BOOL p_enable); +typedef bool(WINAPI *IsDarkModeAllowedForAppPtr)(); +typedef bool(WINAPI *ShouldAppsUseDarkModePtr)(); +typedef DWORD(WINAPI *GetImmersiveColorFromColorSetExPtr)(UINT dwImmersiveColorSet, UINT dwImmersiveColorType, bool bIgnoreHighContrast, UINT dwHighContrastCacheMode); +typedef int(WINAPI *GetImmersiveColorTypeFromNamePtr)(const WCHAR *name); +typedef int(WINAPI *GetImmersiveUserColorSetPreferencePtr)(bool bForceCheckRegistry, bool bSkipCheckOnFail); +typedef HRESULT(WINAPI *RtlGetVersionPtr)(OSVERSIONINFOW *lpVersionInformation); + // Windows Ink API #ifndef POINTER_STRUCTURES @@ -278,6 +285,15 @@ class DisplayServerWindows : public DisplayServer { _THREAD_SAFE_CLASS_ + // UXTheme API + static bool dark_title_available; + static bool ux_theme_available; + static IsDarkModeAllowedForAppPtr IsDarkModeAllowedForApp; + static ShouldAppsUseDarkModePtr ShouldAppsUseDarkMode; + static GetImmersiveColorFromColorSetExPtr GetImmersiveColorFromColorSetEx; + static GetImmersiveColorTypeFromNamePtr GetImmersiveColorTypeFromName; + static GetImmersiveUserColorSetPreferencePtr GetImmersiveUserColorSetPreference; + // WinTab API static bool wintab_available; static WTOpenPtr wintab_WTOpen; @@ -295,8 +311,6 @@ class DisplayServerWindows : public DisplayServer { String tablet_driver; Vector<String> tablet_drivers; - void GetMaskBitmaps(HBITMAP hSourceBitmap, COLORREF clrTransparent, OUT HBITMAP &hAndMaskBitmap, OUT HBITMAP &hXorMaskBitmap); - enum { KEY_EVENT_BUFFER_SIZE = 512 }; @@ -313,7 +327,6 @@ class DisplayServerWindows : public DisplayServer { int key_event_pos; bool old_invalid; - bool outside; int old_x, old_y; Point2i center; @@ -332,12 +345,13 @@ class DisplayServerWindows : public DisplayServer { HINSTANCE hInstance; // Holds The Instance Of The Application String rendering_driver; bool app_focused = false; + bool keep_screen_on = false; + HANDLE power_request; TTS_Windows *tts = nullptr; struct WindowData { HWND hWnd; - //layered window Vector<Vector2> mpath; @@ -377,16 +391,13 @@ class DisplayServerWindows : public DisplayServer { Vector2 last_tilt; bool last_pen_inverted = false; - HBITMAP hBitmap; //DIB section for layered window - uint8_t *dib_data = nullptr; - Size2 dib_size; - HDC hDC_dib; Size2 min_size; Size2 max_size; int width = 0, height = 0; Size2 window_rect; Point2 last_pos; + bool mouse_outside = true; ObjectID instance_id; @@ -476,13 +487,17 @@ public: virtual bool tts_is_speaking() const override; virtual bool tts_is_paused() const override; - virtual Array tts_get_voices() const override; + virtual TypedArray<Dictionary> tts_get_voices() const override; virtual void tts_speak(const String &p_text, const String &p_voice, int p_volume = 50, float p_pitch = 1.f, float p_rate = 1.f, int p_utterance_id = 0, bool p_interrupt = false) override; virtual void tts_pause() override; virtual void tts_resume() override; virtual void tts_stop() override; + virtual bool is_dark_mode_supported() const override; + virtual bool is_dark_mode() const override; + virtual Color get_accent_color() const override; + virtual void mouse_set_mode(MouseMode p_mode) override; virtual MouseMode mouse_get_mode() const override; diff --git a/platform/windows/export/export.cpp b/platform/windows/export/export.cpp index af19f24f09..8f91756c02 100644 --- a/platform/windows/export/export.cpp +++ b/platform/windows/export/export.cpp @@ -30,9 +30,11 @@ #include "export.h" +#include "editor/export/editor_export.h" #include "export_plugin.h" void register_windows_exporter() { +#ifndef ANDROID_ENABLED EDITOR_DEF("export/windows/rcedit", ""); EditorSettings::get_singleton()->add_property_hint(PropertyInfo(Variant::STRING, "export/windows/rcedit", PROPERTY_HINT_GLOBAL_FILE, "*.exe")); #ifdef WINDOWS_ENABLED @@ -45,6 +47,7 @@ void register_windows_exporter() { EDITOR_DEF("export/windows/wine", ""); EditorSettings::get_singleton()->add_property_hint(PropertyInfo(Variant::STRING, "export/windows/wine", PROPERTY_HINT_GLOBAL_FILE)); #endif +#endif Ref<EditorExportPlatformWindows> platform; platform.instantiate(); diff --git a/platform/windows/export/export.h b/platform/windows/export/export.h index 09399f2bee..1054e04b1e 100644 --- a/platform/windows/export/export.h +++ b/platform/windows/export/export.h @@ -33,4 +33,4 @@ void register_windows_exporter(); -#endif +#endif // WINDOWS_EXPORT_H diff --git a/platform/windows/export/export_plugin.cpp b/platform/windows/export/export_plugin.cpp index 16c67345e0..016d201f2c 100644 --- a/platform/windows/export/export_plugin.cpp +++ b/platform/windows/export/export_plugin.cpp @@ -104,7 +104,7 @@ Error EditorExportPlatformWindows::export_project(const Ref<EditorExportPreset> } String EditorExportPlatformWindows::get_template_file_name(const String &p_target, const String &p_arch) const { - return "windows_" + p_arch + "_" + p_target + ".exe"; + return "windows_" + p_target + "_" + p_arch + ".exe"; } List<String> EditorExportPlatformWindows::get_binary_extensions(const Ref<EditorExportPreset> &p_preset) const { @@ -113,7 +113,7 @@ List<String> EditorExportPlatformWindows::get_binary_extensions(const Ref<Editor return list; } -bool EditorExportPlatformWindows::get_export_option_visibility(const String &p_option, const HashMap<StringName, Variant> &p_options) const { +bool EditorExportPlatformWindows::get_export_option_visibility(const EditorExportPreset *p_preset, const String &p_option, const HashMap<StringName, Variant> &p_options) const { // This option is not supported by "osslsigncode", used on non-Windows host. if (!OS::get_singleton()->has_feature("windows") && p_option == "codesign/identity_type") { return false; @@ -123,11 +123,12 @@ bool EditorExportPlatformWindows::get_export_option_visibility(const String &p_o void EditorExportPlatformWindows::get_export_options(List<ExportOption> *r_options) { EditorExportPlatformPC::get_export_options(r_options); + r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "binary_format/architecture", PROPERTY_HINT_ENUM, "x86_64,x86_32,arm64"), "x86_64")); r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "codesign/enable"), false)); r_options->push_back(ExportOption(PropertyInfo(Variant::INT, "codesign/identity_type", PROPERTY_HINT_ENUM, "Select automatically,Use PKCS12 file (specify *.PFX/*.P12 file),Use certificate store (specify SHA1 hash)"), 0)); r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "codesign/identity", PROPERTY_HINT_GLOBAL_FILE, "*.pfx,*.p12"), "")); - r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "codesign/password"), "")); + r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "codesign/password", PROPERTY_HINT_PASSWORD), "")); r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "codesign/timestamp"), true)); r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "codesign/timestamp_server_url"), "")); r_options->push_back(ExportOption(PropertyInfo(Variant::INT, "codesign/digest_algorithm", PROPERTY_HINT_ENUM, "SHA1,SHA256"), 1)); @@ -230,13 +231,13 @@ Error EditorExportPlatformWindows::_rcedit_add_data(const Ref<EditorExportPreset String str; Error err = OS::get_singleton()->execute(rcedit_path, args, &str, nullptr, true); if (err != OK || (str.find("not found") != -1) || (str.find("not recognized") != -1)) { - add_message(EXPORT_MESSAGE_WARNING, TTR("Resources Modification"), TTR("Could not start rcedit executable, configure rcedit path in the Editor Settings (Export > Windows > Rcedit).")); + add_message(EXPORT_MESSAGE_WARNING, TTR("Resources Modification"), TTR("Could not start rcedit executable. Configure rcedit path in the Editor Settings (Export > Windows > rcedit), or disable \"Application > Modify Resources\" in the export preset.")); return err; } print_line("rcedit (" + p_path + "): " + str); if (str.find("Fatal error") != -1) { - add_message(EXPORT_MESSAGE_WARNING, TTR("Resources Modification"), vformat(TTR("rcedit failed to modify executable:\n%s"), str)); + add_message(EXPORT_MESSAGE_WARNING, TTR("Resources Modification"), vformat(TTR("rcedit failed to modify executable: %s."), str)); return FAILED; } @@ -378,7 +379,11 @@ Error EditorExportPlatformWindows::_code_sign(const Ref<EditorExportPreset> &p_p String str; Error err = OS::get_singleton()->execute(signtool_path, args, &str, nullptr, true); if (err != OK || (str.find("not found") != -1) || (str.find("not recognized") != -1)) { - add_message(EXPORT_MESSAGE_WARNING, TTR("Code Signing"), TTR("Could not start signtool executable, configure signtool path in the Editor Settings (Export > Windows > Signtool).")); +#ifndef WINDOWS_ENABLED + add_message(EXPORT_MESSAGE_WARNING, TTR("Code Signing"), TTR("Could not start signtool executable. Configure signtool path in the Editor Settings (Export > Windows > signtool), or disable \"Codesign\" in the export preset.")); +#else + add_message(EXPORT_MESSAGE_WARNING, TTR("Code Signing"), TTR("Could not start osslsigncode executable. Configure signtool path in the Editor Settings (Export > Windows > osslsigncode), or disable \"Codesign\" in the export preset.")); +#endif return err; } @@ -388,7 +393,7 @@ Error EditorExportPlatformWindows::_code_sign(const Ref<EditorExportPreset> &p_p #else if (str.find("Failed") != -1) { #endif - add_message(EXPORT_MESSAGE_WARNING, TTR("Code Signing"), vformat(TTR("Signtool failed to sign executable:\n%s"), str)); + add_message(EXPORT_MESSAGE_WARNING, TTR("Code Signing"), vformat(TTR("Signtool failed to sign executable: %s."), str)); return FAILED; } @@ -411,15 +416,26 @@ Error EditorExportPlatformWindows::_code_sign(const Ref<EditorExportPreset> &p_p return OK; } -bool EditorExportPlatformWindows::can_export(const Ref<EditorExportPreset> &p_preset, String &r_error, bool &r_missing_templates) const { +bool EditorExportPlatformWindows::has_valid_export_configuration(const Ref<EditorExportPreset> &p_preset, String &r_error, bool &r_missing_templates) const { String err = ""; - bool valid = EditorExportPlatformPC::can_export(p_preset, err, r_missing_templates); + bool valid = EditorExportPlatformPC::has_valid_export_configuration(p_preset, err, r_missing_templates); String rcedit_path = EditorSettings::get_singleton()->get("export/windows/rcedit"); if (p_preset->get("application/modify_resources") && rcedit_path.is_empty()) { - err += TTR("The rcedit tool must be configured in the Editor Settings (Export > Windows > Rcedit) to change the icon or app information data.") + "\n"; + err += TTR("The rcedit tool must be configured in the Editor Settings (Export > Windows > rcedit) to change the icon or app information data.") + "\n"; + } + + if (!err.is_empty()) { + r_error = err; } + return valid; +} + +bool EditorExportPlatformWindows::has_valid_project_configuration(const Ref<EditorExportPreset> &p_preset, String &r_error) const { + String err = ""; + bool valid = true; + String icon_path = ProjectSettings::get_singleton()->globalize_path(p_preset->get("application/icon")); if (!icon_path.is_empty() && !FileAccess::exists(icon_path)) { err += TTR("Invalid icon path:") + " " + icon_path + "\n"; diff --git a/platform/windows/export/export_plugin.h b/platform/windows/export/export_plugin.h index 51f98365a9..f85331c898 100644 --- a/platform/windows/export/export_plugin.h +++ b/platform/windows/export/export_plugin.h @@ -33,8 +33,8 @@ #include "core/io/file_access.h" #include "core/os/os.h" -#include "editor/editor_export.h" #include "editor/editor_settings.h" +#include "editor/export/editor_export_platform_pc.h" #include "platform/windows/logo.gen.h" class EditorExportPlatformWindows : public EditorExportPlatformPC { @@ -48,10 +48,11 @@ public: virtual Error sign_shared_object(const Ref<EditorExportPreset> &p_preset, bool p_debug, const String &p_path) override; virtual List<String> get_binary_extensions(const Ref<EditorExportPreset> &p_preset) const override; virtual void get_export_options(List<ExportOption> *r_options) override; - virtual bool get_export_option_visibility(const String &p_option, const HashMap<StringName, Variant> &p_options) const override; - virtual bool can_export(const Ref<EditorExportPreset> &p_preset, String &r_error, bool &r_missing_templates) const override; + virtual bool has_valid_export_configuration(const Ref<EditorExportPreset> &p_preset, String &r_error, bool &r_missing_templates) const override; + virtual bool has_valid_project_configuration(const Ref<EditorExportPreset> &p_preset, String &r_error) const override; + virtual bool get_export_option_visibility(const EditorExportPreset *p_preset, const String &p_option, const HashMap<StringName, Variant> &p_options) const override; virtual String get_template_file_name(const String &p_target, const String &p_arch) const override; virtual Error fixup_embedded_pck(const String &p_path, int64_t p_embedded_start, int64_t p_embedded_size) override; }; -#endif +#endif // WINDOWS_EXPORT_PLUGIN_H diff --git a/platform/windows/gl_manager_windows.cpp b/platform/windows/gl_manager_windows.cpp index d509ff8c51..7689751f1b 100644 --- a/platform/windows/gl_manager_windows.cpp +++ b/platform/windows/gl_manager_windows.cpp @@ -289,12 +289,7 @@ void GLManager_Windows::make_current() { } void GLManager_Windows::swap_buffers() { - // on other platforms, OpenGL swaps buffers for all windows (on all displays, really?) - // Windows swaps buffers on a per-window basis - // REVISIT: this could be structurally bad, should we have "dirty" flags then? - for (KeyValue<DisplayServer::WindowID, GLWindow> &entry : _windows) { - SwapBuffers(entry.value.hDC); - } + SwapBuffers(_current_window->hDC); } Error GLManager_Windows::initialize() { diff --git a/platform/windows/godot.natvis b/platform/windows/godot.natvis index bb855e4ac8..cdd1c14978 100644 --- a/platform/windows/godot.natvis +++ b/platform/windows/godot.natvis @@ -40,11 +40,13 @@ <DisplayString Condition="type == Variant::TRANSFORM2D">{_data._transform2d}</DisplayString> <DisplayString Condition="type == Variant::AABB">{_data._aabb}</DisplayString> <DisplayString Condition="type == Variant::BASIS">{_data._basis}</DisplayString> - <DisplayString Condition="type == Variant::TRANSFORM3D">{_data._transform}</DisplayString> + <DisplayString Condition="type == Variant::TRANSFORM3D">{_data._transform3d}</DisplayString> + <DisplayString Condition="type == Variant::PROJECTION">{_data._projection}</DisplayString> <DisplayString Condition="type == Variant::STRING">{*(String *)_data._mem}</DisplayString> <DisplayString Condition="type == Variant::VECTOR2">{*(Vector2 *)_data._mem}</DisplayString> <DisplayString Condition="type == Variant::RECT2">{*(Rect2 *)_data._mem}</DisplayString> <DisplayString Condition="type == Variant::VECTOR3">{*(Vector3 *)_data._mem}</DisplayString> + <DisplayString Condition="type == Variant::VECTOR4">{*(Vector4 *)_data._mem}</DisplayString> <DisplayString Condition="type == Variant::PLANE">{*(Plane *)_data._mem}</DisplayString> <DisplayString Condition="type == Variant::QUATERNION">{*(Quaternion *)_data._mem}</DisplayString> <DisplayString Condition="type == Variant::COLOR">{*(Color *)_data._mem}</DisplayString> @@ -72,7 +74,7 @@ <Item Name="[value]" Condition="type == Variant::TRANSFORM2D">_data._transform2d</Item> <Item Name="[value]" Condition="type == Variant::AABB">_data._aabb</Item> <Item Name="[value]" Condition="type == Variant::BASIS">_data._basis</Item> - <Item Name="[value]" Condition="type == Variant::TRANSFORM3D">_data._transform</Item> + <Item Name="[value]" Condition="type == Variant::TRANSFORM3D">_data._transform3d</Item> <Item Name="[value]" Condition="type == Variant::STRING">*(String *)_data._mem</Item> <Item Name="[value]" Condition="type == Variant::VECTOR2">*(Vector2 *)_data._mem</Item> <Item Name="[value]" Condition="type == Variant::RECT2">*(Rect2 *)_data._mem</Item> diff --git a/platform/windows/os_windows.cpp b/platform/windows/os_windows.cpp index 6f414c094c..2c268ff3d5 100644 --- a/platform/windows/os_windows.cpp +++ b/platform/windows/os_windows.cpp @@ -48,6 +48,7 @@ #include <avrt.h> #include <bcrypt.h> #include <direct.h> +#include <dwrite.h> #include <knownfolders.h> #include <process.h> #include <regstr.h> @@ -236,7 +237,7 @@ Error OS_Windows::open_dynamic_library(const String p_path, void *&p_library_han if (!FileAccess::exists(path)) { //this code exists so gdnative can load .dll files from within the executable path - path = get_executable_path().get_base_dir().plus_file(p_path.get_file()); + path = get_executable_path().get_base_dir().path_join(p_path.get_file()); } typedef DLL_DIRECTORY_COOKIE(WINAPI * PAddDllDirectory)(PCWSTR); @@ -289,7 +290,7 @@ String OS_Windows::get_name() const { return "Windows"; } -OS::Date OS_Windows::get_date(bool p_utc) const { +OS::DateTime OS_Windows::get_datetime(bool p_utc) const { SYSTEMTIME systemtime; if (p_utc) { GetSystemTime(&systemtime); @@ -304,28 +305,16 @@ OS::Date OS_Windows::get_date(bool p_utc) const { daylight = true; } - Date date; - date.day = systemtime.wDay; - date.month = Month(systemtime.wMonth); - date.weekday = Weekday(systemtime.wDayOfWeek); - date.year = systemtime.wYear; - date.dst = daylight; - return date; -} - -OS::Time OS_Windows::get_time(bool p_utc) const { - SYSTEMTIME systemtime; - if (p_utc) { - GetSystemTime(&systemtime); - } else { - GetLocalTime(&systemtime); - } - - Time time; - time.hour = systemtime.wHour; - time.minute = systemtime.wMinute; - time.second = systemtime.wSecond; - return time; + DateTime dt; + dt.year = systemtime.wYear; + dt.month = Month(systemtime.wMonth); + dt.day = systemtime.wDay; + dt.weekday = Weekday(systemtime.wDayOfWeek); + dt.hour = systemtime.wHour; + dt.minute = systemtime.wMinute; + dt.second = systemtime.wSecond; + dt.dst = daylight; + return dt; } OS::TimeZoneInfo OS_Windows::get_time_zone_info() const { @@ -621,6 +610,135 @@ Error OS_Windows::set_cwd(const String &p_cwd) { return OK; } +Vector<String> OS_Windows::get_system_fonts() const { + Vector<String> ret; + HashSet<String> font_names; + + ComAutoreleaseRef<IDWriteFactory> dwrite_factory; + HRESULT hr = DWriteCreateFactory(DWRITE_FACTORY_TYPE_SHARED, __uuidof(IDWriteFactory), reinterpret_cast<IUnknown **>(&dwrite_factory.reference)); + ERR_FAIL_COND_V(FAILED(hr) || dwrite_factory.is_null(), ret); + + ComAutoreleaseRef<IDWriteFontCollection> font_collection; + hr = dwrite_factory->GetSystemFontCollection(&font_collection.reference, false); + ERR_FAIL_COND_V(FAILED(hr) || font_collection.is_null(), ret); + + UINT32 family_count = font_collection->GetFontFamilyCount(); + for (UINT32 i = 0; i < family_count; i++) { + ComAutoreleaseRef<IDWriteFontFamily> family; + hr = font_collection->GetFontFamily(i, &family.reference); + ERR_CONTINUE(FAILED(hr) || family.is_null()); + + ComAutoreleaseRef<IDWriteLocalizedStrings> family_names; + hr = family->GetFamilyNames(&family_names.reference); + ERR_CONTINUE(FAILED(hr) || family_names.is_null()); + + UINT32 index = 0; + BOOL exists = false; + UINT32 length = 0; + Char16String name; + + hr = family_names->FindLocaleName(L"en-us", &index, &exists); + ERR_CONTINUE(FAILED(hr)); + + hr = family_names->GetStringLength(index, &length); + ERR_CONTINUE(FAILED(hr)); + + name.resize(length + 1); + hr = family_names->GetString(index, (WCHAR *)name.ptrw(), length + 1); + ERR_CONTINUE(FAILED(hr)); + + font_names.insert(String::utf16(name.ptr(), length)); + } + + for (const String &E : font_names) { + ret.push_back(E); + } + return ret; +} + +String OS_Windows::get_system_font_path(const String &p_font_name, bool p_bold, bool p_italic) const { + String font_name = p_font_name; + if (font_name.to_lower() == "sans-serif") { + font_name = "Arial"; + } else if (font_name.to_lower() == "serif") { + font_name = "Times New Roman"; + } else if (font_name.to_lower() == "monospace") { + font_name = "Courier New"; + } else if (font_name.to_lower() == "cursive") { + font_name = "Comic Sans MS"; + } else if (font_name.to_lower() == "fantasy") { + font_name = "Gabriola"; + } + + ComAutoreleaseRef<IDWriteFactory> dwrite_factory; + HRESULT hr = DWriteCreateFactory(DWRITE_FACTORY_TYPE_SHARED, __uuidof(IDWriteFactory), reinterpret_cast<IUnknown **>(&dwrite_factory.reference)); + ERR_FAIL_COND_V(FAILED(hr) || dwrite_factory.is_null(), String()); + + ComAutoreleaseRef<IDWriteFontCollection> font_collection; + hr = dwrite_factory->GetSystemFontCollection(&font_collection.reference, false); + ERR_FAIL_COND_V(FAILED(hr) || font_collection.is_null(), String()); + + UINT32 index = 0; + BOOL exists = false; + font_collection->FindFamilyName((const WCHAR *)font_name.utf16().get_data(), &index, &exists); + if (FAILED(hr)) { + return String(); + } + + ComAutoreleaseRef<IDWriteFontFamily> family; + hr = font_collection->GetFontFamily(index, &family.reference); + if (FAILED(hr) || family.is_null()) { + return String(); + } + + ComAutoreleaseRef<IDWriteFont> dwrite_font; + hr = family->GetFirstMatchingFont(p_bold ? DWRITE_FONT_WEIGHT_BOLD : DWRITE_FONT_WEIGHT_NORMAL, DWRITE_FONT_STRETCH_NORMAL, p_italic ? DWRITE_FONT_STYLE_ITALIC : DWRITE_FONT_STYLE_NORMAL, &dwrite_font.reference); + if (FAILED(hr) || dwrite_font.is_null()) { + return String(); + } + + ComAutoreleaseRef<IDWriteFontFace> dwrite_face; + hr = dwrite_font->CreateFontFace(&dwrite_face.reference); + if (FAILED(hr) || dwrite_face.is_null()) { + return String(); + } + + UINT32 number_of_files = 0; + hr = dwrite_face->GetFiles(&number_of_files, nullptr); + if (FAILED(hr)) { + return String(); + } + Vector<ComAutoreleaseRef<IDWriteFontFile>> files; + files.resize(number_of_files); + hr = dwrite_face->GetFiles(&number_of_files, (IDWriteFontFile **)files.ptrw()); + if (FAILED(hr)) { + return String(); + } + + for (UINT32 i = 0; i < number_of_files; i++) { + void const *reference_key = nullptr; + UINT32 reference_key_size = 0; + ComAutoreleaseRef<IDWriteLocalFontFileLoader> loader; + + hr = files.write[i]->GetLoader((IDWriteFontFileLoader **)&loader.reference); + if (FAILED(hr) || loader.is_null()) { + continue; + } + hr = files.write[i]->GetReferenceKey(&reference_key, &reference_key_size); + if (FAILED(hr)) { + continue; + } + + WCHAR file_path[MAX_PATH]; + hr = loader->GetFilePathFromKey(reference_key, reference_key_size, &file_path[0], MAX_PATH); + if (FAILED(hr)) { + continue; + } + return String::utf16((const char16_t *)&file_path[0]); + } + return String(); +} + String OS_Windows::get_executable_path() const { WCHAR bufname[4096]; GetModuleFileNameW(nullptr, bufname, 4096); @@ -772,7 +890,7 @@ void OS_Windows::run() { main_loop->initialize(); - while (!force_quit) { + while (true) { DisplayServer::get_singleton()->process_events(); // get rid of pending events if (Main::iteration()) { break; @@ -941,19 +1059,19 @@ String OS_Windows::get_user_data_dir() const { if (custom_dir.is_empty()) { custom_dir = appname; } - return get_data_path().plus_file(custom_dir).replace("\\", "/"); + return get_data_path().path_join(custom_dir).replace("\\", "/"); } else { - return get_data_path().plus_file(get_godot_dir_name()).plus_file("app_userdata").plus_file(appname).replace("\\", "/"); + return get_data_path().path_join(get_godot_dir_name()).path_join("app_userdata").path_join(appname).replace("\\", "/"); } } - return get_data_path().plus_file(get_godot_dir_name()).plus_file("app_userdata").plus_file("[unnamed project]"); + return get_data_path().path_join(get_godot_dir_name()).path_join("app_userdata").path_join("[unnamed project]"); } String OS_Windows::get_unique_id() const { - HW_PROFILE_INFO HwProfInfo; - ERR_FAIL_COND_V(!GetCurrentHwProfile(&HwProfInfo), ""); - return String::utf16((const char16_t *)(HwProfInfo.szHwProfileGuid), HW_PROFILE_GUIDLEN); + HW_PROFILE_INFOA HwProfInfo; + ERR_FAIL_COND_V(!GetCurrentHwProfileA(&HwProfInfo), ""); + return String((HwProfInfo.szHwProfileGuid), HW_PROFILE_GUIDLEN); } bool OS_Windows::_check_internal_feature_support(const String &p_feature) { @@ -1002,8 +1120,6 @@ OS_Windows::OS_Windows(HINSTANCE _hInstance) { main_loop = nullptr; process_map = nullptr; - force_quit = false; - hInstance = _hInstance; #ifdef STDOUT_FILE stdo = fopen("stdout.txt", "wb"); @@ -1018,6 +1134,21 @@ OS_Windows::OS_Windows(HINSTANCE _hInstance) { DisplayServerWindows::register_windows_driver(); + // Enable ANSI escape code support on Windows 10 v1607 (Anniversary Update) and later. + // This lets the engine and projects use ANSI escape codes to color text just like on macOS and Linux. + // + // NOTE: The engine does not use ANSI escape codes to color error/warning messages; it uses Windows API calls instead. + // Therefore, error/warning messages are still colored on Windows versions older than 10. + HANDLE stdoutHandle; + stdoutHandle = GetStdHandle(STD_OUTPUT_HANDLE); + DWORD outMode = 0; + outMode |= ENABLE_VIRTUAL_TERMINAL_PROCESSING; + + if (!SetConsoleMode(stdoutHandle, outMode)) { + // Windows 8.1 or below, or Windows 10 prior to Anniversary Update. + print_verbose("Can't set the ENABLE_VIRTUAL_TERMINAL_PROCESSING Windows console mode. `print_rich()` will not work as expected."); + } + Vector<Logger *> loggers; loggers.push_back(memnew(WindowsTerminalLogger)); _set_logger(memnew(CompositeLogger(loggers))); diff --git a/platform/windows/os_windows.h b/platform/windows/os_windows.h index dc702c66e1..53451b780e 100644 --- a/platform/windows/os_windows.h +++ b/platform/windows/os_windows.h @@ -62,6 +62,26 @@ #define WINDOWS_DEBUG_OUTPUT_ENABLED #endif +template <class T> +class ComAutoreleaseRef { +public: + T *reference = nullptr; + + _FORCE_INLINE_ T *operator->() { return reference; } + _FORCE_INLINE_ const T *operator->() const { return reference; } + _FORCE_INLINE_ T *operator*() { return reference; } + _FORCE_INLINE_ const T *operator*() const { return reference; } + _FORCE_INLINE_ bool is_valid() const { return reference != nullptr; } + _FORCE_INLINE_ bool is_null() const { return reference == nullptr; } + ComAutoreleaseRef() {} + ~ComAutoreleaseRef() { + if (reference != nullptr) { + reference->Release(); + reference = nullptr; + } + } +}; + class JoypadWindows; class OS_Windows : public OS { #ifdef STDOUT_FILE @@ -90,7 +110,6 @@ class OS_Windows : public OS { ErrorHandlerList error_handlers; #endif - bool force_quit; HWND main_window; // functions used by main to initialize/deinitialize the OS @@ -127,8 +146,7 @@ public: virtual void initialize_joypads() override {} - virtual Date get_date(bool p_utc) const override; - virtual Time get_time(bool p_utc) const override; + virtual DateTime get_datetime(bool p_utc) const override; virtual TimeZoneInfo get_time_zone_info() const override; virtual double get_unix_time() const override; @@ -147,6 +165,9 @@ public: virtual String get_environment(const String &p_var) const override; virtual bool set_environment(const String &p_var, const String &p_value) const override; + virtual Vector<String> get_system_fonts() const override; + virtual String get_system_font_path(const String &p_font_name, bool p_bold = false, bool p_italic = false) const override; + virtual String get_executable_path() const override; virtual String get_locale() const override; @@ -185,4 +206,4 @@ public: ~OS_Windows(); }; -#endif +#endif // OS_WINDOWS_H diff --git a/platform/windows/platform_windows_builders.py b/platform/windows/platform_windows_builders.py index 22e33b51b4..33ca2e8ffa 100644 --- a/platform/windows/platform_windows_builders.py +++ b/platform/windows/platform_windows_builders.py @@ -9,7 +9,7 @@ from platform_methods import subprocess_main def make_debug_mingw(target, source, env): mingw_prefix = "" - if env["bits"] == "32": + if env["arch"] == "x86_32": mingw_prefix = env["mingw_prefix_32"] else: mingw_prefix = env["mingw_prefix_64"] diff --git a/platform/windows/vulkan_context_win.h b/platform/windows/vulkan_context_win.h index e68f0125ca..d5950a129a 100644 --- a/platform/windows/vulkan_context_win.h +++ b/platform/windows/vulkan_context_win.h @@ -28,8 +28,8 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ -#ifndef VULKAN_DEVICE_WIN_H -#define VULKAN_DEVICE_WIN_H +#ifndef VULKAN_CONTEXT_WIN_H +#define VULKAN_CONTEXT_WIN_H #include "drivers/vulkan/vulkan_context.h" @@ -46,4 +46,4 @@ public: ~VulkanContextWindows(); }; -#endif // VULKAN_DEVICE_WIN_H +#endif // VULKAN_CONTEXT_WIN_H diff --git a/platform/windows/windows_terminal_logger.h b/platform/windows/windows_terminal_logger.h index 1045f12201..348a49c845 100644 --- a/platform/windows/windows_terminal_logger.h +++ b/platform/windows/windows_terminal_logger.h @@ -44,4 +44,4 @@ public: #endif -#endif +#endif // WINDOWS_TERMINAL_LOGGER_H |