diff --git a/src/Cafe/CafeSystem.cpp b/src/Cafe/CafeSystem.cpp index 20a76812..593a171a 100644 --- a/src/Cafe/CafeSystem.cpp +++ b/src/Cafe/CafeSystem.cpp @@ -650,22 +650,23 @@ namespace CafeSystem s_implementation = impl; } - void Shutdown() - { - cemu_assert_debug(s_initialized); - // if a title is running, shut it down - if (sSystemRunning) - ShutdownTitle(); - // shutdown persistent subsystems (deprecated manual shutdown) + void Shutdown() + { + if (!s_initialized) + return; + // if a title is running, shut it down + if (sSystemRunning) + ShutdownTitle(); + // shutdown persistent subsystems (deprecated manual shutdown) iosu::odm::Shutdown(); iosu::act::Stop(); - iosu::mcp::Shutdown(); - iosu::fsa::Shutdown(); + iosu::mcp::Shutdown(); + iosu::fsa::Shutdown(); // shutdown IOSU modules for(auto it = s_iosuModules.rbegin(); it != s_iosuModules.rend(); ++it) (*it)->SystemExit(); - s_initialized = false; - } + s_initialized = false; + } std::string GetInternalVirtualCodeFolder() { @@ -1088,6 +1089,12 @@ namespace CafeSystem sSystemRunning = false; } + void RequestEndTitle(int exitCode) + { + WindowSystem::SetExitCode(exitCode); + WindowSystem::RequestEndCurrentEmulation(); + } + /* Virtual mlc storage */ void InitVirtualMlcStorage() diff --git a/src/Cafe/CafeSystem.h b/src/Cafe/CafeSystem.h index 4003b393..e134877c 100644 --- a/src/Cafe/CafeSystem.h +++ b/src/Cafe/CafeSystem.h @@ -23,7 +23,7 @@ namespace CafeSystem void Initialize(); void SetImplementation(SystemImplementation* impl); - void Shutdown(); + void Shutdown(); PREPARE_STATUS_CODE PrepareForegroundTitle(TitleId titleId); PREPARE_STATUS_CODE PrepareForegroundTitleFromStandaloneRPX(const fs::path& path); @@ -45,6 +45,7 @@ namespace CafeSystem CosCapabilityBits GetForegroundTitleCosCapabilities(CosCapabilityGroup group); void ShutdownTitle(); + void RequestEndTitle(int exitCode); std::string GetMlcStoragePath(TitleId titleId); void MlcStorageMountAllTitles(); diff --git a/src/Cafe/HW/Latte/Renderer/Vulkan/VulkanRenderer.cpp b/src/Cafe/HW/Latte/Renderer/Vulkan/VulkanRenderer.cpp index b4d99e35..e92ffb97 100644 --- a/src/Cafe/HW/Latte/Renderer/Vulkan/VulkanRenderer.cpp +++ b/src/Cafe/HW/Latte/Renderer/Vulkan/VulkanRenderer.cpp @@ -364,7 +364,7 @@ int BreathOfTheWildChildProcessMain() vkEnumeratePhysicalDevices(instance, &count, nullptr); vkDestroyInstance(instance, nullptr); - return 0; + return WindowSystem::GetExitCode(); } static void LinuxBreathOfTheWildWorkaround(VkInstance& instance, const VkInstanceCreateInfo* create_info) diff --git a/src/Cafe/OS/libs/coreinit/coreinit.cpp b/src/Cafe/OS/libs/coreinit/coreinit.cpp index fd3ed23b..24206db1 100644 --- a/src/Cafe/OS/libs/coreinit/coreinit.cpp +++ b/src/Cafe/OS/libs/coreinit/coreinit.cpp @@ -2,6 +2,7 @@ #include "Common/SysAllocator.h" #include "Cafe/OS/RPL/rpl_symbol_storage.h" +#include "Cafe/CafeSystem.h" #include "Cafe/OS/libs/coreinit/coreinit_Misc.h" // includes for Initialize coreinit submodules @@ -241,10 +242,8 @@ namespace coreinit void coreinit_exit(uint32 r) { cemuLog_log(LogType::Force, "The title terminated the process by calling coreinit.exit({})", (sint32)r); - DebugLogStackTrace(coreinit::OSGetCurrentThread(), coreinit::OSGetStackPointer()); - cemu_assert_debug(false); - // never return - while (true) std::this_thread::sleep_for(std::chrono::milliseconds(100)); + DebugLogStackTrace(coreinit::OSGetCurrentThread(), coreinit::OSGetStackPointer()); + CafeSystem::RequestEndTitle((int) r); } bool OSIsOffBoot() diff --git a/src/gui/interface/WindowSystem.h b/src/gui/interface/WindowSystem.h index b2346c17..1cd52108 100644 --- a/src/gui/interface/WindowSystem.h +++ b/src/gui/interface/WindowSystem.h @@ -98,6 +98,10 @@ namespace WindowSystem } void Create(); + int GetExitCode(); + void SetExitCode(int value); + + void RequestEndCurrentEmulation(); WindowInfo& GetWindowInfo(); diff --git a/src/gui/wxgui/CemuApp.cpp b/src/gui/wxgui/CemuApp.cpp index 9a636989..4c22ac1b 100644 --- a/src/gui/wxgui/CemuApp.cpp +++ b/src/gui/wxgui/CemuApp.cpp @@ -1,4 +1,5 @@ #include "wxgui/CemuApp.h" +#include "interface/WindowSystem.h" #include "wxCemuConfig.h" #include "wxgui/MainWindow.h" #include "wxgui/wxgui.h" @@ -422,9 +423,9 @@ int CemuApp::OnExit() SDLControllerProvider::ShutdownSDL(); #endif #if BOOST_OS_WINDOWS - ExitProcess(0); + ExitProcess(WindowSystem::GetExitCode()); #else - _Exit(0); + _Exit(WindowSystem::GetExitCode()); #endif } diff --git a/src/gui/wxgui/MainWindow.cpp b/src/gui/wxgui/MainWindow.cpp index 542554f2..014854d3 100644 --- a/src/gui/wxgui/MainWindow.cpp +++ b/src/gui/wxgui/MainWindow.cpp @@ -161,6 +161,7 @@ enum wxDEFINE_EVENT(wxEVT_SET_WINDOW_TITLE, wxCommandEvent); wxDEFINE_EVENT(wxEVT_REQUEST_GAMELIST_REFRESH, wxCommandEvent); wxDEFINE_EVENT(wxEVT_LAUNCH_GAME, wxLaunchGameEvent); +wxDEFINE_EVENT(wxEVT_END_EMULATION, wxEndEmulationEvent); wxDEFINE_EVENT(wxEVT_REQUEST_RECREATE_CANVAS, wxCommandEvent); wxBEGIN_EVENT_TABLE(MainWindow, wxFrame) @@ -324,11 +325,13 @@ MainWindow::MainWindow() if (load_file) { + m_launched_bare = true; MainWindow::RequestLaunchGame(load_file.value(), wxLaunchGameEvent::INITIATED_BY::COMMAND_LINE); quick_launch = true; } else if (load_title_id) { + m_launched_bare = true; TitleInfo info; TitleId baseId; if (CafeTitleList::FindBaseTitleId(load_title_id.value(), baseId) && CafeTitleList::GetFirstByTitleId(baseId, info)) @@ -370,6 +373,7 @@ MainWindow::MainWindow() Bind(wxEVT_OPEN_GRAPHIC_PACK, &MainWindow::OnGraphicWindowOpen, this); Bind(wxEVT_LAUNCH_GAME, &MainWindow::OnLaunchFromFile, this); + Bind(wxEVT_END_EMULATION, &MainWindow::OnEndEmulation, this); if (LaunchSettings::GDBStubEnabled()) { @@ -625,6 +629,34 @@ void MainWindow::OnLaunchFromFile(wxLaunchGameEvent& event) FileLoad(event.GetPath(), event.GetInitiatedBy()); } +void MainWindow::OnEndEmulation(wxEndEmulationEvent& event) +{ + // Game launched with `-g`, or `-t`, no window to return to. + if (m_launched_bare) + { + if (m_debugger_window) + { + m_debugger_window->CleanupForDestroy(); + m_debugger_window->Destroy(); + m_debugger_window = nullptr; + } + + if(m_game_list) + m_game_list->Close(); + + if (!IsMaximized() && !WindowSystem::IsFullScreen()) + m_restored_size = GetSize(); + + SaveSettings(); + m_timer->Stop(); + + CafeSystem::Shutdown(); + Destroy(); + } + else + EndEmulation(); +} + void MainWindow::OnFileMenu(wxCommandEvent& event) { const auto menuId = event.GetId(); @@ -2452,6 +2484,12 @@ void MainWindow::RequestLaunchGame(fs::path filePath, wxLaunchGameEvent::INITIAT wxPostEvent(g_mainFrame, evt); } +void MainWindow::RequestEndEmulation() +{ + wxEndEmulationEvent evt; + wxPostEvent(g_mainFrame, evt); +} + void MainWindow::OnRequestRecreateCanvas(wxCommandEvent& event) { CounterSemaphore* sem = (CounterSemaphore*)event.GetClientData(); diff --git a/src/gui/wxgui/MainWindow.h b/src/gui/wxgui/MainWindow.h index eec043b8..a4c46ecc 100644 --- a/src/gui/wxgui/MainWindow.h +++ b/src/gui/wxgui/MainWindow.h @@ -23,8 +23,10 @@ class TitleManager; class GraphicPacksWindow2; class EmulatedUSBDeviceFrame; class wxLaunchGameEvent; +class wxEndEmulationEvent; wxDECLARE_EVENT(wxEVT_LAUNCH_GAME, wxLaunchGameEvent); +wxDECLARE_EVENT(wxEVT_END_EMULATION, wxEndEmulationEvent); wxDECLARE_EVENT(wxEVT_SET_WINDOW_TITLE, wxCommandEvent); class wxLaunchGameEvent : public wxCommandEvent @@ -52,6 +54,14 @@ private: INITIATED_BY m_initiatedBy; }; +class wxEndEmulationEvent : public wxCommandEvent +{ +public: + wxEndEmulationEvent() : wxCommandEvent(wxEVT_END_EMULATION) {} + + wxEvent* Clone() const { return new wxEndEmulationEvent(*this); } +}; + class MainWindow : public wxFrame, public CafeSystem::SystemImplementation { friend class CemuApp; @@ -132,6 +142,7 @@ public: void OnGesturePan(wxPanGestureEvent& event); void OnGameLoaded(); + void OnEndEmulation(wxEndEmulationEvent& event); void AsyncSetTitle(std::string_view windowTitle); @@ -144,6 +155,7 @@ public: static void RequestGameListRefresh(); static void RequestLaunchGame(fs::path filePath, wxLaunchGameEvent::INITIATED_BY initiatedBy); + static void RequestEndEmulation(); private: bool FullscreenEnabled() const; @@ -176,6 +188,7 @@ private: bool m_menu_visible = false; bool m_game_launched = false; + bool m_launched_bare = false; #ifdef ENABLE_DISCORD_RPC std::unique_ptr m_discord; diff --git a/src/gui/wxgui/components/wxGameList.cpp b/src/gui/wxgui/components/wxGameList.cpp index a1e5142d..b8ee5d32 100644 --- a/src/gui/wxgui/components/wxGameList.cpp +++ b/src/gui/wxgui/components/wxGameList.cpp @@ -1077,6 +1077,11 @@ void wxGameList::OnColumnResize(wxListEvent& event) void wxGameList::OnClose(wxCloseEvent& event) { event.Skip(); + Close(); +} + +void wxGameList::Close() +{ m_exit = true; } diff --git a/src/gui/wxgui/components/wxGameList.h b/src/gui/wxgui/components/wxGameList.h index 388a9df6..5ed62bb9 100644 --- a/src/gui/wxgui/components/wxGameList.h +++ b/src/gui/wxgui/components/wxGameList.h @@ -57,6 +57,7 @@ public: long FindListItemByTitleId(uint64 title_id) const; void OnClose(wxCloseEvent& event); + void Close(); private: std::atomic_bool m_exit = false; @@ -163,4 +164,3 @@ private: static inline std::once_flag s_launch_file_once; }; - diff --git a/src/gui/wxgui/wxWindowSystem.cpp b/src/gui/wxgui/wxWindowSystem.cpp index bb730db8..4665a1de 100644 --- a/src/gui/wxgui/wxWindowSystem.cpp +++ b/src/gui/wxgui/wxWindowSystem.cpp @@ -30,6 +30,7 @@ WindowSystem::WindowInfo g_window_info{}; +int g_exitCode = 0; std::shared_mutex g_mutex; MainWindow* g_mainFrame = nullptr; @@ -56,6 +57,21 @@ void WindowSystem::Create() #endif } +int WindowSystem::GetExitCode() +{ + return g_exitCode; +} + +void WindowSystem::SetExitCode(int value) +{ + g_exitCode = value; +} + +void WindowSystem::RequestEndCurrentEmulation() +{ + MainWindow::RequestEndEmulation(); +} + void WindowSystem::ShowErrorDialog(std::string_view message, std::string_view title, std::optional /*errorId*/) { wxString caption; diff --git a/src/main.cpp b/src/main.cpp index 9b9e04c2..2b485e3a 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -245,7 +245,7 @@ int wWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPWSTR lpCmdLine, int if (!LaunchSettings::HandleCommandline(lpCmdLine)) return 0; WindowSystem::Create(); - return 0; + return WindowSystem::GetExitCode(); } // entrypoint for debug builds with console @@ -259,7 +259,7 @@ int main(int argc, char* argv[]) if (!LaunchSettings::HandleCommandline(argc, argv)) return 0; WindowSystem::Create(); - return 0; + return WindowSystem::GetExitCode(); } #else @@ -278,7 +278,7 @@ int main(int argc, char *argv[]) if (!LaunchSettings::HandleCommandline(argc, argv)) return 0; WindowSystem::Create(); - return 0; + return WindowSystem::GetExitCode(); } #endif