diff --git a/src/citra/citra.cpp b/src/citra/citra.cpp index 76f5caeb1..9ac7e981a 100644 --- a/src/citra/citra.cpp +++ b/src/citra/citra.cpp @@ -163,6 +163,8 @@ int main(int argc, char** argv) { break; // Expected case } + system.SetExitCallback([&]{ emu_window->CloseWindow(); }); + while (emu_window->IsOpen()) { system.RunLoop(); } diff --git a/src/citra/emu_window/emu_window_sdl2.h b/src/citra/emu_window/emu_window_sdl2.h index b1cbf16d7..02d529e3e 100644 --- a/src/citra/emu_window/emu_window_sdl2.h +++ b/src/citra/emu_window/emu_window_sdl2.h @@ -31,6 +31,10 @@ public: /// Whether the window is still open, and a close request hasn't yet been sent bool IsOpen() const; + void CloseWindow() { + is_open = false; + } + /// Load keymap from configuration void ReloadSetKeymaps() override; diff --git a/src/citra_qt/main.cpp b/src/citra_qt/main.cpp index f765c0147..b74ef6551 100644 --- a/src/citra_qt/main.cpp +++ b/src/citra_qt/main.cpp @@ -342,6 +342,8 @@ void GMainWindow::BootGame(const std::string& filename) { if (!LoadROM(filename)) return; + Core::System::GetInstance().SetExitCallback([&]{ ShutdownGame(); }); + // Create and start the emulation thread emu_thread = std::make_unique(render_window); emit EmulationStarting(emu_thread.get()); diff --git a/src/core/core.cpp b/src/core/core.cpp index 202cd332b..086555de7 100644 --- a/src/core/core.cpp +++ b/src/core/core.cpp @@ -113,6 +113,12 @@ void System::PrepareReschedule() { reschedule_pending = true; } +void System::ExitCallback() { + if (exit_callback) { + exit_callback(); + } +} + void System::Reschedule() { if (!reschedule_pending) { return; diff --git a/src/core/core.h b/src/core/core.h index 17572a74f..7b424cc4f 100644 --- a/src/core/core.h +++ b/src/core/core.h @@ -4,6 +4,7 @@ #pragma once +#include #include #include @@ -83,6 +84,12 @@ public: /// Prepare the core emulation for a reschedule void PrepareReschedule(); + void SetExitCallback(std::function callback) { + exit_callback = callback; + } + + void ExitCallback(); + /** * Gets a reference to the emulated CPU. * @returns A reference to the emulated CPU. @@ -112,6 +119,8 @@ private: /// When true, signals that a reschedule should happen bool reschedule_pending{}; + std::function exit_callback; + static System s_instance; }; diff --git a/src/core/hle/svc.cpp b/src/core/hle/svc.cpp index 96db39ad9..0e0a35b66 100644 --- a/src/core/hle/svc.cpp +++ b/src/core/hle/svc.cpp @@ -770,6 +770,12 @@ static ResultCode CreateEvent(Kernel::Handle* out_handle, u32 reset_type) { return RESULT_SUCCESS; } +/// Exit current process +static void ExitProcess() { + LOG_WARNING(Kernel_SVC, "called"); + Core::System::GetInstance().ExitCallback(); +} + /// Duplicates a kernel handle static ResultCode DuplicateHandle(Kernel::Handle* out, Kernel::Handle handle) { CASCADE_RESULT(*out, Kernel::g_handle_table.Duplicate(handle)); @@ -1074,7 +1080,7 @@ static const FunctionDef SVC_Table[] = { {0x00, nullptr, "Unknown"}, {0x01, HLE::Wrap, "ControlMemory"}, {0x02, HLE::Wrap, "QueryMemory"}, - {0x03, nullptr, "ExitProcess"}, + {0x03, ExitProcess, "ExitProcess"}, {0x04, nullptr, "GetProcessAffinityMask"}, {0x05, nullptr, "SetProcessAffinityMask"}, {0x06, nullptr, "GetProcessIdealProcessor"}, diff --git a/src/core/memory.cpp b/src/core/memory.cpp index 65e4bba85..ac7534f4d 100644 --- a/src/core/memory.cpp +++ b/src/core/memory.cpp @@ -147,6 +147,8 @@ static u8* GetPointerFromVMA(VAddr vaddr) { case Kernel::VMAType::BackingMemory: direct_pointer = vma.backing_memory; break; + case Kernel::VMAType::Free: + return nullptr; default: UNREACHABLE(); }