From 024478e2ee8672cc9e3a64c1b1ccb3c054fd438e Mon Sep 17 00:00:00 2001 From: Jacob Ledbetter Date: Sat, 15 Aug 2026 18:15:46 -0600 Subject: [PATCH 1/4] fix(shell): Avoid initializing layouts during teardown --- Core/GameEngine/Include/GameClient/Shell.h | 2 +- Core/GameEngine/Source/GameClient/GUI/Shell/Shell.cpp | 7 ++++--- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/Core/GameEngine/Include/GameClient/Shell.h b/Core/GameEngine/Include/GameClient/Shell.h index a593f3cbcba..eb10ac608ec 100644 --- a/Core/GameEngine/Include/GameClient/Shell.h +++ b/Core/GameEngine/Include/GameClient/Shell.h @@ -131,7 +131,7 @@ class Shell : public SubsystemInterface // pseudo-stack operations for manipulating layouts void push( AsciiString filename, Bool shutdownImmediate = FALSE ); ///< load new screen on top, optionally doing an immediate shutdown void pop(); ///< pop top layout - void popImmediate(); ///< pop now, don't wait for shutdown + void popImmediate( Bool suppressInit = FALSE ); ///< pop now, optionally suppressing init of the uncovered layout void showShell( Bool runInit = TRUE ); ///< init the top of stack void hideShell(); ///< shutdown the top of stack WindowLayout *top(); ///< return top layout diff --git a/Core/GameEngine/Source/GameClient/GUI/Shell/Shell.cpp b/Core/GameEngine/Source/GameClient/GUI/Shell/Shell.cpp index 1b6278d02db..faa8f30594b 100644 --- a/Core/GameEngine/Source/GameClient/GUI/Shell/Shell.cpp +++ b/Core/GameEngine/Source/GameClient/GUI/Shell/Shell.cpp @@ -93,7 +93,8 @@ void Shell::deconstruct() WindowLayout *newTop = top(); while(newTop) { - popImmediate(); + // TheSuperHackers @bugfix CryoTheRenegade 10/08/2026 Do not initialize uncovered screens while the shell is being destroyed. + popImmediate( TRUE ); newTop = top(); } @@ -424,7 +425,7 @@ void Shell::pop() * from the shutdown() for the screen, it will be immediately popped off * the stack */ //------------------------------------------------------------------------------------------------- -void Shell::popImmediate() +void Shell::popImmediate( Bool suppressInit ) { WindowLayout *screen = top(); @@ -448,7 +449,7 @@ void Shell::popImmediate() screen->runShutdown( &immediatePop ); // pop the screen of the stack - doPop( FALSE ); + doPop( suppressInit ); if (TheIMEManager) TheIMEManager->detach(); From 623d82a3d112de92a434618baeee89d49d6ed0d9 Mon Sep 17 00:00:00 2001 From: Jacob Ledbetter Date: Sun, 16 Aug 2026 11:16:52 -0600 Subject: [PATCH 2/4] refactor(shell): Clarify doPop parameter semantics --- Core/GameEngine/Include/GameClient/Shell.h | 2 +- Core/GameEngine/Source/GameClient/GUI/Shell/Shell.cpp | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Core/GameEngine/Include/GameClient/Shell.h b/Core/GameEngine/Include/GameClient/Shell.h index eb10ac608ec..ea9409a0565 100644 --- a/Core/GameEngine/Include/GameClient/Shell.h +++ b/Core/GameEngine/Include/GameClient/Shell.h @@ -166,7 +166,7 @@ class Shell : public SubsystemInterface void unlinkScreen( WindowLayout *screen ); ///< remove screen from list void doPush( AsciiString layoutFile ); ///< workhorse for push action - void doPop( Bool impendingPush ); ///< workhorse for pop action + void doPop( Bool suppressInit ); ///< workhorse for pop action enum { MAX_SHELL_STACK = 16 }; ///< max simultaneous shell screens WindowLayout *m_screenStack[ MAX_SHELL_STACK ]; ///< the screen layout stack diff --git a/Core/GameEngine/Source/GameClient/GUI/Shell/Shell.cpp b/Core/GameEngine/Source/GameClient/GUI/Shell/Shell.cpp index faa8f30594b..b9f1d1898b4 100644 --- a/Core/GameEngine/Source/GameClient/GUI/Shell/Shell.cpp +++ b/Core/GameEngine/Source/GameClient/GUI/Shell/Shell.cpp @@ -686,7 +686,7 @@ void Shell::doPush( AsciiString layoutFile ) //------------------------------------------------------------------------------------------------- /** Actually do the work for a pop */ //------------------------------------------------------------------------------------------------- -void Shell::doPop( Bool impendingPush ) +void Shell::doPop( Bool suppressInit ) { WindowLayout *currentTop = top(); @@ -707,7 +707,7 @@ void Shell::doPop( Bool impendingPush ) // run the init for the new top of the stack if present WindowLayout *newTop = top(); - if( newTop && !impendingPush ) + if( newTop && !suppressInit ) { newTop->runInit( nullptr ); //newTop->bringForward(); From 623c3e86603e7b49a345ac5a88f65f64bd2161ec Mon Sep 17 00:00:00 2001 From: Jacob Ledbetter Date: Thu, 20 Aug 2026 09:13:27 -0600 Subject: [PATCH 3/4] fix(shell): new destroy function --- Core/GameEngine/Include/GameClient/Shell.h | 5 ++- .../Source/GameClient/GUI/Shell/Shell.cpp | 42 ++++++++++++++----- 2 files changed, 34 insertions(+), 13 deletions(-) diff --git a/Core/GameEngine/Include/GameClient/Shell.h b/Core/GameEngine/Include/GameClient/Shell.h index ea9409a0565..4e6375b690b 100644 --- a/Core/GameEngine/Include/GameClient/Shell.h +++ b/Core/GameEngine/Include/GameClient/Shell.h @@ -131,7 +131,7 @@ class Shell : public SubsystemInterface // pseudo-stack operations for manipulating layouts void push( AsciiString filename, Bool shutdownImmediate = FALSE ); ///< load new screen on top, optionally doing an immediate shutdown void pop(); ///< pop top layout - void popImmediate( Bool suppressInit = FALSE ); ///< pop now, optionally suppressing init of the uncovered layout + void popImmediate(); ///< pop now void showShell( Bool runInit = TRUE ); ///< init the top of stack void hideShell(); ///< shutdown the top of stack WindowLayout *top(); ///< return top layout @@ -161,12 +161,13 @@ class Shell : public SubsystemInterface void construct(); void deconstruct(); + void destroyScreenStack(); ///< tear down all screens without initializing uncovered layouts void linkScreen( WindowLayout *screen ); ///< link screen to list void unlinkScreen( WindowLayout *screen ); ///< remove screen from list void doPush( AsciiString layoutFile ); ///< workhorse for push action - void doPop( Bool suppressInit ); ///< workhorse for pop action + void doPop( Bool impendingPush ); ///< workhorse for pop action enum { MAX_SHELL_STACK = 16 }; ///< max simultaneous shell screens WindowLayout *m_screenStack[ MAX_SHELL_STACK ]; ///< the screen layout stack diff --git a/Core/GameEngine/Source/GameClient/GUI/Shell/Shell.cpp b/Core/GameEngine/Source/GameClient/GUI/Shell/Shell.cpp index b9f1d1898b4..8b3a9baad03 100644 --- a/Core/GameEngine/Source/GameClient/GUI/Shell/Shell.cpp +++ b/Core/GameEngine/Source/GameClient/GUI/Shell/Shell.cpp @@ -90,13 +90,7 @@ void Shell::construct() //------------------------------------------------------------------------------------------------- void Shell::deconstruct() { - WindowLayout *newTop = top(); - while(newTop) - { - // TheSuperHackers @bugfix CryoTheRenegade 10/08/2026 Do not initialize uncovered screens while the shell is being destroyed. - popImmediate( TRUE ); - newTop = top(); - } + destroyScreenStack(); if(m_background) { @@ -139,6 +133,32 @@ void Shell::deconstruct() } } +//------------------------------------------------------------------------------------------------- +/** Tear down every screen on the stack without initializing uncovered layouts. + * Used when the shell itself is being destroyed. */ +//------------------------------------------------------------------------------------------------- +void Shell::destroyScreenStack() +{ + // TheSuperHackers @bugfix CryoTheRenegade 10/08/2026 Do not initialize uncovered screens while the shell is being destroyed. + while( top() ) + { + WindowLayout *screen = top(); + + // do NOT set pending pop, we are going to force a pop after the shutdown is run + m_pendingPop = FALSE; + + Bool immediatePop = TRUE; + screen->runShutdown( &immediatePop ); + + unlinkScreen( screen ); + screen->destroyWindows(); + deleteInstance( screen ); + } + + if (TheIMEManager) + TheIMEManager->detach(); +} + //------------------------------------------------------------------------------------------------- /** Initialize the shell system */ //------------------------------------------------------------------------------------------------- @@ -425,7 +445,7 @@ void Shell::pop() * from the shutdown() for the screen, it will be immediately popped off * the stack */ //------------------------------------------------------------------------------------------------- -void Shell::popImmediate( Bool suppressInit ) +void Shell::popImmediate() { WindowLayout *screen = top(); @@ -449,7 +469,7 @@ void Shell::popImmediate( Bool suppressInit ) screen->runShutdown( &immediatePop ); // pop the screen of the stack - doPop( suppressInit ); + doPop( FALSE ); if (TheIMEManager) TheIMEManager->detach(); @@ -686,7 +706,7 @@ void Shell::doPush( AsciiString layoutFile ) //------------------------------------------------------------------------------------------------- /** Actually do the work for a pop */ //------------------------------------------------------------------------------------------------- -void Shell::doPop( Bool suppressInit ) +void Shell::doPop( Bool impendingPush ) { WindowLayout *currentTop = top(); @@ -707,7 +727,7 @@ void Shell::doPop( Bool suppressInit ) // run the init for the new top of the stack if present WindowLayout *newTop = top(); - if( newTop && !suppressInit ) + if( newTop && !impendingPush ) { newTop->runInit( nullptr ); //newTop->bringForward(); From 0422c07ba48a01cd07b7026f7d9028ee6c1593f9 Mon Sep 17 00:00:00 2001 From: Jacob Ledbetter Date: Fri, 21 Aug 2026 08:31:45 -0600 Subject: [PATCH 4/4] fixup(shell): Address xezon review comments Co-authored-by: Cursor --- Core/GameEngine/Include/GameClient/Shell.h | 2 +- Core/GameEngine/Source/GameClient/GUI/Shell/Shell.cpp | 3 +-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/Core/GameEngine/Include/GameClient/Shell.h b/Core/GameEngine/Include/GameClient/Shell.h index 4e6375b690b..262f89c3bc4 100644 --- a/Core/GameEngine/Include/GameClient/Shell.h +++ b/Core/GameEngine/Include/GameClient/Shell.h @@ -167,7 +167,7 @@ class Shell : public SubsystemInterface void unlinkScreen( WindowLayout *screen ); ///< remove screen from list void doPush( AsciiString layoutFile ); ///< workhorse for push action - void doPop( Bool impendingPush ); ///< workhorse for pop action + void doPop( Bool impendingPush ); ///< workhorse for pop action enum { MAX_SHELL_STACK = 16 }; ///< max simultaneous shell screens WindowLayout *m_screenStack[ MAX_SHELL_STACK ]; ///< the screen layout stack diff --git a/Core/GameEngine/Source/GameClient/GUI/Shell/Shell.cpp b/Core/GameEngine/Source/GameClient/GUI/Shell/Shell.cpp index 8b3a9baad03..a9a65928861 100644 --- a/Core/GameEngine/Source/GameClient/GUI/Shell/Shell.cpp +++ b/Core/GameEngine/Source/GameClient/GUI/Shell/Shell.cpp @@ -134,12 +134,11 @@ void Shell::deconstruct() } //------------------------------------------------------------------------------------------------- -/** Tear down every screen on the stack without initializing uncovered layouts. +/** TheSuperHackers @bugfix CryoTheRenegade 10/08/2026 Tear down every screen on the stack without initializing uncovered layouts. * Used when the shell itself is being destroyed. */ //------------------------------------------------------------------------------------------------- void Shell::destroyScreenStack() { - // TheSuperHackers @bugfix CryoTheRenegade 10/08/2026 Do not initialize uncovered screens while the shell is being destroyed. while( top() ) { WindowLayout *screen = top();