From 3cbc88fe7847e42435389cb906cda7ae657a493d Mon Sep 17 00:00:00 2001 From: omigamedev Date: Wed, 17 Jun 2026 01:44:20 +0200 Subject: [PATCH] Retain Apple bridge services and bind Win32 runtime --- docs/modernization/roadmap.md | 15 +- docs/modernization/tasks.md | 10 + .../legacy_platform_services.cpp | 222 ++---------------- src/platform_legacy/legacy_platform_state.cpp | 214 +++++++++++++++++ src/platform_legacy/legacy_platform_state.h | 3 + .../windows_lifecycle_shell.cpp | 2 + .../windows_platform_services.cpp | 19 +- .../windows_runtime_shell.cpp | 25 ++ src/platform_windows/windows_runtime_shell.h | 4 + 9 files changed, 311 insertions(+), 203 deletions(-) diff --git a/docs/modernization/roadmap.md b/docs/modernization/roadmap.md index d6d181f6..d23063d5 100644 --- a/docs/modernization/roadmap.md +++ b/docs/modernization/roadmap.md @@ -92,6 +92,17 @@ Current hotspot files: Latest slice: +- The full retained Apple document bridge construction no longer lives inline + in `src/platform_legacy/legacy_platform_services.cpp`; it now lives behind + `active_legacy_apple_document_platform_services()` in + `src/platform_legacy/legacy_platform_state.*`, and that retained service now + resets when seeded Apple handles change so first-use bridge capture stays in + sync with the active entrypoint state. +- Win32 main-thread task dispatch no longer reaches `AppRuntime` through + `App::I` inside `src/platform_windows/windows_platform_services.cpp`; + `src/platform_windows/windows_runtime_shell.*` now binds the active runtime + explicitly and clears that binding on shutdown, leaving the Windows queue + helper as a thinner runtime forwarder. - `App` no longer owns `and_app` or `and_engine`; the retained Android entrypoint now seeds only the explicit legacy platform storage snapshot needed by touched platform services instead of storing Android-native @@ -227,7 +238,9 @@ Current architecture mismatches that must be treated as real blockers: `platform_legacy`-mirrored Apple/GLFW handle cluster is now seeded explicitly from platform entrypoints instead of being copied out of `App`, and retained storage roots are now also seeded explicitly instead of being - lazily copied from `App::I` inside `active_legacy_storage_paths()`. + lazily copied from `App::I` inside `active_legacy_storage_paths()`, while the + retained Apple document bridge now also lives in `legacy_platform_state.*` + instead of being built inline in `legacy_platform_services.cpp`. - `src/platform_legacy/legacy_platform_services.*` is still part of the live app shell. - `pp_panopainter_ui` still depends on `pp_legacy_app`. diff --git a/docs/modernization/tasks.md b/docs/modernization/tasks.md index 2877f2ab..ca0a9287 100644 --- a/docs/modernization/tasks.md +++ b/docs/modernization/tasks.md @@ -1154,6 +1154,11 @@ Current slice: also live in `src/platform_legacy/legacy_platform_state.*`, and `src/platform_legacy/legacy_platform_services.cpp` now consumes those snapshots without direct `App::I` reads in the touched paths +- the retained Apple document bridge now also lives behind + `active_legacy_apple_document_platform_services()` in + `src/platform_legacy/legacy_platform_state.*` instead of being built inline + inside `src/platform_legacy/legacy_platform_services.cpp`, and that retained + service resets when seeded Apple handles change - retained Apple callback injection and broader `platform_legacy` singleton reach are still open - the `platform_legacy`-mirrored Apple/GLFW handle cluster is now seeded @@ -1210,6 +1215,11 @@ Current slice: - `App` also no longer owns `and_app` or `and_engine`; the retained Android entrypoint now seeds only the explicit legacy platform storage snapshot needed by touched platform services. +- Win32 main-thread task dispatch also no longer reaches `AppRuntime` through + `App::I`; `src/platform_windows/windows_runtime_shell.*` now binds the + active runtime explicitly and + `src/platform_windows/windows_platform_services.cpp` consumes that bound + runtime for enqueue/drain. - `App` still owns broader retained legacy platform state, so this remains a live ownership task. diff --git a/src/platform_legacy/legacy_platform_services.cpp b/src/platform_legacy/legacy_platform_services.cpp index 717fc624..213cde77 100644 --- a/src/platform_legacy/legacy_platform_services.cpp +++ b/src/platform_legacy/legacy_platform_services.cpp @@ -23,13 +23,6 @@ std::string android_get_clipboard(); bool android_set_clipboard(const std::string& s); #elif __APPLE__ #include -#include "objc_utils.h" -#ifdef __IOS__ -#include "AppDelegate.h" -#include "GameViewController.h" -#elif defined(__OSX__) -#include "main.h" -#endif void delete_all_files_in_path(const std::string& source_path); #ifdef __IOS__ void save_image_library(const std::string& path); @@ -93,16 +86,6 @@ public: } #if defined(__IOS__) || defined(__OSX__) -[[nodiscard]] NSMutableArray* apple_file_types_array(const std::vector& file_types) -{ - NSMutableArray* types = [NSMutableArray arrayWithCapacity:file_types.size()]; - for (const auto& type : file_types) - { - [types addObject:[NSString stringWithCString:type.c_str() encoding:NSUTF8StringEncoding]]; - } - return types; -} - [[nodiscard]] pp::platform::PlatformStoragePaths prepare_legacy_apple_storage_paths() { const auto& apple_state = pp::platform::legacy::active_legacy_apple_state(); @@ -113,161 +96,6 @@ public: #endif return pp::platform::legacy::active_legacy_storage_paths(); } - -[[nodiscard]] pp::platform::apple::AppleDocumentPlatformServices& active_apple_document_platform_services() -{ -#ifdef __IOS__ - const auto& apple_state = pp::platform::legacy::active_legacy_apple_state(); - auto* const ios_view = apple_state.ios_view; - auto* const ios_app = apple_state.ios_app; - static pp::platform::apple::AppleDocumentPlatformServices services( - pp::platform::PlatformFamily::ios, - [ios_view] { - pp::platform::apple::AppleDocumentPickerBridge bridge; - bridge.clipboard_text = [ios_view] { - return [ios_view clipboard_get_string]; - }; - bridge.set_clipboard_text = [ios_view](std::string_view text) { - const std::string value(text); - return [ios_view clipboard_set_string:value]; - }; - bridge.set_virtual_keyboard_visible = [ios_view](bool visible) { - dispatch_async(dispatch_get_main_queue(), ^{ - if (visible) - [ios_view show_keyboard]; - else - [ios_view hide_keyboard]; - }); - }; - bridge.trigger_crash_test = [ios_view] { - [ios_view crash]; - }; - bridge.start_sonarpen = [ios_app] { - [ios_app sonarpen_start]; - }; - bridge.acquire_render_context = [ios_view] { - [ios_view async_lock]; - }; - bridge.release_render_context = [ios_view] { - [ios_view async_unlock]; - }; - bridge.present_render_context = [ios_view] { - [ios_view async_swap]; - }; - bridge.bind_main_render_target = [ios_view] { - [ios_view->glview bindDrawable]; - }; - bridge.display_file = [ios_view](std::string path) { - dispatch_async(dispatch_get_main_queue(), ^{ - [ios_view display_file:path]; - }); - }; - bridge.share_file = [ios_view](std::string path) { - dispatch_async(dispatch_get_main_queue(), ^{ - [ios_view share_file:[NSString stringWithUTF8String:path.c_str()]]; - }); - }; - bridge.pick_image = [ios_view](pp::platform::PickedPathCallback callback) { - dispatch_async(dispatch_get_main_queue(), ^{ - [ios_view pick_photo:callback]; - }); - }; - bridge.pick_file = [ios_view]( - std::vector file_types, - pp::platform::PickedPathCallback callback) { - dispatch_async(dispatch_get_main_queue(), ^{ - [ios_view pick_file:apple_file_types_array(file_types) then:callback]; - }); - }; - bridge.save_prepared_file = [ios_view]( - std::string path, - std::string suggested_name, - pp::platform::PreparedFileCallback callback) { - (void)suggested_name; - dispatch_async(dispatch_get_main_queue(), ^{ - [ios_view pick_file_save:path]; - }); - callback(path, true); - }; - return bridge; - }()); - return services; -#else - const auto& apple_state = pp::platform::legacy::active_legacy_apple_state(); - auto* const osx_view = apple_state.osx_view; - auto* const osx_app = apple_state.osx_app; - static pp::platform::apple::AppleDocumentPlatformServices services( - pp::platform::PlatformFamily::macos, - [osx_view, osx_app] { - pp::platform::apple::AppleDocumentPickerBridge bridge; - bridge.clipboard_text = [osx_view] { - return [osx_view clipboard_get_string]; - }; - bridge.set_clipboard_text = [osx_view](std::string_view text) { - const std::string value(text); - return [osx_view clipboard_set_string:value]; - }; - bridge.share_file = [osx_view](std::string path) { - dispatch_async(dispatch_get_main_queue(), ^{ - [osx_view share_file:[NSString stringWithUTF8String:path.c_str()]]; - }); - }; - bridge.trigger_crash_test = [osx_view] { - [osx_view hockeyapp_crash]; - }; - bridge.request_app_close = [osx_view] { - dispatch_async(dispatch_get_main_queue(), ^{ - [osx_view close]; - }); - }; - bridge.acquire_render_context = [osx_view] { - [osx_view async_lock]; - }; - bridge.release_render_context = [osx_view] { - [osx_view async_unlock]; - }; - bridge.present_render_context = [osx_view] { - [osx_view async_swap]; - }; - bridge.set_cursor_visible = [osx_view](bool visible) { - [osx_view show_cursor:visible]; - }; - bridge.save_ui_state = [osx_app] { - [osx_app save_ui_state]; - }; - bridge.pick_file = [osx_view]( - std::vector file_types, - pp::platform::PickedPathCallback callback) { - dispatch_async(dispatch_get_main_queue(), ^{ - const std::string path = [osx_view pick_file:apple_file_types_array(file_types)]; - callback(path); - }); - }; - bridge.pick_save_file = [osx_view]( - std::vector file_types, - pp::platform::PickedPathCallback callback) { - dispatch_async(dispatch_get_main_queue(), ^{ - const std::string path = [osx_view pick_file_save:apple_file_types_array(file_types)]; - callback(path); - }); - }; - bridge.pick_directory = [osx_view](pp::platform::PickedPathCallback callback) { - dispatch_async(dispatch_get_main_queue(), ^{ - const std::string path = [osx_view pick_dir]; - callback(path); - }); - }; - bridge.format_working_directory_path = [](std::string_view path) { - char path_buffer[4096] = {}; - if (realpath(std::string(path).c_str(), path_buffer)) - return std::string(path_buffer); - return std::string(path); - }; - return bridge; - }()); - return services; -#endif -} #endif // DEBT-0017: fallback for platforms that do not inject PlatformServices yet. @@ -324,9 +152,9 @@ public: void trigger_crash_test() override { #ifdef __IOS__ - active_apple_document_platform_services().trigger_crash_test(); + pp::platform::legacy::active_legacy_apple_document_platform_services().trigger_crash_test(); #elif __OSX__ - active_apple_document_platform_services().trigger_crash_test(); + pp::platform::legacy::active_legacy_apple_document_platform_services().trigger_crash_test(); #elif defined(__ANDROID__) int *x = nullptr; *x = 42; LOG("%d", *x); @@ -338,7 +166,7 @@ public: #if defined(__IOS__) || defined(__OSX__) const auto family = pp::platform::current_platform_family(); if (family == pp::platform::PlatformFamily::ios || family == pp::platform::PlatformFamily::macos) - return active_apple_document_platform_services().clipboard_text(); + return pp::platform::legacy::active_legacy_apple_document_platform_services().clipboard_text(); #endif #ifdef __ANDROID__ return android_get_clipboard(); @@ -352,7 +180,7 @@ public: #if defined(__IOS__) || defined(__OSX__) const auto family = pp::platform::current_platform_family(); if (family == pp::platform::PlatformFamily::ios || family == pp::platform::PlatformFamily::macos) - return active_apple_document_platform_services().set_clipboard_text(text); + return pp::platform::legacy::active_legacy_apple_document_platform_services().set_clipboard_text(text); #endif const std::string value(text); #ifdef __ANDROID__ @@ -366,7 +194,7 @@ public: void set_cursor_visible(bool visible) override { #if defined(__IOS__) || defined(__OSX__) - active_apple_document_platform_services().set_cursor_visible(visible); + pp::platform::legacy::active_legacy_apple_document_platform_services().set_cursor_visible(visible); #else (void)visible; #endif @@ -375,7 +203,7 @@ public: void set_virtual_keyboard_visible(bool visible) override { #ifdef __IOS__ - active_apple_document_platform_services().set_virtual_keyboard_visible(visible); + pp::platform::legacy::active_legacy_apple_document_platform_services().set_virtual_keyboard_visible(visible); #elif __ANDROID__ displayKeyboard(visible); #else @@ -400,7 +228,7 @@ public: void acquire_render_context() override { #if defined(__IOS__) || defined(__OSX__) - active_apple_document_platform_services().acquire_render_context(); + pp::platform::legacy::active_legacy_apple_document_platform_services().acquire_render_context(); #elif __ANDROID__ android_async_lock(); #elif __LINUX__ || __WEB__ @@ -411,7 +239,7 @@ public: void release_render_context() override { #if defined(__IOS__) || defined(__OSX__) - active_apple_document_platform_services().release_render_context(); + pp::platform::legacy::active_legacy_apple_document_platform_services().release_render_context(); #elif __ANDROID__ android_async_unlock(); #endif @@ -420,7 +248,7 @@ public: void present_render_context() override { #if defined(__IOS__) || defined(__OSX__) - active_apple_document_platform_services().present_render_context(); + pp::platform::legacy::active_legacy_apple_document_platform_services().present_render_context(); #elif __ANDROID__ android_async_swap(); #elif __LINUX__ || __WEB__ @@ -438,7 +266,7 @@ public: void bind_main_render_target() override { #if __IOS__ - active_apple_document_platform_services().bind_main_render_target(); + pp::platform::legacy::active_legacy_apple_document_platform_services().bind_main_render_target(); #else bind_default_render_target(); #endif @@ -520,7 +348,7 @@ public: std::string_view data_path) override { #if defined(__IOS__) || defined(__OSX__) - return active_apple_document_platform_services().document_browse_roots(work_path, data_path); + return pp::platform::legacy::active_legacy_apple_document_platform_services().document_browse_roots(work_path, data_path); #else return pp::platform::platform_document_browse_roots( pp::platform::current_platform_family(), @@ -534,7 +362,7 @@ public: if (!pp::platform::platform_saves_native_ui_state(pp::platform::current_platform_family())) return; #if defined(__IOS__) || defined(__OSX__) - active_apple_document_platform_services().save_ui_state(); + pp::platform::legacy::active_legacy_apple_document_platform_services().save_ui_state(); #endif } @@ -561,9 +389,9 @@ public: void pick_image(pp::platform::PickedPathCallback callback) override { #ifdef __IOS__ - active_apple_document_platform_services().pick_image(std::move(callback)); + pp::platform::legacy::active_legacy_apple_document_platform_services().pick_image(std::move(callback)); #elif __OSX__ - active_apple_document_platform_services().pick_image(std::move(callback)); + pp::platform::legacy::active_legacy_apple_document_platform_services().pick_image(std::move(callback)); #elif __ANDROID__ android_pick_file(callback); #elif __LINUX__ @@ -579,9 +407,9 @@ public: void pick_file(std::vector file_types, pp::platform::PickedPathCallback callback) override { #ifdef __IOS__ - active_apple_document_platform_services().pick_file(std::move(file_types), std::move(callback)); + pp::platform::legacy::active_legacy_apple_document_platform_services().pick_file(std::move(file_types), std::move(callback)); #elif __OSX__ - active_apple_document_platform_services().pick_file(std::move(file_types), std::move(callback)); + pp::platform::legacy::active_legacy_apple_document_platform_services().pick_file(std::move(file_types), std::move(callback)); #elif __ANDROID__ android_pick_file(callback); #elif __LINUX__ @@ -598,7 +426,7 @@ public: void pick_save_file(std::vector file_types, pp::platform::PickedPathCallback callback) override { #if __OSX__ - active_apple_document_platform_services().pick_save_file(std::move(file_types), std::move(callback)); + pp::platform::legacy::active_legacy_apple_document_platform_services().pick_save_file(std::move(file_types), std::move(callback)); #elif __ANDROID__ android_pick_file_save(callback); #else @@ -612,7 +440,7 @@ public: #ifdef __IOS__ (void)callback; #elif __OSX__ - active_apple_document_platform_services().pick_directory(std::move(callback)); + pp::platform::legacy::active_legacy_apple_document_platform_services().pick_directory(std::move(callback)); #elif __ANDROID__ (void)callback; #else @@ -623,7 +451,7 @@ public: [[nodiscard]] bool supports_working_directory_picker() override { #if defined(__IOS__) || defined(__OSX__) - return active_apple_document_platform_services().supports_working_directory_picker(); + return pp::platform::legacy::active_legacy_apple_document_platform_services().supports_working_directory_picker(); #else return pp::platform::platform_supports_working_directory_picker( pp::platform::current_platform_family()); @@ -633,7 +461,7 @@ public: [[nodiscard]] std::string format_working_directory_path(std::string_view path) override { #if defined(__IOS__) || defined(__OSX__) - return active_apple_document_platform_services().format_working_directory_path(path); + return pp::platform::legacy::active_legacy_apple_document_platform_services().format_working_directory_path(path); #endif return std::string(path); } @@ -669,7 +497,7 @@ public: void start_sonarpen() override { #if __IOS__ - active_apple_document_platform_services().start_sonarpen(); + pp::platform::legacy::active_legacy_apple_document_platform_services().start_sonarpen(); #endif } @@ -715,7 +543,7 @@ public: void display_file(std::string_view path) override { #if defined(__IOS__) || defined(__OSX__) - active_apple_document_platform_services().display_file(path); + pp::platform::legacy::active_legacy_apple_document_platform_services().display_file(path); #else (void)path; #endif @@ -724,7 +552,7 @@ public: void share_file(std::string_view path) override { #if defined(__IOS__) || defined(__OSX__) - active_apple_document_platform_services().share_file(path); + pp::platform::legacy::active_legacy_apple_document_platform_services().share_file(path); #else (void)path; #endif @@ -733,7 +561,7 @@ public: void request_app_close() override { #ifdef __OSX__ - active_apple_document_platform_services().request_app_close(); + pp::platform::legacy::active_legacy_apple_document_platform_services().request_app_close(); #elif __LINUX__ pp::platform::legacy::active_legacy_glfw_window_hooks().request_app_close(); #endif @@ -766,7 +594,7 @@ public: const std::string value(path); const std::string name(suggested_name); #ifdef __IOS__ - active_apple_document_platform_services().save_prepared_file( + pp::platform::legacy::active_legacy_apple_document_platform_services().save_prepared_file( value, name, std::move(callback)); diff --git a/src/platform_legacy/legacy_platform_state.cpp b/src/platform_legacy/legacy_platform_state.cpp index d1f95e2d..97f9a462 100644 --- a/src/platform_legacy/legacy_platform_state.cpp +++ b/src/platform_legacy/legacy_platform_state.cpp @@ -1,6 +1,11 @@ #include "pch.h" #include "platform_legacy/legacy_platform_state.h" +#if defined(__APPLE__) +#include +#include "objc_utils.h" +#endif + #if defined(__LINUX__) || defined(__WEB__) #include #endif @@ -18,6 +23,187 @@ struct RetainedLegacyStoragePaths final { return state; } +#if defined(__IOS__) || defined(__OSX__) +struct RetainedLegacyAppleDocumentPlatformState final { + std::unique_ptr services; +}; + +[[nodiscard]] NSMutableArray* apple_file_types_array(const std::vector& file_types) +{ + NSMutableArray* types = [NSMutableArray arrayWithCapacity:file_types.size()]; + for (const auto& type : file_types) + { + [types addObject:[NSString stringWithCString:type.c_str() encoding:NSUTF8StringEncoding]]; + } + return types; +} + +[[nodiscard]] RetainedLegacyAppleDocumentPlatformState& retained_legacy_apple_document_platform_state() +{ + static RetainedLegacyAppleDocumentPlatformState state; + return state; +} + +#ifdef __IOS__ +[[nodiscard]] pp::platform::apple::AppleDocumentPickerBridge make_legacy_apple_document_picker_bridge() +{ + const auto& apple_state = active_legacy_apple_state(); + auto* const ios_view = apple_state.ios_view; + auto* const ios_app = apple_state.ios_app; + + pp::platform::apple::AppleDocumentPickerBridge bridge; + bridge.clipboard_text = [ios_view] { + return [ios_view clipboard_get_string]; + }; + bridge.set_clipboard_text = [ios_view](std::string_view text) { + const std::string value(text); + return [ios_view clipboard_set_string:value]; + }; + bridge.set_virtual_keyboard_visible = [ios_view](bool visible) { + dispatch_async(dispatch_get_main_queue(), ^{ + if (visible) + [ios_view show_keyboard]; + else + [ios_view hide_keyboard]; + }); + }; + bridge.trigger_crash_test = [ios_view] { + [ios_view crash]; + }; + bridge.start_sonarpen = [ios_app] { + [ios_app sonarpen_start]; + }; + bridge.acquire_render_context = [ios_view] { + [ios_view async_lock]; + }; + bridge.release_render_context = [ios_view] { + [ios_view async_unlock]; + }; + bridge.present_render_context = [ios_view] { + [ios_view async_swap]; + }; + bridge.bind_main_render_target = [ios_view] { + [ios_view->glview bindDrawable]; + }; + bridge.display_file = [ios_view](std::string path) { + dispatch_async(dispatch_get_main_queue(), ^{ + [ios_view display_file:path]; + }); + }; + bridge.share_file = [ios_view](std::string path) { + dispatch_async(dispatch_get_main_queue(), ^{ + [ios_view share_file:[NSString stringWithUTF8String:path.c_str()]]; + }); + }; + bridge.pick_image = [ios_view](pp::platform::PickedPathCallback callback) { + dispatch_async(dispatch_get_main_queue(), ^{ + [ios_view pick_photo:callback]; + }); + }; + bridge.pick_file = [ios_view]( + std::vector file_types, + pp::platform::PickedPathCallback callback) { + dispatch_async(dispatch_get_main_queue(), ^{ + [ios_view pick_file:apple_file_types_array(file_types) then:callback]; + }); + }; + bridge.save_prepared_file = [ios_view]( + std::string path, + std::string suggested_name, + pp::platform::PreparedFileCallback callback) { + (void)suggested_name; + dispatch_async(dispatch_get_main_queue(), ^{ + [ios_view pick_file_save:path]; + }); + callback(path, true); + }; + return bridge; +} +#elif defined(__OSX__) +[[nodiscard]] pp::platform::apple::AppleDocumentPickerBridge make_legacy_apple_document_picker_bridge() +{ + const auto& apple_state = active_legacy_apple_state(); + auto* const osx_view = apple_state.osx_view; + auto* const osx_app = apple_state.osx_app; + + pp::platform::apple::AppleDocumentPickerBridge bridge; + bridge.clipboard_text = [osx_view] { + return [osx_view clipboard_get_string]; + }; + bridge.set_clipboard_text = [osx_view](std::string_view text) { + const std::string value(text); + return [osx_view clipboard_set_string:value]; + }; + bridge.share_file = [osx_view](std::string path) { + dispatch_async(dispatch_get_main_queue(), ^{ + [osx_view share_file:[NSString stringWithUTF8String:path.c_str()]]; + }); + }; + bridge.trigger_crash_test = [osx_view] { + [osx_view hockeyapp_crash]; + }; + bridge.request_app_close = [osx_view] { + dispatch_async(dispatch_get_main_queue(), ^{ + [osx_view close]; + }); + }; + bridge.acquire_render_context = [osx_view] { + [osx_view async_lock]; + }; + bridge.release_render_context = [osx_view] { + [osx_view async_unlock]; + }; + bridge.present_render_context = [osx_view] { + [osx_view async_swap]; + }; + bridge.set_cursor_visible = [osx_view](bool visible) { + [osx_view show_cursor:visible]; + }; + bridge.save_ui_state = [osx_app] { + [osx_app save_ui_state]; + }; + bridge.pick_file = [osx_view]( + std::vector file_types, + pp::platform::PickedPathCallback callback) { + dispatch_async(dispatch_get_main_queue(), ^{ + const std::string path = [osx_view pick_file:apple_file_types_array(file_types)]; + callback(path); + }); + }; + bridge.pick_save_file = [osx_view]( + std::vector file_types, + pp::platform::PickedPathCallback callback) { + dispatch_async(dispatch_get_main_queue(), ^{ + const std::string path = [osx_view pick_file_save:apple_file_types_array(file_types)]; + callback(path); + }); + }; + bridge.pick_directory = [osx_view](pp::platform::PickedPathCallback callback) { + dispatch_async(dispatch_get_main_queue(), ^{ + const std::string path = [osx_view pick_dir]; + callback(path); + }); + }; + bridge.format_working_directory_path = [](std::string_view path) { + char path_buffer[4096] = {}; + if (realpath(std::string(path).c_str(), path_buffer)) + return std::string(path_buffer); + return std::string(path); + }; + return bridge; +} +#endif + +[[nodiscard]] pp::platform::PlatformFamily legacy_apple_platform_family() +{ +#ifdef __IOS__ + return pp::platform::PlatformFamily::ios; +#else + return pp::platform::PlatformFamily::macos; +#endif +} +#endif + } #if defined(__LINUX__) || defined(__WEB__) @@ -55,6 +241,19 @@ void set_legacy_glfw_window(GLFWwindow* window) return state; } +[[nodiscard]] pp::platform::apple::AppleDocumentPlatformServices& +active_legacy_apple_document_platform_services() +{ + auto& retained = retained_legacy_apple_document_platform_state(); + if (!retained.services) + { + retained.services = std::make_unique( + legacy_apple_platform_family(), + make_legacy_apple_document_picker_bridge()); + } + return *retained.services; +} + void set_legacy_apple_state( #ifdef __IOS__ GameViewController* ios_view, @@ -66,17 +265,32 @@ void set_legacy_apple_state( ) { auto& retained = active_legacy_apple_state(); + bool changed = false; #ifdef __IOS__ if (ios_view) + { + changed = changed || retained.ios_view != ios_view; retained.ios_view = ios_view; + } if (ios_app) + { + changed = changed || retained.ios_app != ios_app; retained.ios_app = ios_app; + } #elif defined(__OSX__) if (osx_view) + { + changed = changed || retained.osx_view != osx_view; retained.osx_view = osx_view; + } if (osx_app) + { + changed = changed || retained.osx_app != osx_app; retained.osx_app = osx_app; + } #endif + if (changed) + retained_legacy_apple_document_platform_state().services.reset(); } #endif diff --git a/src/platform_legacy/legacy_platform_state.h b/src/platform_legacy/legacy_platform_state.h index 3501bcb6..1073506c 100644 --- a/src/platform_legacy/legacy_platform_state.h +++ b/src/platform_legacy/legacy_platform_state.h @@ -1,5 +1,6 @@ #pragma once +#include "platform_apple/apple_platform_services.h" #include "platform_api/platform_services.h" #if __LINUX__ || __WEB__ @@ -47,6 +48,8 @@ struct RetainedLegacyAppleState final { }; [[nodiscard]] RetainedLegacyAppleState& active_legacy_apple_state(); +[[nodiscard]] pp::platform::apple::AppleDocumentPlatformServices& +active_legacy_apple_document_platform_services(); void set_legacy_apple_state( #ifdef __IOS__ GameViewController* ios_view, diff --git a/src/platform_windows/windows_lifecycle_shell.cpp b/src/platform_windows/windows_lifecycle_shell.cpp index 6945ca20..a4fbdae4 100644 --- a/src/platform_windows/windows_lifecycle_shell.cpp +++ b/src/platform_windows/windows_lifecycle_shell.cpp @@ -4,6 +4,7 @@ #include "app.h" #include "legacy_preference_storage.h" +#include "platform_windows/windows_runtime_shell.h" #include "platform_windows/windows_stylus_input.h" namespace pp::platform::windows { @@ -50,6 +51,7 @@ void handle_window_close_message(VrShellState& vr) App::I->runtime().ui_thread_stop(); App::I->runtime().render_thread_stop(); App::I->terminate(); + bind_runtime(nullptr); delete App::I; PostQuitMessage(0); } diff --git a/src/platform_windows/windows_platform_services.cpp b/src/platform_windows/windows_platform_services.cpp index e87524b0..96e4b9bb 100644 --- a/src/platform_windows/windows_platform_services.cpp +++ b/src/platform_windows/windows_platform_services.cpp @@ -2,9 +2,11 @@ #include "platform_windows/windows_bootstrap_helpers.h" #include "platform_windows/windows_lifecycle_shell.h" #include "platform_windows/windows_platform_services.h" +#include "platform_windows/windows_runtime_shell.h" #include "platform_windows/windows_stylus_input.h" #include "platform_windows/windows_window_shell.h" +#include "app_runtime.h" #include "log.h" #include "legacy_gl_runtime_dispatch.h" #include "legacy_ui_gl_dispatch.h" @@ -171,18 +173,25 @@ void swap_async_render_context() void enqueue_main_thread_task(std::packaged_task task) { - if (!App::I) + if (auto* runtime = bound_runtime()) { - task(); + runtime->main_thread_task(std::move(task)); return; } - App::I->runtime().main_thread_task(std::move(task)); + + if (!task.valid()) + return; + + task(); } void drain_main_thread_tasks() { - if (App::I) - App::I->runtime().drain_main_thread_tasks(); + if (auto* runtime = bound_runtime()) + { + runtime->drain_main_thread_tasks(); + return; + } } } // namespace pp::platform::windows diff --git a/src/platform_windows/windows_runtime_shell.cpp b/src/platform_windows/windows_runtime_shell.cpp index fae8e0e3..671b35eb 100644 --- a/src/platform_windows/windows_runtime_shell.cpp +++ b/src/platform_windows/windows_runtime_shell.cpp @@ -3,6 +3,7 @@ #include "platform_windows/windows_runtime_shell.h" #include "app.h" +#include "app_runtime.h" #include "log.h" #include "platform_windows/windows_bootstrap_helpers.h" #include "platform_windows/windows_lifecycle_shell.h" @@ -16,6 +17,16 @@ namespace pp::platform::windows { namespace { +struct RetainedWindowsRuntimeState final { + AppRuntime* runtime = nullptr; +}; + +[[nodiscard]] RetainedWindowsRuntimeState& retained_runtime_state() +{ + static RetainedWindowsRuntimeState state; + return state; +} + void register_touch_window(HWND hWnd) { // link: https://docs.microsoft.com/en-us/windows/desktop/api/winuser/nf-winuser-registertouchwindow @@ -102,12 +113,23 @@ void shutdown_main_window_runtime(const MainWindowStartupState& startup, HINSTAN } +void bind_runtime(AppRuntime* runtime) noexcept +{ + retained_runtime_state().runtime = runtime; +} + +AppRuntime* bound_runtime() noexcept +{ + return retained_runtime_state().runtime; +} + int run_main_application(int argc, char** argv) { auto& state = retained_state(); state.hInst = GetModuleHandle(NULL); App::I = new App(); + bind_runtime(&App::I->runtime()); App::I->set_platform_services(&pp::platform::windows::platform_services()); App::I->initLog(); @@ -136,8 +158,10 @@ int run_main_application(int argc, char** argv) case pp::platform::windows::MainStartupResult::Ok: break; case pp::platform::windows::MainStartupResult::GladLoadFailure: + bind_runtime(nullptr); return 0; case pp::platform::windows::MainStartupResult::MissingCoreContextSupport: + bind_runtime(nullptr); return -1; } @@ -151,6 +175,7 @@ int run_main_application(int argc, char** argv) case const_hash("convert"): App::I->initShaders(); App::I->cmd_convert(argv[2], argv[3]); + bind_runtime(nullptr); return 0; case const_hash("-vrmode"): start_in_vr = true; diff --git a/src/platform_windows/windows_runtime_shell.h b/src/platform_windows/windows_runtime_shell.h index e2dbf5f8..d3f9388d 100644 --- a/src/platform_windows/windows_runtime_shell.h +++ b/src/platform_windows/windows_runtime_shell.h @@ -3,9 +3,13 @@ #include "platform_windows/windows_bootstrap_helpers.h" #include "platform_windows/windows_splash.h" +class AppRuntime; + namespace pp::platform::windows { int run_main_application(int argc, char** argv); void run_main_window_runtime(const MainWindowStartupState& startup, bool start_in_vr, SplashScreen& splash); +void bind_runtime(AppRuntime* runtime) noexcept; +[[nodiscard]] AppRuntime* bound_runtime() noexcept; }