summaryrefslogtreecommitdiff
path: root/src/yuzu
diff options
context:
space:
mode:
Diffstat (limited to 'src/yuzu')
-rw-r--r--src/yuzu/CMakeLists.txt7
-rw-r--r--src/yuzu/configuration/config.cpp21
-rw-r--r--src/yuzu/configuration/config.h2
-rw-r--r--src/yuzu/configuration/configure.ui11
-rw-r--r--src/yuzu/configuration/configure_dialog.cpp5
-rw-r--r--src/yuzu/configuration/configure_general.cpp1
-rw-r--r--src/yuzu/configuration/configure_service.cpp136
-rw-r--r--src/yuzu/configuration/configure_service.h34
-rw-r--r--src/yuzu/configuration/configure_service.ui124
-rw-r--r--src/yuzu/main.cpp43
-rw-r--r--src/yuzu/main.h2
-rw-r--r--src/yuzu/uisettings.cpp2
-rw-r--r--src/yuzu/uisettings.h2
13 files changed, 387 insertions, 3 deletions
diff --git a/src/yuzu/CMakeLists.txt b/src/yuzu/CMakeLists.txt
index dc6fa07fc..ff1c1d985 100644
--- a/src/yuzu/CMakeLists.txt
+++ b/src/yuzu/CMakeLists.txt
@@ -66,6 +66,9 @@ add_executable(yuzu
configuration/configure_profile_manager.cpp
configuration/configure_profile_manager.h
configuration/configure_profile_manager.ui
+ configuration/configure_service.cpp
+ configuration/configure_service.h
+ configuration/configure_service.ui
configuration/configure_system.cpp
configuration/configure_system.h
configuration/configure_system.ui
@@ -186,6 +189,10 @@ if (YUZU_USE_QT_WEB_ENGINE)
target_compile_definitions(yuzu PRIVATE -DYUZU_USE_QT_WEB_ENGINE)
endif ()
+if (YUZU_ENABLE_BOXCAT)
+ target_compile_definitions(yuzu PRIVATE -DYUZU_ENABLE_BOXCAT)
+endif ()
+
if(UNIX AND NOT APPLE)
install(TARGETS yuzu RUNTIME DESTINATION "${CMAKE_INSTALL_PREFIX}/bin")
endif()
diff --git a/src/yuzu/configuration/config.cpp b/src/yuzu/configuration/config.cpp
index 92d9fb161..4cb27ddb2 100644
--- a/src/yuzu/configuration/config.cpp
+++ b/src/yuzu/configuration/config.cpp
@@ -525,6 +525,17 @@ void Config::ReadDebuggingValues() {
qt_config->endGroup();
}
+void Config::ReadServiceValues() {
+ qt_config->beginGroup(QStringLiteral("Services"));
+ Settings::values.bcat_backend =
+ ReadSetting(QStringLiteral("bcat_backend"), QStringLiteral("boxcat"))
+ .toString()
+ .toStdString();
+ Settings::values.bcat_boxcat_local =
+ ReadSetting(QStringLiteral("bcat_boxcat_local"), false).toBool();
+ qt_config->endGroup();
+}
+
void Config::ReadDisabledAddOnValues() {
const auto size = qt_config->beginReadArray(QStringLiteral("DisabledAddOns"));
@@ -769,6 +780,7 @@ void Config::ReadValues() {
ReadMiscellaneousValues();
ReadDebuggingValues();
ReadWebServiceValues();
+ ReadServiceValues();
ReadDisabledAddOnValues();
ReadUIValues();
}
@@ -866,6 +878,7 @@ void Config::SaveValues() {
SaveMiscellaneousValues();
SaveDebuggingValues();
SaveWebServiceValues();
+ SaveServiceValues();
SaveDisabledAddOnValues();
SaveUIValues();
}
@@ -963,6 +976,14 @@ void Config::SaveDebuggingValues() {
qt_config->endGroup();
}
+void Config::SaveServiceValues() {
+ qt_config->beginGroup(QStringLiteral("Services"));
+ WriteSetting(QStringLiteral("bcat_backend"),
+ QString::fromStdString(Settings::values.bcat_backend), QStringLiteral("null"));
+ WriteSetting(QStringLiteral("bcat_boxcat_local"), Settings::values.bcat_boxcat_local, false);
+ qt_config->endGroup();
+}
+
void Config::SaveDisabledAddOnValues() {
qt_config->beginWriteArray(QStringLiteral("DisabledAddOns"));
diff --git a/src/yuzu/configuration/config.h b/src/yuzu/configuration/config.h
index 6b523ecdd..ba6888004 100644
--- a/src/yuzu/configuration/config.h
+++ b/src/yuzu/configuration/config.h
@@ -42,6 +42,7 @@ private:
void ReadCoreValues();
void ReadDataStorageValues();
void ReadDebuggingValues();
+ void ReadServiceValues();
void ReadDisabledAddOnValues();
void ReadMiscellaneousValues();
void ReadPathValues();
@@ -65,6 +66,7 @@ private:
void SaveCoreValues();
void SaveDataStorageValues();
void SaveDebuggingValues();
+ void SaveServiceValues();
void SaveDisabledAddOnValues();
void SaveMiscellaneousValues();
void SavePathValues();
diff --git a/src/yuzu/configuration/configure.ui b/src/yuzu/configuration/configure.ui
index 49fadd0ef..372427ae2 100644
--- a/src/yuzu/configuration/configure.ui
+++ b/src/yuzu/configuration/configure.ui
@@ -98,6 +98,11 @@
<string>Web</string>
</attribute>
</widget>
+ <widget class="ConfigureService" name="serviceTab">
+ <attribute name="title">
+ <string>Services</string>
+ </attribute>
+ </widget>
</widget>
</item>
</layout>
@@ -178,6 +183,12 @@
<header>configuration/configure_hotkeys.h</header>
<container>1</container>
</customwidget>
+ <customwidget>
+ <class>ConfigureService</class>
+ <extends>QWidget</extends>
+ <header>configuration/configure_service.h</header>
+ <container>1</container>
+ </customwidget>
</customwidgets>
<resources/>
<connections>
diff --git a/src/yuzu/configuration/configure_dialog.cpp b/src/yuzu/configuration/configure_dialog.cpp
index 7c875ae87..25b2e1b05 100644
--- a/src/yuzu/configuration/configure_dialog.cpp
+++ b/src/yuzu/configuration/configure_dialog.cpp
@@ -44,6 +44,7 @@ void ConfigureDialog::ApplyConfiguration() {
ui->audioTab->ApplyConfiguration();
ui->debugTab->ApplyConfiguration();
ui->webTab->ApplyConfiguration();
+ ui->serviceTab->ApplyConfiguration();
Settings::Apply();
Settings::LogSettings();
}
@@ -74,7 +75,8 @@ Q_DECLARE_METATYPE(QList<QWidget*>);
void ConfigureDialog::PopulateSelectionList() {
const std::array<std::pair<QString, QList<QWidget*>>, 4> items{
{{tr("General"), {ui->generalTab, ui->webTab, ui->debugTab, ui->gameListTab}},
- {tr("System"), {ui->systemTab, ui->profileManagerTab, ui->filesystemTab, ui->audioTab}},
+ {tr("System"),
+ {ui->systemTab, ui->profileManagerTab, ui->serviceTab, ui->filesystemTab, ui->audioTab}},
{tr("Graphics"), {ui->graphicsTab}},
{tr("Controls"), {ui->inputTab, ui->hotkeysTab}}},
};
@@ -108,6 +110,7 @@ void ConfigureDialog::UpdateVisibleTabs() {
{ui->webTab, tr("Web")},
{ui->gameListTab, tr("Game List")},
{ui->filesystemTab, tr("Filesystem")},
+ {ui->serviceTab, tr("Services")},
};
[[maybe_unused]] const QSignalBlocker blocker(ui->tabWidget);
diff --git a/src/yuzu/configuration/configure_general.cpp b/src/yuzu/configuration/configure_general.cpp
index b49446be9..98bc9b391 100644
--- a/src/yuzu/configuration/configure_general.cpp
+++ b/src/yuzu/configuration/configure_general.cpp
@@ -2,6 +2,7 @@
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
+#include <QCheckBox>
#include <QSpinBox>
#include "core/core.h"
#include "core/settings.h"
diff --git a/src/yuzu/configuration/configure_service.cpp b/src/yuzu/configuration/configure_service.cpp
new file mode 100644
index 000000000..81c9e933f
--- /dev/null
+++ b/src/yuzu/configuration/configure_service.cpp
@@ -0,0 +1,136 @@
+// Copyright 2019 yuzu Emulator Project
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#include <QGraphicsItem>
+#include <QtConcurrent/QtConcurrent>
+#include "core/hle/service/bcat/backend/boxcat.h"
+#include "core/settings.h"
+#include "ui_configure_service.h"
+#include "yuzu/configuration/configure_service.h"
+
+namespace {
+QString FormatEventStatusString(const Service::BCAT::EventStatus& status) {
+ QString out;
+
+ if (status.header.has_value()) {
+ out += QStringLiteral("<i>%1</i><br>").arg(QString::fromStdString(*status.header));
+ }
+
+ if (status.events.size() == 1) {
+ out += QStringLiteral("%1<br>").arg(QString::fromStdString(status.events.front()));
+ } else {
+ for (const auto& event : status.events) {
+ out += QStringLiteral("- %1<br>").arg(QString::fromStdString(event));
+ }
+ }
+
+ if (status.footer.has_value()) {
+ out += QStringLiteral("<i>%1</i><br>").arg(QString::fromStdString(*status.footer));
+ }
+
+ return out;
+}
+} // Anonymous namespace
+
+ConfigureService::ConfigureService(QWidget* parent)
+ : QWidget(parent), ui(std::make_unique<Ui::ConfigureService>()) {
+ ui->setupUi(this);
+
+ ui->bcat_source->addItem(QStringLiteral("None"));
+ ui->bcat_empty_label->setHidden(true);
+ ui->bcat_empty_header->setHidden(true);
+
+#ifdef YUZU_ENABLE_BOXCAT
+ ui->bcat_source->addItem(QStringLiteral("Boxcat"), QStringLiteral("boxcat"));
+#endif
+
+ connect(ui->bcat_source, QOverload<int>::of(&QComboBox::currentIndexChanged), this,
+ &ConfigureService::OnBCATImplChanged);
+
+ this->SetConfiguration();
+}
+
+ConfigureService::~ConfigureService() = default;
+
+void ConfigureService::ApplyConfiguration() {
+ Settings::values.bcat_backend = ui->bcat_source->currentText().toLower().toStdString();
+}
+
+void ConfigureService::RetranslateUi() {
+ ui->retranslateUi(this);
+}
+
+void ConfigureService::SetConfiguration() {
+ const int index =
+ ui->bcat_source->findData(QString::fromStdString(Settings::values.bcat_backend));
+ ui->bcat_source->setCurrentIndex(index == -1 ? 0 : index);
+}
+
+std::pair<QString, QString> ConfigureService::BCATDownloadEvents() {
+ std::optional<std::string> global;
+ std::map<std::string, Service::BCAT::EventStatus> map;
+ const auto res = Service::BCAT::Boxcat::GetStatus(global, map);
+
+ switch (res) {
+ case Service::BCAT::Boxcat::StatusResult::Offline:
+ return {QString{},
+ tr("The boxcat service is offline or you are not connected to the internet.")};
+ case Service::BCAT::Boxcat::StatusResult::ParseError:
+ return {QString{},
+ tr("There was an error while processing the boxcat event data. Contact the yuzu "
+ "developers.")};
+ case Service::BCAT::Boxcat::StatusResult::BadClientVersion:
+ return {QString{},
+ tr("The version of yuzu you are using is either too new or too old for the server. "
+ "Try updating to the latest official release of yuzu.")};
+ }
+
+ if (map.empty()) {
+ return {QStringLiteral("Current Boxcat Events"),
+ tr("There are currently no events on boxcat.")};
+ }
+
+ QString out;
+
+ if (global.has_value()) {
+ out += QStringLiteral("%1<br>").arg(QString::fromStdString(*global));
+ }
+
+ for (const auto& [key, value] : map) {
+ out += QStringLiteral("%1<b>%2</b><br>%3")
+ .arg(out.isEmpty() ? QString{} : QStringLiteral("<br>"))
+ .arg(QString::fromStdString(key))
+ .arg(FormatEventStatusString(value));
+ }
+ return {QStringLiteral("Current Boxcat Events"), std::move(out)};
+}
+
+void ConfigureService::OnBCATImplChanged() {
+#ifdef YUZU_ENABLE_BOXCAT
+ const auto boxcat = ui->bcat_source->currentText() == QStringLiteral("Boxcat");
+ ui->bcat_empty_header->setHidden(!boxcat);
+ ui->bcat_empty_label->setHidden(!boxcat);
+ ui->bcat_empty_header->setText(QString{});
+ ui->bcat_empty_label->setText(tr("Yuzu is retrieving the latest boxcat status..."));
+
+ if (!boxcat)
+ return;
+
+ const auto future = QtConcurrent::run([this] { return BCATDownloadEvents(); });
+
+ watcher.setFuture(future);
+ connect(&watcher, &QFutureWatcher<std::pair<QString, QString>>::finished, this,
+ [this] { OnUpdateBCATEmptyLabel(watcher.result()); });
+#endif
+}
+
+void ConfigureService::OnUpdateBCATEmptyLabel(std::pair<QString, QString> string) {
+#ifdef YUZU_ENABLE_BOXCAT
+ const auto boxcat = ui->bcat_source->currentText() == QStringLiteral("Boxcat");
+ if (boxcat) {
+ ui->bcat_empty_header->setText(string.first);
+ ui->bcat_empty_label->setText(string.second);
+ }
+#endif
+}
diff --git a/src/yuzu/configuration/configure_service.h b/src/yuzu/configuration/configure_service.h
new file mode 100644
index 000000000..f5c1b703a
--- /dev/null
+++ b/src/yuzu/configuration/configure_service.h
@@ -0,0 +1,34 @@
+// Copyright 2019 yuzu Emulator Project
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#pragma once
+
+#include <memory>
+#include <QFutureWatcher>
+#include <QWidget>
+
+namespace Ui {
+class ConfigureService;
+}
+
+class ConfigureService : public QWidget {
+ Q_OBJECT
+
+public:
+ explicit ConfigureService(QWidget* parent = nullptr);
+ ~ConfigureService() override;
+
+ void ApplyConfiguration();
+ void RetranslateUi();
+
+private:
+ void SetConfiguration();
+
+ std::pair<QString, QString> BCATDownloadEvents();
+ void OnBCATImplChanged();
+ void OnUpdateBCATEmptyLabel(std::pair<QString, QString> string);
+
+ std::unique_ptr<Ui::ConfigureService> ui;
+ QFutureWatcher<std::pair<QString, QString>> watcher{this};
+};
diff --git a/src/yuzu/configuration/configure_service.ui b/src/yuzu/configuration/configure_service.ui
new file mode 100644
index 000000000..9668dd557
--- /dev/null
+++ b/src/yuzu/configuration/configure_service.ui
@@ -0,0 +1,124 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>ConfigureService</class>
+ <widget class="QWidget" name="ConfigureService">
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>433</width>
+ <height>561</height>
+ </rect>
+ </property>
+ <property name="windowTitle">
+ <string>Form</string>
+ </property>
+ <layout class="QVBoxLayout" name="verticalLayout">
+ <item>
+ <layout class="QVBoxLayout" name="verticalLayout_3">
+ <item>
+ <widget class="QGroupBox" name="groupBox">
+ <property name="title">
+ <string>BCAT</string>
+ </property>
+ <layout class="QGridLayout" name="gridLayout">
+ <item row="1" column="1" colspan="2">
+ <widget class="QLabel" name="label_2">
+ <property name="maximumSize">
+ <size>
+ <width>260</width>
+ <height>16777215</height>
+ </size>
+ </property>
+ <property name="text">
+ <string>BCAT is Nintendo's way of sending data to games to engage its community and unlock additional content.</string>
+ </property>
+ <property name="wordWrap">
+ <bool>true</bool>
+ </property>
+ </widget>
+ </item>
+ <item row="0" column="0">
+ <widget class="QLabel" name="label">
+ <property name="maximumSize">
+ <size>
+ <width>16777215</width>
+ <height>16777215</height>
+ </size>
+ </property>
+ <property name="text">
+ <string>BCAT Backend</string>
+ </property>
+ </widget>
+ </item>
+ <item row="3" column="1" colspan="2">
+ <widget class="QLabel" name="bcat_empty_label">
+ <property name="enabled">
+ <bool>true</bool>
+ </property>
+ <property name="maximumSize">
+ <size>
+ <width>260</width>
+ <height>16777215</height>
+ </size>
+ </property>
+ <property name="text">
+ <string/>
+ </property>
+ <property name="alignment">
+ <set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop</set>
+ </property>
+ <property name="wordWrap">
+ <bool>true</bool>
+ </property>
+ </widget>
+ </item>
+ <item row="2" column="1" colspan="2">
+ <widget class="QLabel" name="label_3">
+ <property name="text">
+ <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;&lt;a href=&quot;https://yuzu-emu.org/help/feature/boxcat&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#0000ff;&quot;&gt;Learn more about BCAT, Boxcat, and Current Events&lt;/span&gt;&lt;/a&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
+ </property>
+ <property name="openExternalLinks">
+ <bool>true</bool>
+ </property>
+ </widget>
+ </item>
+ <item row="0" column="1" colspan="2">
+ <widget class="QComboBox" name="bcat_source"/>
+ </item>
+ <item row="3" column="0">
+ <widget class="QLabel" name="bcat_empty_header">
+ <property name="text">
+ <string/>
+ </property>
+ <property name="alignment">
+ <set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop</set>
+ </property>
+ <property name="wordWrap">
+ <bool>true</bool>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ <item>
+ <spacer name="verticalSpacer">
+ <property name="orientation">
+ <enum>Qt::Vertical</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>20</width>
+ <height>40</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ </layout>
+ </widget>
+ <resources/>
+ <connections/>
+</ui>
diff --git a/src/yuzu/main.cpp b/src/yuzu/main.cpp
index f147044d9..2d82df739 100644
--- a/src/yuzu/main.cpp
+++ b/src/yuzu/main.cpp
@@ -22,6 +22,8 @@
#include "core/frontend/applets/general_frontend.h"
#include "core/frontend/scope_acquire_window_context.h"
#include "core/hle/service/acc/profile_manager.h"
+#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"
@@ -83,6 +85,7 @@ static FileSys::VirtualFile VfsDirectoryCreateFileWrapper(const FileSys::Virtual
#include "core/file_sys/submission_package.h"
#include "core/frontend/applets/software_keyboard.h"
#include "core/hle/kernel/process.h"
+#include "core/hle/service/am/am.h"
#include "core/hle/service/filesystem/filesystem.h"
#include "core/hle/service/nfp/nfp.h"
#include "core/hle/service/sm/sm.h"
@@ -1674,6 +1677,11 @@ void GMainWindow::OnStartGame() {
}
void GMainWindow::OnPauseGame() {
+ Core::System& system{Core::System::GetInstance()};
+ if (system.GetExitLock() && !ConfirmForceLockedExit()) {
+ return;
+ }
+
emu_thread->SetRunning(false);
ui.action_Start->setEnabled(true);
@@ -1685,6 +1693,11 @@ void GMainWindow::OnPauseGame() {
}
void GMainWindow::OnStopGame() {
+ Core::System& system{Core::System::GetInstance()};
+ if (system.GetExitLock() && !ConfirmForceLockedExit()) {
+ return;
+ }
+
ShutdownGame();
}
@@ -2182,13 +2195,41 @@ bool GMainWindow::ConfirmChangeGame() {
if (emu_thread == nullptr)
return true;
- auto answer = QMessageBox::question(
+ const auto answer = QMessageBox::question(
this, tr("yuzu"),
tr("Are you sure you want to stop the emulation? Any unsaved progress will be lost."),
QMessageBox::Yes | QMessageBox::No, QMessageBox::No);
return answer != QMessageBox::No;
}
+bool GMainWindow::ConfirmForceLockedExit() {
+ if (emu_thread == nullptr)
+ return true;
+
+ const auto answer =
+ QMessageBox::question(this, tr("yuzu"),
+ tr("The currently running application has requested yuzu to not "
+ "exit.\n\nWould you like to bypass this and exit anyway?"),
+ QMessageBox::Yes | QMessageBox::No, QMessageBox::No);
+ return answer != QMessageBox::No;
+}
+
+void GMainWindow::RequestGameExit() {
+ auto& sm{Core::System::GetInstance().ServiceManager()};
+ auto applet_oe = sm.GetService<Service::AM::AppletOE>("appletOE");
+ auto applet_ae = sm.GetService<Service::AM::AppletAE>("appletAE");
+ bool has_signalled = false;
+
+ if (applet_oe != nullptr) {
+ applet_oe->GetMessageQueue()->RequestExit();
+ has_signalled = true;
+ }
+
+ if (applet_ae != nullptr && !has_signalled) {
+ applet_ae->GetMessageQueue()->RequestExit();
+ }
+}
+
void GMainWindow::filterBarSetChecked(bool state) {
ui.action_Show_Filter_Bar->setChecked(state);
emit(OnToggleFilterBar());
diff --git a/src/yuzu/main.h b/src/yuzu/main.h
index 7d16188cb..e942d1248 100644
--- a/src/yuzu/main.h
+++ b/src/yuzu/main.h
@@ -172,6 +172,8 @@ private:
*/
bool ConfirmClose();
bool ConfirmChangeGame();
+ bool ConfirmForceLockedExit();
+ void RequestGameExit();
void closeEvent(QCloseEvent* event) override;
private slots:
diff --git a/src/yuzu/uisettings.cpp b/src/yuzu/uisettings.cpp
index 7f7d247a3..43bad9678 100644
--- a/src/yuzu/uisettings.cpp
+++ b/src/yuzu/uisettings.cpp
@@ -9,6 +9,8 @@ namespace UISettings {
const Themes themes{{
{"Default", "default"},
{"Dark", "qdarkstyle"},
+ {"Colorful", "colorful"},
+ {"Colorful Dark", "colorful_dark"},
}};
Values values = {};
diff --git a/src/yuzu/uisettings.h b/src/yuzu/uisettings.h
index c57290006..a8eaf5f8c 100644
--- a/src/yuzu/uisettings.h
+++ b/src/yuzu/uisettings.h
@@ -24,7 +24,7 @@ struct Shortcut {
ContextualShortcut shortcut;
};
-using Themes = std::array<std::pair<const char*, const char*>, 2>;
+using Themes = std::array<std::pair<const char*, const char*>, 4>;
extern const Themes themes;
struct GameDir {