mirror of
https://github.com/cemu-project/Cemu.git
synced 2026-07-10 01:24:41 -06:00
Merge branch 'cemu-project:main' into main
This commit is contained in:
commit
f0ccc3fbf4
47
.gdbinit
Normal file
47
.gdbinit
Normal file
@ -0,0 +1,47 @@
|
||||
python
|
||||
|
||||
import gdb
|
||||
import re
|
||||
|
||||
|
||||
class BetypePrinter:
|
||||
PATTERN = re.compile("^betype<.*>$")
|
||||
|
||||
def __init__(self, obj):
|
||||
self._obj = obj
|
||||
|
||||
def to_string(self):
|
||||
underlying = self._obj["m_value"]
|
||||
reversed_bytes = bytes(reversed(underlying.bytes))
|
||||
return gdb.Value(reversed_bytes, underlying.type)
|
||||
|
||||
class MemptrPrinter:
|
||||
PATTERN = re.compile("^MEMPTR<.*>$")
|
||||
|
||||
def __init__(self, obj):
|
||||
self._ptr_type = obj.type.strip_typedefs().unqualified().template_argument(0).pointer()
|
||||
self._guest_address = obj["m_value"].cast(gdb.lookup_type("uint32"))
|
||||
|
||||
def ptr(self):
|
||||
if self._guest_address == 0:
|
||||
return gdb.Value(0, self._ptr_type)
|
||||
base_addr = gdb.parse_and_eval('memory_base', global_context=True)
|
||||
return (self._guest_address + base_addr).reinterpret_cast(self._ptr_type)
|
||||
|
||||
def children(self):
|
||||
return [("raw", self.ptr())]
|
||||
|
||||
def to_string(self):
|
||||
return self._guest_address.format_string(format="x")
|
||||
|
||||
def lookup(val):
|
||||
tag = val.type.strip_typedefs().unqualified().tag
|
||||
if tag is None:
|
||||
return None
|
||||
printers = [BetypePrinter, MemptrPrinter]
|
||||
for printer in printers:
|
||||
if printer.PATTERN.match(tag):
|
||||
return printer(val)
|
||||
return None
|
||||
|
||||
gdb.pretty_printers.append(lookup)
|
||||
@ -443,6 +443,7 @@ namespace CafeSystem
|
||||
static SystemImplementation* s_implementation{nullptr};
|
||||
bool sLaunchModeIsStandalone = false;
|
||||
std::optional<std::vector<std::string>> s_overrideArgs;
|
||||
std::optional<sint32> s_foregroundReturnStatus;
|
||||
|
||||
bool sSystemRunning = false;
|
||||
TitleId sForegroundTitleId = 0;
|
||||
@ -685,6 +686,22 @@ namespace CafeSystem
|
||||
fsc_unmount("/cemuBossStorage/", FSC_PRIORITY_BASE);
|
||||
}
|
||||
|
||||
void MountExtras()
|
||||
{
|
||||
for (const auto& [host_path, emulatedPath] : LaunchSettings::CosMounts())
|
||||
{
|
||||
FSCDeviceHostFS_Mount(boost::nowide::narrow(emulatedPath), _pathToUtf8(host_path), FSC_PRIORITY_BASE);
|
||||
}
|
||||
}
|
||||
|
||||
void UnmountExtras()
|
||||
{
|
||||
for (const auto& [_, emulatedPath] : LaunchSettings::CosMounts())
|
||||
{
|
||||
fsc_unmount(boost::nowide::narrow(emulatedPath), FSC_PRIORITY_BASE);
|
||||
}
|
||||
}
|
||||
|
||||
PREPARE_STATUS_CODE LoadAndMountForegroundTitle(TitleId titleId)
|
||||
{
|
||||
cemuLog_log(LogType::Force, "Mounting title {:016x}", (uint64)titleId);
|
||||
@ -820,6 +837,7 @@ namespace CafeSystem
|
||||
{
|
||||
CafeTitleList::WaitForMandatoryScan();
|
||||
sLaunchModeIsStandalone = false;
|
||||
s_foregroundReturnStatus = std::nullopt;
|
||||
_pathToExecutable.clear();
|
||||
TitleIdParser tip(titleId);
|
||||
if (tip.GetType() == TitleIdParser::TITLE_TYPE::AOC || tip.GetType() == TitleIdParser::TITLE_TYPE::BASE_TITLE_UPDATE)
|
||||
@ -838,6 +856,7 @@ namespace CafeSystem
|
||||
if (r != PREPARE_STATUS_CODE::SUCCESS)
|
||||
return r;
|
||||
InitVirtualMlcStorage();
|
||||
MountExtras();
|
||||
return PREPARE_STATUS_CODE::SUCCESS;
|
||||
}
|
||||
|
||||
@ -881,6 +900,7 @@ namespace CafeSystem
|
||||
// load executable
|
||||
PrepareExecutable();
|
||||
InitVirtualMlcStorage();
|
||||
MountExtras();
|
||||
return PREPARE_STATUS_CODE::SUCCESS;
|
||||
}
|
||||
|
||||
@ -960,6 +980,9 @@ namespace CafeSystem
|
||||
|
||||
std::string GetForegroundTitleArgStr()
|
||||
{
|
||||
auto optional_arguments = LaunchSettings::CosArgstr();
|
||||
if (optional_arguments.has_value())
|
||||
return *optional_arguments;
|
||||
if (sLaunchModeIsStandalone)
|
||||
return "";
|
||||
auto& update = sGameInfo_ForegroundTitle.GetUpdate();
|
||||
@ -1044,24 +1067,26 @@ namespace CafeSystem
|
||||
{
|
||||
if(!sSystemRunning)
|
||||
return;
|
||||
coreinit::OSSchedulerEnd();
|
||||
Latte_Stop();
|
||||
// reset Cafe OS userspace modules
|
||||
snd_core::reset();
|
||||
coreinit::OSAlarm_Shutdown();
|
||||
GX2::_GX2DriverReset();
|
||||
nn::save::ResetToDefaultState();
|
||||
coreinit::__OSDeleteAllActivePPCThreads();
|
||||
RPLLoader_UnloadAll();
|
||||
coreinit::OSSchedulerEnd();
|
||||
Latte_Stop();
|
||||
// reset Cafe OS userspace modules
|
||||
snd_core::reset();
|
||||
coreinit::OSAlarm_Shutdown();
|
||||
GX2::_GX2DriverReset();
|
||||
nn::save::ResetToDefaultState();
|
||||
coreinit::__OSDeleteAllActivePPCThreads();
|
||||
RPLLoader_UnloadAll();
|
||||
for(auto it = s_iosuModules.rbegin(); it != s_iosuModules.rend(); ++it)
|
||||
(*it)->TitleStop();
|
||||
// reset Cemu subsystems
|
||||
PPCRecompiler_Shutdown();
|
||||
GraphicPack2::Reset();
|
||||
UnmountCurrentTitle();
|
||||
MlcStorageUnmountAllTitles();
|
||||
UnmountBaseDirectories();
|
||||
DestroyMemorySpace();
|
||||
// reset Cemu subsystems
|
||||
PPCRecompiler_Shutdown();
|
||||
GraphicPack2::Reset();
|
||||
UnmountCurrentTitle();
|
||||
UnmountExtras();
|
||||
MlcStorageUnmountAllTitles();
|
||||
UnmountBaseDirectories();
|
||||
DestroyMemorySpace();
|
||||
LaunchSettings::ClearCosArgstr();
|
||||
sSystemRunning = false;
|
||||
}
|
||||
|
||||
@ -1163,4 +1188,15 @@ namespace CafeSystem
|
||||
s_implementation->CafeRecreateCanvas();
|
||||
}
|
||||
|
||||
void NotifyPPCProcessExit(sint32 status)
|
||||
{
|
||||
s_foregroundReturnStatus = status;
|
||||
s_implementation->CafePPCProcessExit();
|
||||
}
|
||||
|
||||
std::optional<sint32> GetForegroundTitleReturnStatus()
|
||||
{
|
||||
return s_foregroundReturnStatus;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -12,6 +12,7 @@ namespace CafeSystem
|
||||
{
|
||||
public:
|
||||
virtual void CafeRecreateCanvas() = 0;
|
||||
virtual void CafePPCProcessExit() = 0; // emulated process exited
|
||||
};
|
||||
|
||||
enum class PREPARE_STATUS_CODE
|
||||
@ -43,6 +44,7 @@ namespace CafeSystem
|
||||
std::string GetForegroundTitleArgStr();
|
||||
uint32 GetForegroundTitleOlvAccesskey();
|
||||
CosCapabilityBits GetForegroundTitleCosCapabilities(CosCapabilityGroup group);
|
||||
std::optional<sint32> GetForegroundTitleReturnStatus(); // valid once the foreground title exited gracefully via coreinit exit
|
||||
|
||||
void ShutdownTitle();
|
||||
|
||||
@ -55,6 +57,8 @@ namespace CafeSystem
|
||||
uint32 GetRPXHashUpdated();
|
||||
|
||||
void RequestRecreateCanvas();
|
||||
void NotifyPPCProcessExit(sint32 status);
|
||||
|
||||
};
|
||||
|
||||
extern RPLModule* applicationRPX;
|
||||
|
||||
@ -200,7 +200,7 @@ bool FSTVolume::FindDiscKey(const fs::path& path, NCrypto::AesKey& discTitleKey)
|
||||
if (dataSource->readData(0, 0, 0x18000 + 0x100, header, sizeof(header)) != sizeof(header))
|
||||
return false;
|
||||
|
||||
// try all the keys
|
||||
// try all the keys in the key cache
|
||||
uint8 headerDecrypted[sizeof(header)-16];
|
||||
for (sint32 i = 0; i < 0x7FFFFFFF; i++)
|
||||
{
|
||||
@ -215,7 +215,12 @@ bool FSTVolume::FindDiscKey(const fs::path& path, NCrypto::AesKey& discTitleKey)
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
|
||||
// check for a key file next to the WUD file
|
||||
fs::path keyPath = path;
|
||||
keyPath.replace_extension("key");
|
||||
std::unique_ptr<FileStream> keyFile(FileStream::openFile2(keyPath));
|
||||
return keyFile && keyFile->readData(discTitleKey.b, sizeof(discTitleKey.b)) == sizeof(discTitleKey.b);
|
||||
}
|
||||
|
||||
// open WUD image using key cache
|
||||
|
||||
@ -238,15 +238,6 @@ namespace coreinit
|
||||
osLib_returnFromFunction(hCPU, 1);
|
||||
}
|
||||
|
||||
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));
|
||||
}
|
||||
|
||||
bool OSIsOffBoot()
|
||||
{
|
||||
return true;
|
||||
@ -289,7 +280,6 @@ namespace coreinit
|
||||
|
||||
osLib_addFunction("coreinit", "ENVGetEnvironmentVariable", coreinitExport_ENVGetEnvironmentVariable);
|
||||
|
||||
cafeExportRegisterFunc(coreinit_exit, "coreinit", "exit", LogType::CoreinitThread);
|
||||
cafeExportRegister("coreinit", OSIsOffBoot, LogType::CoreinitThread);
|
||||
cafeExportRegister("coreinit", OSGetBootPMFlags, LogType::CoreinitThread);
|
||||
cafeExportRegister("coreinit", OSGetSystemMode, LogType::CoreinitThread);
|
||||
|
||||
@ -15,13 +15,13 @@ void coreinitAsyncCallback_addWithLock(MPTR functionMPTR, uint32 numParameters,
|
||||
// coreinit shared memory
|
||||
struct CoreinitSharedData
|
||||
{
|
||||
MEMPTR<void> MEMAllocFromDefaultHeap;
|
||||
MEMPTR<void> MEMAllocFromDefaultHeapEx;
|
||||
MEMPTR<void> MEMFreeToDefaultHeap;
|
||||
MPTR __atexit_cleanup;
|
||||
MPTR __cpp_exception_init_ptr;
|
||||
MPTR __cpp_exception_cleanup_ptr;
|
||||
MPTR __stdio_cleanup;
|
||||
MEMPTR<void> MEMAllocFromDefaultHeap{nullptr};
|
||||
MEMPTR<void> MEMAllocFromDefaultHeapEx{nullptr};
|
||||
MEMPTR<void> MEMFreeToDefaultHeap{nullptr};
|
||||
MEMPTR<void> __atexit_cleanup{nullptr};
|
||||
MEMPTR<void> __stdio_cleanup{nullptr};
|
||||
MPTR __cpp_exception_init_ptr{0};
|
||||
MPTR __cpp_exception_cleanup_ptr{0};
|
||||
};
|
||||
|
||||
extern CoreinitSharedData* gCoreinitData;
|
||||
|
||||
@ -4,6 +4,7 @@
|
||||
#include "Cafe/OS/libs/coreinit/coreinit_OSScreen.h"
|
||||
#include "Cafe/CafeSystem.h"
|
||||
#include "Cafe/Filesystem/fsc.h"
|
||||
#include "config/LaunchSettings.h"
|
||||
#include <pugixml.hpp>
|
||||
|
||||
namespace coreinit
|
||||
@ -544,6 +545,7 @@ namespace coreinit
|
||||
}
|
||||
|
||||
std::mutex sCafeConsoleMutex;
|
||||
bool s_forwardConsoleLogs;
|
||||
|
||||
void WriteCafeConsole(CafeLogType cafeLogType, const char* msg, sint32 len)
|
||||
{
|
||||
@ -556,6 +558,14 @@ namespace coreinit
|
||||
cafeLogBuffer.lineLength = 0;
|
||||
};
|
||||
|
||||
if (s_forwardConsoleLogs) {
|
||||
if (cafeLogType == CafeLogType::OSCONSOLE) {
|
||||
fwrite(msg, 1, len, stdout);
|
||||
fflush(stdout);
|
||||
} else {
|
||||
fwrite(msg, 1, len, stderr);
|
||||
}
|
||||
}
|
||||
while (len)
|
||||
{
|
||||
char c = *msg;
|
||||
@ -684,7 +694,6 @@ namespace coreinit
|
||||
return s_sdkVersion;
|
||||
}
|
||||
|
||||
// move this to CafeSystem.cpp?
|
||||
void OSLauncherThread(uint64 titleId)
|
||||
{
|
||||
CafeSystem::ShutdownTitle();
|
||||
@ -693,6 +702,12 @@ namespace coreinit
|
||||
CafeSystem::LaunchForegroundTitle();
|
||||
}
|
||||
|
||||
void OSShutdownThread(sint32 status)
|
||||
{
|
||||
CafeSystem::ShutdownTitle();
|
||||
CafeSystem::NotifyPPCProcessExit(status);
|
||||
}
|
||||
|
||||
uint32 __LaunchByTitleId(uint64 titleId, uint32 argc, MEMPTR<char>* argv)
|
||||
{
|
||||
// prepare argument buffer
|
||||
@ -842,10 +857,31 @@ namespace coreinit
|
||||
return 0;
|
||||
}
|
||||
|
||||
void __PPCExit(sint32 status)
|
||||
{
|
||||
// spawn shutdown thread (the current thread has to be destroyed as part of the shutdown process)
|
||||
std::thread shutdownThread(OSShutdownThread, status);
|
||||
shutdownThread.detach();
|
||||
// suspend this thread
|
||||
coreinit::OSSuspendThread(coreinit::OSGetCurrentThread());
|
||||
}
|
||||
|
||||
void coreinit_exit(sint32 status)
|
||||
{
|
||||
cemuLog_log(LogType::Force, "The title terminated the process by calling coreinit.exit({})", (sint32)status);
|
||||
DebugLogStackTrace(coreinit::OSGetCurrentThread(), coreinit::OSGetStackPointer());
|
||||
if (gCoreinitData->__atexit_cleanup)
|
||||
PPCCoreCallback(gCoreinitData->__atexit_cleanup, status);
|
||||
if (gCoreinitData->__stdio_cleanup)
|
||||
PPCCoreCallback(gCoreinitData->__stdio_cleanup);
|
||||
__PPCExit(status);
|
||||
}
|
||||
|
||||
void miscInit()
|
||||
{
|
||||
s_currentTitleId = CafeSystem::GetForegroundTitleId();
|
||||
s_sdkVersion = CafeSystem::GetForegroundTitleSDKVersion();
|
||||
s_forwardConsoleLogs = LaunchSettings::ForwardConsoleLogging();
|
||||
s_transitionToBackground = false;
|
||||
s_transitionToForeground = false;
|
||||
|
||||
@ -876,6 +912,9 @@ namespace coreinit
|
||||
|
||||
cafeExportRegister("coreinit", OSDriver_Register, LogType::Placeholder);
|
||||
cafeExportRegister("coreinit", OSDriver_Deregister, LogType::Placeholder);
|
||||
|
||||
cafeExportRegisterFunc(coreinit_exit, "coreinit", "exit", LogType::CoreinitThread);
|
||||
cafeExportRegister("coreinit", __PPCExit, LogType::CoreinitThread);
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
@ -63,7 +63,7 @@ bool LaunchSettings::HandleCommandline(const std::vector<std::wstring>& args)
|
||||
#endif
|
||||
|
||||
("game,g", po::wvalue<std::wstring>(), "Path of game to launch")
|
||||
("title-id,t", po::value<std::string>(), "Title ID of the title to be launched (overridden by --game)")
|
||||
("title-id,t", po::value<std::string>(), "Title ID of the title to be launched (overridden by --game)")
|
||||
("mlc,m", po::wvalue<std::wstring>(), "Custom mlc folder location")
|
||||
|
||||
("fullscreen,f", po::value<bool>()->implicit_value(true), "Launch games in fullscreen mode")
|
||||
@ -71,6 +71,10 @@ bool LaunchSettings::HandleCommandline(const std::vector<std::wstring>& args)
|
||||
|
||||
("account,a", po::value<std::string>(), "Persistent id of account")
|
||||
|
||||
("cos-mounts", po::wvalue<std::vector<std::wstring>>()->composing(), "A series of mounts in the form of: (path on host:path within emulated system, e.g. `/tmp:/vol/temporary/`)")
|
||||
("forward-console-logging", "Forward OSReport, OSConsoleWrite, etc. to stdout/stderr.")
|
||||
("cos-argstr", po::value<std::string>(), "A custom argstr used to override to the arguments to the first RPX that is launched, will be unset after the first launch.")
|
||||
|
||||
("force-interpreter", po::value<bool>()->implicit_value(true), "Force interpreter CPU emulation, disables recompiler. Useful for debugging purposes where you want to get accurate memory accesses and stack traces.")
|
||||
("force-multicore-interpreter", po::value<bool>()->implicit_value(true), "Force multi-core interpreter CPU emulation, disables recompiler. Only useful for getting stack traces, but slightly faster than the single-core interpreter mode.")
|
||||
("enable-gdbstub", po::value<bool>()->implicit_value(true), "Enable GDB stub to debug executables inside Cemu using an external debugger");
|
||||
@ -189,6 +193,30 @@ bool LaunchSettings::HandleCommandline(const std::vector<std::wstring>& args)
|
||||
if (vm.count("enable-gdbstub"))
|
||||
s_enable_gdbstub = vm["enable-gdbstub"].as<bool>();
|
||||
|
||||
if (vm.count("forward-console-logging"))
|
||||
{
|
||||
requireConsole();
|
||||
s_forward_console_logging = true;
|
||||
}
|
||||
|
||||
if (vm.count("cos-argstr"))
|
||||
s_cos_argstr = vm["cos-argstr"].as<std::string>();
|
||||
|
||||
if (vm.count("cos-mounts"))
|
||||
{
|
||||
for (const auto& argument : vm["cos-mounts"].as<std::vector<std::wstring>>())
|
||||
{
|
||||
size_t colon_location = argument.find(L':');
|
||||
if (colon_location == std::wstring::npos)
|
||||
{
|
||||
std::cerr << "Argument for a mount expects to be in the format: `path on host:path in emulated system`, was not: `" << boost::nowide::narrow(argument) << "`\n";
|
||||
continue;
|
||||
}
|
||||
|
||||
s_cos_mounts[argument.substr(0, colon_location)] = argument.substr(colon_location + 1);
|
||||
}
|
||||
}
|
||||
|
||||
std::wstring extract_path, log_path;
|
||||
std::string output_path;
|
||||
if (vm.count("extract"))
|
||||
|
||||
@ -2,6 +2,7 @@
|
||||
|
||||
#include <optional>
|
||||
#include <string>
|
||||
#include <unordered_map>
|
||||
|
||||
class LaunchSettings
|
||||
{
|
||||
@ -16,7 +17,7 @@ public:
|
||||
static bool HandleCommandline(const std::vector<std::wstring>& args);
|
||||
|
||||
static std::optional<fs::path> GetLoadFile() { return s_load_game_file; }
|
||||
static std::optional<uint64> GetLoadTitleID() {return s_load_title_id;}
|
||||
static std::optional<uint64> GetLoadTitleID() {return s_load_title_id;}
|
||||
static std::optional<fs::path> GetMLCPath() { return s_mlc_path; }
|
||||
|
||||
static std::optional<bool> RenderUpsideDownEnabled() { return s_render_upside_down; }
|
||||
@ -24,6 +25,11 @@ public:
|
||||
|
||||
static bool Verbose() { return s_verbose; }
|
||||
|
||||
static bool ForwardConsoleLogging() { return s_forward_console_logging; }
|
||||
static std::optional<std::string> CosArgstr() { return s_cos_argstr; }
|
||||
static void ClearCosArgstr() { s_cos_argstr.reset(); }
|
||||
static std::unordered_map<fs::path, std::wstring>& CosMounts() { return s_cos_mounts; }
|
||||
|
||||
static bool GDBStubEnabled() { return s_enable_gdbstub; }
|
||||
static bool NSightModeEnabled() { return s_nsight_mode; }
|
||||
|
||||
@ -37,14 +43,18 @@ public:
|
||||
|
||||
private:
|
||||
inline static std::optional<fs::path> s_load_game_file{};
|
||||
inline static std::optional<uint64> s_load_title_id{};
|
||||
inline static std::optional<uint64> s_load_title_id{};
|
||||
inline static std::optional<fs::path> s_mlc_path{};
|
||||
|
||||
inline static std::optional<bool> s_render_upside_down{};
|
||||
inline static std::optional<bool> s_fullscreen{};
|
||||
|
||||
inline static bool s_verbose = false;
|
||||
|
||||
|
||||
inline static bool s_forward_console_logging = false;
|
||||
inline static std::optional<std::string> s_cos_argstr{};
|
||||
inline static std::unordered_map<fs::path, std::wstring> s_cos_mounts{};
|
||||
|
||||
inline static bool s_enable_gdbstub = false;
|
||||
inline static bool s_nsight_mode = false;
|
||||
|
||||
@ -59,5 +69,3 @@ private:
|
||||
|
||||
static bool ExtractorTool(std::wstring_view wud_path, std::string_view output_path, std::wstring_view log_path);
|
||||
};
|
||||
|
||||
|
||||
|
||||
@ -34,6 +34,7 @@
|
||||
|
||||
#include "Cafe/TitleList/TitleList.h"
|
||||
#include "Cafe/TitleList/SaveList.h"
|
||||
#include "Cafe/CafeSystem.h"
|
||||
|
||||
wxIMPLEMENT_APP_NO_MAIN(CemuApp);
|
||||
|
||||
@ -414,17 +415,19 @@ int CemuApp::OnExit()
|
||||
m_sdlEventPumpTimer = nullptr;
|
||||
}
|
||||
#endif
|
||||
|
||||
wxApp::OnExit();
|
||||
wxTheClipboard->Flush();
|
||||
InputManager::instance().Shutdown();
|
||||
int retValue = 0;
|
||||
if (auto r = CafeSystem::GetForegroundTitleReturnStatus(); (LaunchSettings::GetLoadFile() || LaunchSettings::GetLoadTitleID()) && r)
|
||||
retValue = *r;
|
||||
#if BOOST_OS_MACOS
|
||||
SDLControllerProvider::ShutdownSDL();
|
||||
#endif
|
||||
#if BOOST_OS_WINDOWS
|
||||
ExitProcess(0);
|
||||
ExitProcess(retValue);
|
||||
#else
|
||||
_Exit(0);
|
||||
_Exit(retValue);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
@ -162,6 +162,7 @@ wxDEFINE_EVENT(wxEVT_SET_WINDOW_TITLE, wxCommandEvent);
|
||||
wxDEFINE_EVENT(wxEVT_REQUEST_GAMELIST_REFRESH, wxCommandEvent);
|
||||
wxDEFINE_EVENT(wxEVT_LAUNCH_GAME, wxLaunchGameEvent);
|
||||
wxDEFINE_EVENT(wxEVT_REQUEST_RECREATE_CANVAS, wxCommandEvent);
|
||||
wxDEFINE_EVENT(wxEVT_REQUEST_GAME_EXIT, wxCommandEvent);
|
||||
|
||||
wxBEGIN_EVENT_TABLE(MainWindow, wxFrame)
|
||||
EVT_TIMER(MAINFRAME_ID_TIMER1, MainWindow::OnTimer)
|
||||
@ -243,6 +244,7 @@ EVT_COMMAND(wxID_ANY, wxEVT_ACCOUNTLIST_REFRESH, MainWindow::OnAccountListRefres
|
||||
EVT_COMMAND(wxID_ANY, wxEVT_SET_WINDOW_TITLE, MainWindow::OnSetWindowTitle)
|
||||
|
||||
EVT_COMMAND(wxID_ANY, wxEVT_REQUEST_RECREATE_CANVAS, MainWindow::OnRequestRecreateCanvas)
|
||||
EVT_COMMAND(wxID_ANY, wxEVT_REQUEST_GAME_EXIT, MainWindow::OnRequestGameExit)
|
||||
|
||||
wxEND_EVENT_TABLE()
|
||||
|
||||
@ -548,8 +550,7 @@ bool MainWindow::FileLoad(const fs::path launchPath, wxLaunchGameEvent::INITIATE
|
||||
wxMessageBox(t, _("Error"), wxOK | wxCENTRE | wxICON_ERROR);
|
||||
return false;
|
||||
}
|
||||
else if (initiatedBy == wxLaunchGameEvent::INITIATED_BY::MENU ||
|
||||
initiatedBy == wxLaunchGameEvent::INITIATED_BY::COMMAND_LINE)
|
||||
else
|
||||
{
|
||||
wxString t = _("Unable to launch game\nPath:\n");
|
||||
t.append(_pathToUtf8(launchPath));
|
||||
@ -566,13 +567,6 @@ bool MainWindow::FileLoad(const fs::path launchPath, wxLaunchGameEvent::INITIATE
|
||||
wxMessageBox(t, _("Error"), wxOK | wxCENTRE | wxICON_ERROR);
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
wxString t = _("Unable to launch game\nPath:\n");
|
||||
t.append(_pathToUtf8(launchPath));
|
||||
wxMessageBox(t, _("Error"), wxOK | wxCENTRE | wxICON_ERROR);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if(launchTitle.IsValid())
|
||||
@ -2483,6 +2477,27 @@ void MainWindow::CafeRecreateCanvas()
|
||||
sem.decrementWithWait();
|
||||
}
|
||||
|
||||
void MainWindow::CafePPCProcessExit()
|
||||
{
|
||||
// this is called from the emulated PPC thread, so queue an event instead of handling it directly
|
||||
wxQueueEvent(g_mainFrame, new wxCommandEvent(wxEVT_REQUEST_GAME_EXIT));
|
||||
}
|
||||
|
||||
void MainWindow::OnRequestGameExit(wxCommandEvent& event)
|
||||
{
|
||||
// if the title was launched via the command line we close Cemu and use the foreground title's exit status as Cemu's process return code (via CemuApp:OnExit)
|
||||
// this is useful for homebrew testing setups that use Cemu via CLI
|
||||
// otherwise the title was launched from the game list, so we just stop it and return to the game list instead of closing Cemu
|
||||
if (LaunchSettings::GetLoadFile() || LaunchSettings::GetLoadTitleID())
|
||||
{
|
||||
Close();
|
||||
}
|
||||
else
|
||||
{
|
||||
EndEmulation();
|
||||
}
|
||||
}
|
||||
|
||||
bool MainWindow::FullscreenEnabled() const
|
||||
{
|
||||
return LaunchSettings::FullscreenEnabled().value_or(GetWxGUIConfig().fullscreen);
|
||||
|
||||
@ -157,8 +157,10 @@ private:
|
||||
|
||||
// CafeSystem implementation
|
||||
void CafeRecreateCanvas() override;
|
||||
void CafePPCProcessExit() override;
|
||||
|
||||
void OnRequestRecreateCanvas(wxCommandEvent& event);
|
||||
void OnRequestGameExit(wxCommandEvent& event);
|
||||
|
||||
wxRect GetDesktopRect();
|
||||
|
||||
|
||||
Loading…
Reference in New Issue
Block a user