summaryrefslogtreecommitdiffstats
path: root/src/yuzu/main.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/yuzu/main.cpp')
-rw-r--r--src/yuzu/main.cpp151
1 files changed, 113 insertions, 38 deletions
diff --git a/src/yuzu/main.cpp b/src/yuzu/main.cpp
index cd32623b4..8304c6517 100644
--- a/src/yuzu/main.cpp
+++ b/src/yuzu/main.cpp
@@ -6,6 +6,9 @@
#include <clocale>
#include <memory>
#include <thread>
+#ifdef __APPLE__
+#include <unistd.h> // for chdir
+#endif
// VFS includes must be before glad as they will conflict with Windows file api, which uses defines.
#include "applets/error.h"
@@ -100,7 +103,7 @@ static FileSys::VirtualFile VfsDirectoryCreateFileWrapper(const FileSys::Virtual
#include "yuzu/hotkeys.h"
#include "yuzu/loading_screen.h"
#include "yuzu/main.h"
-#include "yuzu/ui_settings.h"
+#include "yuzu/uisettings.h"
#ifdef USE_DISCORD_PRESENCE
#include "yuzu/discord_impl.h"
@@ -119,6 +122,7 @@ Q_IMPORT_PLUGIN(QWindowsIntegrationPlugin);
#endif
#ifdef _WIN32
+#include <windows.h>
extern "C" {
// tells Nvidia and AMD drivers to use the dedicated GPU by default on laptops with switchable
// graphics
@@ -215,8 +219,7 @@ GMainWindow::GMainWindow()
OnReinitializeKeys(ReinitializeKeyBehavior::NoWarning);
game_list->LoadCompatibilityList();
- game_list->PopulateAsync(UISettings::values.game_directory_path,
- UISettings::values.game_directory_deepscan);
+ game_list->PopulateAsync(UISettings::values.game_dirs);
// Show one-time "callout" messages to the user
ShowTelemetryCallout();
@@ -426,6 +429,10 @@ void GMainWindow::InitializeWidgets() {
game_list = new GameList(vfs, provider.get(), this);
ui.horizontalLayout->addWidget(game_list);
+ game_list_placeholder = new GameListPlaceholder(this);
+ ui.horizontalLayout->addWidget(game_list_placeholder);
+ game_list_placeholder->setVisible(false);
+
loading_screen = new LoadingScreen(this);
loading_screen->hide();
ui.horizontalLayout->addWidget(loading_screen);
@@ -659,6 +666,7 @@ void GMainWindow::RestoreUIState() {
void GMainWindow::ConnectWidgetEvents() {
connect(game_list, &GameList::GameChosen, this, &GMainWindow::OnGameListLoadFile);
+ connect(game_list, &GameList::OpenDirectory, this, &GMainWindow::OnGameListOpenDirectory);
connect(game_list, &GameList::OpenFolderRequested, this, &GMainWindow::OnGameListOpenFolder);
connect(game_list, &GameList::OpenTransferableShaderCacheRequested, this,
&GMainWindow::OnTransferableShaderCacheOpenFile);
@@ -666,6 +674,11 @@ void GMainWindow::ConnectWidgetEvents() {
connect(game_list, &GameList::CopyTIDRequested, this, &GMainWindow::OnGameListCopyTID);
connect(game_list, &GameList::NavigateToGamedbEntryRequested, this,
&GMainWindow::OnGameListNavigateToGamedbEntry);
+ connect(game_list, &GameList::AddDirectory, this, &GMainWindow::OnGameListAddDirectory);
+ connect(game_list_placeholder, &GameListPlaceholder::AddDirectory, this,
+ &GMainWindow::OnGameListAddDirectory);
+ connect(game_list, &GameList::ShowList, this, &GMainWindow::OnGameListShowList);
+
connect(game_list, &GameList::OpenPerGameGeneralRequested, this,
&GMainWindow::OnGameListOpenPerGameProperties);
@@ -683,8 +696,6 @@ void GMainWindow::ConnectMenuEvents() {
connect(ui.action_Load_Folder, &QAction::triggered, this, &GMainWindow::OnMenuLoadFolder);
connect(ui.action_Install_File_NAND, &QAction::triggered, this,
&GMainWindow::OnMenuInstallToNAND);
- connect(ui.action_Select_Game_List_Root, &QAction::triggered, this,
- &GMainWindow::OnMenuSelectGameListRoot);
connect(ui.action_Select_NAND_Directory, &QAction::triggered, this,
[this] { OnMenuSelectEmulatedDirectory(EmulatedDirectoryTarget::NAND); });
connect(ui.action_Select_SDMC_Directory, &QAction::triggered, this,
@@ -747,9 +758,24 @@ void GMainWindow::OnDisplayTitleBars(bool show) {
}
}
+void GMainWindow::PreventOSSleep() {
+#ifdef _WIN32
+ SetThreadExecutionState(ES_CONTINUOUS | ES_SYSTEM_REQUIRED | ES_DISPLAY_REQUIRED);
+#endif
+}
+
+void GMainWindow::AllowOSSleep() {
+#ifdef _WIN32
+ SetThreadExecutionState(ES_CONTINUOUS);
+#endif
+}
+
QStringList GMainWindow::GetUnsupportedGLExtensions() {
QStringList unsupported_ext;
+ if (!GLAD_GL_ARB_buffer_storage) {
+ unsupported_ext.append(QStringLiteral("ARB_buffer_storage"));
+ }
if (!GLAD_GL_ARB_direct_state_access) {
unsupported_ext.append(QStringLiteral("ARB_direct_state_access"));
}
@@ -814,11 +840,13 @@ bool GMainWindow::LoadROM(const QString& filename) {
system.SetGPUDebugContext(debug_context);
system.SetAppletFrontendSet({
- std::make_unique<QtErrorDisplay>(*this),
- nullptr,
- std::make_unique<QtProfileSelector>(*this),
- std::make_unique<QtSoftwareKeyboard>(*this),
- std::make_unique<QtWebBrowser>(*this),
+ nullptr, // Parental Controls
+ std::make_unique<QtErrorDisplay>(*this), //
+ nullptr, // Photo Viewer
+ std::make_unique<QtProfileSelector>(*this), //
+ std::make_unique<QtSoftwareKeyboard>(*this), //
+ std::make_unique<QtWebBrowser>(*this), //
+ nullptr, // E-Commerce
});
const Core::System::ResultStatus result{system.Load(*render_window, filename.toStdString())};
@@ -932,6 +960,7 @@ void GMainWindow::BootGame(const QString& filename) {
// Update the GUI
if (ui.action_Single_Window_Mode->isChecked()) {
game_list->hide();
+ game_list_placeholder->hide();
}
status_bar_update_timer.start(2000);
@@ -961,6 +990,8 @@ void GMainWindow::BootGame(const QString& filename) {
}
void GMainWindow::ShutdownGame() {
+ AllowOSSleep();
+
discord_rpc->Pause();
emu_thread->RequestStop();
@@ -987,7 +1018,10 @@ void GMainWindow::ShutdownGame() {
render_window->hide();
loading_screen->hide();
loading_screen->Clear();
- game_list->show();
+ if (game_list->isEmpty())
+ game_list_placeholder->show();
+ else
+ game_list->show();
game_list->setFilterFocus();
UpdateWindowTitle();
@@ -1278,6 +1312,47 @@ void GMainWindow::OnGameListNavigateToGamedbEntry(u64 program_id,
QDesktopServices::openUrl(QUrl(QStringLiteral("https://yuzu-emu.org/game/") + directory));
}
+void GMainWindow::OnGameListOpenDirectory(const QString& directory) {
+ QString path;
+ if (directory == QStringLiteral("SDMC")) {
+ path = QString::fromStdString(FileUtil::GetUserPath(FileUtil::UserPath::SDMCDir) +
+ "Nintendo/Contents/registered");
+ } else if (directory == QStringLiteral("UserNAND")) {
+ path = QString::fromStdString(FileUtil::GetUserPath(FileUtil::UserPath::NANDDir) +
+ "user/Contents/registered");
+ } else if (directory == QStringLiteral("SysNAND")) {
+ path = QString::fromStdString(FileUtil::GetUserPath(FileUtil::UserPath::NANDDir) +
+ "system/Contents/registered");
+ } else {
+ path = directory;
+ }
+ if (!QFileInfo::exists(path)) {
+ QMessageBox::critical(this, tr("Error Opening %1").arg(path), tr("Folder does not exist!"));
+ return;
+ }
+ QDesktopServices::openUrl(QUrl::fromLocalFile(path));
+}
+
+void GMainWindow::OnGameListAddDirectory() {
+ const QString dir_path = QFileDialog::getExistingDirectory(this, tr("Select Directory"));
+ if (dir_path.isEmpty())
+ return;
+ UISettings::GameDir game_dir{dir_path, false, true};
+ if (!UISettings::values.game_dirs.contains(game_dir)) {
+ UISettings::values.game_dirs.append(game_dir);
+ game_list->PopulateAsync(UISettings::values.game_dirs);
+ } else {
+ LOG_WARNING(Frontend, "Selected directory is already in the game list");
+ }
+}
+
+void GMainWindow::OnGameListShowList(bool show) {
+ if (emulation_running && ui.action_Single_Window_Mode->isChecked())
+ return;
+ game_list->setVisible(show);
+ game_list_placeholder->setVisible(!show);
+};
+
void GMainWindow::OnGameListOpenPerGameProperties(const std::string& file) {
u64 title_id{};
const auto v_file = Core::GetGameFileFromPath(vfs, file);
@@ -1296,8 +1371,7 @@ void GMainWindow::OnGameListOpenPerGameProperties(const std::string& file) {
const auto reload = UISettings::values.is_game_list_reload_pending.exchange(false);
if (reload) {
- game_list->PopulateAsync(UISettings::values.game_directory_path,
- UISettings::values.game_directory_deepscan);
+ game_list->PopulateAsync(UISettings::values.game_dirs);
}
config->Save();
@@ -1387,8 +1461,7 @@ void GMainWindow::OnMenuInstallToNAND() {
const auto success = [this]() {
QMessageBox::information(this, tr("Successfully Installed"),
tr("The file was successfully installed."));
- game_list->PopulateAsync(UISettings::values.game_directory_path,
- UISettings::values.game_directory_deepscan);
+ game_list->PopulateAsync(UISettings::values.game_dirs);
FileUtil::DeleteDirRecursively(FileUtil::GetUserPath(FileUtil::UserPath::CacheDir) +
DIR_SEP + "game_list");
};
@@ -1513,14 +1586,6 @@ void GMainWindow::OnMenuInstallToNAND() {
}
}
-void GMainWindow::OnMenuSelectGameListRoot() {
- QString dir_path = QFileDialog::getExistingDirectory(this, tr("Select Directory"));
- if (!dir_path.isEmpty()) {
- UISettings::values.game_directory_path = dir_path;
- game_list->PopulateAsync(dir_path, UISettings::values.game_directory_deepscan);
- }
-}
-
void GMainWindow::OnMenuSelectEmulatedDirectory(EmulatedDirectoryTarget target) {
const auto res = QMessageBox::information(
this, tr("Changing Emulated Directory"),
@@ -1539,8 +1604,7 @@ void GMainWindow::OnMenuSelectEmulatedDirectory(EmulatedDirectoryTarget target)
: FileUtil::UserPath::NANDDir,
dir_path.toStdString());
Service::FileSystem::CreateFactories(*vfs);
- game_list->PopulateAsync(UISettings::values.game_directory_path,
- UISettings::values.game_directory_deepscan);
+ game_list->PopulateAsync(UISettings::values.game_dirs);
}
}
@@ -1562,6 +1626,8 @@ void GMainWindow::OnMenuRecentFile() {
}
void GMainWindow::OnStartGame() {
+ PreventOSSleep();
+
emu_thread->SetRunning(true);
qRegisterMetaType<Core::Frontend::SoftwareKeyboardParameters>(
@@ -1593,6 +1659,8 @@ void GMainWindow::OnPauseGame() {
ui.action_Pause->setEnabled(false);
ui.action_Stop->setEnabled(true);
ui.action_Capture_Screenshot->setEnabled(false);
+
+ AllowOSSleep();
}
void GMainWindow::OnStopGame() {
@@ -1700,11 +1768,11 @@ void GMainWindow::OnConfigure() {
if (UISettings::values.enable_discord_presence != old_discord_presence) {
SetDiscordEnabled(UISettings::values.enable_discord_presence);
}
+ emit UpdateThemedIcons();
const auto reload = UISettings::values.is_game_list_reload_pending.exchange(false);
if (reload) {
- game_list->PopulateAsync(UISettings::values.game_directory_path,
- UISettings::values.game_directory_deepscan);
+ game_list->PopulateAsync(UISettings::values.game_dirs);
}
config->Save();
@@ -1838,13 +1906,14 @@ void GMainWindow::OnCoreError(Core::System::ResultStatus result, std::string det
"data, or other bugs.");
switch (result) {
case Core::System::ResultStatus::ErrorSystemFiles: {
- QString message = tr("yuzu was unable to locate a Switch system archive");
- if (!details.empty()) {
- message.append(tr(": %1. ").arg(QString::fromStdString(details)));
+ QString message;
+ if (details.empty()) {
+ message =
+ tr("yuzu was unable to locate a Switch system archive. %1").arg(common_message);
} else {
- message.append(tr(". "));
+ message = tr("yuzu was unable to locate a Switch system archive: %1. %2")
+ .arg(QString::fromStdString(details), common_message);
}
- message.append(common_message);
answer = QMessageBox::question(this, tr("System Archive Not Found"), message,
QMessageBox::Yes | QMessageBox::No, QMessageBox::No);
@@ -1853,8 +1922,8 @@ void GMainWindow::OnCoreError(Core::System::ResultStatus result, std::string det
}
case Core::System::ResultStatus::ErrorSharedFont: {
- QString message = tr("yuzu was unable to locate the Switch shared fonts. ");
- message.append(common_message);
+ const QString message =
+ tr("yuzu was unable to locate the Switch shared fonts. %1").arg(common_message);
answer = QMessageBox::question(this, tr("Shared Fonts Not Found"), message,
QMessageBox::Yes | QMessageBox::No, QMessageBox::No);
status_message = tr("Shared Font Missing");
@@ -1944,7 +2013,7 @@ void GMainWindow::OnReinitializeKeys(ReinitializeKeyBehavior behavior) {
errors +
tr("<br><br>You can get all of these and dump all of your games easily by "
"following <a href='https://yuzu-emu.org/help/quickstart/'>the "
- "quickstart guide</a>. Alternatively, you can use another method of dumping"
+ "quickstart guide</a>. Alternatively, you can use another method of dumping "
"to obtain all of your keys."));
}
@@ -1967,8 +2036,7 @@ void GMainWindow::OnReinitializeKeys(ReinitializeKeyBehavior behavior) {
Service::FileSystem::CreateFactories(*vfs);
if (behavior == ReinitializeKeyBehavior::Warning) {
- game_list->PopulateAsync(UISettings::values.game_directory_path,
- UISettings::values.game_directory_deepscan);
+ game_list->PopulateAsync(UISettings::values.game_dirs);
}
}
@@ -2133,7 +2201,6 @@ void GMainWindow::UpdateUITheme() {
}
QIcon::setThemeSearchPaths(theme_paths);
- emit UpdateThemedIcons();
}
void GMainWindow::SetDiscordEnabled([[maybe_unused]] bool state) {
@@ -2162,6 +2229,14 @@ int main(int argc, char* argv[]) {
QCoreApplication::setOrganizationName(QStringLiteral("yuzu team"));
QCoreApplication::setApplicationName(QStringLiteral("yuzu"));
+#ifdef __APPLE__
+ // If you start a bundle (binary) on OSX without the Terminal, the working directory is "/".
+ // But since we require the working directory to be the executable path for the location of the
+ // user folder in the Qt Frontend, we need to cd into that working directory
+ const std::string bin_path = FileUtil::GetBundleDirectory() + DIR_SEP + "..";
+ chdir(bin_path.c_str());
+#endif
+
// Enables the core to make the qt created contexts current on std::threads
QCoreApplication::setAttribute(Qt::AA_DontCheckOpenGLContextThreadAffinity);
QApplication app(argc, argv);