diff options
Diffstat (limited to 'src/yuzu/main.cpp')
-rw-r--r-- | src/yuzu/main.cpp | 265 |
1 files changed, 145 insertions, 120 deletions
diff --git a/src/yuzu/main.cpp b/src/yuzu/main.cpp index 920789f6f..44ca3db8b 100644 --- a/src/yuzu/main.cpp +++ b/src/yuzu/main.cpp @@ -28,8 +28,6 @@ #include "core/hle/service/am/applet_ae.h" #include "core/hle/service/am/applet_oe.h" #include "core/hle/service/am/applets/applets.h" -#include "core/hle/service/hid/controllers/npad.h" -#include "core/hle/service/hid/hid.h" // These are wrappers to avoid the calls to CreateDirectory and CreateFile because of the Windows // defines. @@ -125,14 +123,6 @@ static FileSys::VirtualFile VfsDirectoryCreateFileWrapper(const FileSys::Virtual #include "yuzu/discord_impl.h" #endif -#ifdef YUZU_USE_QT_WEB_ENGINE -#include <QWebEngineProfile> -#include <QWebEngineScript> -#include <QWebEngineScriptCollection> -#include <QWebEngineSettings> -#include <QWebEngineView> -#endif - #ifdef QT_STATICPLUGIN Q_IMPORT_PLUGIN(QWindowsIntegrationPlugin); #endif @@ -190,6 +180,30 @@ static void InitializeLogging() { #endif } +static void RemoveCachedContents() { + const auto offline_fonts = Common::FS::SanitizePath( + fmt::format("{}/fonts", Common::FS::GetUserPath(Common::FS::UserPath::CacheDir)), + Common::FS::DirectorySeparator::PlatformDefault); + + const auto offline_manual = Common::FS::SanitizePath( + fmt::format("{}/offline_web_applet_manual", + Common::FS::GetUserPath(Common::FS::UserPath::CacheDir)), + Common::FS::DirectorySeparator::PlatformDefault); + const auto offline_legal_information = Common::FS::SanitizePath( + fmt::format("{}/offline_web_applet_legal_information", + Common::FS::GetUserPath(Common::FS::UserPath::CacheDir)), + Common::FS::DirectorySeparator::PlatformDefault); + const auto offline_system_data = Common::FS::SanitizePath( + fmt::format("{}/offline_web_applet_system_data", + Common::FS::GetUserPath(Common::FS::UserPath::CacheDir)), + Common::FS::DirectorySeparator::PlatformDefault); + + Common::FS::DeleteDirRecursively(offline_fonts); + Common::FS::DeleteDirRecursively(offline_manual); + Common::FS::DeleteDirRecursively(offline_legal_information); + Common::FS::DeleteDirRecursively(offline_system_data); +} + GMainWindow::GMainWindow() : input_subsystem{std::make_shared<InputCommon::InputSubsystem>()}, config{std::make_unique<Config>()}, vfs{std::make_shared<FileSys::RealVfsFilesystem>()}, @@ -258,6 +272,9 @@ GMainWindow::GMainWindow() FileSys::ContentProviderUnionSlot::FrontendManual, provider.get()); Core::System::GetInstance().GetFileSystemController().CreateFactories(*vfs); + // Remove cached contents generated during the previous session + RemoveCachedContents(); + // Gen keys if necessary OnReinitializeKeys(ReinitializeKeyBehavior::NoWarning); @@ -349,150 +366,141 @@ void GMainWindow::SoftwareKeyboardInvokeCheckDialog(std::u16string error_message emit SoftwareKeyboardFinishedCheckDialog(); } +void GMainWindow::WebBrowserOpenWebPage(std::string_view main_url, std::string_view additional_args, + bool is_local) { #ifdef YUZU_USE_QT_WEB_ENGINE -void GMainWindow::WebBrowserOpenPage(std::string_view filename, std::string_view additional_args) { - NXInputWebEngineView web_browser_view(this); + if (disable_web_applet) { + emit WebBrowserClosed(Service::AM::Applets::WebExitReason::WindowClosed, + "http://localhost/"); + return; + } - // Scope to contain the QProgressDialog for initialization - { - QProgressDialog progress(this); - progress.setMinimumDuration(200); - progress.setLabelText(tr("Loading Web Applet...")); - progress.setRange(0, 4); - progress.setValue(0); - progress.show(); + QtNXWebEngineView web_browser_view(this, Core::System::GetInstance(), input_subsystem.get()); + + ui.action_Pause->setEnabled(false); + ui.action_Restart->setEnabled(false); + ui.action_Stop->setEnabled(false); - auto future = QtConcurrent::run([this] { emit WebBrowserUnpackRomFS(); }); + { + QProgressDialog loading_progress(this); + loading_progress.setLabelText(tr("Loading Web Applet...")); + loading_progress.setRange(0, 3); + loading_progress.setValue(0); - while (!future.isFinished()) - QApplication::processEvents(); + if (is_local && !Common::FS::Exists(std::string(main_url))) { + loading_progress.show(); - progress.setValue(1); + auto future = QtConcurrent::run([this] { emit WebBrowserExtractOfflineRomFS(); }); - // Load the special shim script to handle input and exit. - QWebEngineScript nx_shim; - nx_shim.setSourceCode(GetNXShimInjectionScript()); - nx_shim.setWorldId(QWebEngineScript::MainWorld); - nx_shim.setName(QStringLiteral("nx_inject.js")); - nx_shim.setInjectionPoint(QWebEngineScript::DocumentCreation); - nx_shim.setRunsOnSubFrames(true); - web_browser_view.page()->profile()->scripts()->insert(nx_shim); + while (!future.isFinished()) { + QCoreApplication::processEvents(); + } + } - web_browser_view.load( - QUrl(QUrl::fromLocalFile(QString::fromStdString(std::string(filename))).toString() + - QString::fromStdString(std::string(additional_args)))); + loading_progress.setValue(1); - progress.setValue(2); + if (is_local) { + web_browser_view.LoadLocalWebPage(main_url, additional_args); + } else { + web_browser_view.LoadExternalWebPage(main_url, additional_args); + } - render_window->hide(); - web_browser_view.setFocus(); + if (render_window->IsLoadingComplete()) { + render_window->hide(); + } const auto& layout = render_window->GetFramebufferLayout(); web_browser_view.resize(layout.screen.GetWidth(), layout.screen.GetHeight()); web_browser_view.move(layout.screen.left, layout.screen.top + menuBar()->height()); web_browser_view.setZoomFactor(static_cast<qreal>(layout.screen.GetWidth()) / - Layout::ScreenUndocked::Width); - web_browser_view.settings()->setAttribute( - QWebEngineSettings::LocalContentCanAccessRemoteUrls, true); + static_cast<qreal>(Layout::ScreenUndocked::Width)); + web_browser_view.setFocus(); web_browser_view.show(); - progress.setValue(3); + loading_progress.setValue(2); - QApplication::processEvents(); + QCoreApplication::processEvents(); - progress.setValue(4); + loading_progress.setValue(3); } - bool finished = false; - QAction* exit_action = new QAction(tr("Exit Web Applet"), this); - connect(exit_action, &QAction::triggered, this, [&finished] { finished = true; }); - ui.menubar->addAction(exit_action); + bool exit_check = false; - auto& npad = - Core::System::GetInstance() - .ServiceManager() - .GetService<Service::HID::Hid>("hid") - ->GetAppletResource() - ->GetController<Service::HID::Controller_NPad>(Service::HID::HidController::NPad); - - const auto fire_js_keypress = [&web_browser_view](u32 key_code) { - web_browser_view.page()->runJavaScript( - QStringLiteral("document.dispatchEvent(new KeyboardEvent('keydown', {'key': %1}));") - .arg(key_code)); - }; + // TODO (Morph): Remove this + QAction* exit_action = new QAction(tr("Disable Web Applet"), this); + connect(exit_action, &QAction::triggered, this, [this, &web_browser_view] { + const auto result = QMessageBox::warning( + this, tr("Disable Web Applet"), + tr("Disabling the web applet will cause it to not be shown again for the rest of the " + "emulated session. This can lead to undefined behavior and should only be used with " + "Super Mario 3D All-Stars. Are you sure you want to disable the web applet?"), + QMessageBox::Yes | QMessageBox::No); + if (result == QMessageBox::Yes) { + disable_web_applet = true; + web_browser_view.SetFinished(true); + } + }); + ui.menubar->addAction(exit_action); - QMessageBox::information( - this, tr("Exit"), - tr("To exit the web application, use the game provided controls to select exit, select the " - "'Exit Web Applet' option in the menu bar, or press the 'Enter' key.")); - - bool running_exit_check = false; - while (!finished) { - QApplication::processEvents(); - - if (!running_exit_check) { - web_browser_view.page()->runJavaScript(QStringLiteral("applet_done;"), - [&](const QVariant& res) { - running_exit_check = false; - if (res.toBool()) - finished = true; - }); - running_exit_check = true; + while (!web_browser_view.IsFinished()) { + QCoreApplication::processEvents(); + + if (!exit_check) { + web_browser_view.page()->runJavaScript( + QStringLiteral("end_applet;"), [&](const QVariant& variant) { + exit_check = false; + if (variant.toBool()) { + web_browser_view.SetFinished(true); + web_browser_view.SetExitReason( + Service::AM::Applets::WebExitReason::EndButtonPressed); + } + }); + + exit_check = true; } - const auto input = npad.GetAndResetPressState(); - for (std::size_t i = 0; i < Settings::NativeButton::NumButtons; ++i) { - if ((input & (1 << i)) != 0) { - LOG_DEBUG(Frontend, "firing input for button id={:02X}", i); - web_browser_view.page()->runJavaScript( - QStringLiteral("yuzu_key_callbacks[%1]();").arg(i)); + if (web_browser_view.GetCurrentURL().contains(QStringLiteral("localhost"))) { + if (!web_browser_view.IsFinished()) { + web_browser_view.SetFinished(true); + web_browser_view.SetExitReason(Service::AM::Applets::WebExitReason::CallbackURL); } + + web_browser_view.SetLastURL(web_browser_view.GetCurrentURL().toStdString()); } - if (input & 0x00888000) // RStick Down | LStick Down | DPad Down - fire_js_keypress(40); // Down Arrow Key - else if (input & 0x00444000) // RStick Right | LStick Right | DPad Right - fire_js_keypress(39); // Right Arrow Key - else if (input & 0x00222000) // RStick Up | LStick Up | DPad Up - fire_js_keypress(38); // Up Arrow Key - else if (input & 0x00111000) // RStick Left | LStick Left | DPad Left - fire_js_keypress(37); // Left Arrow Key - else if (input & 0x00000001) // A Button - fire_js_keypress(13); // Enter Key + std::this_thread::sleep_for(std::chrono::milliseconds(1)); } + const auto exit_reason = web_browser_view.GetExitReason(); + const auto last_url = web_browser_view.GetLastURL(); + web_browser_view.hide(); - render_window->show(); + render_window->setFocus(); - ui.menubar->removeAction(exit_action); - // Needed to update render window focus/show and remove menubar action - QApplication::processEvents(); - emit WebBrowserFinishedBrowsing(); -} + if (render_window->IsLoadingComplete()) { + render_window->show(); + } -#else + ui.action_Pause->setEnabled(true); + ui.action_Restart->setEnabled(true); + ui.action_Stop->setEnabled(true); -void GMainWindow::WebBrowserOpenPage(std::string_view filename, std::string_view additional_args) { -#ifndef __linux__ - QMessageBox::warning( - this, tr("Web Applet"), - tr("This version of yuzu was built without QtWebEngine support, meaning that yuzu cannot " - "properly display the game manual or web page requested."), - QMessageBox::Ok, QMessageBox::Ok); -#endif + ui.menubar->removeAction(exit_action); - LOG_INFO(Frontend, - "(STUBBED) called - Missing QtWebEngine dependency needed to open website page at " - "'{}' with arguments '{}'!", - filename, additional_args); + QCoreApplication::processEvents(); - emit WebBrowserFinishedBrowsing(); -} + emit WebBrowserClosed(exit_reason, last_url); + +#else + + // Utilize the same fallback as the default web browser applet. + emit WebBrowserClosed(Service::AM::Applets::WebExitReason::WindowClosed, "http://localhost/"); #endif +} void GMainWindow::InitializeWidgets() { #ifdef YUZU_ENABLE_COMPATIBILITY_REPORTING @@ -669,7 +677,7 @@ void GMainWindow::InitializeRecentFileMenuActions() { } ui.menu_recent_files->addSeparator(); QAction* action_clear_recent_files = new QAction(this); - action_clear_recent_files->setText(tr("Clear Recent Files")); + action_clear_recent_files->setText(tr("&Clear Recent Files")); connect(action_clear_recent_files, &QAction::triggered, this, [this] { UISettings::values.recent_files.clear(); UpdateRecentFiles(); @@ -931,7 +939,10 @@ void GMainWindow::ConnectMenuEvents() { &GMainWindow::OnDisplayTitleBars); connect(ui.action_Show_Filter_Bar, &QAction::triggered, this, &GMainWindow::OnToggleFilterBar); connect(ui.action_Show_Status_Bar, &QAction::triggered, statusBar(), &QStatusBar::setVisible); - connect(ui.action_Reset_Window_Size, &QAction::triggered, this, &GMainWindow::ResetWindowSize); + connect(ui.action_Reset_Window_Size_720, &QAction::triggered, this, + &GMainWindow::ResetWindowSize720); + connect(ui.action_Reset_Window_Size_1080, &QAction::triggered, this, + &GMainWindow::ResetWindowSize1080); // Fullscreen connect(ui.action_Fullscreen, &QAction::triggered, this, &GMainWindow::ToggleFullscreen); @@ -993,7 +1004,6 @@ bool GMainWindow::LoadROM(const QString& filename, std::size_t program_index) { system.SetAppletFrontendSet({ std::make_unique<QtControllerSelector>(*this), // Controller Selector - nullptr, // E-Commerce std::make_unique<QtErrorDisplay>(*this), // Error Display nullptr, // Parental Controls nullptr, // Photo Viewer @@ -2107,11 +2117,12 @@ void GMainWindow::OnStartGame() { qRegisterMetaType<std::string>("std::string"); qRegisterMetaType<std::optional<std::u16string>>("std::optional<std::u16string>"); qRegisterMetaType<std::string_view>("std::string_view"); + qRegisterMetaType<Service::AM::Applets::WebExitReason>("Service::AM::Applets::WebExitReason"); connect(emu_thread.get(), &EmuThread::ErrorThrown, this, &GMainWindow::OnCoreError); ui.action_Start->setEnabled(false); - ui.action_Start->setText(tr("Continue")); + ui.action_Start->setText(tr("&Continue")); ui.action_Pause->setEnabled(true); ui.action_Stop->setEnabled(true); @@ -2255,7 +2266,7 @@ void GMainWindow::ToggleWindowMode() { } } -void GMainWindow::ResetWindowSize() { +void GMainWindow::ResetWindowSize720() { const auto aspect_ratio = Layout::EmulationAspectRatio( static_cast<Layout::AspectRatio>(Settings::values.aspect_ratio.GetValue()), static_cast<float>(Layout::ScreenUndocked::Height) / Layout::ScreenUndocked::Width); @@ -2269,6 +2280,20 @@ void GMainWindow::ResetWindowSize() { } } +void GMainWindow::ResetWindowSize1080() { + const auto aspect_ratio = Layout::EmulationAspectRatio( + static_cast<Layout::AspectRatio>(Settings::values.aspect_ratio.GetValue()), + static_cast<float>(Layout::ScreenDocked::Height) / Layout::ScreenDocked::Width); + if (!ui.action_Single_Window_Mode->isChecked()) { + render_window->resize(Layout::ScreenDocked::Height / aspect_ratio, + Layout::ScreenDocked::Height); + } else { + resize(Layout::ScreenDocked::Height / aspect_ratio, + Layout::ScreenDocked::Height + menuBar()->height() + + (ui.action_Show_Status_Bar->isChecked() ? statusBar()->height() : 0)); + } +} + void GMainWindow::OnConfigure() { const auto old_theme = UISettings::values.theme; const bool old_discord_presence = UISettings::values.enable_discord_presence; @@ -2953,7 +2978,7 @@ void GMainWindow::OnLanguageChanged(const QString& locale) { UpdateWindowTitle(); if (emulation_running) - ui.action_Start->setText(tr("Continue")); + ui.action_Start->setText(tr("&Continue")); } void GMainWindow::SetDiscordEnabled([[maybe_unused]] bool state) { |