diff --git a/PanoPainter-OSX/main.cpp b/PanoPainter-OSX/main.cpp index 7ccf14c0..da1a4655 100644 --- a/PanoPainter-OSX/main.cpp +++ b/PanoPainter-OSX/main.cpp @@ -8,7 +8,6 @@ #include "keymap.h" #include "main.h" #include "platform_apple/apple_platform_services.h" -#include "platform_legacy/legacy_platform_services.h" #include "settings.h" #include #include @@ -525,11 +524,7 @@ NSString* keyCodeToString(NSUInteger keyCode, NSUInteger mods) [MSCrashes class] ]]; - g_platform_services = pp::platform::legacy::create_platform_services({ - .apple_document_services = []() -> pp::platform::apple::AppleDocumentPlatformServices& { - return pp::platform::apple::active_legacy_apple_document_platform_services(); - }, - }); + g_platform_services = pp::platform::apple::create_apple_platform_services(); App::I->set_platform_services(g_platform_services.get()); App::I->initLog(); App::I->create(); diff --git a/PanoPainter/GameViewController.m b/PanoPainter/GameViewController.m index c5d18955..13120367 100644 --- a/PanoPainter/GameViewController.m +++ b/PanoPainter/GameViewController.m @@ -10,7 +10,6 @@ #import "GameViewController.h" #import #include "app.h" -#include "platform_legacy/legacy_platform_services.h" #include "platform_apple/apple_platform_services.h" #include "settings.h" #import "objc_utils.h" @@ -582,11 +581,7 @@ bool is_tap = true; pp::platform::apple::set_legacy_apple_state( self, (AppDelegate*)[[UIApplication sharedApplication] delegate]); - g_platform_services = pp::platform::legacy::create_platform_services({ - .apple_document_services = []() -> pp::platform::apple::AppleDocumentPlatformServices& { - return pp::platform::apple::active_legacy_apple_document_platform_services(); - }, - }); + g_platform_services = pp::platform::apple::create_apple_platform_services(); App::I->set_platform_services(g_platform_services.get()); App::I->initLog(); diff --git a/docs/modernization/debt.md b/docs/modernization/debt.md index 478b60a4..0da41238 100644 --- a/docs/modernization/debt.md +++ b/docs/modernization/debt.md @@ -18,6 +18,13 @@ agent or engineer to remove them without reconstructing context from chat. ## Reductions +- 2026-06-17: `DEBT-0016`/`DEBT-0017`/`DEBT-0050`/`DEBT-0051`/`DEBT-0052`/ + `DEBT-0053` were narrowed again. `src/platform_apple/apple_platform_services.*` + now owns the concrete Apple `PlatformServices` implementation and + `create_apple_platform_services()`, the Apple entrypoints bind that owned + service directly, and `src/platform_legacy/legacy_platform_services.*` no + longer carries the touched Apple execution branches or Apple provider + configuration surface. - 2026-06-17: `DEBT-0016`/`DEBT-0017`/`DEBT-0051`/`DEBT-0052`/`DEBT-0053` were narrowed again. `PanoPainter-OSX/main.cpp` and `PanoPainter/GameViewController.m` now bind owned legacy @@ -2390,8 +2397,8 @@ agent or engineer to remove them without reconstructing context from chat. | DEBT-0013 | Open | Modernization | `pp_assets`, `pp_document`, `pano_cli inspect-project`, `pano_cli load-project`, and `pano_cli save-project` validate the fixed PPI header, thumbnail/body byte layout, generated multi-layer/multi-frame PPI writing with explicit layer opacity/blend/alpha-lock/visibility metadata, per-layer frame durations, metadata-only and targeted dirty-face-payload save/load round-trips, layer/frame index, dirty-face descriptors, dirty-face PNG payload metadata, asset-level RGBA PNG payload decoding, pure document-to-PPI export, CLI document export automation, file-writing document export automation, stroke-script-generated document payload export, decoded pixel attachment to `pp_document`, live save-path snapshot-readiness reporting, and app-core canvas-snapshot-to-PPI export automation, but full legacy PPI round-trip parity and pure live save writer replacement are not yet extracted | Full PPI save parity requires staged extraction of legacy `Canvas` serialization and image/layer payload handling | `ctest --preset desktop-fast --build-config Debug`; `pp_assets_image_pixels_tests`; `pp_assets_ppi_header_tests`; `pp_document_ppi_import_tests`; `pp_document_ppi_export_tests`; `pano_cli_inspect_project_layout_smoke`; `pano_cli_load_project_metadata_smoke`; `pano_cli_save_project_roundtrip_smoke`; `pano_cli_save_project_payload_roundtrip_smoke`; `pano_cli_simulate_document_export_smoke`; `pano_cli_save_document_project_roundtrip_smoke`; `pano_cli_apply_stroke_script_roundtrip_smoke`; `pano_cli_apply_stroke_script_rejects_tiny_canvas` | Full PPI load/save fixtures cover thumbnails, decoded layer face payloads attached to documents, frames, corrupt payloads, dirty-face payload saving, arbitrary legacy canvas payload/layout combinations, and legacy app round-trip compatibility | | DEBT-0014 | Open | Modernization | `windows-clangcl-asan` now configures as a headless Ninja/clang-cl preset and uses the release MSVC runtime required by ASan, but local builds still fail because installed clang-cl 18.1.8 is paired with VS 2026-preview STL headers that require Clang 20 or newer | Sanitizer validation should be local and repeatable, but this machine's compiler/header pairing is incompatible | `cmake --fresh --preset windows-clangcl-asan`; `cmake --build --preset windows-clangcl-asan --target pp_foundation` | Install/use Clang 20+ with the VS 2026 STL, or point the preset at a compatible VS 2022 toolchain, then make `platform-build.ps1 -Presets windows-clangcl-asan` pass for the headless matrix | | DEBT-0015 | Open | Modernization | Cursor visibility requests now consume pure `pp_app_core` planning through `pano_cli plan-cursor-visibility`, `App::show_cursor`/`App::hide_cursor` dispatch through `PlatformServices` without platform guards, and Windows live execution uses injected `WindowsPlatformServices`, but macOS cursor execution still reaches the retained fallback adapter | Keep canvas cursor behavior stable while platform shells are extracted incrementally | `pp_app_core_document_platform_io_tests`; `pano_cli plan-cursor-visibility --visible`; `ctest --preset desktop-fast --build-config Debug` | Cursor visibility execution is owned by injected `pp_platform_*` services for every supported platform | -| DEBT-0016 | Open | Modernization | Clipboard get/set requests now consume pure `pp_app_core` planning through `pano_cli plan-clipboard-read` and `pano_cli plan-clipboard-write`, and Windows live execution uses injected `WindowsPlatformServices`, but Apple/Android clipboard execution still reaches retained fallback adapter branches from `App::clipboard_get_text` and `App::clipboard_set_text` | Keep picker/color text clipboard behavior stable while platform shells are extracted incrementally | `pp_app_core_document_platform_io_tests`; `pano_cli plan-clipboard-write --text #ff00aa`; `ctest --preset desktop-fast --build-config Debug` | Clipboard execution is owned by injected `pp_platform_*` services for every supported platform | -| DEBT-0017 | Open | Modernization | Startup storage path preparation, `App::clipboard_get_text`, `App::clipboard_set_text`, `App::show_cursor`, `App::hide_cursor`, `App::showKeyboard`, `App::hideKeyboard`, `App::display_file`, `App::share_file`, native app/window close, UI-thread lifecycle hooks, render-context acquire/release/present hooks, render-target binding hooks, render platform hint hooks, render debug callback hooks, render-capture frame hooks, recording cleanup, live asset/layout reload policy, diagnostic stacktrace/crash hooks, per-frame platform hooks, `App::pick_image`, `App::pick_file`, the non-writer `App::pick_file_save`, `App::pick_dir`, working-directory picker/display-path policy, canvas input tip/pressure policy, prepared-file save/download handoff, work-directory document export collection policy, app network TLS verification policy, PPBR export data-directory policy, SonarPen availability/startup, and VR mode start/stop now call the SDK-free `pp::platform::PlatformServices` interface, and Windows injects `WindowsPlatformServices` from `src/platform_windows/windows_platform_services.*`; Windows render-platform hint and debug-output state token/enable sequencing now delegates to tested `pp_renderer_gl` helpers, leaving Windows with context, callback, console, and Win32 ownership; the retained macOS fallback render-platform hint enable sequence also delegates to the same tested `pp_renderer_gl` helper; non-Windows live implementations still use `src/platform_legacy/legacy_platform_services.*`, a named fallback adapter that forwards to retained Apple/Android/Linux/Web bridge functions and retained no-op branches, including retained iOS canvas tip behavior, retained macOS directory picker/display-path behavior, retained iOS SonarPen bridge, retained non-Windows VR unsupported/no-op behavior, and retained macOS PPBR export directory override; `pp_platform_api` also owns the default network TLS policy helper consumed by retained curl sites that cannot yet depend on injected services | Preserve behavior while moving platform execution behind a testable service boundary before platform shell implementations are injected | `pp_platform_api_tests`; `pp_app_core_document_export_tests`; `pp_app_core_document_platform_io_tests`; `ctest --preset desktop-fast --build-config Debug`; `powershell -ExecutionPolicy Bypass -File scripts\automation\package-smoke.ps1 -Preset windows-msvc-default -Configuration Debug` | Replace `src/platform_legacy/legacy_platform_services.*` with injected `pp_platform_*` service implementations owned by each non-Windows platform shell | +| DEBT-0016 | Open | Modernization | Clipboard get/set requests now consume pure `pp_app_core` planning through `pano_cli plan-clipboard-read` and `pano_cli plan-clipboard-write`; Windows live execution uses injected `WindowsPlatformServices`, Apple clipboard execution now uses `src/platform_apple/apple_platform_services.*`, and Android clipboard execution still reaches the retained non-Windows fallback adapter | Keep picker/color text clipboard behavior stable while platform shells are extracted incrementally | `pp_app_core_document_platform_io_tests`; `pano_cli plan-clipboard-write --text #ff00aa`; `ctest --preset desktop-fast --build-config Debug` | Clipboard execution is owned by injected `pp_platform_*` services for every supported platform | +| DEBT-0017 | Open | Modernization | Startup storage path preparation, `App::clipboard_get_text`, `App::clipboard_set_text`, `App::show_cursor`, `App::hide_cursor`, `App::showKeyboard`, `App::hideKeyboard`, `App::display_file`, `App::share_file`, native app/window close, UI-thread lifecycle hooks, render-context acquire/release/present hooks, render-target binding hooks, render platform hint hooks, render debug callback hooks, render-capture frame hooks, recording cleanup, live asset/layout reload policy, diagnostic stacktrace/crash hooks, per-frame platform hooks, `App::pick_image`, `App::pick_file`, the non-writer `App::pick_file_save`, `App::pick_dir`, working-directory picker/display-path policy, canvas input tip/pressure policy, prepared-file save/download handoff, work-directory document export collection policy, app network TLS verification policy, PPBR export data-directory policy, SonarPen availability/startup, and VR mode start/stop now call the SDK-free `pp::platform::PlatformServices` interface. Windows injects `WindowsPlatformServices` from `src/platform_windows/windows_platform_services.*`, Apple now injects `src/platform_apple/apple_platform_services.*`, and the retained non-Windows fallback adapter in `src/platform_legacy/legacy_platform_services.*` is narrowed to Android/Linux/Web bridge functions plus retained no-op branches, including retained iOS canvas tip behavior, retained non-Windows VR unsupported/no-op behavior, and retained macOS PPBR export directory override; `pp_platform_api` also owns the default network TLS policy helper consumed by retained curl sites that cannot yet depend on injected services | Preserve behavior while moving platform execution behind a testable service boundary before platform shell implementations are injected | `pp_platform_api_tests`; `pp_app_core_document_export_tests`; `pp_app_core_document_platform_io_tests`; `ctest --preset desktop-fast --build-config Debug`; `powershell -ExecutionPolicy Bypass -File scripts\automation\package-smoke.ps1 -Preset windows-msvc-default -Configuration Debug` | Replace `src/platform_legacy/legacy_platform_services.*` with injected `pp_platform_*` service implementations owned by each non-Windows platform shell | | DEBT-0019 | Open | Modernization | Unreferenced-parameter warnings are muted globally through `pp_project_warnings` with MSVC `/wd4100` and Clang/GCC `-Wno-unused-parameter` | Legacy callbacks, virtual hooks, serializer methods, and platform/API compatibility functions carry many intentionally unused parameters during the component split; muting this keeps stricter warning builds focused on higher-signal migration issues | `cmake --build --preset windows-msvc-default --config Debug --target PanoPainter`; `ctest --preset desktop-fast --build-config Debug`; `cmake --build --preset linux-clang --target pp_foundation` | Remove `/wd4100` and `-Wno-unused-parameter`, mark intentionally unused parameters with names/comments or `[[maybe_unused]]`, and make the Windows app plus headless Clang/GCC tests pass without unreferenced-parameter warnings | | DEBT-0020 | Open | Modernization | Document resize dialog state, selected-resolution planning, and execution dispatch now consume pure `pp_app_core` through `NodeDialogResize`, `App::dialog_resize`, `pano_cli plan-document-resize`, and the `DocumentResizeServices` boundary, and live resize shares `src/legacy_document_canvas_services.*` with canvas clear commands; resize history clearing is an explicit app-core execution output implemented directly by the retained `ActionManager`, but the shared live bridge still calls legacy `Canvas::resize`, updates the legacy app title, and owns the retained `ActionManager` call site | Preserve existing layer/frame GPU resize behavior while the document model and canvas execution boundary are extracted incrementally | `pp_app_core_document_resize_tests`; `pano_cli plan-document-resize --current-resolution 2048 --selected-resolution-index 4`; `ctest --preset desktop-fast --build-config Debug` | Document resize execution is owned by injected document/app services with no legacy resize adapter, title shim, or retained `ActionManager` history clearing | | DEBT-0021 | Open | Modernization | Layer rename planning/execution dispatch, layer panel operation planning/execution dispatch, layer panel selected-control/visibility view projection, and explicit layer history-intent helpers now consume pure `pp_app_core` through `App::dialog_layer_rename`, `App::init_sidebar` layer callbacks, `NodePanelLayer::update_attributes()`, `pano_cli plan-layer-rename`, `pano_cli plan-layer-operation`, `pano_cli plan-layer-panel-view`, `DocumentLayerRenameServices`, and `DocumentLayerOperationServices`, and the live execution adapters are centralized in `src/legacy_document_layer_services.*`; rename now records undo before applying the new name through separate app-core service calls, but the shared bridge and panel adapter still mutate legacy `Canvas` layer state, `NodeLayer`/`NodePanelLayer`, and retained `ActionManager` undo entries for add/remove/property-change/clear paths | Preserve existing UI/canvas behavior while document layer commands, panel projection, and undo history are extracted incrementally | `pp_app_core_document_layer_tests`; `pano_cli plan-layer-rename --old-name Base --new-name Paint`; `pano_cli plan-layer-operation --kind add --layer-count 2 --index 1 --name Paint`; `pano_cli plan-layer-panel-view --layer-count 3 --current-index 1 --hidden-index 2 --locked-index 1 --current-opacity 0.25 --current-blend-mode 4`; `ctest --preset desktop-fast --build-config Debug` | Layer command execution and panel state projection are owned by the document/app command boundary with legacy `Canvas`/UI nodes acting only as adapters or removed entirely | @@ -2423,10 +2430,10 @@ agent or engineer to remove them without reconstructing context from chat. | DEBT-0047 | Open | Modernization | PPBR brush package export request validation, success-dialog metadata, and execution dispatch now consume pure `pp_app_core` through `App::dialog_ppbr_export`, `pano_cli plan-brush-package-export`, `BrushPackageExportServices`, and `src/legacy_brush_package_export_services.*`; PPBR header/path planning now consumes `pp_assets::brush_package`, the macOS data-directory override now routes through `PlatformServices`, and the desktop async path now uses a service-owned `std::jthread` worker with UI-thread dialog close/message handoff, but the bridge still reads `NodeDialogExportPPBR`, carries the legacy `Image` header object outside the pure request, converts to `NodePanelBrushPreset::PPBRInfo`, calls `NodePanelBrushPreset::export_ppbr`, and handles mobile/Web completion directly | Preserve current PPBR export behavior while brush assets, PPBR serialization, picker completion, and UI lifetime move toward asset/storage/UI/platform services | `pp_assets_brush_package_tests`; `pp_app_core_brush_package_export_tests`; `pp_platform_api_tests`; `pano_cli plan-brush-package-export --path D:/Paint/clouds.ppbr --author Artist --dest-path D:/Paint/BrushPreviews --export-data --header-image`; `pano_cli plan-brush-package-export --path D:/Paint/clouds.ppbr`; `pano_cli plan-brush-package-export`; `pano_cli plan-brush-package-export --path clouds`; `pano_cli plan-brush-package-export --path D:/Paint/clouds.ppbr --dest-path D:/Paint/BrushPreviews --no-export-data`; `ctest --preset desktop-fast --build-config Debug`; `cmake --build --preset windows-msvc-default --config Debug --target PanoPainter` | PPBR metadata collection, header-image ownership, serialization, picker-selected path execution, desktop threading, dialog lifetime, and mobile/Web completion are owned by injected brush asset/storage/UI/platform services with `App::dialog_ppbr_export` acting only as a UI adapter | | DEBT-0048 | Open | Modernization | ABR/PPBR brush package import execution now consumes pure `pp_app_core` through document-open confirmation callbacks, `pano_cli plan-brush-package-import`, `BrushPackageImportServices`, and `src/legacy_brush_package_import_services.*`; imported brush tip/pattern target paths now consume `pp_assets::brush_package`, and the retained bridge now uses a service-owned `std::jthread` worker with UI-thread completion handoff instead of detached `NodePanelBrushPreset::import_abr`/`import_ppbr` launches, but it still depends on the legacy preset panel as the importer/storage owner | Preserve current brush import behavior while brush package parsing, preset storage, progress/error reporting, and UI refresh move toward asset/paint/UI services | `pp_assets_brush_package_tests`; `pp_app_core_brush_package_import_tests`; `pano_cli plan-brush-package-import --kind ppbr --path D:/Paint/Brushes/clouds.ppbr`; `pano_cli plan-brush-package-import --kind abr --path D:/Paint/Brushes/clouds.abr`; `pano_cli plan-brush-package-import --kind ppbr`; `ctest --preset desktop-fast --build-config Debug`; `cmake --build --preset windows-msvc-default --config Debug --target PanoPainter` | ABR/PPBR parsing, preset creation/storage, import threading/progress, duplicate asset policy, and UI refresh are owned by injected brush asset/paint/UI services with document-open callbacks only confirming user intent | | DEBT-0049 | Open | Modernization | `pp_assets::validate_ppbr_header` intentionally preserves the legacy PPBR version check from `NodePanelBrushPreset::import_ppbr`, which accepts files when either major is `0` or minor is `1` instead of requiring exactly version `0.1` | Avoid rejecting existing brush packages before compatibility fixtures prove the stricter rule is safe | `pp_assets_brush_package_tests`; `pano_cli plan-brush-package-export --path D:/Paint/clouds.ppbr`; `ctest --preset desktop-fast --build-config Debug`; `cmake --build --preset windows-msvc-default --config Debug --target PanoPainter` | Add PPBR compatibility fixtures for accepted/rejected historical package versions, then require canonical `0.1` or an explicit supported-version matrix and update live import accordingly | -| DEBT-0050 | Open | Modernization | iOS exported-image photo-library publishing and WebGL persistent-storage flushing now dispatch through platform service boundaries; the iOS/Web policy decision lives in tested `pp_platform_api::platform_policy`, and WebGL flushing now goes through injectable `pp::platform::WebPlatformServices`, but non-Windows execution still lives in retained fallback adapters and forwards to retained `save_image_library`/`webgl_sync` bridges | Preserve current iOS/Web export and save behavior while the Apple/Web platform shells are extracted incrementally | `pp_platform_api_tests`; `ctest --preset desktop-fast --build-config Debug`; platform package smoke once Apple/Web root builds exist | Exported-image publishing and persistent-storage flushing are owned by injected Apple/Web `pp_platform_*` services with no legacy adapter branch | -| DEBT-0051 | Open | Modernization | Document browser search roots, Apple file/image/save/directory picker dispatch, Browse dialog working-directory picker visibility/path formatting, iOS Inbox roots, macOS empty-selection filtering, and macOS display-path formatting now dispatch through the tested `src/platform_apple/apple_platform_services.*` boundary consumed by `PlatformServices`; retained `src/platform_legacy/legacy_platform_services.*` still creates the Apple bridge and owns other non-Apple fallback behavior | Preserve current iOS document import/browse and desktop browse picker behavior while Apple platform shells are extracted incrementally | `pp_platform_api_tests`; `ctest --preset desktop-fast --build-config Debug`; Apple package smoke once root Apple builds exist | Document browse roots and browse-directory picker/display formatting are owned by injected Apple and desktop `pp_platform_*` services with no legacy adapter branch | -| DEBT-0052 | Open | Modernization | Native UI/window state saving now dispatches through `PlatformServices`; Windows/macOS save policy lives in tested `pp_platform_api::platform_policy`, and Windows placement reads/writes now use `LegacyWindowPreferenceSnapshot` plus `src/legacy_preference_storage.*`, but macOS execution still lives in `src/platform_legacy/legacy_platform_services.*` and forwards to the retained Objective-C app bridge while Windows still stores placement through retained `Settings` behind the adapter | Preserve current Windows/macOS UI persistence while platform shells are extracted incrementally | `pp_platform_api_tests`; `ctest --preset desktop-fast --build-config Debug`; Windows app build; Apple package smoke once root Apple builds exist | UI/window state persistence is owned by injected platform services with no legacy adapter branch | -| DEBT-0053 | Open | Modernization | Prepared-file writable target selection and prepared-file export-dialog policy now dispatch through platform service boundaries; iOS temporary-file and WebGL data-path target planning live in tested `pp_platform_api::platform_policy`, and WebGL prepared-file handoff now goes through injectable `pp::platform::WebPlatformServices`, but retained iOS/Web save/download handoff execution still lives in retained fallback adapters | Preserve mobile/Web export handoff behavior while platform shells are extracted incrementally | `pp_platform_api_tests`; `ctest --preset desktop-fast --build-config Debug`; Windows app build; Apple/Web package smoke once root package builds exist | Prepared-file target selection, export-dialog policy, and save/download handoff are owned by injected platform services with no legacy adapter branch | +| DEBT-0050 | Open | Modernization | iOS exported-image photo-library publishing and WebGL persistent-storage flushing now dispatch through platform service boundaries; the iOS/Web policy decision lives in tested `pp_platform_api::platform_policy`, iOS execution now lives in injected `src/platform_apple/apple_platform_services.*`, and WebGL flushing now goes through injectable `pp::platform::WebPlatformServices`, but retained Web execution still forwards to `webgl_sync` bridges | Preserve current iOS/Web export and save behavior while the Apple/Web platform shells are extracted incrementally | `pp_platform_api_tests`; `ctest --preset desktop-fast --build-config Debug`; platform package smoke once Apple/Web root builds exist | Exported-image publishing and persistent-storage flushing are owned by injected Apple/Web `pp_platform_*` services with no legacy adapter branch | +| DEBT-0051 | Open | Modernization | Document browser search roots, Apple file/image/save/directory picker dispatch, Browse dialog working-directory picker visibility/path formatting, iOS Inbox roots, macOS empty-selection filtering, and macOS display-path formatting now dispatch through the tested `src/platform_apple/apple_platform_services.*` boundary consumed by `PlatformServices`; retained `src/platform_legacy/legacy_platform_services.*` still owns other non-Apple fallback behavior | Preserve current iOS document import/browse and desktop browse picker behavior while Apple platform shells are extracted incrementally | `pp_platform_api_tests`; `ctest --preset desktop-fast --build-config Debug`; Apple package smoke once root Apple builds exist | Document browse roots and browse-directory picker/display formatting are owned by injected Apple and desktop `pp_platform_*` services with no legacy adapter branch | +| DEBT-0052 | Open | Modernization | Native UI/window state saving now dispatches through `PlatformServices`; Windows/macOS save policy lives in tested `pp_platform_api::platform_policy`, macOS execution now lives in injected `src/platform_apple/apple_platform_services.*`, and Windows placement reads/writes now use `LegacyWindowPreferenceSnapshot` plus `src/legacy_preference_storage.*`, but Windows still stores placement through retained `Settings` behind the adapter | Preserve current Windows/macOS UI persistence while platform shells are extracted incrementally | `pp_platform_api_tests`; `ctest --preset desktop-fast --build-config Debug`; Windows app build; Apple package smoke once root Apple builds exist | UI/window state persistence is owned by injected platform services with no legacy adapter branch | +| DEBT-0053 | Open | Modernization | Prepared-file writable target selection and prepared-file export-dialog policy now dispatch through platform service boundaries; iOS temporary-file policy plus prepared-file save handoff now live in injected `src/platform_apple/apple_platform_services.*`, WebGL data-path planning lives in tested `pp_platform_api::platform_policy`, and WebGL prepared-file handoff now goes through injectable `pp::platform::WebPlatformServices`, but retained Web save/download handoff execution still lives in fallback adapters | Preserve mobile/Web export handoff behavior while platform shells are extracted incrementally | `pp_platform_api_tests`; `ctest --preset desktop-fast --build-config Debug`; Windows app build; Apple/Web package smoke once root package builds exist | Prepared-file target selection, export-dialog policy, and save/download handoff are owned by injected platform services with no legacy adapter branch | | DEBT-0054 | Open | Modernization | Layout XML file read/reload decisions now consume `pp_platform_api::plan_asset_file_load`; platform-family reload behavior lives in tested `pp_platform_api::platform_policy` and pure probed planning, but the live wrapper still performs direct `stat` probing for Windows/macOS mtime reload checks until platform storage/file-watch services exist | Preserve current layout hot-reload and mobile/Web single-load behavior while removing platform guards from the shared `LayoutManager` parser | `pp_platform_api_tests`; `ctest --preset desktop-fast --build-config Debug -R pp_platform_api_tests`; Windows app build | Layout reload decisions are owned by injected platform storage/file-watch services or an asset manager boundary with platform-specific file watching removed from compile-time helpers | | DEBT-0055 | Open | Modernization | `src/app.h` now forward-declares retained iOS/macOS/Android/Linux/Web platform handles instead of including platform SDK headers, and full SDK includes are isolated in `src/platform_legacy/legacy_platform_services.cpp`, but the `App` singleton still stores those platform handles directly | Reduce central header platform coupling incrementally without rewriting non-Windows platform entrypoints before Phase 6 | Windows app build; Apple/Android/Linux/Web package smoke once platform root builds are active | Platform handles are owned by injected `pp_platform_*` shell state or services, and `App` has no platform SDK handle fields or platform conditional members | | DEBT-0056 | Open | Modernization | `src/asset.h` is now Android-SDK-free and uses opaque Android asset handles behind `Asset::set_android_asset_manager`, but retained `Asset` still owns a static Android asset-manager bridge and `src/asset.cpp` still performs Android `AAssetManager` reads directly; the current `android-arm64` root preset is headless and does not expose `pp_legacy_assets_io`, though the retained Android standard package `native-lib` now builds through its refreshed C++23 CMake path | Reduce legacy asset I/O header coupling without rewriting Android asset loading before the asset manager/storage boundary exists | Windows app build; `powershell -ExecutionPolicy Bypass -File scripts\automation\platform-build.ps1 -Presets android-arm64 -Targets pp_assets`; `powershell -ExecutionPolicy Bypass -File scripts\automation\android-legacy-package-build.ps1 -Packages standard` | Android asset loading is owned by injected asset storage/platform services or `pp_assets` file providers, with no static Android asset manager on `Asset` | diff --git a/docs/modernization/roadmap.md b/docs/modernization/roadmap.md index bcfb2b0b..53f47b10 100644 --- a/docs/modernization/roadmap.md +++ b/docs/modernization/roadmap.md @@ -70,16 +70,22 @@ What is already real: - `pp_app_core` Latest slice: +- `src/platform_apple/apple_platform_services.*` now owns the concrete Apple + `PlatformServices` implementation plus the `create_apple_platform_services()` + factory instead of leaving the live Apple execution surface inside + `platform_legacy`. - `PanoPainter-OSX/main.cpp` and `PanoPainter/GameViewController.m` now bind - owned legacy `PlatformServices` instances into `App` explicitly at the Apple + owned Apple `PlatformServices` instances into `App` directly at the Apple entrypoints. -- `src/platform_legacy/legacy_platform_services.*` now takes an injected Apple - document-service provider through `create_platform_services(...)` instead of - hardcoding direct calls to - `active_legacy_apple_document_platform_services()` in the touched path. - The touched Apple clipboard, keyboard visibility, render-context, - document-picker, display/share, save-ui-state, app-close, SonarPen, and - prepared-file execution now route through that injected Apple-owned provider. + document-picker, display/share, save-ui-state, app-close, SonarPen, + recording cleanup, exported-image publish, and prepared-file execution now + route through `src/platform_apple/apple_platform_services.*` instead of the + cross-platform fallback adapter. +- `src/platform_legacy/legacy_platform_services.*` no longer carries the Apple + document-service provider/configuration surface or the touched Apple method + branches, so the retained fallback adapter is narrower and now focused on the + Android/Linux/Web path. - `src/platform_legacy/legacy_platform_services.*` now takes an explicit Android bridge through `create_platform_services(...)` instead of declaring Android JNI/EGL/clipboard/file-picker hooks directly inside the legacy @@ -103,14 +109,21 @@ Latest slice: - Linux, WebGL, and Android were already on owned `create_platform_services(...)` instances, so removing that legacy singleton surface does not change the live entrypoint ownership path. -- `src/platform_windows/windows_runtime_state.*` now owns the Win32 bound-app - and bound-tablet bindings beside the retained owned `App`, `AppRuntime*`, - and `WacomTablet` objects instead of leaving that binding surface in - `windows_runtime_shell.cpp`. +- `src/platform_windows/windows_runtime_state.*` now owns the Win32 bound-app, + bound-runtime shutdown, and bound-tablet bindings beside the retained owned + `App`, `AppRuntime*`, and `WacomTablet` objects instead of leaving that + binding surface in `windows_runtime_shell.cpp`. - `src/platform_windows/windows_runtime_state.*` now also owns the Win32 owned-app creation plus app/runtime binding handoff, so `windows_runtime_shell.cpp` is down to a thinner startup dispatcher over the retained runtime-state helper. +- `src/platform_windows/windows_runtime_state.*` now also owns the bound + Win32 app/runtime shutdown order, so `windows_lifecycle_shell.cpp` is down + to close-message dispatch instead of manually stopping threads and + terminating the bound app itself. +- `src/platform_windows/windows_lifecycle_state.*` now also owns the Win32 + lifecycle close/VR control handoff, so `windows_lifecycle_shell.cpp` is + down to a thinner message adapter over the retained lifecycle state helper. - `src/platform_windows/windows_runtime_shell.h` is now a thinner runtime entrypoint header that picks up the retained binding surface from `windows_runtime_state.h` instead of declaring a second shell-owned binding diff --git a/docs/modernization/tasks.md b/docs/modernization/tasks.md index 941d88db..f50ffe73 100644 --- a/docs/modernization/tasks.md +++ b/docs/modernization/tasks.md @@ -49,8 +49,10 @@ Completed, blocked, and superseded task history moved to `platform_legacy` - Apple retained bridge/state ownership now lives in `src/platform_apple/apple_platform_state.cpp` and - `src/platform_apple/apple_platform_services.*`, but the legacy platform - facade still routes a broad Apple service surface instead of disappearing + `src/platform_apple/apple_platform_services.*`, and the live Apple + `PlatformServices` surface now binds directly from those Apple-owned files, + but the broader non-Windows fallback adapter still exists for + Android/Linux/Web - `platform_legacy` is still part of the live app shell - The app runtime boundary is not finished: - render/UI queues are static `App` state @@ -78,16 +80,22 @@ Completed, blocked, and superseded task history moved to the queue is now ordered by code movement instead. Current slice: +- `src/platform_apple/apple_platform_services.*` now owns the concrete Apple + `PlatformServices` implementation plus the `create_apple_platform_services()` + factory instead of leaving the live Apple execution surface in + `platform_legacy`. - `PanoPainter-OSX/main.cpp` and `PanoPainter/GameViewController.m` now bind - owned legacy `PlatformServices` instances into `App` explicitly at the Apple + owned Apple `PlatformServices` instances into `App` directly at the Apple entrypoints. -- `src/platform_legacy/legacy_platform_services.*` now takes an injected Apple - document-service provider through `create_platform_services(...)` instead of - hardcoding direct calls to - `active_legacy_apple_document_platform_services()` in the touched path. - The touched Apple clipboard, keyboard visibility, render-context, - document-picker, display/share, save-ui-state, app-close, SonarPen, and - prepared-file execution now route through that injected Apple-owned provider. + document-picker, display/share, save-ui-state, app-close, SonarPen, + recording cleanup, exported-image publish, and prepared-file execution now + route through `src/platform_apple/apple_platform_services.*` instead of the + cross-platform fallback adapter. +- `src/platform_legacy/legacy_platform_services.*` no longer carries the Apple + document-service provider/configuration surface or the touched Apple method + branches, so the retained fallback adapter is narrower and now focused on the + Android/Linux/Web path. - `src/platform_legacy/legacy_platform_services.*` now takes an explicit Android bridge through `create_platform_services(...)` instead of declaring Android JNI/EGL/clipboard/file-picker hooks directly inside the legacy @@ -112,12 +120,19 @@ Current slice: `create_platform_services(...)` instances, so removing that singleton does not change the live entrypoint ownership path. - `src/platform_windows/windows_runtime_state.*` now also owns the bound - Win32 `App*` / tablet binding surface alongside the retained owned `App`, - runtime, and tablet objects. + Win32 `App*`, bound-runtime shutdown, and tablet binding surface alongside + the retained owned `App`, runtime, and tablet objects. - `src/platform_windows/windows_runtime_state.*` now also owns the Win32 owned-app creation plus app/runtime binding handoff, so `windows_runtime_shell.cpp` is thinner and no longer open-codes that retained runtime-state setup. +- `src/platform_windows/windows_runtime_state.*` now also owns the bound + Win32 app/runtime shutdown order, so `windows_lifecycle_shell.cpp` is down + to close-message dispatch instead of manually stopping threads and + terminating the bound app. +- `src/platform_windows/windows_lifecycle_state.*` now also owns the Win32 + lifecycle close/VR control handoff, so `windows_lifecycle_shell.cpp` is + down to a thinner message adapter over the retained lifecycle state helper. - `src/platform_windows/windows_runtime_shell.h` is thinner again and now imports that binding surface from `windows_runtime_state.h` instead of declaring shell-owned bind/release accessors itself. diff --git a/src/platform_apple/apple_platform_services.cpp b/src/platform_apple/apple_platform_services.cpp index 2e55f5b0..077cec9b 100644 --- a/src/platform_apple/apple_platform_services.cpp +++ b/src/platform_apple/apple_platform_services.cpp @@ -1,9 +1,18 @@ #include "platform_apple/apple_platform_services.h" #include "app_core/document_platform_io.h" +#include "platform_api/network_tls_policy.h" #include "platform_api/platform_policy.h" +#if defined(__APPLE__) +#include "legacy_ui_gl_dispatch.h" +#include "log.h" +#include "objc_utils.h" +#include "renderer_gl/opengl_capabilities.h" +#endif + #include +#include #include namespace pp::platform::apple { @@ -31,6 +40,25 @@ void invoke_picked_path_if_selected( callback(path); } +[[nodiscard]] AppleDocumentPlatformServices& active_document_platform_services() noexcept +{ +#if defined(__APPLE__) + return active_legacy_apple_document_platform_services(); +#else + static AppleDocumentPlatformServices services(PlatformFamily::macos, {}); + return services; +#endif +} + +[[nodiscard]] PlatformFamily active_platform_family() noexcept +{ +#if defined(__APPLE__) + return legacy_apple_platform_family(); +#else + return PlatformFamily::macos; +#endif +} + } AppleDocumentPlatformServices::AppleDocumentPlatformServices( @@ -254,4 +282,305 @@ void AppleDocumentPlatformServices::save_ui_state() const #endif } +PlatformStoragePaths ApplePlatformServices::prepare_storage_paths() +{ +#if defined(__APPLE__) + return prepare_legacy_apple_storage_paths(); +#else + return {}; +#endif +} + +void ApplePlatformServices::log_stacktrace() +{ +#if defined(__OSX__) + NSString* callstack = [[NSThread callStackSymbols] componentsJoinedByString:@"\n"]; + LOG("callstack:\n%s", [callstack cStringUsingEncoding:NSUTF8StringEncoding]); +#endif +} + +void ApplePlatformServices::trigger_crash_test() +{ + active_document_platform_services().trigger_crash_test(); +} + +std::string ApplePlatformServices::clipboard_text() +{ + return active_document_platform_services().clipboard_text(); +} + +bool ApplePlatformServices::set_clipboard_text(std::string_view text) +{ + return active_document_platform_services().set_clipboard_text(text); +} + +void ApplePlatformServices::set_cursor_visible(bool visible) +{ + active_document_platform_services().set_cursor_visible(visible); +} + +void ApplePlatformServices::set_virtual_keyboard_visible(bool visible) +{ + active_document_platform_services().set_virtual_keyboard_visible(visible); +} + +void ApplePlatformServices::attach_ui_thread() +{ +} + +void ApplePlatformServices::detach_ui_thread() +{ +} + +void ApplePlatformServices::acquire_render_context() +{ + active_document_platform_services().acquire_render_context(); +} + +void ApplePlatformServices::release_render_context() +{ + active_document_platform_services().release_render_context(); +} + +void ApplePlatformServices::present_render_context() +{ + active_document_platform_services().present_render_context(); +} + +void ApplePlatformServices::bind_default_render_target() +{ +#if defined(__APPLE__) + pp::legacy::ui_gl::bind_opengl_framebuffer( + pp::renderer::gl::framebuffer_target(), + pp::renderer::gl::default_framebuffer_id()); +#endif +} + +void ApplePlatformServices::bind_main_render_target() +{ +#if defined(__IOS__) + active_document_platform_services().bind_main_render_target(); +#else + bind_default_render_target(); +#endif +} + +void ApplePlatformServices::apply_render_platform_hints() +{ +#if defined(__OSX__) + const auto status = pp::renderer::gl::apply_opengl_render_platform_hints( + pp::renderer::gl::OpenGlRenderPlatformHintDispatch { + .enable = pp::legacy::ui_gl::enable_opengl_state, + }); + if (!status.ok()) + LOG("OpenGL legacy render platform hints failed: %s", status.message); +#endif +} + +void ApplePlatformServices::install_render_debug_callback() +{ +} + +void ApplePlatformServices::begin_render_capture_frame() +{ +} + +void ApplePlatformServices::end_render_capture_frame() +{ +} + +bool ApplePlatformServices::deletes_recorded_files_on_clear() +{ + return platform_deletes_recorded_files_on_clear(active_platform_family()); +} + +void ApplePlatformServices::clear_recorded_files(std::string_view recording_path) +{ +#if defined(__APPLE__) + delete_all_files_in_path(std::string(recording_path)); +#else + (void)recording_path; +#endif +} + +void ApplePlatformServices::publish_exported_image(std::string_view path) +{ + if (!platform_publishes_exported_images(active_platform_family())) + return; +#if defined(__IOS__) + save_image_library(std::string(path)); +#else + (void)path; +#endif +} + +void ApplePlatformServices::flush_persistent_storage() +{ +} + +std::vector ApplePlatformServices::document_browse_roots( + std::string_view work_path, + std::string_view data_path) +{ + return active_document_platform_services().document_browse_roots(work_path, data_path); +} + +void ApplePlatformServices::save_ui_state() +{ + if (!platform_saves_native_ui_state(active_platform_family())) + return; + active_document_platform_services().save_ui_state(); +} + +bool ApplePlatformServices::enables_live_asset_reloading() +{ + return platform_enables_live_asset_reloading(active_platform_family()); +} + +void ApplePlatformServices::update_platform_frame(float delta_time_seconds) +{ + (void)delta_time_seconds; +} + +void ApplePlatformServices::report_rendered_frames(int frames) +{ + (void)frames; +} + +void ApplePlatformServices::pick_image(PickedPathCallback callback) +{ + active_document_platform_services().pick_image(std::move(callback)); +} + +void ApplePlatformServices::pick_file(std::vector file_types, PickedPathCallback callback) +{ + active_document_platform_services().pick_file(std::move(file_types), std::move(callback)); +} + +void ApplePlatformServices::pick_save_file(std::vector file_types, PickedPathCallback callback) +{ + active_document_platform_services().pick_save_file(std::move(file_types), std::move(callback)); +} + +void ApplePlatformServices::pick_directory(PickedPathCallback callback) +{ + active_document_platform_services().pick_directory(std::move(callback)); +} + +bool ApplePlatformServices::supports_working_directory_picker() +{ + return active_document_platform_services().supports_working_directory_picker(); +} + +std::string ApplePlatformServices::format_working_directory_path(std::string_view path) +{ + return active_document_platform_services().format_working_directory_path(path); +} + +bool ApplePlatformServices::uses_prepared_file_writes() +{ + return platform_uses_prepared_file_writes(active_platform_family()); +} + +bool ApplePlatformServices::uses_work_directory_document_export_collections() +{ + return platform_uses_work_directory_document_export_collections(active_platform_family()); +} + +bool ApplePlatformServices::disables_network_tls_verification() +{ + return default_disables_network_tls_verification(); +} + +bool ApplePlatformServices::uses_ppbr_export_data_directory_override() +{ + return platform_uses_ppbr_export_data_directory_override(active_platform_family()); +} + +bool ApplePlatformServices::supports_sonarpen() +{ + return platform_supports_sonarpen(active_platform_family()); +} + +void ApplePlatformServices::start_sonarpen() +{ + active_document_platform_services().start_sonarpen(); +} + +int ApplePlatformServices::default_canvas_resolution() +{ + return platform_default_canvas_resolution(active_platform_family()); +} + +bool ApplePlatformServices::draws_canvas_tip_for_pointer( + bool is_mouse, + bool is_stylus, + bool is_left_button_release) +{ + return platform_draws_canvas_tip_for_pointer( + active_platform_family(), + is_mouse, + is_stylus, + is_left_button_release); +} + +float ApplePlatformServices::adjust_canvas_input_pressure(float pressure) +{ + return pressure; +} + +PreparedFileTarget ApplePlatformServices::prepare_writable_file( + std::string_view type, + std::string_view default_name, + std::string_view data_path, + std::string_view temporary_path) +{ + return plan_platform_writable_file( + active_platform_family(), + type, + default_name, + data_path, + temporary_path); +} + +void ApplePlatformServices::display_file(std::string_view path) +{ + active_document_platform_services().display_file(path); +} + +void ApplePlatformServices::share_file(std::string_view path) +{ + active_document_platform_services().share_file(path); +} + +void ApplePlatformServices::request_app_close() +{ + active_document_platform_services().request_app_close(); +} + +bool ApplePlatformServices::start_vr_mode() +{ + return false; +} + +void ApplePlatformServices::stop_vr_mode() +{ +} + +void ApplePlatformServices::save_prepared_file( + std::string_view path, + std::string_view suggested_name, + PreparedFileCallback callback) +{ + active_document_platform_services().save_prepared_file( + path, + suggested_name, + std::move(callback)); +} + +std::unique_ptr create_apple_platform_services() +{ + return std::make_unique(); +} + } diff --git a/src/platform_apple/apple_platform_services.h b/src/platform_apple/apple_platform_services.h index aac956b0..1537410f 100644 --- a/src/platform_apple/apple_platform_services.h +++ b/src/platform_apple/apple_platform_services.h @@ -4,6 +4,7 @@ #include "platform_api/platform_services.h" #include +#include #include #include #include @@ -95,6 +96,74 @@ private: AppleDocumentPickerBridge bridge_; }; +class ApplePlatformServices final : public PlatformServices { +public: + ApplePlatformServices() = default; + + [[nodiscard]] PlatformStoragePaths prepare_storage_paths() override; + void log_stacktrace() override; + void trigger_crash_test() override; + [[nodiscard]] std::string clipboard_text() override; + [[nodiscard]] bool set_clipboard_text(std::string_view text) override; + void set_cursor_visible(bool visible) override; + void set_virtual_keyboard_visible(bool visible) override; + void attach_ui_thread() override; + void detach_ui_thread() override; + void acquire_render_context() override; + void release_render_context() override; + void present_render_context() override; + void bind_default_render_target() override; + void bind_main_render_target() override; + void apply_render_platform_hints() override; + void install_render_debug_callback() override; + void begin_render_capture_frame() override; + void end_render_capture_frame() override; + [[nodiscard]] bool deletes_recorded_files_on_clear() override; + void clear_recorded_files(std::string_view recording_path) override; + void publish_exported_image(std::string_view path) override; + void flush_persistent_storage() override; + [[nodiscard]] std::vector document_browse_roots( + std::string_view work_path, + std::string_view data_path) override; + void save_ui_state() override; + [[nodiscard]] bool enables_live_asset_reloading() override; + void update_platform_frame(float delta_time_seconds) override; + void report_rendered_frames(int frames) override; + void pick_image(PickedPathCallback callback) override; + void pick_file(std::vector file_types, PickedPathCallback callback) override; + void pick_save_file(std::vector file_types, PickedPathCallback callback) override; + void pick_directory(PickedPathCallback callback) override; + [[nodiscard]] bool supports_working_directory_picker() override; + [[nodiscard]] std::string format_working_directory_path(std::string_view path) override; + [[nodiscard]] bool uses_prepared_file_writes() override; + [[nodiscard]] bool uses_work_directory_document_export_collections() override; + [[nodiscard]] bool disables_network_tls_verification() override; + [[nodiscard]] bool uses_ppbr_export_data_directory_override() override; + [[nodiscard]] bool supports_sonarpen() override; + void start_sonarpen() override; + [[nodiscard]] int default_canvas_resolution() override; + [[nodiscard]] bool draws_canvas_tip_for_pointer( + bool is_mouse, + bool is_stylus, + bool is_left_button_release) override; + [[nodiscard]] float adjust_canvas_input_pressure(float pressure) override; + [[nodiscard]] PreparedFileTarget prepare_writable_file( + std::string_view type, + std::string_view default_name, + std::string_view data_path, + std::string_view temporary_path) override; + void display_file(std::string_view path) override; + void share_file(std::string_view path) override; + void request_app_close() override; + [[nodiscard]] bool start_vr_mode() override; + void stop_vr_mode() override; + void save_prepared_file( + std::string_view path, + std::string_view suggested_name, + PreparedFileCallback callback) override; +}; + +[[nodiscard]] std::unique_ptr create_apple_platform_services(); [[nodiscard]] RetainedLegacyAppleState& active_legacy_apple_state(); [[nodiscard]] AppleDocumentPlatformServices& active_legacy_apple_document_platform_services(); diff --git a/src/platform_legacy/legacy_platform_services.cpp b/src/platform_legacy/legacy_platform_services.cpp index ce82560c..d8b4a94d 100644 --- a/src/platform_legacy/legacy_platform_services.cpp +++ b/src/platform_legacy/legacy_platform_services.cpp @@ -5,19 +5,12 @@ #include "legacy_ui_gl_dispatch.h" #include "log.h" -#include "platform_apple/apple_platform_services.h" #include "platform_api/network_tls_policy.h" #include "platform_api/platform_policy.h" #include "renderer_gl/opengl_capabilities.h" #ifdef __ANDROID__ #include "main.h" -#elif __APPLE__ -#include -void delete_all_files_in_path(const std::string& source_path); -#ifdef __IOS__ -void save_image_library(const std::string& path); -#endif #elif __LINUX__ #include #include "platform_linux/linux_platform_services.h" @@ -45,17 +38,12 @@ public: , android_storage_paths_(std::move(config.android_storage_paths)) #endif , web_platform_services_(config.web_platform_services) - , apple_document_services_(std::move(config.apple_document_services)) { } [[nodiscard]] pp::platform::PlatformStoragePaths prepare_storage_paths() override { -#if defined(__IOS__) - return pp::platform::apple::prepare_legacy_apple_storage_paths(); -#elif defined(__OSX__) - return pp::platform::apple::prepare_legacy_apple_storage_paths(); -#elif __LINUX__ +#if __LINUX__ const std::string data_path = linux_home_path() + "/PanoPainter"; mkpath(data_path + "/brushes"); mkpath(data_path + "/brushes/thumbs"); @@ -93,19 +81,11 @@ public: void log_stacktrace() override { -#if defined(__OSX__) - NSString* callstack = [[NSThread callStackSymbols] componentsJoinedByString:@"\n"]; - LOG("callstack:\n%s", [callstack cStringUsingEncoding:NSUTF8StringEncoding]); -#endif } void trigger_crash_test() override { -#ifdef __IOS__ - active_apple_document_platform_services().trigger_crash_test(); -#elif __OSX__ - active_apple_document_platform_services().trigger_crash_test(); -#elif defined(__ANDROID__) +#if defined(__ANDROID__) int *x = nullptr; *x = 42; LOG("%d", *x); #endif @@ -113,11 +93,6 @@ public: [[nodiscard]] std::string clipboard_text() override { -#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(); -#endif #ifdef __ANDROID__ if (android_bridge_.clipboard_text) return android_bridge_.clipboard_text(); @@ -129,11 +104,6 @@ public: [[nodiscard]] bool set_clipboard_text(std::string_view text) override { -#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); -#endif const std::string value(text); #ifdef __ANDROID__ if (android_bridge_.set_clipboard_text) @@ -147,18 +117,12 @@ public: void set_cursor_visible(bool visible) override { -#if defined(__IOS__) || defined(__OSX__) - active_apple_document_platform_services().set_cursor_visible(visible); -#else (void)visible; -#endif } void set_virtual_keyboard_visible(bool visible) override { -#ifdef __IOS__ - active_apple_document_platform_services().set_virtual_keyboard_visible(visible); -#elif __ANDROID__ +#ifdef __ANDROID__ if (android_bridge_.set_virtual_keyboard_visible) android_bridge_.set_virtual_keyboard_visible(visible); #else @@ -184,9 +148,7 @@ public: void acquire_render_context() override { -#if defined(__IOS__) || defined(__OSX__) - active_apple_document_platform_services().acquire_render_context(); -#elif __ANDROID__ +#if __ANDROID__ if (android_bridge_.acquire_render_context) android_bridge_.acquire_render_context(); #elif __LINUX__ || __WEB__ @@ -196,9 +158,7 @@ public: void release_render_context() override { -#if defined(__IOS__) || defined(__OSX__) - active_apple_document_platform_services().release_render_context(); -#elif __ANDROID__ +#if __ANDROID__ if (android_bridge_.release_render_context) android_bridge_.release_render_context(); #endif @@ -206,9 +166,7 @@ public: void present_render_context() override { -#if defined(__IOS__) || defined(__OSX__) - active_apple_document_platform_services().present_render_context(); -#elif __ANDROID__ +#if __ANDROID__ if (android_bridge_.present_render_context) android_bridge_.present_render_context(); #elif __LINUX__ || __WEB__ @@ -225,23 +183,11 @@ public: void bind_main_render_target() override { -#if __IOS__ - active_apple_document_platform_services().bind_main_render_target(); -#else bind_default_render_target(); -#endif } void apply_render_platform_hints() override { -#if defined(__OSX__) - const auto status = pp::renderer::gl::apply_opengl_render_platform_hints( - pp::renderer::gl::OpenGlRenderPlatformHintDispatch { - .enable = pp::legacy::ui_gl::enable_opengl_state, - }); - if (!status.ok()) - LOG("OpenGL legacy render platform hints failed: %s", status.message); -#endif } void install_render_debug_callback() override @@ -264,11 +210,7 @@ public: void clear_recorded_files(std::string_view recording_path) override { -#if defined(__IOS__) || defined(__OSX__) - delete_all_files_in_path(std::string(recording_path)); -#else (void)recording_path; -#endif } void publish_exported_image(std::string_view path) override @@ -284,11 +226,7 @@ public: (void)path; return; } -#ifdef __IOS__ - save_image_library(std::string(path)); -#else (void)path; -#endif } void flush_persistent_storage() override @@ -307,23 +245,16 @@ public: std::string_view work_path, std::string_view data_path) override { -#if defined(__IOS__) || defined(__OSX__) - return active_apple_document_platform_services().document_browse_roots(work_path, data_path); -#else return pp::platform::platform_document_browse_roots( pp::platform::current_platform_family(), work_path, data_path); -#endif } void save_ui_state() override { 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(); -#endif } [[nodiscard]] bool enables_live_asset_reloading() override @@ -348,11 +279,7 @@ public: void pick_image(pp::platform::PickedPathCallback callback) override { -#ifdef __IOS__ - active_apple_document_platform_services().pick_image(std::move(callback)); -#elif __OSX__ - active_apple_document_platform_services().pick_image(std::move(callback)); -#elif __ANDROID__ +#ifdef __ANDROID__ if (android_bridge_.pick_file) android_bridge_.pick_file(std::move(callback)); #elif __LINUX__ @@ -367,11 +294,7 @@ 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)); -#elif __OSX__ - active_apple_document_platform_services().pick_file(std::move(file_types), std::move(callback)); -#elif __ANDROID__ +#ifdef __ANDROID__ if (android_bridge_.pick_file) android_bridge_.pick_file(std::move(callback)); #elif __LINUX__ @@ -387,9 +310,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)); -#elif __ANDROID__ +#if __ANDROID__ if (android_bridge_.pick_save_file) android_bridge_.pick_save_file(std::move(callback)); #else @@ -400,11 +321,7 @@ public: void pick_directory(pp::platform::PickedPathCallback callback) override { -#ifdef __IOS__ - (void)callback; -#elif __OSX__ - active_apple_document_platform_services().pick_directory(std::move(callback)); -#elif __ANDROID__ +#ifdef __ANDROID__ (void)callback; #else (void)callback; @@ -413,19 +330,12 @@ public: [[nodiscard]] bool supports_working_directory_picker() override { -#if defined(__IOS__) || defined(__OSX__) - return active_apple_document_platform_services().supports_working_directory_picker(); -#else return pp::platform::platform_supports_working_directory_picker( pp::platform::current_platform_family()); -#endif } [[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); -#endif return std::string(path); } @@ -459,9 +369,6 @@ public: void start_sonarpen() override { -#if __IOS__ - active_apple_document_platform_services().start_sonarpen(); -#endif } [[nodiscard]] int default_canvas_resolution() override @@ -505,27 +412,17 @@ public: void display_file(std::string_view path) override { -#if defined(__IOS__) || defined(__OSX__) - active_apple_document_platform_services().display_file(path); -#else (void)path; -#endif } void share_file(std::string_view path) override { -#if defined(__IOS__) || defined(__OSX__) - active_apple_document_platform_services().share_file(path); -#else (void)path; -#endif } void request_app_close() override { -#ifdef __OSX__ - active_apple_document_platform_services().request_app_close(); -#elif __LINUX__ +#ifdef __LINUX__ invoke_legacy_glfw_shell_callback(glfw_shell_.request_app_close); #endif } @@ -556,25 +453,11 @@ public: const std::string value(path); const std::string name(suggested_name); -#ifdef __IOS__ - active_apple_document_platform_services().save_prepared_file( - value, - name, - std::move(callback)); -#else (void)name; callback(value, false); -#endif } private: - [[nodiscard]] pp::platform::apple::AppleDocumentPlatformServices& active_apple_document_platform_services() const noexcept - { - if (apple_document_services_) - return apple_document_services_(); - return pp::platform::apple::active_legacy_apple_document_platform_services(); - } - [[nodiscard]] pp::platform::WebPlatformServices& active_web_platform_services() const noexcept { if (web_platform_services_) @@ -594,7 +477,6 @@ private: std::shared_ptr android_storage_paths_; #endif pp::platform::WebPlatformServices* web_platform_services_ = nullptr; - std::function apple_document_services_; }; } diff --git a/src/platform_legacy/legacy_platform_services.h b/src/platform_legacy/legacy_platform_services.h index 0fcb467b..183521cf 100644 --- a/src/platform_legacy/legacy_platform_services.h +++ b/src/platform_legacy/legacy_platform_services.h @@ -1,14 +1,10 @@ #pragma once -#include #include +#include #include "platform_api/platform_services.h" -namespace pp::platform::apple { -class AppleDocumentPlatformServices; -} - namespace pp::platform::legacy { struct LegacyGlfwPlatformShell { @@ -35,7 +31,6 @@ struct LegacyPlatformServicesConfig { LegacyAndroidPlatformBridge android_bridge; std::shared_ptr android_storage_paths; pp::platform::WebPlatformServices* web_platform_services = nullptr; - std::function apple_document_services; }; [[nodiscard]] std::unique_ptr create_platform_services( diff --git a/src/platform_windows/windows_lifecycle_shell.cpp b/src/platform_windows/windows_lifecycle_shell.cpp index ca3ab9b1..20b41cf7 100644 --- a/src/platform_windows/windows_lifecycle_shell.cpp +++ b/src/platform_windows/windows_lifecycle_shell.cpp @@ -2,12 +2,9 @@ #include "platform_windows/windows_lifecycle_shell.h" -#include "app.h" #include "legacy_preference_storage.h" #include "platform_windows/windows_lifecycle_state.h" #include "platform_windows/windows_main_window_session.h" -#include "platform_windows/windows_runtime_shell.h" -#include "platform_windows/windows_runtime_state.h" #include "platform_windows/windows_stylus_input.h" namespace pp::platform::windows { @@ -19,17 +16,7 @@ void request_window_close(HWND hWnd) void handle_window_close_message(VrShellState& vr) { - auto* app = bound_app(); - auto* runtime = retained_bound_runtime(); - mark_lifecycle_stopped(); - request_stop_and_join_vr_thread(vr); - if (runtime) - { - runtime->ui_thread_stop(); - runtime->render_thread_stop(); - } - app->terminate(); - release_bound_app(); + shutdown_bound_lifecycle(vr); PostQuitMessage(0); } @@ -64,12 +51,12 @@ void save_window_preferences(HWND hWnd) bool start_window_vr(VrShellState& vr, bool sandboxed) { - return start_vr_shell(vr, sandboxed, retained_lifecycle_running_state()); + return start_bound_lifecycle_vr(vr, sandboxed); } void stop_window_vr(VrShellState& vr) { - stop_vr_shell(vr); + stop_bound_lifecycle_vr(vr); } } diff --git a/src/platform_windows/windows_lifecycle_state.cpp b/src/platform_windows/windows_lifecycle_state.cpp index 80c52a28..9cbf180b 100644 --- a/src/platform_windows/windows_lifecycle_state.cpp +++ b/src/platform_windows/windows_lifecycle_state.cpp @@ -2,6 +2,8 @@ #include "platform_windows/windows_lifecycle_state.h" +#include "platform_windows/windows_runtime_state.h" + namespace pp::platform::windows { namespace { @@ -37,4 +39,21 @@ std::atomic& retained_lifecycle_running_state() noexcept return retained_window_lifecycle_state().running; } +void shutdown_bound_lifecycle(VrShellState& vr) +{ + mark_lifecycle_stopped(); + request_stop_and_join_vr_thread(vr); + shutdown_bound_app_runtime(); +} + +bool start_bound_lifecycle_vr(VrShellState& vr, bool sandboxed) +{ + return start_vr_shell(vr, sandboxed, retained_lifecycle_running_state()); +} + +void stop_bound_lifecycle_vr(VrShellState& vr) +{ + stop_vr_shell(vr); +} + } diff --git a/src/platform_windows/windows_lifecycle_state.h b/src/platform_windows/windows_lifecycle_state.h index 5f97a18a..2c1e3255 100644 --- a/src/platform_windows/windows_lifecycle_state.h +++ b/src/platform_windows/windows_lifecycle_state.h @@ -4,11 +4,16 @@ #include +#include "platform_windows/windows_vr_shell.h" + namespace pp::platform::windows { void mark_lifecycle_running() noexcept; void mark_lifecycle_stopped() noexcept; [[nodiscard]] bool lifecycle_is_running() noexcept; [[nodiscard]] std::atomic& retained_lifecycle_running_state() noexcept; +void shutdown_bound_lifecycle(VrShellState& vr); +[[nodiscard]] bool start_bound_lifecycle_vr(VrShellState& vr, bool sandboxed); +void stop_bound_lifecycle_vr(VrShellState& vr); } diff --git a/src/platform_windows/windows_runtime_state.cpp b/src/platform_windows/windows_runtime_state.cpp index e592ad48..d36879d8 100644 --- a/src/platform_windows/windows_runtime_state.cpp +++ b/src/platform_windows/windows_runtime_state.cpp @@ -53,6 +53,20 @@ void release_bound_app() noexcept retained_owned_app().reset(); } +void shutdown_bound_app_runtime() noexcept +{ + if (auto* runtime = retained_bound_runtime()) + { + runtime->ui_thread_stop(); + runtime->render_thread_stop(); + } + + if (auto* app = bound_app()) + app->terminate(); + + release_bound_app(); +} + WacomTablet* bound_wacom_tablet() noexcept { return &retained_wacom_tablet(); diff --git a/src/platform_windows/windows_runtime_state.h b/src/platform_windows/windows_runtime_state.h index c1b0a98c..c2127728 100644 --- a/src/platform_windows/windows_runtime_state.h +++ b/src/platform_windows/windows_runtime_state.h @@ -12,6 +12,7 @@ namespace pp::platform::windows { void bind_app(App* app) noexcept; [[nodiscard]] App* bound_app() noexcept; void release_bound_app() noexcept; +void shutdown_bound_app_runtime() noexcept; [[nodiscard]] WacomTablet* bound_wacom_tablet() noexcept; [[nodiscard]] std::unique_ptr& retained_owned_app() noexcept; [[nodiscard]] WacomTablet& retained_wacom_tablet() noexcept;