Own Apple platform services and thin Win32 lifecycle shell

This commit is contained in:
2026-06-17 14:39:18 +02:00
parent 065717f89b
commit 2f33b00b2a
14 changed files with 517 additions and 191 deletions

View File

@@ -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 <CoreFoundation/CoreFoundation.h>
#include <Cocoa/Cocoa.h>
@@ -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();

View File

@@ -10,7 +10,6 @@
#import "GameViewController.h"
#import <OpenGLES/ES3/glext.h>
#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();

View File

@@ -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` |

View File

@@ -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

View File

@@ -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.

View File

@@ -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 <array>
#include <memory>
#include <utility>
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<std::string> 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<std::string> file_types, PickedPathCallback callback)
{
active_document_platform_services().pick_file(std::move(file_types), std::move(callback));
}
void ApplePlatformServices::pick_save_file(std::vector<std::string> 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<PlatformServices> create_apple_platform_services()
{
return std::make_unique<ApplePlatformServices>();
}
}

View File

@@ -4,6 +4,7 @@
#include "platform_api/platform_services.h"
#include <functional>
#include <memory>
#include <string>
#include <string_view>
#include <vector>
@@ -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<std::string> 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<std::string> file_types, PickedPathCallback callback) override;
void pick_save_file(std::vector<std::string> 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<PlatformServices> create_apple_platform_services();
[[nodiscard]] RetainedLegacyAppleState& active_legacy_apple_state();
[[nodiscard]] AppleDocumentPlatformServices&
active_legacy_apple_document_platform_services();

View File

@@ -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 <Foundation/Foundation.h>
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 <tinyfiledialogs.h>
#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<std::string> 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<std::string> 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<pp::platform::PlatformStoragePaths> android_storage_paths_;
#endif
pp::platform::WebPlatformServices* web_platform_services_ = nullptr;
std::function<pp::platform::apple::AppleDocumentPlatformServices&()> apple_document_services_;
};
}

View File

@@ -1,14 +1,10 @@
#pragma once
#include <memory>
#include <functional>
#include <memory>
#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<pp::platform::PlatformStoragePaths> android_storage_paths;
pp::platform::WebPlatformServices* web_platform_services = nullptr;
std::function<pp::platform::apple::AppleDocumentPlatformServices&()> apple_document_services;
};
[[nodiscard]] std::unique_ptr<PlatformServices> create_platform_services(

View File

@@ -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);
}
}

View File

@@ -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<int>& 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);
}
}

View File

@@ -4,11 +4,16 @@
#include <atomic>
#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<int>& 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);
}

View File

@@ -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();

View File

@@ -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<App>& retained_owned_app() noexcept;
[[nodiscard]] WacomTablet& retained_wacom_tablet() noexcept;