diff --git a/src/xenia/app/emulator_window.h b/src/xenia/app/emulator_window.h index 54ddae867..fa8db88b3 100644 --- a/src/xenia/app/emulator_window.h +++ b/src/xenia/app/emulator_window.h @@ -35,11 +35,12 @@ class EmulatorWindow { ui::Loop* loop() const { return loop_.get(); } ui::Window* window() const { return window_.get(); } + void UpdateTitle(); + private: explicit EmulatorWindow(Emulator* emulator); bool Initialize(); - void UpdateTitle(); void CpuTimeScalarReset(); void CpuTimeScalarSetHalf(); diff --git a/src/xenia/app/xenia_main.cc b/src/xenia/app/xenia_main.cc index 865d28cf3..ab4934666 100644 --- a/src/xenia/app/xenia_main.cc +++ b/src/xenia/app/xenia_main.cc @@ -195,7 +195,8 @@ int xenia_main(const std::vector& args) { // Normalize the path and make absolute. std::wstring abs_path = xe::to_absolute_path(path); - result = emulator->LaunchPath(abs_path); + result = emulator->LaunchPath(abs_path, + [&]() { emulator_window->UpdateTitle(); }); if (XFAILED(result)) { XELOGE("Failed to launch target: %.8X", result); emulator.reset(); diff --git a/src/xenia/cpu/xex_module.cc b/src/xenia/cpu/xex_module.cc index 860b204b5..da3d79773 100644 --- a/src/xenia/cpu/xex_module.cc +++ b/src/xenia/cpu/xex_module.cc @@ -465,8 +465,8 @@ bool XexModule::SetupLibraryImports(const char* name, GuestFunction::ExternHandler handler = nullptr; if (kernel_export) { if (kernel_export->function_data.trampoline) { - handler = (GuestFunction::ExternHandler)kernel_export - ->function_data.trampoline; + handler = (GuestFunction::ExternHandler) + kernel_export->function_data.trampoline; } else { handler = (GuestFunction::ExternHandler)kernel_export->function_data.shim; diff --git a/src/xenia/emulator.cc b/src/xenia/emulator.cc index ca36a53bf..f2182f62f 100644 --- a/src/xenia/emulator.cc +++ b/src/xenia/emulator.cc @@ -192,7 +192,8 @@ X_STATUS Emulator::Setup( return result; } -X_STATUS Emulator::LaunchPath(std::wstring path) { +X_STATUS Emulator::LaunchPath(std::wstring path, + std::function on_launch) { // Launch based on file type. // This is a silly guess based on file extension. auto last_slash = path.find_last_of(xe::kPathSeparator); @@ -202,18 +203,19 @@ X_STATUS Emulator::LaunchPath(std::wstring path) { } if (last_dot == std::wstring::npos) { // Likely an STFS container. - return LaunchStfsContainer(path); + return LaunchStfsContainer(path, on_launch); } else if (path.substr(last_dot) == L".xex" || path.substr(last_dot) == L".elf") { // Treat as a naked xex file. - return LaunchXexFile(path); + return LaunchXexFile(path, on_launch); } else { // Assume a disc image. - return LaunchDiscImage(path); + return LaunchDiscImage(path, on_launch); } } -X_STATUS Emulator::LaunchXexFile(std::wstring path) { +X_STATUS Emulator::LaunchXexFile(std::wstring path, + std::function on_launch) { // We create a virtual filesystem pointing to its directory and symlink // that to the game filesystem. // e.g., /my/files/foo.xex will get a local fs at: @@ -245,10 +247,11 @@ X_STATUS Emulator::LaunchXexFile(std::wstring path) { // Launch the game. std::string fs_path = "game:\\" + xe::to_string(file_name); - return CompleteLaunch(path, fs_path); + return CompleteLaunch(path, fs_path, on_launch); } -X_STATUS Emulator::LaunchDiscImage(std::wstring path) { +X_STATUS Emulator::LaunchDiscImage(std::wstring path, + std::function on_launch) { auto mount_path = "\\Device\\Cdrom0"; // Register the disc image in the virtual filesystem. @@ -267,10 +270,11 @@ X_STATUS Emulator::LaunchDiscImage(std::wstring path) { file_system_->RegisterSymbolicLink("d:", mount_path); // Launch the game. - return CompleteLaunch(path, "game:\\default.xex"); + return CompleteLaunch(path, "game:\\default.xex", on_launch); } -X_STATUS Emulator::LaunchStfsContainer(std::wstring path) { +X_STATUS Emulator::LaunchStfsContainer(std::wstring path, + std::function on_launch) { auto mount_path = "\\Device\\Cdrom0"; // Register the container in the virtual filesystem. @@ -289,7 +293,7 @@ X_STATUS Emulator::LaunchStfsContainer(std::wstring path) { file_system_->RegisterSymbolicLink("d:", mount_path); // Launch the game. - return CompleteLaunch(path, "game:\\default.xex"); + return CompleteLaunch(path, "game:\\default.xex", on_launch); } void Emulator::Pause() { @@ -494,8 +498,9 @@ void Emulator::WaitUntilExit() { } } -X_STATUS Emulator::CompleteLaunch(const std::wstring& path, - const std::string& module_path) { +X_STATUS Emulator::CompleteLaunch(const std::wstring &path, + const std::string &module_path, + std::function on_launch) { // Allow xam to request module loads. auto xam = kernel_state()->GetKernelModule("xam.xex"); @@ -510,10 +515,6 @@ X_STATUS Emulator::CompleteLaunch(const std::wstring& path, } kernel_state_->SetExecutableModule(module); - auto main_xthread = module->Launch(); - if (!main_xthread) { - return X_STATUS_UNSUCCESSFUL; - } // Try and load the resource database (xex only) char title[9] = {0}; @@ -526,15 +527,7 @@ X_STATUS Emulator::CompleteLaunch(const std::wstring& path, if (xdb_ptr != nullptr) { xe::xdbf::XdbfWrapper db; if (db.initialize(xdb_ptr, static_cast(resource_size))) { - - std::string game_title(xe::xdbf::get_title(db)); - if (!game_title.empty()) { - game_title_ = xe::to_wstring(game_title); - // TODO(x1nixmzeng): Need to somehow callback to - // EmulatorWindow::UpdateTitle - display_window_->set_title(game_title_ + L" - " + - display_window_->title()); - } + game_title_ = xe::to_wstring(xe::xdbf::get_title(db)); xe::xdbf::XdbfBlock icon_block = xe::xdbf::get_icon(db); if (icon_block.buffer != nullptr) { display_window_->SetIconFromBuffer(icon_block.buffer, @@ -544,6 +537,12 @@ X_STATUS Emulator::CompleteLaunch(const std::wstring& path, } } + auto main_xthread = module->Launch(); + if (!main_xthread) { + return X_STATUS_UNSUCCESSFUL; + } + + on_launch(); main_thread_ = main_xthread->thread(); WaitUntilExit(); diff --git a/src/xenia/emulator.h b/src/xenia/emulator.h index 72a943371..23a71561f 100644 --- a/src/xenia/emulator.h +++ b/src/xenia/emulator.h @@ -54,7 +54,7 @@ class Emulator { const std::wstring& command_line() const { return command_line_; } // Title of the game in the default language. - const std::wstring &game_title() const { return game_title_; } + const std::wstring& game_title() const { return game_title_; } // Window used for displaying graphical output. ui::Window* display_window() const { return display_window_; } @@ -109,17 +109,18 @@ class Emulator { // Launches a game from the given file path. // This will attempt to infer the type of the given file (such as an iso, etc) // using heuristics. - X_STATUS LaunchPath(std::wstring path); + X_STATUS LaunchPath(std::wstring path, std::function on_launch); // Launches a game from a .xex file by mounting the containing folder as if it // was an extracted STFS container. - X_STATUS LaunchXexFile(std::wstring path); + X_STATUS LaunchXexFile(std::wstring path, std::function on_launch); // Launches a game from a disc image file (.iso, etc). - X_STATUS LaunchDiscImage(std::wstring path); + X_STATUS LaunchDiscImage(std::wstring path, std::function on_launch); // Launches a game from an STFS container file. - X_STATUS LaunchStfsContainer(std::wstring path); + X_STATUS LaunchStfsContainer(std::wstring path, + std::function on_launch); void Pause(); void Resume(); @@ -134,8 +135,9 @@ class Emulator { static bool ExceptionCallbackThunk(Exception* ex, void* data); bool ExceptionCallback(Exception* ex); - X_STATUS CompleteLaunch(const std::wstring& path, - const std::string& module_path); + X_STATUS CompleteLaunch(const std::wstring &path, + const std::string &module_path, + std::function on_launch); std::wstring command_line_; std::wstring game_title_; diff --git a/src/xenia/kernel/kernel_module.cc b/src/xenia/kernel/kernel_module.cc index befa08d33..fdad0256f 100644 --- a/src/xenia/kernel/kernel_module.cc +++ b/src/xenia/kernel/kernel_module.cc @@ -105,8 +105,8 @@ uint32_t KernelModule::GetProcAddressByOrdinal(uint16_t ordinal) { cpu::GuestFunction::ExternHandler handler = nullptr; if (export_entry->function_data.trampoline) { - handler = (cpu::GuestFunction::ExternHandler)export_entry - ->function_data.trampoline; + handler = (cpu::GuestFunction::ExternHandler) + export_entry->function_data.trampoline; } else { handler = (cpu::GuestFunction::ExternHandler)export_entry->function_data.shim; diff --git a/src/xenia/ui/window.h b/src/xenia/ui/window.h index ee6cd9ac9..d894d9276 100644 --- a/src/xenia/ui/window.h +++ b/src/xenia/ui/window.h @@ -53,7 +53,7 @@ class Window { return true; } - virtual bool SetIconFromBuffer(void *buffer, size_t size) = 0; + virtual bool SetIconFromBuffer(void* buffer, size_t size) = 0; virtual bool is_fullscreen() const { return false; } virtual void ToggleFullscreen(bool fullscreen) {} diff --git a/src/xenia/ui/window_win.cc b/src/xenia/ui/window_win.cc index 9a03b5a3c..d3c6224b7 100644 --- a/src/xenia/ui/window_win.cc +++ b/src/xenia/ui/window_win.cc @@ -167,7 +167,7 @@ bool Win32Window::set_title(const std::wstring& title) { return true; } -bool Win32Window::SetIconFromBuffer(void *buffer, size_t size) { +bool Win32Window::SetIconFromBuffer(void* buffer, size_t size) { if (icon_ != nullptr) { DestroyIcon(icon_); } diff --git a/src/xenia/ui/window_win.h b/src/xenia/ui/window_win.h index 36cc38b95..296baba45 100644 --- a/src/xenia/ui/window_win.h +++ b/src/xenia/ui/window_win.h @@ -31,7 +31,7 @@ class Win32Window : public Window { HWND hwnd() const { return hwnd_; } bool set_title(const std::wstring& title) override; - bool SetIconFromBuffer(void *buffer, size_t size) override; + bool SetIconFromBuffer(void* buffer, size_t size) override; bool is_fullscreen() const override; void ToggleFullscreen(bool fullscreen) override; diff --git a/src/xenia/xdbf/xdbf_utils.cc b/src/xenia/xdbf/xdbf_utils.cc index 100a57926..e60a88d80 100644 --- a/src/xenia/xdbf/xdbf_utils.cc +++ b/src/xenia/xdbf/xdbf_utils.cc @@ -84,14 +84,14 @@ XdbfBlock XdbfWrapper::get_entry(XdbfSection section, uint64_t id) const { return block; } -XdbfBlock get_icon(const XdbfWrapper &ref) { +XdbfBlock get_icon(const XdbfWrapper& ref) { return ref.get_entry(kSectionImage, kIdTitle); } -XdbfLocale get_default_language(const XdbfWrapper &ref) { +XdbfLocale get_default_language(const XdbfWrapper& ref) { XdbfBlock block = ref.get_entry(kSectionMetadata, kIdXSTC); if (block.buffer != nullptr) { - XDBF_XSTC *xstc = reinterpret_cast(block.buffer); + XDBF_XSTC* xstc = reinterpret_cast(block.buffer); assert_true(xstc->magic == kMagicXSTC); uint32_t default_language = xstc->default_language; @@ -101,7 +101,7 @@ XdbfLocale get_default_language(const XdbfWrapper &ref) { return kLocaleEnglish; } -std::string get_title(const XdbfWrapper &ref) { +std::string get_title(const XdbfWrapper& ref) { std::string title_str; uint64_t language_id = static_cast(get_default_language(ref)); @@ -109,19 +109,19 @@ std::string get_title(const XdbfWrapper &ref) { XdbfBlock lang_block = ref.get_entry(kSectionStringTable, language_id); if (lang_block.buffer != nullptr) { - XDBF_XSTR_HEADER *xstr_head = - reinterpret_cast(lang_block.buffer); + XDBF_XSTR_HEADER* xstr_head = + reinterpret_cast(lang_block.buffer); assert_true(xstr_head->magic == kMagicXSTR); assert_true(xstr_head->version == 1); uint16_t str_count = xstr_head->string_count; - uint8_t *currentAddress = lang_block.buffer + sizeof(XDBF_XSTR_HEADER); + uint8_t* currentAddress = lang_block.buffer + sizeof(XDBF_XSTR_HEADER); uint16_t s = 0; while (s < str_count && title_str.empty()) { - XDBF_STRINGTABLE_ENTRY *entry = - reinterpret_cast(currentAddress); + XDBF_STRINGTABLE_ENTRY* entry = + reinterpret_cast(currentAddress); currentAddress += sizeof(XDBF_STRINGTABLE_ENTRY); uint16_t len = entry->string_length; diff --git a/src/xenia/xdbf/xdbf_utils.h b/src/xenia/xdbf/xdbf_utils.h index be6db4541..4431eeda1 100644 --- a/src/xenia/xdbf/xdbf_utils.h +++ b/src/xenia/xdbf/xdbf_utils.h @@ -119,9 +119,9 @@ class XdbfWrapper { XdbfState state_; }; -XdbfBlock get_icon(const XdbfWrapper &ref); -XdbfLocale get_default_language(const XdbfWrapper &ref); -std::string get_title(const XdbfWrapper &ref); +XdbfBlock get_icon(const XdbfWrapper& ref); +XdbfLocale get_default_language(const XdbfWrapper& ref); +std::string get_title(const XdbfWrapper& ref); } // namespace xdbf } // namespace xe