Handle window close cleanly and show exit popup selection

This commit is contained in:
2025-11-22 11:43:20 +01:00
parent a257c5cd79
commit 838b5b1836
6 changed files with 39 additions and 15 deletions

View File

@ -217,6 +217,7 @@ void Audio::startBackgroundLoading() {
return; return;
} }
} }
loadingAbort = false;
loadingComplete = false; loadingComplete = false;
loadedCount = 0; loadedCount = 0;
loadingThread = std::thread(&Audio::backgroundLoadingThread, this); loadingThread = std::thread(&Audio::backgroundLoadingThread, this);
@ -235,12 +236,18 @@ void Audio::backgroundLoadingThread() {
#endif #endif
while (true) { while (true) {
if (loadingAbort.load()) {
break;
}
std::string path; std::string path;
{ {
std::lock_guard<std::mutex> lock(pendingTracksMutex); std::lock_guard<std::mutex> lock(pendingTracksMutex);
if (pendingTracks.empty()) break; if (pendingTracks.empty()) break;
path = std::move(pendingTracks.front()); path = std::move(pendingTracks.front());
pendingTracks.erase(pendingTracks.begin()); pendingTracks.erase(pendingTracks.begin());
if (loadingAbort.load()) {
break;
}
} }
AudioTrack t; AudioTrack t;
t.path = path; t.path = path;
@ -255,6 +262,10 @@ void Audio::backgroundLoadingThread() {
#endif #endif
// Thread-safe addition to tracks // Thread-safe addition to tracks
if (loadingAbort.load()) {
break;
}
{ {
std::lock_guard<std::mutex> lock(tracksMutex); std::lock_guard<std::mutex> lock(tracksMutex);
tracks.push_back(std::move(t)); tracks.push_back(std::move(t));
@ -262,8 +273,12 @@ void Audio::backgroundLoadingThread() {
loadedCount++; loadedCount++;
// Small delay to prevent overwhelming the system // Small delay to prevent overwhelming the system (unless abort requested)
std::this_thread::sleep_for(std::chrono::milliseconds(10)); if (!loadingAbort.load()) {
std::this_thread::sleep_for(std::chrono::milliseconds(10));
} else {
break;
}
} }
#ifdef _WIN32 #ifdef _WIN32
@ -328,9 +343,15 @@ void Audio::playGameMusic() {
void Audio::shutdown(){ void Audio::shutdown(){
// Stop background loading thread first // Stop background loading thread first
loadingAbort = true;
{
std::lock_guard<std::mutex> lock(pendingTracksMutex);
pendingTracks.clear();
}
if (loadingThread.joinable()) { if (loadingThread.joinable()) {
loadingThread.join(); loadingThread.join();
} }
loadingComplete = true;
if(audioStream){ SDL_DestroyAudioStream(audioStream); audioStream=nullptr; } if(audioStream){ SDL_DestroyAudioStream(audioStream); audioStream=nullptr; }
tracks.clear(); tracks.clear();

View File

@ -72,6 +72,7 @@ private:
std::mutex tracksMutex; std::mutex tracksMutex;
std::mutex pendingTracksMutex; std::mutex pendingTracksMutex;
std::atomic<bool> loadingComplete{false}; std::atomic<bool> loadingComplete{false};
std::atomic<bool> loadingAbort{false};
std::atomic<int> loadedCount{0}; std::atomic<int> loadedCount{0};
// SFX mixing support // SFX mixing support

View File

@ -398,13 +398,14 @@ bool ApplicationManager::initializeManagers() {
// Forward all window events to StateManager // Forward all window events to StateManager
if (!m_stateManager) return; if (!m_stateManager) return;
SDL_Event ev{}; SDL_Event ev{};
ev.type = SDL_EVENT_WINDOW_RESIZED; // generic mapping; handlers can inspect inner fields ev.type = we.type;
ev.window = we; ev.window = we;
m_stateManager->handleEvent(ev); m_stateManager->handleEvent(ev);
}); });
m_inputManager->registerQuitHandler([this](){ m_inputManager->registerQuitHandler([this](){
SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION, "[QUIT] InputManager quit handler invoked - setting running=false"); SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION, "[QUIT] InputManager quit handler invoked - setting running=false");
traceFile("ApplicationManager: quit handler -> m_running=false");
m_running = false; m_running = false;
}); });
} }

View File

@ -22,16 +22,8 @@ void InputManager::processEvents() {
} }
switch (event.type) { switch (event.type) {
case SDL_EVENT_QUIT: case SDL_EVENT_QUIT:
m_shouldQuit = true; case SDL_EVENT_WINDOW_CLOSE_REQUESTED:
for (auto& handler : m_quitHandlers) { handleQuitEvent();
try {
// Trace quit event handling
FILE* f = fopen("tetris_trace.log", "a"); if (f) { fprintf(f, "InputManager: SDL_EVENT_QUIT polled\n"); fclose(f); }
handler();
} catch (const std::exception& e) {
SDL_LogError(SDL_LOG_CATEGORY_INPUT, "Exception in quit handler: %s", e.what());
}
}
break; break;
case SDL_EVENT_KEY_DOWN: case SDL_EVENT_KEY_DOWN:
@ -254,6 +246,10 @@ void InputManager::handleMouseMotionEvent(const SDL_MouseMotionEvent& event) {
} }
void InputManager::handleWindowEvent(const SDL_WindowEvent& event) { void InputManager::handleWindowEvent(const SDL_WindowEvent& event) {
if (event.type == SDL_EVENT_WINDOW_CLOSE_REQUESTED) {
handleQuitEvent();
}
// Notify handlers // Notify handlers
for (auto& handler : m_windowEventHandlers) { for (auto& handler : m_windowEventHandlers) {
try { try {
@ -353,6 +349,11 @@ void InputManager::reset() {
} }
void InputManager::handleQuitEvent() { void InputManager::handleQuitEvent() {
FILE* f = fopen("tetris_trace.log", "a");
if (f) {
fprintf(f, "InputManager::handleQuitEvent invoked\n");
fclose(f);
}
m_shouldQuit = true; m_shouldQuit = true;
for (auto& handler : m_quitHandlers) { for (auto& handler : m_quitHandlers) {
handler(); handler();

View File

@ -700,7 +700,7 @@ int main(int, char **)
SDL_Event e; SDL_Event e;
while (SDL_PollEvent(&e)) while (SDL_PollEvent(&e))
{ {
if (e.type == SDL_EVENT_QUIT) if (e.type == SDL_EVENT_QUIT || e.type == SDL_EVENT_WINDOW_CLOSE_REQUESTED)
running = false; running = false;
else { else {
// Route event to state manager handlers for per-state logic // Route event to state manager handlers for per-state logic

View File

@ -712,7 +712,7 @@ int main(int, char **)
SDL_Event e; SDL_Event e;
while (SDL_PollEvent(&e)) while (SDL_PollEvent(&e))
{ {
if (e.type == SDL_EVENT_QUIT) if (e.type == SDL_EVENT_QUIT || e.type == SDL_EVENT_WINDOW_CLOSE_REQUESTED)
running = false; running = false;
else { else {
// Route event to state manager handlers for per-state logic // Route event to state manager handlers for per-state logic