summaryrefslogtreecommitdiff
path: root/src/yuzu
diff options
context:
space:
mode:
Diffstat (limited to 'src/yuzu')
-rw-r--r--src/yuzu/CMakeLists.txt10
-rw-r--r--src/yuzu/applets/qt_controller.cpp1
-rw-r--r--src/yuzu/breakpad.cpp77
-rw-r--r--src/yuzu/breakpad.h10
-rw-r--r--src/yuzu/configuration/config.cpp3
-rw-r--r--src/yuzu/configuration/config.h2
-rw-r--r--src/yuzu/configuration/configure_audio.cpp10
-rw-r--r--src/yuzu/configuration/configure_camera.h2
-rw-r--r--src/yuzu/configuration/configure_debug.cpp18
-rw-r--r--src/yuzu/configuration/configure_debug.ui7
-rw-r--r--src/yuzu/configuration/configure_input.cpp2
-rw-r--r--src/yuzu/configuration/configure_input.h2
-rw-r--r--src/yuzu/configuration/configure_input_advanced.cpp8
-rw-r--r--src/yuzu/configuration/configure_input_advanced.h8
-rw-r--r--src/yuzu/configuration/configure_input_player.cpp36
-rw-r--r--src/yuzu/configuration/configure_input_player.h2
-rw-r--r--src/yuzu/configuration/configure_input_player.ui389
-rw-r--r--src/yuzu/configuration/configure_input_player_widget.cpp45
-rw-r--r--src/yuzu/configuration/configure_per_game.h2
-rw-r--r--src/yuzu/configuration/configure_profile_manager.cpp6
-rw-r--r--src/yuzu/configuration/configure_ringcon.h2
-rw-r--r--src/yuzu/configuration/configure_tas.h2
-rw-r--r--src/yuzu/configuration/configure_touchscreen_advanced.h2
-rw-r--r--src/yuzu/configuration/shared_translation.cpp1
-rw-r--r--src/yuzu/main.cpp99
-rw-r--r--src/yuzu/main.h25
-rw-r--r--src/yuzu/mini_dump.cpp202
-rw-r--r--src/yuzu/mini_dump.h19
-rw-r--r--src/yuzu/uisettings.h14
-rw-r--r--src/yuzu/vk_device_info.cpp1
30 files changed, 544 insertions, 463 deletions
diff --git a/src/yuzu/CMakeLists.txt b/src/yuzu/CMakeLists.txt
index 34208ed74..33e1fb663 100644
--- a/src/yuzu/CMakeLists.txt
+++ b/src/yuzu/CMakeLists.txt
@@ -227,14 +227,14 @@ add_executable(yuzu
yuzu.rc
)
-if (WIN32 AND YUZU_CRASH_DUMPS)
+if (YUZU_CRASH_DUMPS)
target_sources(yuzu PRIVATE
- mini_dump.cpp
- mini_dump.h
+ breakpad.cpp
+ breakpad.h
)
- target_link_libraries(yuzu PRIVATE ${DBGHELP_LIBRARY})
- target_compile_definitions(yuzu PRIVATE -DYUZU_DBGHELP)
+ target_link_libraries(yuzu PRIVATE libbreakpad_client)
+ target_compile_definitions(yuzu PRIVATE YUZU_CRASH_DUMPS)
endif()
if (CMAKE_CXX_COMPILER_ID STREQUAL "Clang")
diff --git a/src/yuzu/applets/qt_controller.cpp b/src/yuzu/applets/qt_controller.cpp
index 515cb7ce6..9e5319716 100644
--- a/src/yuzu/applets/qt_controller.cpp
+++ b/src/yuzu/applets/qt_controller.cpp
@@ -13,7 +13,6 @@
#include "core/hid/hid_core.h"
#include "core/hid/hid_types.h"
#include "core/hle/service/hid/controllers/npad.h"
-#include "core/hle/service/hid/hid.h"
#include "core/hle/service/sm/sm.h"
#include "ui_qt_controller.h"
#include "yuzu/applets/qt_controller.h"
diff --git a/src/yuzu/breakpad.cpp b/src/yuzu/breakpad.cpp
new file mode 100644
index 000000000..0f6a71ab0
--- /dev/null
+++ b/src/yuzu/breakpad.cpp
@@ -0,0 +1,77 @@
+// SPDX-FileCopyrightText: 2023 yuzu Emulator Project
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+#include <algorithm>
+#include <ranges>
+
+#if defined(_WIN32)
+#include <client/windows/handler/exception_handler.h>
+#elif defined(__linux__)
+#include <client/linux/handler/exception_handler.h>
+#else
+#error Minidump creation not supported on this platform
+#endif
+
+#include "common/fs/fs_paths.h"
+#include "common/fs/path_util.h"
+#include "yuzu/breakpad.h"
+
+namespace Breakpad {
+
+static void PruneDumpDirectory(const std::filesystem::path& dump_path) {
+ // Code in this function should be exception-safe.
+ struct Entry {
+ std::filesystem::path path;
+ std::filesystem::file_time_type last_write_time;
+ };
+ std::vector<Entry> existing_dumps;
+
+ // Get existing entries.
+ std::error_code ec;
+ std::filesystem::directory_iterator dir(dump_path, ec);
+ for (auto& entry : dir) {
+ if (entry.is_regular_file()) {
+ existing_dumps.push_back(Entry{
+ .path = entry.path(),
+ .last_write_time = entry.last_write_time(ec),
+ });
+ }
+ }
+
+ // Sort descending by creation date.
+ std::ranges::stable_sort(existing_dumps, [](const auto& a, const auto& b) {
+ return a.last_write_time > b.last_write_time;
+ });
+
+ // Delete older dumps.
+ for (size_t i = 5; i < existing_dumps.size(); i++) {
+ std::filesystem::remove(existing_dumps[i].path, ec);
+ }
+}
+
+#if defined(__linux__)
+[[noreturn]] bool DumpCallback(const google_breakpad::MinidumpDescriptor& descriptor, void* context,
+ bool succeeded) {
+ // Prevent time- and space-consuming core dumps from being generated, as we have
+ // already generated a minidump and a core file will not be useful anyway.
+ _exit(1);
+}
+#endif
+
+void InstallCrashHandler() {
+ // Write crash dumps to profile directory.
+ const auto dump_path = GetYuzuPath(Common::FS::YuzuPath::CrashDumpsDir);
+ PruneDumpDirectory(dump_path);
+
+#if defined(_WIN32)
+ // TODO: If we switch to MinGW builds for Windows, this needs to be wrapped in a C API.
+ static google_breakpad::ExceptionHandler eh{dump_path, nullptr, nullptr, nullptr,
+ google_breakpad::ExceptionHandler::HANDLER_ALL};
+#elif defined(__linux__)
+ static google_breakpad::MinidumpDescriptor descriptor{dump_path};
+ static google_breakpad::ExceptionHandler eh{descriptor, nullptr, DumpCallback,
+ nullptr, true, -1};
+#endif
+}
+
+} // namespace Breakpad
diff --git a/src/yuzu/breakpad.h b/src/yuzu/breakpad.h
new file mode 100644
index 000000000..0f911aa9c
--- /dev/null
+++ b/src/yuzu/breakpad.h
@@ -0,0 +1,10 @@
+// SPDX-FileCopyrightText: 2023 yuzu Emulator Project
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+#pragma once
+
+namespace Breakpad {
+
+void InstallCrashHandler();
+
+}
diff --git a/src/yuzu/configuration/config.cpp b/src/yuzu/configuration/config.cpp
index baa3e55f3..c0ae6468b 100644
--- a/src/yuzu/configuration/config.cpp
+++ b/src/yuzu/configuration/config.cpp
@@ -35,6 +35,7 @@ const std::array<int, Settings::NativeButton::NumButtons> Config::default_button
Qt::Key_G, Qt::Key_Q, Qt::Key_E, Qt::Key_R, Qt::Key_T,
Qt::Key_M, Qt::Key_N, Qt::Key_Left, Qt::Key_Up, Qt::Key_Right,
Qt::Key_Down, Qt::Key_Q, Qt::Key_E, 0, 0,
+ Qt::Key_Q, Qt::Key_E,
};
const std::array<int, Settings::NativeMotion::NumMotions> Config::default_motions = {
@@ -360,6 +361,7 @@ void Config::ReadAudioValues() {
qt_config->beginGroup(QStringLiteral("Audio"));
ReadCategory(Settings::Category::Audio);
+ ReadCategory(Settings::Category::UiAudio);
qt_config->endGroup();
}
@@ -900,6 +902,7 @@ void Config::SaveAudioValues() {
qt_config->beginGroup(QStringLiteral("Audio"));
WriteCategory(Settings::Category::Audio);
+ WriteCategory(Settings::Category::UiAudio);
qt_config->endGroup();
}
diff --git a/src/yuzu/configuration/config.h b/src/yuzu/configuration/config.h
index 74ec4f771..1589ba057 100644
--- a/src/yuzu/configuration/config.h
+++ b/src/yuzu/configuration/config.h
@@ -1,4 +1,4 @@
-// SPDX-FileCopyrightText: 2014 Citra Emulator Project
+// SPDX-FileCopyrightText: 2014 Citra Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#pragma once
diff --git a/src/yuzu/configuration/configure_audio.cpp b/src/yuzu/configuration/configure_audio.cpp
index 81dd51ad3..9b6ef47a7 100644
--- a/src/yuzu/configuration/configure_audio.cpp
+++ b/src/yuzu/configuration/configure_audio.cpp
@@ -38,17 +38,21 @@ void ConfigureAudio::Setup(const ConfigurationShared::Builder& builder) {
std::map<u32, QWidget*> hold;
- auto push = [&](Settings::Category category) {
+ auto push_settings = [&](Settings::Category category) {
for (auto* setting : Settings::values.linkage.by_category[category]) {
settings.push_back(setting);
}
+ };
+
+ auto push_ui_settings = [&](Settings::Category category) {
for (auto* setting : UISettings::values.linkage.by_category[category]) {
settings.push_back(setting);
}
};
- push(Settings::Category::Audio);
- push(Settings::Category::SystemAudio);
+ push_settings(Settings::Category::Audio);
+ push_settings(Settings::Category::SystemAudio);
+ push_ui_settings(Settings::Category::UiAudio);
for (auto* setting : settings) {
auto* widget = builder.BuildWidget(setting, apply_funcs);
diff --git a/src/yuzu/configuration/configure_camera.h b/src/yuzu/configuration/configure_camera.h
index 9a90512b3..3d822da7b 100644
--- a/src/yuzu/configuration/configure_camera.h
+++ b/src/yuzu/configuration/configure_camera.h
@@ -1,4 +1,4 @@
-// Text : Copyright 2022 yuzu Emulator Project
+// Text : Copyright 2022 yuzu Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
#pragma once
diff --git a/src/yuzu/configuration/configure_debug.cpp b/src/yuzu/configuration/configure_debug.cpp
index b22fda746..ef421c754 100644
--- a/src/yuzu/configuration/configure_debug.cpp
+++ b/src/yuzu/configuration/configure_debug.cpp
@@ -27,16 +27,6 @@ ConfigureDebug::ConfigureDebug(const Core::System& system_, QWidget* parent)
connect(ui->toggle_gdbstub, &QCheckBox::toggled,
[&]() { ui->gdbport_spinbox->setEnabled(ui->toggle_gdbstub->isChecked()); });
-
- connect(ui->create_crash_dumps, &QCheckBox::stateChanged, [&](int) {
- if (crash_dump_warning_shown) {
- return;
- }
- QMessageBox::warning(this, tr("Restart Required"),
- tr("yuzu is required to restart in order to apply this setting."),
- QMessageBox::Ok, QMessageBox::Ok);
- crash_dump_warning_shown = true;
- });
}
ConfigureDebug::~ConfigureDebug() = default;
@@ -89,13 +79,6 @@ void ConfigureDebug::SetConfiguration() {
ui->disable_web_applet->setEnabled(false);
ui->disable_web_applet->setText(tr("Web applet not compiled"));
#endif
-
-#ifdef YUZU_DBGHELP
- ui->create_crash_dumps->setChecked(Settings::values.create_crash_dumps.GetValue());
-#else
- ui->create_crash_dumps->setEnabled(false);
- ui->create_crash_dumps->setText(tr("MiniDump creation not compiled"));
-#endif
}
void ConfigureDebug::ApplyConfiguration() {
@@ -107,7 +90,6 @@ void ConfigureDebug::ApplyConfiguration() {
Settings::values.enable_fs_access_log = ui->fs_access_log->isChecked();
Settings::values.reporting_services = ui->reporting_services->isChecked();
Settings::values.dump_audio_commands = ui->dump_audio_commands->isChecked();
- Settings::values.create_crash_dumps = ui->create_crash_dumps->isChecked();
Settings::values.quest_flag = ui->quest_flag->isChecked();
Settings::values.use_debug_asserts = ui->use_debug_asserts->isChecked();
Settings::values.use_auto_stub = ui->use_auto_stub->isChecked();
diff --git a/src/yuzu/configuration/configure_debug.ui b/src/yuzu/configuration/configure_debug.ui
index 66b8b7459..76fe98924 100644
--- a/src/yuzu/configuration/configure_debug.ui
+++ b/src/yuzu/configuration/configure_debug.ui
@@ -471,13 +471,6 @@
</property>
</widget>
</item>
- <item row="4" column="0">
- <widget class="QCheckBox" name="create_crash_dumps">
- <property name="text">
- <string>Create Minidump After Crash</string>
- </property>
- </widget>
- </item>
<item row="3" column="0">
<widget class="QCheckBox" name="dump_audio_commands">
<property name="toolTip">
diff --git a/src/yuzu/configuration/configure_input.cpp b/src/yuzu/configuration/configure_input.cpp
index 3dcad2701..02e23cce6 100644
--- a/src/yuzu/configuration/configure_input.cpp
+++ b/src/yuzu/configuration/configure_input.cpp
@@ -152,7 +152,7 @@ void ConfigureInput::Initialize(InputCommon::InputSubsystem* input_subsystem,
connect(player_controllers[0], &ConfigureInputPlayer::HandheldStateChanged,
[this](bool is_handheld) { UpdateDockedState(is_handheld); });
- advanced = new ConfigureInputAdvanced(this);
+ advanced = new ConfigureInputAdvanced(hid_core, this);
ui->tabAdvanced->setLayout(new QHBoxLayout(ui->tabAdvanced));
ui->tabAdvanced->layout()->addWidget(advanced);
diff --git a/src/yuzu/configuration/configure_input.h b/src/yuzu/configuration/configure_input.h
index 136cd3a0a..beb503dae 100644
--- a/src/yuzu/configuration/configure_input.h
+++ b/src/yuzu/configuration/configure_input.h
@@ -1,4 +1,4 @@
-// SPDX-FileCopyrightText: 2016 Citra Emulator Project
+// SPDX-FileCopyrightText: 2016 Citra Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#pragma once
diff --git a/src/yuzu/configuration/configure_input_advanced.cpp b/src/yuzu/configuration/configure_input_advanced.cpp
index 3cfd5d439..441cea3f6 100644
--- a/src/yuzu/configuration/configure_input_advanced.cpp
+++ b/src/yuzu/configuration/configure_input_advanced.cpp
@@ -4,11 +4,13 @@
#include <QColorDialog>
#include "common/settings.h"
#include "core/core.h"
+#include "core/hid/emulated_controller.h"
+#include "core/hid/hid_core.h"
#include "ui_configure_input_advanced.h"
#include "yuzu/configuration/configure_input_advanced.h"
-ConfigureInputAdvanced::ConfigureInputAdvanced(QWidget* parent)
- : QWidget(parent), ui(std::make_unique<Ui::ConfigureInputAdvanced>()) {
+ConfigureInputAdvanced::ConfigureInputAdvanced(Core::HID::HIDCore& hid_core_, QWidget* parent)
+ : QWidget(parent), ui(std::make_unique<Ui::ConfigureInputAdvanced>()), hid_core{hid_core_} {
ui->setupUi(this);
controllers_color_buttons = {{
@@ -123,6 +125,8 @@ void ConfigureInputAdvanced::ApplyConfiguration() {
player.button_color_left = colors[1];
player.body_color_right = colors[2];
player.button_color_right = colors[3];
+
+ hid_core.GetEmulatedControllerByIndex(player_idx)->ReloadColorsFromSettings();
}
Settings::values.debug_pad_enabled = ui->debug_enabled->isChecked();
diff --git a/src/yuzu/configuration/configure_input_advanced.h b/src/yuzu/configuration/configure_input_advanced.h
index fc1230284..41f822c4a 100644
--- a/src/yuzu/configuration/configure_input_advanced.h
+++ b/src/yuzu/configuration/configure_input_advanced.h
@@ -14,11 +14,15 @@ namespace Ui {
class ConfigureInputAdvanced;
}
+namespace Core::HID {
+class HIDCore;
+} // namespace Core::HID
+
class ConfigureInputAdvanced : public QWidget {
Q_OBJECT
public:
- explicit ConfigureInputAdvanced(QWidget* parent = nullptr);
+ explicit ConfigureInputAdvanced(Core::HID::HIDCore& hid_core_, QWidget* parent = nullptr);
~ConfigureInputAdvanced() override;
void ApplyConfiguration();
@@ -44,4 +48,6 @@ private:
std::array<std::array<QColor, 4>, 8> controllers_colors;
std::array<std::array<QPushButton*, 4>, 8> controllers_color_buttons;
+
+ Core::HID::HIDCore& hid_core;
};
diff --git a/src/yuzu/configuration/configure_input_player.cpp b/src/yuzu/configuration/configure_input_player.cpp
index 576f5b571..9259e2a5d 100644
--- a/src/yuzu/configuration/configure_input_player.cpp
+++ b/src/yuzu/configuration/configure_input_player.cpp
@@ -322,11 +322,12 @@ ConfigureInputPlayer::ConfigureInputPlayer(QWidget* parent, std::size_t player_i
setFocusPolicy(Qt::ClickFocus);
button_map = {
- ui->buttonA, ui->buttonB, ui->buttonX, ui->buttonY,
- ui->buttonLStick, ui->buttonRStick, ui->buttonL, ui->buttonR,
- ui->buttonZL, ui->buttonZR, ui->buttonPlus, ui->buttonMinus,
- ui->buttonDpadLeft, ui->buttonDpadUp, ui->buttonDpadRight, ui->buttonDpadDown,
- ui->buttonSL, ui->buttonSR, ui->buttonHome, ui->buttonScreenshot,
+ ui->buttonA, ui->buttonB, ui->buttonX, ui->buttonY,
+ ui->buttonLStick, ui->buttonRStick, ui->buttonL, ui->buttonR,
+ ui->buttonZL, ui->buttonZR, ui->buttonPlus, ui->buttonMinus,
+ ui->buttonDpadLeft, ui->buttonDpadUp, ui->buttonDpadRight, ui->buttonDpadDown,
+ ui->buttonSLLeft, ui->buttonSRLeft, ui->buttonHome, ui->buttonScreenshot,
+ ui->buttonSLRight, ui->buttonSRRight,
};
analog_map_buttons = {{
@@ -1181,10 +1182,13 @@ void ConfigureInputPlayer::UpdateControllerAvailableButtons() {
// List of all the widgets that will be hidden by any of the following layouts that need
// "unhidden" after the controller type changes
- const std::array<QWidget*, 11> layout_show = {
- ui->buttonShoulderButtonsSLSR,
+ const std::array<QWidget*, 14> layout_show = {
+ ui->buttonShoulderButtonsSLSRLeft,
+ ui->buttonShoulderButtonsSLSRRight,
ui->horizontalSpacerShoulderButtonsWidget,
ui->horizontalSpacerShoulderButtonsWidget2,
+ ui->horizontalSpacerShoulderButtonsWidget3,
+ ui->horizontalSpacerShoulderButtonsWidget4,
ui->buttonShoulderButtonsLeft,
ui->buttonMiscButtonsMinusScreenshot,
ui->bottomLeft,
@@ -1202,16 +1206,19 @@ void ConfigureInputPlayer::UpdateControllerAvailableButtons() {
std::vector<QWidget*> layout_hidden;
switch (layout) {
case Core::HID::NpadStyleIndex::ProController:
- case Core::HID::NpadStyleIndex::JoyconDual:
case Core::HID::NpadStyleIndex::Handheld:
layout_hidden = {
- ui->buttonShoulderButtonsSLSR,
+ ui->buttonShoulderButtonsSLSRLeft,
+ ui->buttonShoulderButtonsSLSRRight,
ui->horizontalSpacerShoulderButtonsWidget2,
+ ui->horizontalSpacerShoulderButtonsWidget4,
};
break;
case Core::HID::NpadStyleIndex::JoyconLeft:
layout_hidden = {
+ ui->buttonShoulderButtonsSLSRRight,
ui->horizontalSpacerShoulderButtonsWidget2,
+ ui->horizontalSpacerShoulderButtonsWidget3,
ui->buttonShoulderButtonsRight,
ui->buttonMiscButtonsPlusHome,
ui->bottomRight,
@@ -1219,16 +1226,17 @@ void ConfigureInputPlayer::UpdateControllerAvailableButtons() {
break;
case Core::HID::NpadStyleIndex::JoyconRight:
layout_hidden = {
- ui->horizontalSpacerShoulderButtonsWidget,
- ui->buttonShoulderButtonsLeft,
- ui->buttonMiscButtonsMinusScreenshot,
- ui->bottomLeft,
+ ui->buttonShoulderButtonsSLSRLeft, ui->horizontalSpacerShoulderButtonsWidget,
+ ui->horizontalSpacerShoulderButtonsWidget4, ui->buttonShoulderButtonsLeft,
+ ui->buttonMiscButtonsMinusScreenshot, ui->bottomLeft,
};
break;
case Core::HID::NpadStyleIndex::GameCube:
layout_hidden = {
- ui->buttonShoulderButtonsSLSR,
+ ui->buttonShoulderButtonsSLSRLeft,
+ ui->buttonShoulderButtonsSLSRRight,
ui->horizontalSpacerShoulderButtonsWidget2,
+ ui->horizontalSpacerShoulderButtonsWidget4,
ui->buttonMiscButtonsMinusGroup,
ui->buttonMiscButtonsScreenshotGroup,
};
diff --git a/src/yuzu/configuration/configure_input_player.h b/src/yuzu/configuration/configure_input_player.h
index d3255d2b4..fda09e925 100644
--- a/src/yuzu/configuration/configure_input_player.h
+++ b/src/yuzu/configuration/configure_input_player.h
@@ -1,4 +1,4 @@
-// SPDX-FileCopyrightText: 2016 Citra Emulator Project
+// SPDX-FileCopyrightText: 2016 Citra Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#pragma once
diff --git a/src/yuzu/configuration/configure_input_player.ui b/src/yuzu/configuration/configure_input_player.ui
index 611a79477..5518cccd1 100644
--- a/src/yuzu/configuration/configure_input_player.ui
+++ b/src/yuzu/configuration/configure_input_player.ui
@@ -1208,6 +1208,159 @@
<property name="spacing">
<number>3</number>
</property>
+ <item>
+ <widget class="QWidget" name="buttonShoulderButtonsSLSRLeft" native="true">
+ <layout class="QVBoxLayout" name="buttonShoulderButtonsSLSRLeftVerticalLayout">
+ <property name="spacing">
+ <number>0</number>
+ </property>
+ <property name="leftMargin">
+ <number>0</number>
+ </property>
+ <property name="topMargin">
+ <number>0</number>
+ </property>
+ <property name="rightMargin">
+ <number>0</number>
+ </property>
+ <property name="bottomMargin">
+ <number>0</number>
+ </property>
+ <item alignment="Qt::AlignHCenter">
+ <widget class="QGroupBox" name="buttonShoulderButtonsSLLeftGroup">
+ <property name="title">
+ <string>SL</string>
+ </property>
+ <property name="alignment">
+ <set>Qt::AlignCenter</set>
+ </property>
+ <layout class="QVBoxLayout" name="buttonShoulderButtonsSLLeftVerticalLayout">
+ <property name="spacing">
+ <number>3</number>
+ </property>
+ <property name="leftMargin">
+ <number>3</number>
+ </property>
+ <property name="topMargin">
+ <number>3</number>
+ </property>
+ <property name="rightMargin">
+ <number>3</number>
+ </property>
+ <property name="bottomMargin">
+ <number>3</number>
+ </property>
+ <item>
+ <widget class="QPushButton" name="buttonSLLeft">
+ <property name="minimumSize">
+ <size>
+ <width>68</width>
+ <height>0</height>
+ </size>
+ </property>
+ <property name="maximumSize">
+ <size>
+ <width>68</width>
+ <height>16777215</height>
+ </size>
+ </property>
+ <property name="styleSheet">
+ <string notr="true">min-width: 68px;</string>
+ </property>
+ <property name="text">
+ <string>SL</string>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ <item alignment="Qt::AlignHCenter">
+ <widget class="QGroupBox" name="buttonShoulderButtonsSRLeftGroup">
+ <property name="title">
+ <string>SR</string>
+ </property>
+ <property name="alignment">
+ <set>Qt::AlignCenter</set>
+ </property>
+ <layout class="QVBoxLayout" name="buttonShoulderButtonsSRLeftVerticalLayout">
+ <property name="spacing">
+ <number>3</number>
+ </property>
+ <property name="leftMargin">
+ <number>3</number>
+ </property>
+ <property name="topMargin">
+ <number>3</number>
+ </property>
+ <property name="rightMargin">
+ <number>3</number>
+ </property>
+ <property name="bottomMargin">
+ <number>3</number>
+ </property>
+ <item>
+ <widget class="QPushButton" name="buttonSRLeft">
+ <property name="minimumSize">
+ <size>
+ <width>68</width>
+ <height>0</height>
+ </size>
+ </property>
+ <property name="maximumSize">
+ <size>
+ <width>68</width>
+ <height>16777215</height>
+ </size>
+ </property>
+ <property name="styleSheet">
+ <string notr="true">min-width: 68px;</string>
+ </property>
+ <property name="text">
+ <string>SR</string>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ <item>
+ <widget class="QWidget" name="horizontalSpacerShoulderButtonsWidget4" native="true">
+ <layout class="QHBoxLayout" name="horizontalSpacerShoulderButtonsWidget4Layout">
+ <property name="spacing">
+ <number>0</number>
+ </property>
+ <property name="leftMargin">
+ <number>0</number>
+ </property>
+ <property name="topMargin">
+ <number>0</number>
+ </property>
+ <property name="rightMargin">
+ <number>0</number>
+ </property>
+ <property name="bottomMargin">
+ <number>0</number>
+ </property>
+ <item>
+ <spacer name="horizontalSpacerShoulderButtons5">
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>0</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ </layout>
+ </widget>
+ </item>
<item>
<widget class="QWidget" name="buttonShoulderButtonsLeft" native="true">
<layout class="QVBoxLayout" name="buttonShoulderButtonsLeftVerticalLayout">
@@ -1830,125 +1983,125 @@
</layout>
</widget>
</item>
- <item>
- <widget class="QWidget" name="buttonShoulderButtonsSLSR" native="true">
- <layout class="QVBoxLayout" name="buttonShoulderButtonsSLSRVerticalLayout">
- <property name="spacing">
- <number>0</number>
- </property>
- <property name="leftMargin">
- <number>0</number>
- </property>
- <property name="topMargin">
- <number>0</number>
- </property>
- <property name="rightMargin">
- <number>0</number>
- </property>
- <property name="bottomMargin">
- <number>0</number>
- </property>
- <item alignment="Qt::AlignHCenter">
- <widget class="QGroupBox" name="buttonShoulderButtonsSLGroup">
- <property name="title">
- <string>SL</string>
- </property>
- <property name="alignment">
- <set>Qt::AlignCenter</set>
- </property>
- <layout class="QVBoxLayout" name="buttonShoulderButtonsSLVerticalLayout">
- <property name="spacing">
- <number>3</number>
- </property>
- <property name="leftMargin">
- <number>3</number>
- </property>
- <property name="topMargin">
- <number>3</number>
- </property>
- <property name="rightMargin">
- <number>3</number>
- </property>
- <property name="bottomMargin">
- <number>3</number>
- </property>
- <item>
- <widget class="QPushButton" name="buttonSL">
- <property name="minimumSize">
- <size>
- <width>68</width>
- <height>0</height>
- </size>
- </property>
- <property name="maximumSize">
- <size>
- <width>68</width>
- <height>16777215</height>
- </size>
- </property>
- <property name="styleSheet">
- <string notr="true">min-width: 68px;</string>
- </property>
- <property name="text">
- <string>SL</string>
- </property>
- </widget>
- </item>
- </layout>
- </widget>
- </item>
- <item alignment="Qt::AlignHCenter">
- <widget class="QGroupBox" name="buttonShoulderButtonsSRGroup">
- <property name="title">
- <string>SR</string>
- </property>
- <property name="alignment">
- <set>Qt::AlignCenter</set>
- </property>
- <layout class="QVBoxLayout" name="buttonShoulderButtonsSRVerticalLayout">
- <property name="spacing">
- <number>3</number>
- </property>
- <property name="leftMargin">
- <number>3</number>
- </property>
- <property name="topMargin">
- <number>3</number>
- </property>
- <property name="rightMargin">
- <number>3</number>
- </property>
- <property name="bottomMargin">
- <number>3</number>
- </property>
- <item>
- <widget class="QPushButton" name="buttonSR">
- <property name="minimumSize">
- <size>
- <width>68</width>
- <height>0</height>
- </size>
- </property>
- <property name="maximumSize">
- <size>
- <width>68</width>
- <height>16777215</height>
- </size>
- </property>
- <property name="styleSheet">
- <string notr="true">min-width: 68px;</string>
- </property>
- <property name="text">
- <string>SR</string>
- </property>
- </widget>
- </item>
+ <item>
+ <widget class="QWidget" name="buttonShoulderButtonsSLSRRight" native="true">
+ <layout class="QVBoxLayout" name="buttonShoulderButtonsSLSRRightVerticalLayout">
+ <property name="spacing">
+ <number>0</number>
+ </property>
+ <property name="leftMargin">
+ <number>0</number>
+ </property>
+ <property name="topMargin">
+ <number>0</number>
+ </property>
+ <property name="rightMargin">
+ <number>0</number>
+ </property>
+ <property name="bottomMargin">
+ <number>0</number>
+ </property>
+ <item alignment="Qt::AlignHCenter">
+ <widget class="QGroupBox" name="buttonShoulderButtonsSLRightGroup">
+ <property name="title">
+ <string>SL</string>
+ </property>
+ <property name="alignment">
+ <set>Qt::AlignCenter</set>
+ </property>
+ <layout class="QVBoxLayout" name="buttonShoulderButtonsSLRightVerticalLayout">
+ <property name="spacing">
+ <number>3</number>
+ </property>
+ <property name="leftMargin">
+ <number>3</number>
+ </property>
+ <property name="topMargin">
+ <number>3</number>
+ </property>
+ <property name="rightMargin">
+ <number>3</number>
+ </property>
+ <property name="bottomMargin">
+ <number>3</number>
+ </property>
+ <item>
+ <widget class="QPushButton" name="buttonSLRight">
+ <property name="minimumSize">
+ <size>
+ <width>68</width>
+ <height>0</height>
+ </size>
+ </property>
+ <property name="maximumSize">
+ <size>
+ <width>68</width>
+ <height>16777215</height>
+ </size>
+ </property>
+ <property name="styleSheet">
+ <string notr="true">min-width: 68px;</string>
+ </property>
+ <property name="text">
+ <string>SL</string>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ <item alignment="Qt::AlignHCenter">
+ <widget class="QGroupBox" name="buttonShoulderButtonsSRRightGroup">
+ <property name="title">
+ <string>SR</string>
+ </property>
+ <property name="alignment">
+ <set>Qt::AlignCenter</set>
+ </property>
+ <layout class="QVBoxLayout" name="buttonShoulderButtonsSRRightVerticalLayout">
+ <property name="spacing">
+ <number>3</number>
+ </property>
+ <property name="leftMargin">
+ <number>3</number>
+ </property>
+ <property name="topMargin">
+ <number>3</number>
+ </property>
+ <property name="rightMargin">
+ <number>3</number>
+ </property>
+ <property name="bottomMargin">
+ <number>3</number>
+ </property>
+ <item>
+ <widget class="QPushButton" name="buttonSRRight">
+ <property name="minimumSize">
+ <size>
+ <width>68</width>
+ <height>0</height>
+ </size>
+ </property>
+ <property name="maximumSize">
+ <size>
+ <width>68</width>
+ <height>16777215</height>
+ </size>
+ </property>
+ <property name="styleSheet">
+ <string notr="true">min-width: 68px;</string>
+ </property>
+ <property name="text">
+ <string>SR</string>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ </item>
</layout>
- </widget>
- </item>
- </layout>
- </widget>
- </item>
+ </widget>
+ </item>
</layout>
</item>
<item>
diff --git a/src/yuzu/configuration/configure_input_player_widget.cpp b/src/yuzu/configuration/configure_input_player_widget.cpp
index a188eef92..550cff9a0 100644
--- a/src/yuzu/configuration/configure_input_player_widget.cpp
+++ b/src/yuzu/configuration/configure_input_player_widget.cpp
@@ -297,8 +297,8 @@ void PlayerControlPreview::DrawLeftController(QPainter& p, const QPointF center)
// Sideview SL and SR buttons
button_color = colors.slider_button;
- DrawRoundButton(p, center + QPoint(59, 52), button_values[SR], 5, 12, Direction::Left);
- DrawRoundButton(p, center + QPoint(59, -69), button_values[SL], 5, 12, Direction::Left);
+ DrawRoundButton(p, center + QPoint(59, 52), button_values[SRLeft], 5, 12, Direction::Left);
+ DrawRoundButton(p, center + QPoint(59, -69), button_values[SLLeft], 5, 12, Direction::Left);
DrawLeftBody(p, center);
@@ -353,8 +353,10 @@ void PlayerControlPreview::DrawLeftController(QPainter& p, const QPointF center)
// SR and SL buttons
p.setPen(colors.outline);
button_color = colors.slider_button;
- DrawRoundButton(p, center + QPoint(155, 52), button_values[SR], 5.2f, 12, Direction::None, 4);
- DrawRoundButton(p, center + QPoint(155, -69), button_values[SL], 5.2f, 12, Direction::None, 4);
+ DrawRoundButton(p, center + QPoint(155, 52), button_values[SRLeft], 5.2f, 12, Direction::None,
+ 4);
+ DrawRoundButton(p, center + QPoint(155, -69), button_values[SLLeft], 5.2f, 12, Direction::None,
+ 4);
// SR and SL text
p.setPen(colors.transparent);
@@ -428,8 +430,10 @@ void PlayerControlPreview::DrawRightController(QPainter& p, const QPointF center
// Sideview SL and SR buttons
button_color = colors.slider_button;
- DrawRoundButton(p, center + QPoint(-59, 52), button_values[SL], 5, 11, Direction::Right);
- DrawRoundButton(p, center + QPoint(-59, -69), button_values[SR], 5, 11, Direction::Right);
+ DrawRoundButton(p, center + QPoint(-59, 52), button_values[SLRight], 5, 11,
+ Direction::Right);
+ DrawRoundButton(p, center + QPoint(-59, -69), button_values[SRRight], 5, 11,
+ Direction::Right);
DrawRightBody(p, center);
@@ -484,8 +488,10 @@ void PlayerControlPreview::DrawRightController(QPainter& p, const QPointF center
// SR and SL buttons
p.setPen(colors.outline);
button_color = colors.slider_button;
- DrawRoundButton(p, center + QPoint(-155, 52), button_values[SL], 5, 12, Direction::None, 4.0f);
- DrawRoundButton(p, center + QPoint(-155, -69), button_values[SR], 5, 12, Direction::None, 4.0f);
+ DrawRoundButton(p, center + QPoint(-155, 52), button_values[SLRight], 5, 12, Direction::None,
+ 4.0f);
+ DrawRoundButton(p, center + QPoint(-155, -69), button_values[SRRight], 5, 12, Direction::None,
+ 4.0f);
// SR and SL text
p.setPen(colors.transparent);
@@ -557,6 +563,19 @@ void PlayerControlPreview::DrawDualController(QPainter& p, const QPointF center)
DrawRoundButton(p, center + QPoint(-154, -72), button_values[Minus], 7, 4, Direction::Up,
1);
+ // Left SR and SL sideview buttons
+ button_color = colors.slider_button;
+ DrawRoundButton(p, center + QPoint(-20, -62), button_values[SLLeft], 4, 11,
+ Direction::Left);
+ DrawRoundButton(p, center + QPoint(-20, 47), button_values[SRLeft], 4, 11, Direction::Left);
+
+ // Right SR and SL sideview buttons
+ button_color = colors.slider_button;
+ DrawRoundButton(p, center + QPoint(20, 47), button_values[SLRight], 4, 11,
+ Direction::Right);
+ DrawRoundButton(p, center + QPoint(20, -62), button_values[SRRight], 4, 11,
+ Direction::Right);
+
DrawDualBody(p, center);
// Right trigger top view
@@ -1792,16 +1811,6 @@ void PlayerControlPreview::DrawDualBody(QPainter& p, const QPointF center) {
p.setBrush(colors.right);
DrawPolygon(p, qright_joycon_topview);
- // Right SR and SL sideview buttons
- p.setPen(colors.outline);
- p.setBrush(colors.slider_button);
- DrawRoundRectangle(p, center + QPoint(19, 47), 7, 22, 1);
- DrawRoundRectangle(p, center + QPoint(19, -62), 7, 22, 1);
-
- // Left SR and SL sideview buttons
- DrawRoundRectangle(p, center + QPoint(-19, 47), 7, 22, 1);
- DrawRoundRectangle(p, center + QPoint(-19, -62), 7, 22, 1);
-
// Right Sideview body
p.setBrush(colors.slider);
DrawPolygon(p, qright_joycon_slider);
diff --git a/src/yuzu/configuration/configure_per_game.h b/src/yuzu/configuration/configure_per_game.h
index 1a727f32c..cc2513001 100644
--- a/src/yuzu/configuration/configure_per_game.h
+++ b/src/yuzu/configuration/configure_per_game.h
@@ -1,4 +1,4 @@
-// SPDX-FileCopyrightText: Copyright 2020 yuzu Emulator Project
+// SPDX-FileCopyrightText: Copyright 2020 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#pragma once
diff --git a/src/yuzu/configuration/configure_profile_manager.cpp b/src/yuzu/configuration/configure_profile_manager.cpp
index a47089988..6d2219bf5 100644
--- a/src/yuzu/configuration/configure_profile_manager.cpp
+++ b/src/yuzu/configuration/configure_profile_manager.cpp
@@ -306,10 +306,10 @@ void ConfigureProfileManager::SetUserImage() {
return;
}
- // Some games crash when the profile image is too big. Resize any image bigger than 256x256
+ // Profile image must be 256x256
QImage image(image_path);
- if (image.width() > 256 || image.height() > 256) {
- image = image.scaled(256, 256, Qt::KeepAspectRatio);
+ if (image.width() != 256 || image.height() != 256) {
+ image = image.scaled(256, 256, Qt::KeepAspectRatioByExpanding, Qt::SmoothTransformation);
if (!image.save(image_path)) {
QMessageBox::warning(this, tr("Error resizing user image"),
tr("Unable to resize image"));
diff --git a/src/yuzu/configuration/configure_ringcon.h b/src/yuzu/configuration/configure_ringcon.h
index b23c27906..6fd95e2b8 100644
--- a/src/yuzu/configuration/configure_ringcon.h
+++ b/src/yuzu/configuration/configure_ringcon.h
@@ -1,4 +1,4 @@
-// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
+// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#pragma once
diff --git a/src/yuzu/configuration/configure_tas.h b/src/yuzu/configuration/configure_tas.h
index 4a6b0ba4e..a91891906 100644
--- a/src/yuzu/configuration/configure_tas.h
+++ b/src/yuzu/configuration/configure_tas.h
@@ -1,4 +1,4 @@
-// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project
+// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#pragma once
diff --git a/src/yuzu/configuration/configure_touchscreen_advanced.h b/src/yuzu/configuration/configure_touchscreen_advanced.h
index 034dc0d46..b6fdffdc8 100644
--- a/src/yuzu/configuration/configure_touchscreen_advanced.h
+++ b/src/yuzu/configuration/configure_touchscreen_advanced.h
@@ -1,4 +1,4 @@
-// SPDX-FileCopyrightText: 2016 Citra Emulator Project
+// SPDX-FileCopyrightText: 2016 Citra Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#pragma once
diff --git a/src/yuzu/configuration/shared_translation.cpp b/src/yuzu/configuration/shared_translation.cpp
index 3fe448f27..1434b1a56 100644
--- a/src/yuzu/configuration/shared_translation.cpp
+++ b/src/yuzu/configuration/shared_translation.cpp
@@ -156,7 +156,6 @@ std::unique_ptr<TranslationMap> InitializeTranslations(QWidget* parent) {
// Ui General
INSERT(UISettings, select_user_on_boot, "Prompt for user on game boot", "");
INSERT(UISettings, pause_when_in_background, "Pause emulation when in background", "");
- INSERT(UISettings, confirm_before_closing, "Confirm exit while emulation is running", "");
INSERT(UISettings, confirm_before_stopping, "Confirm before stopping emulation", "");
INSERT(UISettings, hide_mouse, "Hide mouse on inactivity", "");
INSERT(UISettings, controller_applet_disabled, "Disable controller applet", "");
diff --git a/src/yuzu/main.cpp b/src/yuzu/main.cpp
index 816d804c4..f077d7f9c 100644
--- a/src/yuzu/main.cpp
+++ b/src/yuzu/main.cpp
@@ -159,8 +159,8 @@ static FileSys::VirtualFile VfsDirectoryCreateFileWrapper(const FileSys::Virtual
#include "yuzu/util/clickable_label.h"
#include "yuzu/vk_device_info.h"
-#ifdef YUZU_DBGHELP
-#include "yuzu/mini_dump.h"
+#ifdef YUZU_CRASH_DUMPS
+#include "yuzu/breakpad.h"
#endif
using namespace Common::Literals;
@@ -1064,19 +1064,19 @@ void GMainWindow::InitializeWidgets() {
volume_slider->setObjectName(QStringLiteral("volume_slider"));
volume_slider->setMaximum(200);
volume_slider->setPageStep(5);
- connect(volume_slider, &QSlider::valueChanged, this, [this](int percentage) {
- Settings::values.audio_muted = false;
- const auto volume = static_cast<u8>(percentage);
- Settings::values.volume.SetValue(volume);
- UpdateVolumeUI();
- });
volume_popup->layout()->addWidget(volume_slider);
- volume_button = new QPushButton();
+ volume_button = new VolumeButton();
volume_button->setObjectName(QStringLiteral("TogglableStatusBarButton"));
volume_button->setFocusPolicy(Qt::NoFocus);
volume_button->setCheckable(true);
UpdateVolumeUI();
+ connect(volume_slider, &QSlider::valueChanged, this, [this](int percentage) {
+ Settings::values.audio_muted = false;
+ const auto volume = static_cast<u8>(percentage);
+ Settings::values.volume.SetValue(volume);
+ UpdateVolumeUI();
+ });
connect(volume_button, &QPushButton::clicked, this, [&] {
UpdateVolumeUI();
volume_popup->setVisible(!volume_popup->isVisible());
@@ -1103,6 +1103,8 @@ void GMainWindow::InitializeWidgets() {
context_menu.exec(volume_button->mapToGlobal(menu_location));
volume_button->repaint();
});
+ connect(volume_button, &VolumeButton::VolumeChanged, this, &GMainWindow::UpdateVolumeUI);
+
statusBar()->insertPermanentWidget(0, volume_button);
// setup AA button
@@ -1906,7 +1908,11 @@ void GMainWindow::ConfigureFilesystemProvider(const std::string& filepath) {
void GMainWindow::BootGame(const QString& filename, u64 program_id, std::size_t program_index,
StartGameType type, AmLaunchType launch_type) {
LOG_INFO(Frontend, "yuzu starting...");
- StoreRecentFile(filename); // Put the filename on top of the list
+
+ if (program_id == 0 ||
+ program_id > static_cast<u64>(Service::AM::Applets::AppletProgramId::MaxProgramId)) {
+ StoreRecentFile(filename); // Put the filename on top of the list
+ }
// Save configurations
UpdateUISettings();
@@ -2172,6 +2178,7 @@ void GMainWindow::ShutdownGame() {
return;
}
+ play_time_manager->Stop();
OnShutdownBegin();
OnEmulationStopTimeExpired();
OnEmulationStopped();
@@ -2735,7 +2742,7 @@ void GMainWindow::OnGameListDumpRomFS(u64 program_id, const std::string& game_pa
return;
}
- const auto extracted = FileSys::ExtractRomFS(romfs, FileSys::RomFSExtractionType::Full);
+ const auto extracted = FileSys::ExtractRomFS(romfs);
if (extracted == nullptr) {
failed();
return;
@@ -2906,7 +2913,7 @@ void GMainWindow::OnGameListCreateShortcut(u64 program_id, const std::string& ga
const std::string game_file_name = std::filesystem::path(game_path).filename().string();
// Determine full paths for icon and shortcut
-#if defined(__linux__) || defined(__FreeBSD__)
+#if defined(__linux__) || defined(__FreeBSD__) || defined(__APPLE__)
const char* home = std::getenv("HOME");
const std::filesystem::path home_path = (home == nullptr ? "~" : home);
const char* xdg_data_home = std::getenv("XDG_DATA_HOME");
@@ -2963,7 +2970,7 @@ void GMainWindow::OnGameListCreateShortcut(u64 program_id, const std::string& ga
QImage icon_data =
QImage::fromData(icon_image_file.data(), static_cast<int>(icon_image_file.size()));
-#if defined(__linux__) || defined(__FreeBSD__)
+#if defined(__linux__) || defined(__FreeBSD__) || defined(__APPLE__)
// Convert and write the icon as a PNG
if (!icon_data.save(QString::fromStdString(icon_path.string()))) {
LOG_ERROR(Frontend, "Could not write icon as PNG to file");
@@ -3482,7 +3489,7 @@ void GMainWindow::OnExecuteProgram(std::size_t program_index) {
}
void GMainWindow::OnExit() {
- OnStopGame();
+ ShutdownGame();
}
void GMainWindow::OnSaveConfig() {
@@ -4002,7 +4009,7 @@ bool GMainWindow::CreateShortcut(const std::string& shortcut_path, const std::st
const std::string& comment, const std::string& icon_path,
const std::string& command, const std::string& arguments,
const std::string& categories, const std::string& keywords) {
-#if defined(__linux__) || defined(__FreeBSD__)
+#if defined(__linux__) || defined(__FreeBSD__) || defined(__APPLE__)
// This desktop file template was writing referencing
// https://specifications.freedesktop.org/desktop-entry-spec/desktop-entry-spec-1.0.html
std::string shortcut_contents{};
@@ -4270,7 +4277,7 @@ void GMainWindow::OnToggleStatusBar() {
}
void GMainWindow::OnAlbum() {
- constexpr u64 AlbumId = 0x010000000000100Dull;
+ constexpr u64 AlbumId = static_cast<u64>(Service::AM::Applets::AppletProgramId::PhotoViewer);
auto bis_system = system->GetFileSystemController().GetSystemNANDContents();
if (!bis_system) {
QMessageBox::warning(this, tr("No firmware available"),
@@ -4289,11 +4296,11 @@ void GMainWindow::OnAlbum() {
const auto filename = QString::fromStdString(album_nca->GetFullPath());
UISettings::values.roms_path = QFileInfo(filename).path();
- BootGame(filename);
+ BootGame(filename, AlbumId);
}
void GMainWindow::OnCabinet(Service::NFP::CabinetMode mode) {
- constexpr u64 CabinetId = 0x0100000000001002ull;
+ constexpr u64 CabinetId = static_cast<u64>(Service::AM::Applets::AppletProgramId::Cabinet);
auto bis_system = system->GetFileSystemController().GetSystemNANDContents();
if (!bis_system) {
QMessageBox::warning(this, tr("No firmware available"),
@@ -4313,11 +4320,11 @@ void GMainWindow::OnCabinet(Service::NFP::CabinetMode mode) {
const auto filename = QString::fromStdString(cabinet_nca->GetFullPath());
UISettings::values.roms_path = QFileInfo(filename).path();
- BootGame(filename);
+ BootGame(filename, CabinetId);
}
void GMainWindow::OnMiiEdit() {
- constexpr u64 MiiEditId = 0x0100000000001009ull;
+ constexpr u64 MiiEditId = static_cast<u64>(Service::AM::Applets::AppletProgramId::MiiEdit);
auto bis_system = system->GetFileSystemController().GetSystemNANDContents();
if (!bis_system) {
QMessageBox::warning(this, tr("No firmware available"),
@@ -4336,7 +4343,7 @@ void GMainWindow::OnMiiEdit() {
const auto filename = QString::fromStdString((mii_applet_nca->GetFullPath()));
UISettings::values.roms_path = QFileInfo(filename).path();
- BootGame(filename);
+ BootGame(filename, MiiEditId);
}
void GMainWindow::OnCaptureScreenshot() {
@@ -4845,7 +4852,12 @@ bool GMainWindow::SelectRomFSDumpTarget(const FileSys::ContentProvider& installe
}
bool GMainWindow::ConfirmClose() {
- if (emu_thread == nullptr || !UISettings::values.confirm_before_closing) {
+ if (emu_thread == nullptr ||
+ UISettings::values.confirm_before_stopping.GetValue() == ConfirmStop::Ask_Never) {
+ return true;
+ }
+ if (!system->GetExitLocked() &&
+ UISettings::values.confirm_before_stopping.GetValue() == ConfirmStop::Ask_Based_On_Game) {
return true;
}
const auto text = tr("Are you sure you want to close yuzu?");
@@ -4950,7 +4962,7 @@ bool GMainWindow::ConfirmChangeGame() {
}
bool GMainWindow::ConfirmForceLockedExit() {
- if (emu_thread == nullptr || !UISettings::values.confirm_before_closing) {
+ if (emu_thread == nullptr) {
return true;
}
const auto text = tr("The currently running application has requested yuzu to not exit.\n\n"
@@ -5126,6 +5138,32 @@ void GMainWindow::changeEvent(QEvent* event) {
QWidget::changeEvent(event);
}
+void VolumeButton::wheelEvent(QWheelEvent* event) {
+
+ int num_degrees = event->angleDelta().y() / 8;
+ int num_steps = (num_degrees / 15) * scroll_multiplier;
+ // Stated in QT docs: Most mouse types work in steps of 15 degrees, in which case the delta
+ // value is a multiple of 120; i.e., 120 units * 1/8 = 15 degrees.
+
+ if (num_steps > 0) {
+ Settings::values.volume.SetValue(
+ std::min(200, Settings::values.volume.GetValue() + num_steps));
+ } else {
+ Settings::values.volume.SetValue(
+ std::max(0, Settings::values.volume.GetValue() + num_steps));
+ }
+
+ scroll_multiplier = std::min(MaxMultiplier, scroll_multiplier * 2);
+ scroll_timer.start(100); // reset the multiplier if no scroll event occurs within 100 ms
+
+ emit VolumeChanged();
+ event->accept();
+}
+
+void VolumeButton::ResetMultiplier() {
+ scroll_multiplier = 1;
+}
+
#ifdef main
#undef main
#endif
@@ -5187,22 +5225,15 @@ int main(int argc, char* argv[]) {
return 0;
}
-#ifdef YUZU_DBGHELP
- PROCESS_INFORMATION pi;
- if (!is_child && Settings::values.create_crash_dumps.GetValue() &&
- MiniDump::SpawnDebuggee(argv[0], pi)) {
- // Delete the config object so that it doesn't save when the program exits
- config.reset(nullptr);
- MiniDump::DebugDebuggee(pi);
- return 0;
- }
-#endif
-
if (StartupChecks(argv[0], &has_broken_vulkan,
Settings::values.perform_vulkan_check.GetValue())) {
return 0;
}
+#ifdef YUZU_CRASH_DUMPS
+ Breakpad::InstallCrashHandler();
+#endif
+
Common::DetachedTasks detached_tasks;
MicroProfileOnThreadCreate("Frontend");
SCOPE_EXIT({ MicroProfileShutdown(); });
diff --git a/src/yuzu/main.h b/src/yuzu/main.h
index 270a40c5f..f9c6efe4f 100644
--- a/src/yuzu/main.h
+++ b/src/yuzu/main.h
@@ -8,6 +8,7 @@
#include <QMainWindow>
#include <QMessageBox>
+#include <QPushButton>
#include <QTimer>
#include <QTranslator>
@@ -137,6 +138,28 @@ namespace VkDeviceInfo {
class Record;
}
+class VolumeButton : public QPushButton {
+ Q_OBJECT
+public:
+ explicit VolumeButton(QWidget* parent = nullptr) : QPushButton(parent), scroll_multiplier(1) {
+ connect(&scroll_timer, &QTimer::timeout, this, &VolumeButton::ResetMultiplier);
+ }
+
+signals:
+ void VolumeChanged();
+
+protected:
+ void wheelEvent(QWheelEvent* event) override;
+
+private slots:
+ void ResetMultiplier();
+
+private:
+ int scroll_multiplier;
+ QTimer scroll_timer;
+ constexpr static int MaxMultiplier = 8;
+};
+
class GMainWindow : public QMainWindow {
Q_OBJECT
@@ -481,7 +504,7 @@ private:
QPushButton* dock_status_button = nullptr;
QPushButton* filter_status_button = nullptr;
QPushButton* aa_status_button = nullptr;
- QPushButton* volume_button = nullptr;
+ VolumeButton* volume_button = nullptr;
QWidget* volume_popup = nullptr;
QSlider* volume_slider = nullptr;
QTimer status_bar_update_timer;
diff --git a/src/yuzu/mini_dump.cpp b/src/yuzu/mini_dump.cpp
deleted file mode 100644
index a34dc6a9c..000000000
--- a/src/yuzu/mini_dump.cpp
+++ /dev/null
@@ -1,202 +0,0 @@
-// SPDX-FileCopyrightText: 2022 yuzu Emulator Project
-// SPDX-License-Identifier: GPL-2.0-or-later
-
-#include <cstdio>
-#include <cstring>
-#include <ctime>
-#include <filesystem>
-#include <fmt/format.h>
-#include <windows.h>
-#include "yuzu/mini_dump.h"
-#include "yuzu/startup_checks.h"
-
-// dbghelp.h must be included after windows.h
-#include <dbghelp.h>
-
-namespace MiniDump {
-
-void CreateMiniDump(HANDLE process_handle, DWORD process_id, MINIDUMP_EXCEPTION_INFORMATION* info,
- EXCEPTION_POINTERS* pep) {
- char file_name[255];
- const std::time_t the_time = std::time(nullptr);
- std::strftime(file_name, 255, "yuzu-crash-%Y%m%d%H%M%S.dmp", std::localtime(&the_time));
-
- // Open the file
- HANDLE file_handle = CreateFileA(file_name, GENERIC_READ | GENERIC_WRITE, 0, nullptr,
- CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, nullptr);
-
- if (file_handle == nullptr || file_handle == INVALID_HANDLE_VALUE) {
- fmt::print(stderr, "CreateFileA failed. Error: {}", GetLastError());
- return;
- }
-
- // Create the minidump
- const MINIDUMP_TYPE dump_type = MiniDumpNormal;
-
- const bool write_dump_status = MiniDumpWriteDump(process_handle, process_id, file_handle,
- dump_type, (pep != 0) ? info : 0, 0, 0);
-
- if (write_dump_status) {
- fmt::print(stderr, "MiniDump created: {}", file_name);
- } else {
- fmt::print(stderr, "MiniDumpWriteDump failed. Error: {}", GetLastError());
- }
-
- // Close the file
- CloseHandle(file_handle);
-}
-
-void DumpFromDebugEvent(DEBUG_EVENT& deb_ev, PROCESS_INFORMATION& pi) {
- EXCEPTION_RECORD& record = deb_ev.u.Exception.ExceptionRecord;
-
- HANDLE thread_handle = OpenThread(THREAD_GET_CONTEXT, false, deb_ev.dwThreadId);
- if (thread_handle == nullptr) {
- fmt::print(stderr, "OpenThread failed ({})", GetLastError());
- return;
- }
-
- // Get child process context
- CONTEXT context = {};
- context.ContextFlags = CONTEXT_ALL;
- if (!GetThreadContext(thread_handle, &context)) {
- fmt::print(stderr, "GetThreadContext failed ({})", GetLastError());
- return;
- }
-
- // Create exception pointers for minidump
- EXCEPTION_POINTERS ep;
- ep.ExceptionRecord = &record;
- ep.ContextRecord = &context;
-
- MINIDUMP_EXCEPTION_INFORMATION info;
- info.ThreadId = deb_ev.dwThreadId;
- info.ExceptionPointers = &ep;
- info.ClientPointers = false;
-
- CreateMiniDump(pi.hProcess, pi.dwProcessId, &info, &ep);
-
- if (CloseHandle(thread_handle) == 0) {
- fmt::print(stderr, "error: CloseHandle(thread_handle) failed ({})", GetLastError());
- }
-}
-
-bool SpawnDebuggee(const char* arg0, PROCESS_INFORMATION& pi) {
- std::memset(&pi, 0, sizeof(pi));
-
- // Don't debug if we are already being debugged
- if (IsDebuggerPresent()) {
- return false;
- }
-
- if (!SpawnChild(arg0, &pi, 0)) {
- fmt::print(stderr, "warning: continuing without crash dumps");
- return false;
- }
-
- const bool can_debug = DebugActiveProcess(pi.dwProcessId);
- if (!can_debug) {
- fmt::print(stderr,
- "warning: DebugActiveProcess failed ({}), continuing without crash dumps",
- GetLastError());
- return false;
- }
-
- return true;
-}
-
-static const char* ExceptionName(DWORD exception) {
- switch (exception) {
- case EXCEPTION_ACCESS_VIOLATION:
- return "EXCEPTION_ACCESS_VIOLATION";
- case EXCEPTION_DATATYPE_MISALIGNMENT:
- return "EXCEPTION_DATATYPE_MISALIGNMENT";
- case EXCEPTION_BREAKPOINT:
- return "EXCEPTION_BREAKPOINT";
- case EXCEPTION_SINGLE_STEP:
- return "EXCEPTION_SINGLE_STEP";
- case EXCEPTION_ARRAY_BOUNDS_EXCEEDED:
- return "EXCEPTION_ARRAY_BOUNDS_EXCEEDED";
- case EXCEPTION_FLT_DENORMAL_OPERAND:
- return "EXCEPTION_FLT_DENORMAL_OPERAND";
- case EXCEPTION_FLT_DIVIDE_BY_ZERO:
- return "EXCEPTION_FLT_DIVIDE_BY_ZERO";
- case EXCEPTION_FLT_INEXACT_RESULT:
- return "EXCEPTION_FLT_INEXACT_RESULT";
- case EXCEPTION_FLT_INVALID_OPERATION:
- return "EXCEPTION_FLT_INVALID_OPERATION";
- case EXCEPTION_FLT_OVERFLOW:
- return "EXCEPTION_FLT_OVERFLOW";
- case EXCEPTION_FLT_STACK_CHECK:
- return "EXCEPTION_FLT_STACK_CHECK";
- case EXCEPTION_FLT_UNDERFLOW:
- return "EXCEPTION_FLT_UNDERFLOW";
- case EXCEPTION_INT_DIVIDE_BY_ZERO:
- return "EXCEPTION_INT_DIVIDE_BY_ZERO";
- case EXCEPTION_INT_OVERFLOW:
- return "EXCEPTION_INT_OVERFLOW";
- case EXCEPTION_PRIV_INSTRUCTION:
- return "EXCEPTION_PRIV_INSTRUCTION";
- case EXCEPTION_IN_PAGE_ERROR:
- return "EXCEPTION_IN_PAGE_ERROR";
- case EXCEPTION_ILLEGAL_INSTRUCTION:
- return "EXCEPTION_ILLEGAL_INSTRUCTION";
- case EXCEPTION_NONCONTINUABLE_EXCEPTION:
- return "EXCEPTION_NONCONTINUABLE_EXCEPTION";
- case EXCEPTION_STACK_OVERFLOW:
- return "EXCEPTION_STACK_OVERFLOW";
- case EXCEPTION_INVALID_DISPOSITION:
- return "EXCEPTION_INVALID_DISPOSITION";
- case EXCEPTION_GUARD_PAGE:
- return "EXCEPTION_GUARD_PAGE";
- case EXCEPTION_INVALID_HANDLE:
- return "EXCEPTION_INVALID_HANDLE";
- default:
- return "unknown exception type";
- }
-}
-
-void DebugDebuggee(PROCESS_INFORMATION& pi) {
- DEBUG_EVENT deb_ev = {};
-
- while (deb_ev.dwDebugEventCode != EXIT_PROCESS_DEBUG_EVENT) {
- const bool wait_success = WaitForDebugEvent(&deb_ev, INFINITE);
- if (!wait_success) {
- fmt::print(stderr, "error: WaitForDebugEvent failed ({})", GetLastError());
- return;
- }
-
- switch (deb_ev.dwDebugEventCode) {
- case OUTPUT_DEBUG_STRING_EVENT:
- case CREATE_PROCESS_DEBUG_EVENT:
- case CREATE_THREAD_DEBUG_EVENT:
- case EXIT_PROCESS_DEBUG_EVENT:
- case EXIT_THREAD_DEBUG_EVENT:
- case LOAD_DLL_DEBUG_EVENT:
- case RIP_EVENT:
- case UNLOAD_DLL_DEBUG_EVENT:
- // Continue on all other debug events
- ContinueDebugEvent(deb_ev.dwProcessId, deb_ev.dwThreadId, DBG_CONTINUE);
- break;
- case EXCEPTION_DEBUG_EVENT:
- EXCEPTION_RECORD& record = deb_ev.u.Exception.ExceptionRecord;
-
- // We want to generate a crash dump if we are seeing the same exception again.
- if (!deb_ev.u.Exception.dwFirstChance) {
- fmt::print(stderr, "Creating MiniDump on ExceptionCode: 0x{:08x} {}\n",
- record.ExceptionCode, ExceptionName(record.ExceptionCode));
- DumpFromDebugEvent(deb_ev, pi);
- }
-
- // Continue without handling the exception.
- // Lets the debuggee use its own exception handler.
- // - If one does not exist, we will see the exception once more where we make a minidump
- // for. Then when it reaches here again, yuzu will probably crash.
- // - DBG_CONTINUE on an exception that the debuggee does not handle can set us up for an
- // infinite loop of exceptions.
- ContinueDebugEvent(deb_ev.dwProcessId, deb_ev.dwThreadId, DBG_EXCEPTION_NOT_HANDLED);
- break;
- }
- }
-}
-
-} // namespace MiniDump
diff --git a/src/yuzu/mini_dump.h b/src/yuzu/mini_dump.h
deleted file mode 100644
index d6b6cca84..000000000
--- a/src/yuzu/mini_dump.h
+++ /dev/null
@@ -1,19 +0,0 @@
-// SPDX-FileCopyrightText: 2022 yuzu Emulator Project
-// SPDX-License-Identifier: GPL-2.0-or-later
-
-#pragma once
-
-#include <windows.h>
-
-#include <dbghelp.h>
-
-namespace MiniDump {
-
-void CreateMiniDump(HANDLE process_handle, DWORD process_id, MINIDUMP_EXCEPTION_INFORMATION* info,
- EXCEPTION_POINTERS* pep);
-
-void DumpFromDebugEvent(DEBUG_EVENT& deb_ev, PROCESS_INFORMATION& pi);
-bool SpawnDebuggee(const char* arg0, PROCESS_INFORMATION& pi);
-void DebugDebuggee(PROCESS_INFORMATION& pi);
-
-} // namespace MiniDump
diff --git a/src/yuzu/uisettings.h b/src/yuzu/uisettings.h
index b62ff620c..3485a6347 100644
--- a/src/yuzu/uisettings.h
+++ b/src/yuzu/uisettings.h
@@ -93,10 +93,6 @@ struct Values {
Setting<bool> show_filter_bar{linkage, true, "showFilterBar", Category::Ui};
Setting<bool> show_status_bar{linkage, true, "showStatusBar", Category::Ui};
- Setting<bool> confirm_before_closing{
- linkage, true, "confirmClose", Category::UiGeneral, Settings::Specialization::Default,
- true, true};
-
SwitchableSetting<ConfirmStop> confirm_before_stopping{linkage,
ConfirmStop::Ask_Always,
"confirmStop",
@@ -113,9 +109,13 @@ struct Values {
Settings::Specialization::Default,
true,
true};
- Setting<bool> mute_when_in_background{
- linkage, false, "muteWhenInBackground", Category::Audio, Settings::Specialization::Default,
- true, true};
+ Setting<bool> mute_when_in_background{linkage,
+ false,
+ "muteWhenInBackground",
+ Category::UiAudio,
+ Settings::Specialization::Default,
+ true,
+ true};
Setting<bool> hide_mouse{
linkage, true, "hideInactiveMouse", Category::UiGeneral, Settings::Specialization::Default,
true, true};
diff --git a/src/yuzu/vk_device_info.cpp b/src/yuzu/vk_device_info.cpp
index 92f10d315..ab0d39c25 100644
--- a/src/yuzu/vk_device_info.cpp
+++ b/src/yuzu/vk_device_info.cpp
@@ -31,6 +31,7 @@ void PopulateRecords(std::vector<Record>& records, QWindow* window) try {
// Create a test window with a Vulkan surface type for checking present modes.
QWindow test_window(window);
test_window.setSurfaceType(QWindow::VulkanSurface);
+ test_window.create();
auto wsi = QtCommon::GetWindowSystemInfo(&test_window);
vk::InstanceDispatch dld;