diff --git a/docs/modernization/debt.md b/docs/modernization/debt.md index d19fcd25..393bb332 100644 --- a/docs/modernization/debt.md +++ b/docs/modernization/debt.md @@ -18,6 +18,11 @@ agent or engineer to remove them without reconstructing context from chat. ## Reductions +- 2026-06-17: `DEBT-0003` was narrowed again. + `src/platform_windows/windows_runtime_shell.cpp` now binds a local + `MainWindowSession` object for the live Win32 session, and the window handle, + title buffer, and sandbox flag now live on that explicit runtime-owned + session instead of the retired retained accessor pocket. - 2026-06-17: `DEBT-0016`/`DEBT-0017`/`DEBT-0050`/`DEBT-0051`/`DEBT-0053`/ `DEBT-0057` were narrowed again. `src/platform_web/web_platform_services.*` now owns the concrete Web `PlatformServices` implementation and diff --git a/docs/modernization/roadmap.md b/docs/modernization/roadmap.md index abf83857..4c1e816e 100644 --- a/docs/modernization/roadmap.md +++ b/docs/modernization/roadmap.md @@ -209,9 +209,10 @@ Latest slice: `windows_platform_services.cpp`. - `src/platform_windows/windows_platform_services.cpp` now keeps the VR/runtime adapter surface without also owning the async GL context pocket. -- `src/platform_windows/windows_main_window_session.*` now owns the retained - Win32 main-window session fields (`HWND`, title buffer, sandbox flag) - instead of leaving them inside `windows_runtime_shell.cpp`. +- `src/platform_windows/windows_main_window_session.*` now owns the explicit + Win32 `MainWindowSession` object (`HWND`, title buffer, sandbox flag) that + the runtime shell binds for the live session instead of leaving those fields + behind retained accessors inside `windows_runtime_shell.cpp`. - `src/platform_windows/windows_runtime_shell.cpp` now keeps Windows runtime ownership focused on `App` and tablet lifetime rather than also owning main-window session metadata. diff --git a/docs/modernization/tasks.md b/docs/modernization/tasks.md index b8030de2..dad4089e 100644 --- a/docs/modernization/tasks.md +++ b/docs/modernization/tasks.md @@ -211,8 +211,9 @@ Current slice: Win32 async GL context lock/swap state. - `src/platform_windows/windows_platform_services.cpp` no longer carries the retained async render-context pocket. -- `src/platform_windows/windows_main_window_session.*` now owns the retained - Win32 main-window session fields. +- `src/platform_windows/windows_main_window_session.*` now owns the explicit + Win32 `MainWindowSession` object that the runtime shell binds for the live + session. - `src/platform_windows/windows_runtime_shell.cpp` no longer carries the retained `HWND` / title-buffer / sandbox pocket. - `src/platform_legacy/legacy_platform_services.*` now takes Android storage diff --git a/src/platform_windows/windows_bootstrap_helpers.cpp b/src/platform_windows/windows_bootstrap_helpers.cpp index ca324a10..8fff1cc4 100644 --- a/src/platform_windows/windows_bootstrap_helpers.cpp +++ b/src/platform_windows/windows_bootstrap_helpers.cpp @@ -164,6 +164,7 @@ void setup_exception_handler(const App& app) BT_SetPreErrHandler([](INT_PTR nErrHandlerParam){ const auto* app = reinterpret_cast(nErrHandlerParam); auto* canvas_document = app && app->canvas ? app->canvas->m_canvas.get() : nullptr; + const auto* session = bound_main_window_session(); if (canvas_document && canvas_document->m_unsaved) { auto t = std::time(nullptr); @@ -177,7 +178,7 @@ void setup_exception_handler(const App& app) GetFullPathNameA(path.c_str(), MAX_PATH, abspath, NULL); static char message[4096]; snprintf(message, sizeof(message), "File recovered in: %s", abspath); - MessageBoxA(retained_main_window_handle_ref(), message, "File Recovery", MB_OK | MB_ICONWARNING); + MessageBoxA(session ? session->handle : nullptr, message, "File Recovery", MB_OK | MB_ICONWARNING); } LogRemote::I.file_close(); }, reinterpret_cast(&app)); @@ -339,7 +340,8 @@ int read_WMI_info() if (get_int(clsObj, L"CodeIntegrityPolicyEnforcementStatus") > 0) { LOG("SANDBOX DETECTED"); - set_retained_main_window_sandboxed(true); + if (auto* session = bound_main_window_session()) + session->sandboxed = true; } SAFEARRAY *psaNames = NULL; @@ -427,11 +429,11 @@ MainWindowStartupState initialize_main_window_startup_state(App& app) return startup; } -void create_main_window(const MainWindowStartupState& startup, HWND& hWnd, HINSTANCE hInst, const wchar_t* window_title) +void create_main_window(const MainWindowStartupState& startup, MainWindowSession& session, HINSTANCE hInst, const wchar_t* window_title) { const int window_width = startup.client_rect.right - startup.client_rect.left; const int window_height = startup.client_rect.bottom - startup.client_rect.top; - hWnd = CreateWindow( + session.handle = CreateWindow( startup.window_class.lpszClassName, window_title, startup.window_style, @@ -492,7 +494,11 @@ pp::renderer::gl::OpenGlRuntimeInfo log_runtime_info() return runtime_info; } -bool upgrade_to_core_gl_context(const MainWindowStartupState& startup, HWND& hWnd, HINSTANCE hInst, const wchar_t* window_title, OpenGlWindowContext& context) +bool upgrade_to_core_gl_context( + const MainWindowStartupState& startup, + MainWindowSession& session, + HINSTANCE hInst, + OpenGlWindowContext& context) { if (!GLAD_WGL_ARB_create_context) { @@ -506,11 +512,10 @@ bool upgrade_to_core_gl_context(const MainWindowStartupState& startup, HWND& hWn wglMakeCurrent(NULL, NULL); wglDeleteContext(context.render_context); - DestroyWindow(hWnd); + DestroyWindow(session.handle); + create_main_window(startup, session, hInst, session.title); - create_main_window(startup, hWnd, hInst, window_title); - - context.device_context = GetDC(hWnd); + context.device_context = GetDC(session.handle); int pixel_format = 0; wglChoosePixelFormatARB( context.device_context, @@ -529,12 +534,12 @@ bool upgrade_to_core_gl_context(const MainWindowStartupState& startup, HWND& hWn return true; } -MainStartupResult initialize_main_window_and_gl(MainWindowStartupState& startup, HWND& hWnd, HINSTANCE hInst, wchar_t* window_title, OpenGlWindowContext& context) +MainStartupResult initialize_main_window_and_gl(MainWindowStartupState& startup, MainWindowSession& session, HINSTANCE hInst, OpenGlWindowContext& context) { - create_main_window(startup, hWnd, hInst, L"PanoPainter"); + create_main_window(startup, session, hInst, L"PanoPainter"); initialize_pixel_format_descriptor(startup.pixel_format); - context.device_context = GetDC(hWnd); + context.device_context = GetDC(session.handle); const int pixel_format = ChoosePixelFormat(context.device_context, &startup.pixel_format); SetPixelFormat(context.device_context, pixel_format, &startup.pixel_format); context.render_context = wglCreateContext(context.device_context); @@ -553,13 +558,13 @@ MainStartupResult initialize_main_window_and_gl(MainWindowStartupState& startup, const auto renderer_name = std::string(context.runtime_info.renderer != nullptr ? context.runtime_info.renderer : ""); swprintf_s( - window_title, + session.title, 512, L"PanoPainter %s (%s)", g_version_number_w, str2wstr(renderer_name).c_str()); - if (!upgrade_to_core_gl_context(startup, hWnd, hInst, window_title, context)) + if (!upgrade_to_core_gl_context(startup, session, hInst, context)) return MainStartupResult::MissingCoreContextSupport; return MainStartupResult::Ok; diff --git a/src/platform_windows/windows_bootstrap_helpers.h b/src/platform_windows/windows_bootstrap_helpers.h index cfddeda6..a1c5bda9 100644 --- a/src/platform_windows/windows_bootstrap_helpers.h +++ b/src/platform_windows/windows_bootstrap_helpers.h @@ -5,6 +5,7 @@ #include +#include "platform_windows/windows_main_window_session.h" #include "renderer_gl/opengl_capabilities.h" class App; @@ -52,11 +53,11 @@ void ensure_runtime_data_directory(); void setup_exception_handler(const App& app); int run_winmain_entry(int (*entry_point)(int, char**)); 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, MainWindowSession& session, HINSTANCE hInst, const wchar_t* window_title); void initialize_pixel_format_descriptor(PIXELFORMATDESCRIPTOR& pixel_format); bool load_glad_entry_points(HDC device_context); pp::renderer::gl::OpenGlRuntimeInfo log_runtime_info(); -bool upgrade_to_core_gl_context(const MainWindowStartupState& startup, HWND& hWnd, HINSTANCE hInst, const wchar_t* window_title, OpenGlWindowContext& context); -MainStartupResult initialize_main_window_and_gl(MainWindowStartupState& startup, HWND& hWnd, HINSTANCE hInst, wchar_t* window_title, OpenGlWindowContext& context); +bool upgrade_to_core_gl_context(const MainWindowStartupState& startup, MainWindowSession& session, HINSTANCE hInst, OpenGlWindowContext& context); +MainStartupResult initialize_main_window_and_gl(MainWindowStartupState& startup, MainWindowSession& session, HINSTANCE hInst, OpenGlWindowContext& context); } diff --git a/src/platform_windows/windows_lifecycle_shell.cpp b/src/platform_windows/windows_lifecycle_shell.cpp index c88db603..a1771d04 100644 --- a/src/platform_windows/windows_lifecycle_shell.cpp +++ b/src/platform_windows/windows_lifecycle_shell.cpp @@ -4,7 +4,6 @@ #include "legacy_preference_storage.h" #include "platform_windows/windows_lifecycle_state.h" -#include "platform_windows/windows_main_window_session.h" #include "platform_windows/windows_stylus_input.h" namespace pp::platform::windows { diff --git a/src/platform_windows/windows_main_window_session.cpp b/src/platform_windows/windows_main_window_session.cpp index 89e5c436..3be28578 100644 --- a/src/platform_windows/windows_main_window_session.cpp +++ b/src/platform_windows/windows_main_window_session.cpp @@ -5,43 +5,18 @@ namespace pp::platform::windows { namespace { -struct RetainedMainWindowSessionState final { - HWND handle{}; - wchar_t title[512]{}; - bool sandboxed = false; -}; +MainWindowSession* retained_main_window_session = nullptr; -[[nodiscard]] RetainedMainWindowSessionState& retained_main_window_session_state() noexcept +} + +void bind_main_window_session(MainWindowSession* session) noexcept { - static RetainedMainWindowSessionState state; - return state; + retained_main_window_session = session; } -} - -HWND& retained_main_window_handle_ref() noexcept +MainWindowSession* bound_main_window_session() noexcept { - return retained_main_window_session_state().handle; -} - -wchar_t* retained_main_window_title_buffer() noexcept -{ - return retained_main_window_session_state().title; -} - -const wchar_t* retained_main_window_title() noexcept -{ - return retained_main_window_session_state().title; -} - -bool retained_main_window_sandboxed() noexcept -{ - return retained_main_window_session_state().sandboxed; -} - -void set_retained_main_window_sandboxed(bool sandboxed) noexcept -{ - retained_main_window_session_state().sandboxed = sandboxed; + return retained_main_window_session; } } diff --git a/src/platform_windows/windows_main_window_session.h b/src/platform_windows/windows_main_window_session.h index 1fae17a5..30b7c27c 100644 --- a/src/platform_windows/windows_main_window_session.h +++ b/src/platform_windows/windows_main_window_session.h @@ -4,10 +4,13 @@ namespace pp::platform::windows { -[[nodiscard]] HWND& retained_main_window_handle_ref() noexcept; -[[nodiscard]] wchar_t* retained_main_window_title_buffer() noexcept; -[[nodiscard]] const wchar_t* retained_main_window_title() noexcept; -[[nodiscard]] bool retained_main_window_sandboxed() noexcept; -void set_retained_main_window_sandboxed(bool sandboxed) noexcept; +struct MainWindowSession final { + HWND handle{}; + wchar_t title[512]{}; + bool sandboxed = false; +}; + +void bind_main_window_session(MainWindowSession* session) noexcept; +[[nodiscard]] MainWindowSession* bound_main_window_session() noexcept; } diff --git a/src/platform_windows/windows_platform_services.cpp b/src/platform_windows/windows_platform_services.cpp index 00c5d6e5..4f44c08f 100644 --- a/src/platform_windows/windows_platform_services.cpp +++ b/src/platform_windows/windows_platform_services.cpp @@ -34,12 +34,18 @@ HWND pp_windows_main_window_handle(); HWND pp_windows_main_window_handle() { - return pp::platform::windows::retained_main_window_handle_ref(); + if (const auto* session = pp::platform::windows::bound_main_window_session()) + return session->handle; + return nullptr; } void destroy_window() { - pp::platform::windows::enqueue_main_thread_task(std::packaged_task([hWnd = pp::platform::windows::retained_main_window_handle_ref()] { + const auto* session = pp::platform::windows::bound_main_window_session(); + if (!session) + return; + + pp::platform::windows::enqueue_main_thread_task(std::packaged_task([hWnd = session->handle] { pp::platform::windows::request_window_close(hWnd); })); } @@ -71,9 +77,13 @@ void win32_update_stylus(float dt) void win32_update_fps(int frames) { + const auto* session = pp::platform::windows::bound_main_window_session(); + if (!session) + return; + pp::platform::windows::enqueue_main_thread_task(std::packaged_task([ - hWnd = pp::platform::windows::retained_main_window_handle_ref(), - window_title = pp::platform::windows::retained_main_window_title(), + hWnd = session->handle, + window_title = session->title, vr = &pp::platform::windows::platform_vr_state(), frames] { pp::platform::windows::update_window_fps(hWnd, window_title, *vr, frames); @@ -82,9 +92,13 @@ void win32_update_fps(int frames) bool win32_vr_start() { + const auto* session = pp::platform::windows::bound_main_window_session(); + if (!session) + return false; + return pp::platform::windows::start_window_vr( pp::platform::windows::platform_vr_state(), - pp::platform::windows::retained_main_window_sandboxed()); + session->sandboxed); } void win32_vr_stop() @@ -94,7 +108,8 @@ void win32_vr_stop() void win32_save_window_state() { - pp::platform::windows::save_window_preferences(pp::platform::windows::retained_main_window_handle_ref()); + if (const auto* session = pp::platform::windows::bound_main_window_session()) + pp::platform::windows::save_window_preferences(session->handle); } namespace pp::platform::windows { diff --git a/src/platform_windows/windows_runtime_flow.cpp b/src/platform_windows/windows_runtime_flow.cpp index 85fbdfe1..5502ecaf 100644 --- a/src/platform_windows/windows_runtime_flow.cpp +++ b/src/platform_windows/windows_runtime_flow.cpp @@ -8,11 +8,12 @@ namespace pp::platform::windows { void run_bound_main_window_runtime( const MainWindowStartupState& startup, + MainWindowSession& session, bool start_in_vr, HINSTANCE instance, SplashScreen& splash) { - run_main_window_runtime_session(startup, start_in_vr, instance, splash); + run_main_window_runtime_session(startup, session, start_in_vr, instance, splash); } } diff --git a/src/platform_windows/windows_runtime_flow.h b/src/platform_windows/windows_runtime_flow.h index e25fdc31..b84638ea 100644 --- a/src/platform_windows/windows_runtime_flow.h +++ b/src/platform_windows/windows_runtime_flow.h @@ -1,12 +1,14 @@ #pragma once #include "platform_windows/windows_bootstrap_helpers.h" +#include "platform_windows/windows_main_window_session.h" #include "platform_windows/windows_splash.h" namespace pp::platform::windows { void run_bound_main_window_runtime( const MainWindowStartupState& startup, + MainWindowSession& session, bool start_in_vr, HINSTANCE instance, SplashScreen& splash); diff --git a/src/platform_windows/windows_runtime_session.cpp b/src/platform_windows/windows_runtime_session.cpp index aa20c712..3fc8f295 100644 --- a/src/platform_windows/windows_runtime_session.cpp +++ b/src/platform_windows/windows_runtime_session.cpp @@ -108,26 +108,26 @@ void shutdown_main_window_runtime(const MainWindowStartupState& startup, HINSTAN } -void run_main_window_runtime_session(const MainWindowStartupState& startup, bool start_in_vr, HINSTANCE instance, SplashScreen& splash) +void run_main_window_runtime_session(const MainWindowStartupState& startup, MainWindowSession& session, bool start_in_vr, HINSTANCE instance, SplashScreen& splash) { auto* app = bound_app(); - register_touch_window(retained_main_window_handle_ref()); + register_touch_window(session.handle); wglMakeCurrent(NULL, NULL); initialize_runtime_threads(); install_debug_gl_callbacks(); - initialize_wintab(retained_main_window_handle_ref(), retained_main_window_sandboxed()); - set_main_window_icon(retained_main_window_handle_ref()); + initialize_wintab(session.handle, session.sandboxed); + set_main_window_icon(session.handle); app->ui_sync(); - restore_window_placement(retained_main_window_handle_ref(), startup.show_command); + restore_window_placement(session.handle, startup.show_command); if (start_in_vr) app->vr_start(); LOG("show main window"); - SetForegroundWindow(retained_main_window_handle_ref()); + SetForegroundWindow(session.handle); splash.dismiss(); diff --git a/src/platform_windows/windows_runtime_session.h b/src/platform_windows/windows_runtime_session.h index bf6dce68..0a8b852e 100644 --- a/src/platform_windows/windows_runtime_session.h +++ b/src/platform_windows/windows_runtime_session.h @@ -1,12 +1,14 @@ #pragma once #include "platform_windows/windows_bootstrap_helpers.h" +#include "platform_windows/windows_main_window_session.h" #include "platform_windows/windows_splash.h" namespace pp::platform::windows { void run_main_window_runtime_session( const MainWindowStartupState& startup, + MainWindowSession& session, bool start_in_vr, HINSTANCE instance, SplashScreen& splash); diff --git a/src/platform_windows/windows_runtime_shell.cpp b/src/platform_windows/windows_runtime_shell.cpp index 00b379ab..022a3097 100644 --- a/src/platform_windows/windows_runtime_shell.cpp +++ b/src/platform_windows/windows_runtime_shell.cpp @@ -16,6 +16,8 @@ namespace pp::platform::windows { int run_main_application(int argc, char** argv) { const auto instance = GetModuleHandle(NULL); + auto session = MainWindowSession {}; + bind_main_window_session(&session); auto& app = initialize_bound_app_runtime(); app.set_platform_services(&pp::platform::windows::platform_services()); @@ -43,18 +45,19 @@ int run_main_application(int argc, char** argv) auto context = pp::platform::windows::OpenGlWindowContext {}; switch (pp::platform::windows::initialize_main_window_and_gl( startup, - retained_main_window_handle_ref(), + session, instance, - retained_main_window_title_buffer(), context)) { case pp::platform::windows::MainStartupResult::Ok: break; case pp::platform::windows::MainStartupResult::GladLoadFailure: release_bound_app(); + bind_main_window_session(nullptr); return 0; case pp::platform::windows::MainStartupResult::MissingCoreContextSupport: release_bound_app(); + bind_main_window_session(nullptr); return -1; } @@ -69,6 +72,7 @@ int run_main_application(int argc, char** argv) app.initShaders(); app.cmd_convert(argv[2], argv[3]); release_bound_app(); + bind_main_window_session(nullptr); return 0; case const_hash("-vrmode"): start_in_vr = true; @@ -78,8 +82,9 @@ int run_main_application(int argc, char** argv) } } - pp::platform::windows::run_bound_main_window_runtime(startup, start_in_vr, instance, splash); + pp::platform::windows::run_bound_main_window_runtime(startup, session, start_in_vr, instance, splash); release_bound_app(); + bind_main_window_session(nullptr); return 0; } diff --git a/src/platform_windows/windows_window_shell.cpp b/src/platform_windows/windows_window_shell.cpp index 7378bc5f..3484f145 100644 --- a/src/platform_windows/windows_window_shell.cpp +++ b/src/platform_windows/windows_window_shell.cpp @@ -5,7 +5,6 @@ #include "app.h" #include "platform_windows/windows_lifecycle_state.h" #include "platform_windows/windows_lifecycle_shell.h" -#include "platform_windows/windows_main_window_session.h" #include "platform_windows/windows_platform_services.h" #include "platform_windows/windows_runtime_shell.h" #include "platform_windows/windows_stylus_input.h"