Move Windows bootstrap off App::I

This commit is contained in:
2026-06-17 07:52:35 +02:00
parent 5c8a87faa0
commit 3930e70817
6 changed files with 90 additions and 72 deletions

View File

@@ -92,6 +92,13 @@ Current hotspot files:
Latest slice: Latest slice:
- The remaining dense Windows bootstrap singleton pocket moved off
`App::I`: `setup_exception_handler(...)`, `initialize_main_window_startup_state(...)`,
and `_pre_call_callback(...)` now use explicit app/bound-runtime state
instead of reading the app singleton directly in
`src/platform_windows/windows_bootstrap_helpers.*`, and the app-side
platform dispatch helpers in `src/app_events.cpp` now also use the
instance they are invoked on instead of a global `App::I` fallback.
- The retained Web fallback service object and the Apple storage-path - The retained Web fallback service object and the Apple storage-path
preparation helper now also live in preparation helper now also live in
`src/platform_legacy/legacy_platform_state.*` instead of being built inline `src/platform_legacy/legacy_platform_state.*` instead of being built inline

View File

@@ -1202,6 +1202,13 @@ Why now:
platform-handle state on `App`, which blocks a real `pp_platform_*` shell split. platform-handle state on `App`, which blocks a real `pp_platform_*` shell split.
Current slice: Current slice:
- The remaining dense Windows bootstrap singleton pocket moved off
`App::I`: `setup_exception_handler(...)`,
`initialize_main_window_startup_state(...)`, and `_pre_call_callback(...)`
now use explicit app/bound-runtime state in
`src/platform_windows/windows_bootstrap_helpers.*`, and
`src/app_events.cpp` now dispatches platform services through the
`App` instance it is operating on instead of a global fallback.
- The retained Web fallback service object and the Apple storage-path - The retained Web fallback service object and the Apple storage-path
preparation helper now also live in preparation helper now also live in
`src/platform_legacy/legacy_platform_state.*` instead of being built inline `src/platform_legacy/legacy_platform_state.*` instead of being built inline

View File

@@ -46,11 +46,11 @@ namespace {
namespace { namespace {
[[nodiscard]] pp::platform::PlatformServices& active_platform_services() [[nodiscard]] pp::platform::PlatformServices& active_platform_services(const App* app)
{ {
if (App::I) if (app)
{ {
if (auto* services = App::I->platform_services()) if (auto* services = app->platform_services())
return *services; return *services;
} }
return pp::platform::legacy::platform_services(); return pp::platform::legacy::platform_services();
@@ -87,7 +87,7 @@ pp::platform::PlatformServices* App::platform_services() const noexcept
pp::platform::PlatformStoragePaths App::prepare_storage_paths() pp::platform::PlatformStoragePaths App::prepare_storage_paths()
{ {
return active_platform_services().prepare_storage_paths(); return active_platform_services(this).prepare_storage_paths();
} }
std::string App::clipboard_get_text() std::string App::clipboard_get_text()
@@ -95,7 +95,7 @@ std::string App::clipboard_get_text()
if (pp::app::plan_clipboard_read() != pp::app::ClipboardReadAction::read_text) if (pp::app::plan_clipboard_read() != pp::app::ClipboardReadAction::read_text)
return {}; return {};
return active_platform_services().clipboard_text(); return active_platform_services(this).clipboard_text();
} }
bool App::clipboard_set_text(const std::string& s) bool App::clipboard_set_text(const std::string& s)
@@ -103,17 +103,17 @@ bool App::clipboard_set_text(const std::string& s)
if (pp::app::plan_clipboard_write(s) != pp::app::ClipboardWriteAction::write_text) if (pp::app::plan_clipboard_write(s) != pp::app::ClipboardWriteAction::write_text)
return false; return false;
return active_platform_services().set_clipboard_text(s); return active_platform_services(this).set_clipboard_text(s);
} }
void App::stacktrace() void App::stacktrace()
{ {
active_platform_services().log_stacktrace(); active_platform_services(this).log_stacktrace();
} }
void App::crash_test() void App::crash_test()
{ {
active_platform_services().trigger_crash_test(); active_platform_services(this).trigger_crash_test();
} }
void App::tick(float dt) void App::tick(float dt)
@@ -154,7 +154,7 @@ void App::show_cursor()
if (!should_dispatch_cursor_visibility(true)) if (!should_dispatch_cursor_visibility(true))
return; return;
active_platform_services().set_cursor_visible(true); active_platform_services(this).set_cursor_visible(true);
} }
void App::hide_cursor() void App::hide_cursor()
@@ -162,7 +162,7 @@ void App::hide_cursor()
if (!should_dispatch_cursor_visibility(false)) if (!should_dispatch_cursor_visibility(false))
return; return;
active_platform_services().set_cursor_visible(false); active_platform_services(this).set_cursor_visible(false);
} }
void App::showKeyboard() void App::showKeyboard()
@@ -172,7 +172,7 @@ void App::showKeyboard()
if (!should_dispatch_keyboard_visibility(true)) if (!should_dispatch_keyboard_visibility(true))
return; return;
active_platform_services().set_virtual_keyboard_visible(true); active_platform_services(this).set_virtual_keyboard_visible(true);
} }
void App::hideKeyboard() void App::hideKeyboard()
@@ -182,26 +182,26 @@ void App::hideKeyboard()
if (!should_dispatch_keyboard_visibility(false)) if (!should_dispatch_keyboard_visibility(false))
return; return;
active_platform_services().set_virtual_keyboard_visible(false); active_platform_services(this).set_virtual_keyboard_visible(false);
} }
void App::pick_image(std::function<void(std::string path)> callback) void App::pick_image(std::function<void(std::string path)> callback)
{ {
redraw = true; redraw = true;
active_platform_services().pick_image(std::move(callback)); active_platform_services(this).pick_image(std::move(callback));
} }
void App::pick_file(std::vector<std::string> types, std::function<void (std::string)> callback) void App::pick_file(std::vector<std::string> types, std::function<void (std::string)> callback)
{ {
redraw = true; redraw = true;
active_platform_services().pick_file(std::move(types), std::move(callback)); active_platform_services(this).pick_file(std::move(types), std::move(callback));
} }
void App::pick_file_save(const std::string& type, const std::string& default_name, void App::pick_file_save(const std::string& type, const std::string& default_name,
std::function<void(std::string)> writer, std::function<void(const std::string& path, bool saved)> callback) std::function<void(std::string)> writer, std::function<void(const std::string& path, bool saved)> callback)
{ {
redraw = true; redraw = true;
const auto target = active_platform_services().prepare_writable_file(type, default_name, data_path, tmp_path); const auto target = active_platform_services(this).prepare_writable_file(type, default_name, data_path, tmp_path);
if (target.path.empty()) if (target.path.empty())
{ {
callback({}, false); callback({}, false);
@@ -239,47 +239,47 @@ void App::pick_file_save(const std::string& type, const std::string& default_nam
void App::pick_file_save(std::vector<std::string> types, std::function<void(std::string)> callback) void App::pick_file_save(std::vector<std::string> types, std::function<void(std::string)> callback)
{ {
redraw = true; redraw = true;
active_platform_services().pick_save_file(std::move(types), std::move(callback)); active_platform_services(this).pick_save_file(std::move(types), std::move(callback));
} }
bool App::uses_prepared_file_writes() const bool App::uses_prepared_file_writes() const
{ {
return active_platform_services().uses_prepared_file_writes(); return active_platform_services(this).uses_prepared_file_writes();
} }
bool App::uses_work_directory_document_export_collections() const bool App::uses_work_directory_document_export_collections() const
{ {
return active_platform_services().uses_work_directory_document_export_collections(); return active_platform_services(this).uses_work_directory_document_export_collections();
} }
bool App::disables_network_tls_verification() const bool App::disables_network_tls_verification() const
{ {
return active_platform_services().disables_network_tls_verification(); return active_platform_services(this).disables_network_tls_verification();
} }
bool App::uses_ppbr_export_data_directory_override() const bool App::uses_ppbr_export_data_directory_override() const
{ {
return active_platform_services().uses_ppbr_export_data_directory_override(); return active_platform_services(this).uses_ppbr_export_data_directory_override();
} }
bool App::platform_supports_sonarpen() const bool App::platform_supports_sonarpen() const
{ {
return active_platform_services().supports_sonarpen(); return active_platform_services(this).supports_sonarpen();
} }
void App::start_platform_sonarpen() void App::start_platform_sonarpen()
{ {
active_platform_services().start_sonarpen(); active_platform_services(this).start_sonarpen();
} }
int App::default_canvas_resolution() const int App::default_canvas_resolution() const
{ {
return active_platform_services().default_canvas_resolution(); return active_platform_services(this).default_canvas_resolution();
} }
bool App::draws_canvas_tip_for_input(kEventSource source, kEventType type) const bool App::draws_canvas_tip_for_input(kEventSource source, kEventType type) const
{ {
return active_platform_services().draws_canvas_tip_for_pointer( return active_platform_services(this).draws_canvas_tip_for_pointer(
source == kEventSource::Mouse, source == kEventSource::Mouse,
source == kEventSource::Stylus, source == kEventSource::Stylus,
type == kEventType::MouseUpL); type == kEventType::MouseUpL);
@@ -287,23 +287,23 @@ bool App::draws_canvas_tip_for_input(kEventSource source, kEventType type) const
float App::adjust_canvas_input_pressure(float pressure) const float App::adjust_canvas_input_pressure(float pressure) const
{ {
return active_platform_services().adjust_canvas_input_pressure(pressure); return active_platform_services(this).adjust_canvas_input_pressure(pressure);
} }
void App::pick_dir(std::function<void(std::string path)> callback) void App::pick_dir(std::function<void(std::string path)> callback)
{ {
redraw = true; redraw = true;
active_platform_services().pick_directory(std::move(callback)); active_platform_services(this).pick_directory(std::move(callback));
} }
bool App::supports_working_directory_picker() const bool App::supports_working_directory_picker() const
{ {
return active_platform_services().supports_working_directory_picker(); return active_platform_services(this).supports_working_directory_picker();
} }
std::string App::format_working_directory_path(std::string_view path) const std::string App::format_working_directory_path(std::string_view path) const
{ {
return active_platform_services().format_working_directory_path(path); return active_platform_services(this).format_working_directory_path(path);
} }
void App::display_file(std::string path) void App::display_file(std::string path)
@@ -311,7 +311,7 @@ void App::display_file(std::string path)
if (pp::app::plan_display_file(path) == pp::app::DisplayFileAction::ignore_empty_path) if (pp::app::plan_display_file(path) == pp::app::DisplayFileAction::ignore_empty_path)
return; return;
active_platform_services().display_file(path); active_platform_services(this).display_file(path);
} }
void App::share_file(std::string path) void App::share_file(std::string path)
@@ -322,122 +322,122 @@ void App::share_file(std::string path)
message_box("Sharing failed", "Please save the document before sharing it."); message_box("Sharing failed", "Please save the document before sharing it.");
return; return;
} }
active_platform_services().share_file(path); active_platform_services(this).share_file(path);
} }
void App::request_app_close() void App::request_app_close()
{ {
active_platform_services().request_app_close(); active_platform_services(this).request_app_close();
} }
bool App::start_platform_vr_mode() bool App::start_platform_vr_mode()
{ {
return active_platform_services().start_vr_mode(); return active_platform_services(this).start_vr_mode();
} }
void App::stop_platform_vr_mode() void App::stop_platform_vr_mode()
{ {
active_platform_services().stop_vr_mode(); active_platform_services(this).stop_vr_mode();
} }
void App::attach_ui_thread() void App::attach_ui_thread()
{ {
active_platform_services().attach_ui_thread(); active_platform_services(this).attach_ui_thread();
} }
void App::detach_ui_thread() void App::detach_ui_thread()
{ {
active_platform_services().detach_ui_thread(); active_platform_services(this).detach_ui_thread();
} }
void App::acquire_render_context() void App::acquire_render_context()
{ {
active_platform_services().acquire_render_context(); active_platform_services(this).acquire_render_context();
} }
void App::release_render_context() void App::release_render_context()
{ {
active_platform_services().release_render_context(); active_platform_services(this).release_render_context();
} }
void App::present_render_context() void App::present_render_context()
{ {
active_platform_services().present_render_context(); active_platform_services(this).present_render_context();
} }
void App::bind_default_render_target() void App::bind_default_render_target()
{ {
active_platform_services().bind_default_render_target(); active_platform_services(this).bind_default_render_target();
} }
void App::bind_main_render_target() void App::bind_main_render_target()
{ {
active_platform_services().bind_main_render_target(); active_platform_services(this).bind_main_render_target();
} }
void App::apply_render_platform_hints() void App::apply_render_platform_hints()
{ {
active_platform_services().apply_render_platform_hints(); active_platform_services(this).apply_render_platform_hints();
} }
void App::install_render_debug_callback() void App::install_render_debug_callback()
{ {
active_platform_services().install_render_debug_callback(); active_platform_services(this).install_render_debug_callback();
} }
void App::begin_render_capture_frame() void App::begin_render_capture_frame()
{ {
active_platform_services().begin_render_capture_frame(); active_platform_services(this).begin_render_capture_frame();
} }
void App::end_render_capture_frame() void App::end_render_capture_frame()
{ {
active_platform_services().end_render_capture_frame(); active_platform_services(this).end_render_capture_frame();
} }
bool App::platform_deletes_recorded_files_on_clear() bool App::platform_deletes_recorded_files_on_clear()
{ {
return active_platform_services().deletes_recorded_files_on_clear(); return active_platform_services(this).deletes_recorded_files_on_clear();
} }
void App::clear_platform_recorded_files(std::string path) void App::clear_platform_recorded_files(std::string path)
{ {
active_platform_services().clear_recorded_files(path); active_platform_services(this).clear_recorded_files(path);
} }
void App::publish_exported_image(std::string path) void App::publish_exported_image(std::string path)
{ {
active_platform_services().publish_exported_image(path); active_platform_services(this).publish_exported_image(path);
} }
void App::flush_platform_storage() void App::flush_platform_storage()
{ {
active_platform_services().flush_persistent_storage(); active_platform_services(this).flush_persistent_storage();
} }
std::vector<std::string> App::document_browse_roots() const std::vector<std::string> App::document_browse_roots() const
{ {
return active_platform_services().document_browse_roots(work_path, data_path); return active_platform_services(this).document_browse_roots(work_path, data_path);
} }
void App::save_platform_ui_state() void App::save_platform_ui_state()
{ {
active_platform_services().save_ui_state(); active_platform_services(this).save_ui_state();
} }
bool App::platform_enables_live_asset_reloading() bool App::platform_enables_live_asset_reloading()
{ {
return active_platform_services().enables_live_asset_reloading(); return active_platform_services(this).enables_live_asset_reloading();
} }
void App::update_platform_frame(float delta_time_seconds) void App::update_platform_frame(float delta_time_seconds)
{ {
active_platform_services().update_platform_frame(delta_time_seconds); active_platform_services(this).update_platform_frame(delta_time_seconds);
} }
void App::report_rendered_frames(int frames) void App::report_rendered_frames(int frames)
{ {
active_platform_services().report_rendered_frames(frames); active_platform_services(this).report_rendered_frames(frames);
} }
VrSessionSnapshot App::vr_session_snapshot() const VrSessionSnapshot App::vr_session_snapshot() const
@@ -454,7 +454,7 @@ void App::save_prepared_file(
std::string suggested_name, std::string suggested_name,
std::function<void(const std::string& path, bool saved)> callback) std::function<void(const std::string& path, bool saved)> callback)
{ {
active_platform_services().save_prepared_file( active_platform_services(this).save_prepared_file(
path, path,
suggested_name, suggested_name,
[callback = std::move(callback)](std::string saved_path, bool saved) { [callback = std::move(callback)](std::string saved_path, bool saved) {

View File

@@ -25,6 +25,7 @@
namespace pp::platform::windows { namespace pp::platform::windows {
void set_async_render_context(HDC hdc, HGLRC hrc); void set_async_render_context(HDC hdc, HGLRC hrc);
App* bound_app() noexcept;
} }
namespace pp::platform::windows { namespace pp::platform::windows {
@@ -130,7 +131,7 @@ int run_winmain_entry(int (*entry_point)(int, char**))
return entry_point(argc, argv); return entry_point(argc, argv);
} }
void setup_exception_handler() void setup_exception_handler(const App& app)
{ {
// Setup exception handler // Setup exception handler
BT_SetAppName(_T("PanoPainter")); BT_SetAppName(_T("PanoPainter"));
@@ -155,11 +156,12 @@ void setup_exception_handler()
// Add custom log file using default name // Add custom log file using default name
TCHAR wpath[MAX_PATH]; TCHAR wpath[MAX_PATH];
//GetFullPathNameW(L"panopainter-log.txt", 1024, wpath, nullptr); //GetFullPathNameW(L"panopainter-log.txt", 1024, wpath, nullptr);
auto log_file = App::I->data_path + "/panopainter-log.txt"; auto log_file = app.data_path + "/panopainter-log.txt";
std::mbstowcs(wpath, log_file.c_str(), log_file.size()); std::mbstowcs(wpath, log_file.c_str(), log_file.size());
BT_AddLogFile(wpath); BT_AddLogFile(wpath);
BT_SetPreErrHandler([](INT_PTR){ BT_SetPreErrHandler([](INT_PTR nErrHandlerParam){
const auto* app = reinterpret_cast<const App*>(nErrHandlerParam);
if (Canvas::I && Canvas::I->m_unsaved) if (Canvas::I && Canvas::I->m_unsaved)
{ {
auto t = std::time(nullptr); auto t = std::time(nullptr);
@@ -167,7 +169,7 @@ void setup_exception_handler()
std::ostringstream oss; std::ostringstream oss;
oss << std::put_time(&tm, "%d-%m-%Y %H-%M-%S"); oss << std::put_time(&tm, "%d-%m-%Y %H-%M-%S");
auto path = App::I->data_path + "/" + App::I->doc_name + "-recovery (" + oss.str() + ").ppi"; auto path = app->data_path + "/" + app->doc_name + "-recovery (" + oss.str() + ").ppi";
Canvas::I->project_save_thread(path, false); Canvas::I->project_save_thread(path, false);
static char abspath[MAX_PATH]; static char abspath[MAX_PATH];
GetFullPathNameA(path.c_str(), MAX_PATH, abspath, NULL); GetFullPathNameA(path.c_str(), MAX_PATH, abspath, NULL);
@@ -176,7 +178,7 @@ void setup_exception_handler()
MessageBoxA(retained_state().hWnd, message, "File Recovery", MB_OK | MB_ICONWARNING); MessageBoxA(retained_state().hWnd, message, "File Recovery", MB_OK | MB_ICONWARNING);
} }
LogRemote::I.file_close(); LogRemote::I.file_close();
}, 0); }, reinterpret_cast<INT_PTR>(&app));
BT_SetTerminate(); BT_SetTerminate();
} }
@@ -373,7 +375,7 @@ int read_WMI_info()
return 0; return 0;
} }
MainWindowStartupState initialize_main_window_startup_state() MainWindowStartupState initialize_main_window_startup_state(App& app)
{ {
auto startup = MainWindowStartupState {}; auto startup = MainWindowStartupState {};
const auto hInst = GetModuleHandle(NULL); const auto hInst = GetModuleHandle(NULL);
@@ -392,26 +394,26 @@ MainWindowStartupState initialize_main_window_startup_state()
auto y = unsigned{ 96 }; auto y = unsigned{ 96 };
if (GetDpiForMonitor_fn) if (GetDpiForMonitor_fn)
GetDpiForMonitor_fn(monitor, MDT_EFFECTIVE_DPI, &x, &y); GetDpiForMonitor_fn(monitor, MDT_EFFECTIVE_DPI, &x, &y);
App::I->display_density = (float)x / 96.f; app.display_density = (float)x / 96.f;
const auto window_preferences = pp::panopainter::read_legacy_window_preferences(SW_NORMAL); const auto window_preferences = pp::panopainter::read_legacy_window_preferences(SW_NORMAL);
if (window_preferences.has_ui_scale) if (window_preferences.has_ui_scale)
App::I->zoom = window_preferences.ui_scale; app.zoom = window_preferences.ui_scale;
else else
App::I->zoom = (float)x / 96.f; app.zoom = (float)x / 96.f;
startup.show_command = window_preferences.show_command; startup.show_command = window_preferences.show_command;
startup.client_rect = { startup.client_rect = {
0, 0,
0, 0,
static_cast<LONG>(App::I->width * App::I->zoom), static_cast<LONG>(app.width * app.zoom),
static_cast<LONG>(App::I->height * App::I->zoom), static_cast<LONG>(app.height * app.zoom),
}; };
if (window_preferences.has_window_rect) if (window_preferences.has_window_rect)
{ {
auto wnd_rect = window_preferences.window_rect; auto wnd_rect = window_preferences.window_rect;
App::I->width = wnd_rect.z - wnd_rect.x; app.width = wnd_rect.z - wnd_rect.x;
App::I->height = wnd_rect.w - wnd_rect.y; app.height = wnd_rect.w - wnd_rect.y;
startup.client_rect = { wnd_rect.x, wnd_rect.y, wnd_rect.z, wnd_rect.w }; startup.client_rect = { wnd_rect.x, wnd_rect.y, wnd_rect.z, wnd_rect.w };
startup.client_pos = { wnd_rect.x, wnd_rect.y }; startup.client_pos = { wnd_rect.x, wnd_rect.y };
} }
@@ -577,7 +579,7 @@ BOOL UnadjustWindowRectEx(LPRECT prc, DWORD dwStyle, BOOL fMenu, DWORD dwExStyle
void _pre_call_callback(const char* name, void* funcptr, int len_args, ...) void _pre_call_callback(const char* name, void* funcptr, int len_args, ...)
{ {
assert(App::I->is_render_thread()); assert(bound_app()->is_render_thread());
} }
void _post_call_callback(const char* name, void* funcptr, int len_args, ...) void _post_call_callback(const char* name, void* funcptr, int len_args, ...)

View File

@@ -7,6 +7,8 @@
#include "renderer_gl/opengl_capabilities.h" #include "renderer_gl/opengl_capabilities.h"
class App;
namespace pp::platform::windows { namespace pp::platform::windows {
bool win32_renderdoc_init(); bool win32_renderdoc_init();
@@ -47,9 +49,9 @@ enum class MainStartupResult
}; };
void ensure_runtime_data_directory(); void ensure_runtime_data_directory();
void setup_exception_handler(); void setup_exception_handler(const App& app);
int run_winmain_entry(int (*entry_point)(int, char**)); int run_winmain_entry(int (*entry_point)(int, char**));
MainWindowStartupState initialize_main_window_startup_state(); MainWindowStartupState initialize_main_window_startup_state(App& app);
void create_main_window(const MainWindowStartupState& startup, HWND& hWnd, HINSTANCE hInst, const wchar_t* window_title); void create_main_window(const MainWindowStartupState& startup, HWND& hWnd, HINSTANCE hInst, const wchar_t* window_title);
void initialize_pixel_format_descriptor(PIXELFORMATDESCRIPTOR& pixel_format); void initialize_pixel_format_descriptor(PIXELFORMATDESCRIPTOR& pixel_format);
bool load_glad_entry_points(HDC device_context); bool load_glad_entry_points(HDC device_context);

View File

@@ -161,13 +161,13 @@ int run_main_application(int argc, char** argv)
pp::platform::windows::initialize_retained_input_state(); pp::platform::windows::initialize_retained_input_state();
pp::platform::windows::setup_exception_handler(); pp::platform::windows::setup_exception_handler(*app);
pp::platform::windows::read_WMI_info(); pp::platform::windows::read_WMI_info();
app->create(); app->create();
auto startup = pp::platform::windows::initialize_main_window_startup_state(); auto startup = pp::platform::windows::initialize_main_window_startup_state(*app);
auto context = pp::platform::windows::OpenGlWindowContext {}; auto context = pp::platform::windows::OpenGlWindowContext {};
switch (pp::platform::windows::initialize_main_window_and_gl(startup, state.hWnd, state.hInst, state.window_title, context)) switch (pp::platform::windows::initialize_main_window_and_gl(startup, state.hWnd, state.hInst, state.window_title, context))
{ {