Own Windows app lifetime in runtime shell
This commit is contained in:
@@ -70,6 +70,15 @@ What is already real:
|
|||||||
- `pp_app_core`
|
- `pp_app_core`
|
||||||
|
|
||||||
Latest slice:
|
Latest slice:
|
||||||
|
- `src/platform_windows/windows_runtime_shell.cpp` now explicitly owns the
|
||||||
|
Windows `App` lifetime through a retained `std::unique_ptr<App>` instead of
|
||||||
|
raw `new`/`delete` plus shutdown-side manual cleanup in the lifecycle shell.
|
||||||
|
- `src/platform_windows/windows_lifecycle_shell.cpp` now releases the bound
|
||||||
|
Windows app through `release_bound_app()` after runtime shutdown instead of
|
||||||
|
deleting it directly through the global shutdown path.
|
||||||
|
- `src/platform_windows/windows_window_shell.cpp` now routes the touched
|
||||||
|
key-map and VR-state reads through narrow helpers instead of keeping the
|
||||||
|
broader retained-state bundle live across the main window-proc body.
|
||||||
- `scripts/automation/quiet-validate.ps1` is now the bundled checkpoint path
|
- `scripts/automation/quiet-validate.ps1` is now the bundled checkpoint path
|
||||||
for Windows build/test plus optional platform and Apple remote validation,
|
for Windows build/test plus optional platform and Apple remote validation,
|
||||||
with one compact JSON summary under `out/logs/quiet-validation`.
|
with one compact JSON summary under `out/logs/quiet-validation`.
|
||||||
|
|||||||
@@ -78,6 +78,15 @@ Completed, blocked, and superseded task history moved to
|
|||||||
the queue is now ordered by code movement instead.
|
the queue is now ordered by code movement instead.
|
||||||
|
|
||||||
Current slice:
|
Current slice:
|
||||||
|
- `src/platform_windows/windows_runtime_shell.cpp` now owns the Windows `App`
|
||||||
|
through a retained `std::unique_ptr<App>`, so startup/early-return/convert
|
||||||
|
paths no longer manage raw `new`/`delete` app lifetime manually.
|
||||||
|
- `src/platform_windows/windows_lifecycle_shell.cpp` now releases the bound
|
||||||
|
app through `release_bound_app()` after runtime shutdown instead of deleting
|
||||||
|
it directly through the lifecycle shell.
|
||||||
|
- `src/platform_windows/windows_window_shell.cpp` now routes the touched
|
||||||
|
key-map synchronization and VR close state through narrow helpers instead of
|
||||||
|
carrying the broader retained window bundle live across the window-proc path.
|
||||||
- `scripts/automation/quiet-validate.ps1` now owns the recommended quiet
|
- `scripts/automation/quiet-validate.ps1` now owns the recommended quiet
|
||||||
checkpoint path and can bundle Windows build/test, Android/platform sweeps,
|
checkpoint path and can bundle Windows build/test, Android/platform sweeps,
|
||||||
and Apple remote compile gates into one compact JSON summary with
|
and Apple remote compile gates into one compact JSON summary with
|
||||||
|
|||||||
@@ -53,9 +53,7 @@ void handle_window_close_message(VrShellState& vr)
|
|||||||
runtime->ui_thread_stop();
|
runtime->ui_thread_stop();
|
||||||
runtime->render_thread_stop();
|
runtime->render_thread_stop();
|
||||||
app->terminate();
|
app->terminate();
|
||||||
bind_app(nullptr);
|
release_bound_app();
|
||||||
bind_runtime(nullptr);
|
|
||||||
delete app;
|
|
||||||
PostQuitMessage(0);
|
PostQuitMessage(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -18,6 +18,7 @@ namespace pp::platform::windows {
|
|||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
struct RetainedWindowsRuntimeState final {
|
struct RetainedWindowsRuntimeState final {
|
||||||
|
std::unique_ptr<App> owned_app;
|
||||||
App* app = nullptr;
|
App* app = nullptr;
|
||||||
AppRuntime* runtime = nullptr;
|
AppRuntime* runtime = nullptr;
|
||||||
WacomTablet* tablet = nullptr;
|
WacomTablet* tablet = nullptr;
|
||||||
@@ -132,6 +133,14 @@ App* bound_app() noexcept
|
|||||||
return retained_runtime_state().app;
|
return retained_runtime_state().app;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void release_bound_app() noexcept
|
||||||
|
{
|
||||||
|
auto& state = retained_runtime_state();
|
||||||
|
bind_runtime(nullptr);
|
||||||
|
bind_app(nullptr);
|
||||||
|
state.owned_app.reset();
|
||||||
|
}
|
||||||
|
|
||||||
void bind_runtime(AppRuntime* runtime) noexcept
|
void bind_runtime(AppRuntime* runtime) noexcept
|
||||||
{
|
{
|
||||||
retained_runtime_state().runtime = runtime;
|
retained_runtime_state().runtime = runtime;
|
||||||
@@ -177,7 +186,9 @@ int run_main_application(int argc, char** argv)
|
|||||||
auto& state = retained_state();
|
auto& state = retained_state();
|
||||||
state.hInst = GetModuleHandle(NULL);
|
state.hInst = GetModuleHandle(NULL);
|
||||||
|
|
||||||
auto* app = new App();
|
auto& runtime_state = retained_runtime_state();
|
||||||
|
runtime_state.owned_app = std::make_unique<App>();
|
||||||
|
auto* app = runtime_state.owned_app.get();
|
||||||
bind_app(app);
|
bind_app(app);
|
||||||
bind_runtime(&app->runtime());
|
bind_runtime(&app->runtime());
|
||||||
bind_wacom_tablet(&WacomTablet::I);
|
bind_wacom_tablet(&WacomTablet::I);
|
||||||
@@ -209,13 +220,11 @@ int run_main_application(int argc, char** argv)
|
|||||||
case pp::platform::windows::MainStartupResult::Ok:
|
case pp::platform::windows::MainStartupResult::Ok:
|
||||||
break;
|
break;
|
||||||
case pp::platform::windows::MainStartupResult::GladLoadFailure:
|
case pp::platform::windows::MainStartupResult::GladLoadFailure:
|
||||||
bind_app(nullptr);
|
release_bound_app();
|
||||||
bind_runtime(nullptr);
|
|
||||||
bind_wacom_tablet(nullptr);
|
bind_wacom_tablet(nullptr);
|
||||||
return 0;
|
return 0;
|
||||||
case pp::platform::windows::MainStartupResult::MissingCoreContextSupport:
|
case pp::platform::windows::MainStartupResult::MissingCoreContextSupport:
|
||||||
bind_app(nullptr);
|
release_bound_app();
|
||||||
bind_runtime(nullptr);
|
|
||||||
bind_wacom_tablet(nullptr);
|
bind_wacom_tablet(nullptr);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
@@ -230,8 +239,7 @@ int run_main_application(int argc, char** argv)
|
|||||||
case const_hash("convert"):
|
case const_hash("convert"):
|
||||||
app->initShaders();
|
app->initShaders();
|
||||||
app->cmd_convert(argv[2], argv[3]);
|
app->cmd_convert(argv[2], argv[3]);
|
||||||
bind_app(nullptr);
|
release_bound_app();
|
||||||
bind_runtime(nullptr);
|
|
||||||
bind_wacom_tablet(nullptr);
|
bind_wacom_tablet(nullptr);
|
||||||
return 0;
|
return 0;
|
||||||
case const_hash("-vrmode"):
|
case const_hash("-vrmode"):
|
||||||
@@ -243,6 +251,7 @@ int run_main_application(int argc, char** argv)
|
|||||||
}
|
}
|
||||||
|
|
||||||
pp::platform::windows::run_main_window_runtime(startup, start_in_vr, splash);
|
pp::platform::windows::run_main_window_runtime(startup, start_in_vr, splash);
|
||||||
|
release_bound_app();
|
||||||
bind_wacom_tablet(nullptr);
|
bind_wacom_tablet(nullptr);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -13,6 +13,7 @@ int run_main_application(int argc, char** argv);
|
|||||||
void run_main_window_runtime(const MainWindowStartupState& startup, bool start_in_vr, SplashScreen& splash);
|
void run_main_window_runtime(const MainWindowStartupState& startup, bool start_in_vr, SplashScreen& splash);
|
||||||
void bind_app(App* app) noexcept;
|
void bind_app(App* app) noexcept;
|
||||||
[[nodiscard]] App* bound_app() noexcept;
|
[[nodiscard]] App* bound_app() noexcept;
|
||||||
|
void release_bound_app() noexcept;
|
||||||
void bind_runtime(AppRuntime* runtime) noexcept;
|
void bind_runtime(AppRuntime* runtime) noexcept;
|
||||||
[[nodiscard]] AppRuntime* bound_runtime() noexcept;
|
[[nodiscard]] AppRuntime* bound_runtime() noexcept;
|
||||||
void bind_wacom_tablet(WacomTablet* tablet) noexcept;
|
void bind_wacom_tablet(WacomTablet* tablet) noexcept;
|
||||||
|
|||||||
@@ -34,11 +34,42 @@ namespace {
|
|||||||
return pointer_source;
|
return pointer_source;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[[nodiscard]] std::map<kKey, int>& retained_virtual_key_map()
|
||||||
|
{
|
||||||
|
return retained_state().vkey_map;
|
||||||
|
}
|
||||||
|
|
||||||
|
[[nodiscard]] pp::platform::windows::VrShellState& retained_vr_shell_state()
|
||||||
|
{
|
||||||
|
return retained_state().vr;
|
||||||
|
}
|
||||||
|
|
||||||
|
void synchronize_app_key_state_from_keyboard(App& app)
|
||||||
|
{
|
||||||
|
static BYTE keys[256];
|
||||||
|
if (!GetKeyboardState(keys))
|
||||||
|
return;
|
||||||
|
|
||||||
|
const bool alt = (keys[VK_MENU] & 0x80) != 0;
|
||||||
|
for (const auto& [key, vk] : retained_virtual_key_map())
|
||||||
|
{
|
||||||
|
if (alt && key == kKey::KeyTab)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
const bool down = (keys[vk] & 0x80) != 0;
|
||||||
|
if (app.keys[(int)key] && !down)
|
||||||
|
app.key_up(key);
|
||||||
|
else if (!app.keys[(int)key] && down)
|
||||||
|
app.key_down(key);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void initialize_retained_input_state()
|
void initialize_retained_input_state()
|
||||||
{
|
{
|
||||||
auto& state = retained_state();
|
auto& state = retained_state();
|
||||||
|
auto& vkey_map = retained_virtual_key_map();
|
||||||
memset(&state.keys, 0, sizeof(state.keys));
|
memset(&state.keys, 0, sizeof(state.keys));
|
||||||
for (int k = 1; k < 256; ++k) // ignore kKey::Unknown = 0
|
for (int k = 1; k < 256; ++k) // ignore kKey::Unknown = 0
|
||||||
{
|
{
|
||||||
@@ -48,14 +79,14 @@ void initialize_retained_input_state()
|
|||||||
continue;
|
continue;
|
||||||
|
|
||||||
auto key = (kKey)k;
|
auto key = (kKey)k;
|
||||||
if (state.vkey_map.find(key) == state.vkey_map.end())
|
if (vkey_map.find(key) == vkey_map.end())
|
||||||
{
|
{
|
||||||
state.vkey_map.insert({ key, vk });
|
vkey_map.insert({ key, vk });
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
LOG("KEY MAP COLLISION %d and %d maps to %d",
|
LOG("KEY MAP COLLISION %d and %d maps to %d",
|
||||||
vk, state.vkey_map[key], k);
|
vk, vkey_map[key], k);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -69,7 +100,6 @@ RetainedState& retained_state()
|
|||||||
|
|
||||||
LRESULT CALLBACK main_window_proc(HWND hWnd, UINT msg, WPARAM wp, LPARAM lp)
|
LRESULT CALLBACK main_window_proc(HWND hWnd, UINT msg, WPARAM wp, LPARAM lp)
|
||||||
{
|
{
|
||||||
auto& state = retained_state();
|
|
||||||
auto* app = bound_app();
|
auto* app = bound_app();
|
||||||
static glm::vec2 lastPoint;
|
static glm::vec2 lastPoint;
|
||||||
|
|
||||||
@@ -78,7 +108,7 @@ LRESULT CALLBACK main_window_proc(HWND hWnd, UINT msg, WPARAM wp, LPARAM lp)
|
|||||||
switch (msg)
|
switch (msg)
|
||||||
{
|
{
|
||||||
case kUserCloseMessage:
|
case kUserCloseMessage:
|
||||||
handle_window_close_message(state.vr);
|
handle_window_close_message(retained_vr_shell_state());
|
||||||
return 0;
|
return 0;
|
||||||
case WM_PAINT:
|
case WM_PAINT:
|
||||||
app->redraw = true;
|
app->redraw = true;
|
||||||
@@ -114,24 +144,10 @@ LRESULT CALLBACK main_window_proc(HWND hWnd, UINT msg, WPARAM wp, LPARAM lp)
|
|||||||
case WM_ACTIVATE:
|
case WM_ACTIVATE:
|
||||||
{
|
{
|
||||||
platform_services().set_cursor_visible(true);
|
platform_services().set_cursor_visible(true);
|
||||||
app->ui_task_async([app, &state, wp, lp] {
|
app->ui_task_async([app, wp, lp] {
|
||||||
int active = GET_WM_ACTIVATE_STATE(wp, lp);
|
int active = GET_WM_ACTIVATE_STATE(wp, lp);
|
||||||
active_wacom_tablet().set_focus(active);
|
active_wacom_tablet().set_focus(active);
|
||||||
static BYTE keys[256];
|
synchronize_app_key_state_from_keyboard(*app);
|
||||||
if (GetKeyboardState(keys))
|
|
||||||
{
|
|
||||||
bool alt = keys[VK_MENU] & 0x80;
|
|
||||||
for (auto k : state.vkey_map)
|
|
||||||
{
|
|
||||||
if (alt && k.first == kKey::KeyTab)
|
|
||||||
continue;
|
|
||||||
bool down = keys[k.second] & 0x80;
|
|
||||||
if (app->keys[(int)k.first] && !down)
|
|
||||||
app->key_up(k.first);
|
|
||||||
else if (!app->keys[(int)k.first] && down)
|
|
||||||
app->key_down(k.first);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user