diff options
Diffstat (limited to 'src/yuzu')
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;  | 
