summaryrefslogtreecommitdiff
path: root/src/yuzu
diff options
context:
space:
mode:
Diffstat (limited to 'src/yuzu')
-rw-r--r--src/yuzu/bootmanager.cpp117
-rw-r--r--src/yuzu/bootmanager.h61
-rw-r--r--src/yuzu/configuration/config.cpp4
-rw-r--r--src/yuzu/configuration/configure_input_player.cpp12
-rw-r--r--src/yuzu/configuration/configure_input_player.h3
-rw-r--r--src/yuzu/configuration/configure_input_player.ui19
-rw-r--r--src/yuzu/configuration/configure_system.cpp4
-rw-r--r--src/yuzu/configuration/configure_system.ui14
-rw-r--r--src/yuzu/game_list.cpp14
-rw-r--r--src/yuzu/game_list.h7
-rw-r--r--src/yuzu/main.cpp365
-rw-r--r--src/yuzu/main.h16
-rw-r--r--src/yuzu/startup_checks.cpp2
-rw-r--r--src/yuzu/uisettings.h1
-rw-r--r--src/yuzu/util/overlay_dialog.cpp21
-rw-r--r--src/yuzu/util/overlay_dialog.h1
16 files changed, 447 insertions, 214 deletions
diff --git a/src/yuzu/bootmanager.cpp b/src/yuzu/bootmanager.cpp
index 5b5b6fed8..3d560f303 100644
--- a/src/yuzu/bootmanager.cpp
+++ b/src/yuzu/bootmanager.cpp
@@ -44,32 +44,30 @@
#include "yuzu/bootmanager.h"
#include "yuzu/main.h"
-EmuThread::EmuThread(Core::System& system_) : system{system_} {}
+static Core::Frontend::WindowSystemType GetWindowSystemType();
+
+EmuThread::EmuThread(Core::System& system) : m_system{system} {}
EmuThread::~EmuThread() = default;
void EmuThread::run() {
- std::string name = "EmuControlThread";
- MicroProfileOnThreadCreate(name.c_str());
- Common::SetCurrentThreadName(name.c_str());
+ const char* name = "EmuControlThread";
+ MicroProfileOnThreadCreate(name);
+ Common::SetCurrentThreadName(name);
- auto& gpu = system.GPU();
- auto stop_token = stop_source.get_token();
- bool debugger_should_start = system.DebuggerEnabled();
+ auto& gpu = m_system.GPU();
+ auto stop_token = m_stop_source.get_token();
- system.RegisterHostThread();
+ m_system.RegisterHostThread();
// Main process has been loaded. Make the context current to this thread and begin GPU and CPU
// execution.
- gpu.Start();
-
gpu.ObtainContext();
emit LoadProgress(VideoCore::LoadCallbackStage::Prepare, 0, 0);
-
if (Settings::values.use_disk_shader_cache.GetValue()) {
- system.Renderer().ReadRasterizer()->LoadDiskResources(
- system.GetCurrentProcessProgramID(), stop_token,
+ m_system.Renderer().ReadRasterizer()->LoadDiskResources(
+ m_system.GetCurrentProcessProgramID(), stop_token,
[this](VideoCore::LoadCallbackStage stage, std::size_t value, std::size_t total) {
emit LoadProgress(stage, value, total);
});
@@ -77,53 +75,36 @@ void EmuThread::run() {
emit LoadProgress(VideoCore::LoadCallbackStage::Complete, 0, 0);
gpu.ReleaseContext();
+ gpu.Start();
- system.GetCpuManager().OnGpuReady();
-
- // Holds whether the cpu was running during the last iteration,
- // so that the DebugModeLeft signal can be emitted before the
- // next execution step
- bool was_active = false;
- while (!stop_token.stop_requested()) {
- if (running) {
- if (was_active) {
- emit DebugModeLeft();
- }
-
- running_guard = true;
- Core::SystemResultStatus result = system.Run();
- if (result != Core::SystemResultStatus::Success) {
- running_guard = false;
- this->SetRunning(false);
- emit ErrorThrown(result, system.GetStatusDetails());
- }
+ m_system.GetCpuManager().OnGpuReady();
- if (debugger_should_start) {
- system.InitializeDebugger();
- debugger_should_start = false;
- }
+ if (m_system.DebuggerEnabled()) {
+ m_system.InitializeDebugger();
+ }
- running_wait.Wait();
- result = system.Pause();
- if (result != Core::SystemResultStatus::Success) {
- running_guard = false;
- this->SetRunning(false);
- emit ErrorThrown(result, system.GetStatusDetails());
- }
- running_guard = false;
+ while (!stop_token.stop_requested()) {
+ std::unique_lock lk{m_should_run_mutex};
+ if (m_should_run) {
+ m_system.Run();
+ m_is_running.store(true);
+ m_is_running.notify_all();
- if (!stop_token.stop_requested()) {
- was_active = true;
- emit DebugModeEntered();
- }
+ Common::CondvarWait(m_should_run_cv, lk, stop_token, [&] { return !m_should_run; });
} else {
- std::unique_lock lock{running_mutex};
- Common::CondvarWait(running_cv, lock, stop_token, [&] { return IsRunning(); });
+ m_system.Pause();
+ m_is_running.store(false);
+ m_is_running.notify_all();
+
+ emit DebugModeEntered();
+ Common::CondvarWait(m_should_run_cv, lk, stop_token, [&] { return m_should_run; });
+ emit DebugModeLeft();
}
}
// Shutdown the main emulated process
- system.ShutdownMainProcess();
+ m_system.DetachDebugger();
+ m_system.ShutdownMainProcess();
#if MICROPROFILE_ENABLED
MicroProfileOnThreadExit();
@@ -225,6 +206,9 @@ public:
explicit RenderWidget(GRenderWindow* parent) : QWidget(parent), render_window(parent) {
setAttribute(Qt::WA_NativeWindow);
setAttribute(Qt::WA_PaintOnScreen);
+ if (GetWindowSystemType() == Core::Frontend::WindowSystemType::Wayland) {
+ setAttribute(Qt::WA_DontCreateNativeAncestors);
+ }
}
virtual ~RenderWidget() = default;
@@ -269,12 +253,14 @@ static Core::Frontend::WindowSystemType GetWindowSystemType() {
return Core::Frontend::WindowSystemType::X11;
else if (platform_name == QStringLiteral("wayland"))
return Core::Frontend::WindowSystemType::Wayland;
+ else if (platform_name == QStringLiteral("wayland-egl"))
+ return Core::Frontend::WindowSystemType::Wayland;
else if (platform_name == QStringLiteral("cocoa"))
return Core::Frontend::WindowSystemType::Cocoa;
else if (platform_name == QStringLiteral("android"))
return Core::Frontend::WindowSystemType::Android;
- LOG_CRITICAL(Frontend, "Unknown Qt platform!");
+ LOG_CRITICAL(Frontend, "Unknown Qt platform {}!", platform_name.toStdString());
return Core::Frontend::WindowSystemType::Windows;
}
@@ -314,6 +300,9 @@ GRenderWindow::GRenderWindow(GMainWindow* parent, EmuThread* emu_thread_,
input_subsystem->Initialize();
this->setMouseTracking(true);
+ strict_context_required = QGuiApplication::platformName() == QStringLiteral("wayland") ||
+ QGuiApplication::platformName() == QStringLiteral("wayland-egl");
+
connect(this, &GRenderWindow::FirstFrameDisplayed, parent, &GMainWindow::OnLoadComplete);
connect(this, &GRenderWindow::ExecuteProgramSignal, parent, &GMainWindow::OnExecuteProgram,
Qt::QueuedConnection);
@@ -750,6 +739,9 @@ void GRenderWindow::InitializeCamera() {
return;
}
+ const auto camera_width = input_subsystem->GetCamera()->getImageWidth();
+ const auto camera_height = input_subsystem->GetCamera()->getImageHeight();
+ camera_data.resize(camera_width * camera_height);
camera_capture->setCaptureDestination(QCameraImageCapture::CaptureDestination::CaptureToBuffer);
connect(camera_capture.get(), &QCameraImageCapture::imageCaptured, this,
&GRenderWindow::OnCameraCapture);
@@ -805,17 +797,22 @@ void GRenderWindow::RequestCameraCapture() {
}
void GRenderWindow::OnCameraCapture(int requestId, const QImage& img) {
- constexpr std::size_t camera_width = 320;
- constexpr std::size_t camera_height = 240;
+#if (QT_VERSION < QT_VERSION_CHECK(6, 0, 0)) && YUZU_USE_QT_MULTIMEDIA
+ // TODO: Capture directly in the format and resolution needed
+ const auto camera_width = input_subsystem->GetCamera()->getImageWidth();
+ const auto camera_height = input_subsystem->GetCamera()->getImageHeight();
const auto converted =
- img.scaled(camera_width, camera_height, Qt::AspectRatioMode::IgnoreAspectRatio,
+ img.scaled(static_cast<int>(camera_width), static_cast<int>(camera_height),
+ Qt::AspectRatioMode::IgnoreAspectRatio,
Qt::TransformationMode::SmoothTransformation)
.mirrored(false, true);
- std::vector<u32> camera_data{};
- camera_data.resize(camera_width * camera_height);
+ if (camera_data.size() != camera_width * camera_height) {
+ camera_data.resize(camera_width * camera_height);
+ }
std::memcpy(camera_data.data(), converted.bits(), camera_width * camera_height * sizeof(u32));
input_subsystem->GetCamera()->SetCameraData(camera_width, camera_height, camera_data);
pending_camera_snapshots = 0;
+#endif
}
bool GRenderWindow::event(QEvent* event) {
@@ -952,6 +949,12 @@ void GRenderWindow::OnMinimalClientAreaChangeRequest(std::pair<u32, u32> minimal
bool GRenderWindow::InitializeOpenGL() {
#ifdef HAS_OPENGL
+ if (!QOpenGLContext::supportsThreadedOpenGL()) {
+ QMessageBox::warning(this, tr("OpenGL not available!"),
+ tr("OpenGL shared contexts are not supported."));
+ return false;
+ }
+
// TODO: One of these flags might be interesting: WA_OpaquePaintEvent, WA_NoBackground,
// WA_DontShowOnScreen, WA_DeleteOnClose
auto child = new OpenGLRenderWidget(this);
diff --git a/src/yuzu/bootmanager.h b/src/yuzu/bootmanager.h
index f4deae4ee..eca16b313 100644
--- a/src/yuzu/bootmanager.h
+++ b/src/yuzu/bootmanager.h
@@ -47,7 +47,7 @@ class EmuThread final : public QThread {
Q_OBJECT
public:
- explicit EmuThread(Core::System& system_);
+ explicit EmuThread(Core::System& system);
~EmuThread() override;
/**
@@ -57,48 +57,48 @@ public:
void run() override;
/**
- * Sets whether the emulation thread is running or not
- * @param running_ Boolean value, set the emulation thread to running if true
- * @note This function is thread-safe
+ * Sets whether the emulation thread should run or not
+ * @param should_run Boolean value, set the emulation thread to running if true
*/
- void SetRunning(bool running_) {
- std::unique_lock lock{running_mutex};
- running = running_;
- lock.unlock();
- running_cv.notify_all();
- if (!running) {
- running_wait.Set();
- /// Wait until effectively paused
- while (running_guard)
- ;
+ void SetRunning(bool should_run) {
+ // TODO: Prevent other threads from modifying the state until we finish.
+ {
+ // Notify the running thread to change state.
+ std::unique_lock run_lk{m_should_run_mutex};
+ m_should_run = should_run;
+ m_should_run_cv.notify_one();
+ }
+
+ // Wait until paused, if pausing.
+ if (!should_run) {
+ m_is_running.wait(true);
}
}
/**
* Check if the emulation thread is running or not
* @return True if the emulation thread is running, otherwise false
- * @note This function is thread-safe
*/
bool IsRunning() const {
- return running;
+ return m_is_running.load() || m_should_run;
}
/**
- * Requests for the emulation thread to stop running
+ * Requests for the emulation thread to immediately stop running
*/
- void RequestStop() {
- stop_source.request_stop();
- SetRunning(false);
+ void ForceStop() {
+ LOG_WARNING(Frontend, "Force stopping EmuThread");
+ m_stop_source.request_stop();
}
private:
- bool running = false;
- std::stop_source stop_source;
- std::mutex running_mutex;
- std::condition_variable_any running_cv;
- Common::Event running_wait{};
- std::atomic_bool running_guard{false};
- Core::System& system;
+ Core::System& m_system;
+
+ std::stop_source m_stop_source;
+ std::mutex m_should_run_mutex;
+ std::condition_variable_any m_should_run_cv;
+ std::atomic<bool> m_is_running{false};
+ bool m_should_run{true};
signals:
/**
@@ -119,8 +119,6 @@ signals:
*/
void DebugModeLeft();
- void ErrorThrown(Core::SystemResultStatus, std::string);
-
void LoadProgress(VideoCore::LoadCallbackStage stage, std::size_t value, std::size_t total);
};
@@ -241,13 +239,14 @@ private:
bool first_frame = false;
InputCommon::TasInput::TasState last_tas_state;
+#if (QT_VERSION < QT_VERSION_CHECK(6, 0, 0)) && YUZU_USE_QT_MULTIMEDIA
bool is_virtual_camera;
int pending_camera_snapshots;
-#if (QT_VERSION < QT_VERSION_CHECK(6, 0, 0)) && YUZU_USE_QT_MULTIMEDIA
+ std::vector<u32> camera_data;
std::unique_ptr<QCamera> camera;
std::unique_ptr<QCameraImageCapture> camera_capture;
-#endif
std::unique_ptr<QTimer> camera_timer;
+#endif
Core::System& system;
diff --git a/src/yuzu/configuration/config.cpp b/src/yuzu/configuration/config.cpp
index 722fc708e..2ea4f367b 100644
--- a/src/yuzu/configuration/config.cpp
+++ b/src/yuzu/configuration/config.cpp
@@ -697,7 +697,6 @@ void Config::ReadRendererValues() {
ReadGlobalSetting(Settings::values.fsr_sharpening_slider);
ReadGlobalSetting(Settings::values.anti_aliasing);
ReadGlobalSetting(Settings::values.max_anisotropy);
- ReadGlobalSetting(Settings::values.use_speed_limit);
ReadGlobalSetting(Settings::values.speed_limit);
ReadGlobalSetting(Settings::values.use_disk_shader_cache);
ReadGlobalSetting(Settings::values.gpu_accuracy);
@@ -796,6 +795,7 @@ void Config::ReadSystemValues() {
} else {
Settings::values.custom_rtc = std::nullopt;
}
+ ReadBasicSetting(Settings::values.device_name);
}
ReadGlobalSetting(Settings::values.sound_index);
@@ -1328,7 +1328,6 @@ void Config::SaveRendererValues() {
static_cast<u32>(Settings::values.anti_aliasing.GetDefault()),
Settings::values.anti_aliasing.UsingGlobal());
WriteGlobalSetting(Settings::values.max_anisotropy);
- WriteGlobalSetting(Settings::values.use_speed_limit);
WriteGlobalSetting(Settings::values.speed_limit);
WriteGlobalSetting(Settings::values.use_disk_shader_cache);
WriteSetting(QString::fromStdString(Settings::values.gpu_accuracy.GetLabel()),
@@ -1415,6 +1414,7 @@ void Config::SaveSystemValues() {
false);
WriteSetting(QStringLiteral("custom_rtc"),
QVariant::fromValue<long long>(Settings::values.custom_rtc.value_or(0)), 0);
+ WriteBasicSetting(Settings::values.device_name);
}
WriteGlobalSetting(Settings::values.sound_index);
diff --git a/src/yuzu/configuration/configure_input_player.cpp b/src/yuzu/configuration/configure_input_player.cpp
index b1575b0d3..183cbe562 100644
--- a/src/yuzu/configuration/configure_input_player.cpp
+++ b/src/yuzu/configuration/configure_input_player.cpp
@@ -738,13 +738,10 @@ ConfigureInputPlayer::ConfigureInputPlayer(QWidget* parent, std::size_t player_i
connect(ui->comboDevices, qOverload<int>(&QComboBox::activated), this,
&ConfigureInputPlayer::UpdateMappingWithDefaults);
+ ui->comboDevices->installEventFilter(this);
ui->comboDevices->setCurrentIndex(-1);
- ui->buttonRefreshDevices->setIcon(QIcon::fromTheme(QStringLiteral("view-refresh")));
- connect(ui->buttonRefreshDevices, &QPushButton::clicked,
- [this] { emit RefreshInputDevices(); });
-
timeout_timer->setSingleShot(true);
connect(timeout_timer.get(), &QTimer::timeout, [this] { SetPollingResult({}, true); });
@@ -1479,6 +1476,13 @@ void ConfigureInputPlayer::keyPressEvent(QKeyEvent* event) {
}
}
+bool ConfigureInputPlayer::eventFilter(QObject* object, QEvent* event) {
+ if (object == ui->comboDevices && event->type() == QEvent::MouseButtonPress) {
+ RefreshInputDevices();
+ }
+ return object->eventFilter(object, event);
+}
+
void ConfigureInputPlayer::CreateProfile() {
const auto profile_name =
LimitableInputDialog::GetText(this, tr("New Profile"), tr("Enter a profile name:"), 1, 30,
diff --git a/src/yuzu/configuration/configure_input_player.h b/src/yuzu/configuration/configure_input_player.h
index 26f60d121..6d1876f2b 100644
--- a/src/yuzu/configuration/configure_input_player.h
+++ b/src/yuzu/configuration/configure_input_player.h
@@ -119,6 +119,9 @@ private:
/// Handle key press events.
void keyPressEvent(QKeyEvent* event) override;
+ /// Handle combobox list refresh
+ bool eventFilter(QObject* object, QEvent* event) override;
+
/// Update UI to reflect current configuration.
void UpdateUI();
diff --git a/src/yuzu/configuration/configure_input_player.ui b/src/yuzu/configuration/configure_input_player.ui
index a62b57501..a9567c6ee 100644
--- a/src/yuzu/configuration/configure_input_player.ui
+++ b/src/yuzu/configuration/configure_input_player.ui
@@ -122,25 +122,6 @@
</property>
</widget>
</item>
- <item>
- <widget class="QPushButton" name="buttonRefreshDevices">
- <property name="minimumSize">
- <size>
- <width>21</width>
- <height>21</height>
- </size>
- </property>
- <property name="maximumSize">
- <size>
- <width>21</width>
- <height>21</height>
- </size>
- </property>
- <property name="styleSheet">
- <string notr="true"/>
- </property>
- </widget>
- </item>
</layout>
</widget>
</item>
diff --git a/src/yuzu/configuration/configure_system.cpp b/src/yuzu/configuration/configure_system.cpp
index bc9d9d77a..9b14e5903 100644
--- a/src/yuzu/configuration/configure_system.cpp
+++ b/src/yuzu/configuration/configure_system.cpp
@@ -72,6 +72,8 @@ void ConfigureSystem::SetConfiguration() {
ui->custom_rtc_checkbox->setChecked(Settings::values.custom_rtc.has_value());
ui->custom_rtc_edit->setEnabled(Settings::values.custom_rtc.has_value());
ui->custom_rtc_edit->setDateTime(QDateTime::fromSecsSinceEpoch(rtc_time));
+ ui->device_name_edit->setText(
+ QString::fromUtf8(Settings::values.device_name.GetValue().c_str()));
if (Settings::IsConfiguringGlobal()) {
ui->combo_language->setCurrentIndex(Settings::values.language_index.GetValue());
@@ -115,6 +117,8 @@ void ConfigureSystem::ApplyConfiguration() {
}
}
+ Settings::values.device_name = ui->device_name_edit->text().toStdString();
+
if (!enabled) {
return;
}
diff --git a/src/yuzu/configuration/configure_system.ui b/src/yuzu/configuration/configure_system.ui
index b234ea87b..46892f5c1 100644
--- a/src/yuzu/configuration/configure_system.ui
+++ b/src/yuzu/configuration/configure_system.ui
@@ -432,6 +432,13 @@
</property>
</widget>
</item>
+ <item row="7" column="0">
+ <widget class="QLabel" name="device_name_label">
+ <property name="text">
+ <string>Device Name</string>
+ </property>
+ </widget>
+ </item>
<item row="3" column="1">
<widget class="QComboBox" name="combo_sound">
<item>
@@ -476,6 +483,13 @@
</property>
</widget>
</item>
+ <item row="7" column="1">
+ <widget class="QLineEdit" name="device_name_edit">
+ <property name="maxLength">
+ <number>128</number>
+ </property>
+ </widget>
+ </item>
<item row="6" column="1">
<widget class="QLineEdit" name="rng_seed_edit">
<property name="sizePolicy">
diff --git a/src/yuzu/game_list.cpp b/src/yuzu/game_list.cpp
index 5c33c1b0f..22aa19c56 100644
--- a/src/yuzu/game_list.cpp
+++ b/src/yuzu/game_list.cpp
@@ -554,6 +554,12 @@ void GameList::AddGamePopup(QMenu& context_menu, u64 program_id, const std::stri
QAction* dump_romfs_sdmc = dump_romfs_menu->addAction(tr("Dump RomFS to SDMC"));
QAction* copy_tid = context_menu.addAction(tr("Copy Title ID to Clipboard"));
QAction* navigate_to_gamedb_entry = context_menu.addAction(tr("Navigate to GameDB entry"));
+#ifndef WIN32
+ QMenu* shortcut_menu = context_menu.addMenu(tr("Create Shortcut"));
+ QAction* create_desktop_shortcut = shortcut_menu->addAction(tr("Add to Desktop"));
+ QAction* create_applications_menu_shortcut =
+ shortcut_menu->addAction(tr("Add to Applications Menu"));
+#endif
context_menu.addSeparator();
QAction* properties = context_menu.addAction(tr("Properties"));
@@ -619,6 +625,14 @@ void GameList::AddGamePopup(QMenu& context_menu, u64 program_id, const std::stri
connect(navigate_to_gamedb_entry, &QAction::triggered, [this, program_id]() {
emit NavigateToGamedbEntryRequested(program_id, compatibility_list);
});
+#ifndef WIN32
+ connect(create_desktop_shortcut, &QAction::triggered, [this, program_id, path]() {
+ emit CreateShortcut(program_id, path, GameListShortcutTarget::Desktop);
+ });
+ connect(create_applications_menu_shortcut, &QAction::triggered, [this, program_id, path]() {
+ emit CreateShortcut(program_id, path, GameListShortcutTarget::Applications);
+ });
+#endif
connect(properties, &QAction::triggered,
[this, path]() { emit OpenPerGameGeneralRequested(path); });
};
diff --git a/src/yuzu/game_list.h b/src/yuzu/game_list.h
index cdf085019..f7ff93ed9 100644
--- a/src/yuzu/game_list.h
+++ b/src/yuzu/game_list.h
@@ -52,6 +52,11 @@ enum class DumpRomFSTarget {
SDMC,
};
+enum class GameListShortcutTarget {
+ Desktop,
+ Applications,
+};
+
enum class InstalledEntryType {
Game,
Update,
@@ -108,6 +113,8 @@ signals:
const std::string& game_path);
void DumpRomFSRequested(u64 program_id, const std::string& game_path, DumpRomFSTarget target);
void CopyTIDRequested(u64 program_id);
+ void CreateShortcut(u64 program_id, const std::string& game_path,
+ GameListShortcutTarget target);
void NavigateToGamedbEntryRequested(u64 program_id,
const CompatibilityList& compatibility_list);
void OpenPerGameGeneralRequested(const std::string& file);
diff --git a/src/yuzu/main.cpp b/src/yuzu/main.cpp
index b11b26f7b..524650144 100644
--- a/src/yuzu/main.cpp
+++ b/src/yuzu/main.cpp
@@ -4,6 +4,8 @@
#include <cinttypes>
#include <clocale>
#include <cmath>
+#include <fstream>
+#include <iostream>
#include <memory>
#include <thread>
#ifdef __APPLE__
@@ -1249,6 +1251,7 @@ void GMainWindow::ConnectWidgetEvents() {
connect(game_list, &GameList::CopyTIDRequested, this, &GMainWindow::OnGameListCopyTID);
connect(game_list, &GameList::NavigateToGamedbEntryRequested, this,
&GMainWindow::OnGameListNavigateToGamedbEntry);
+ connect(game_list, &GameList::CreateShortcut, this, &GMainWindow::OnGameListCreateShortcut);
connect(game_list, &GameList::AddDirectory, this, &GMainWindow::OnGameListAddDirectory);
connect(game_list_placeholder, &GameListPlaceholder::AddDirectory, this,
&GMainWindow::OnGameListAddDirectory);
@@ -1495,7 +1498,7 @@ void GMainWindow::SetupSigInterrupts() {
void GMainWindow::HandleSigInterrupt(int sig) {
if (sig == SIGINT) {
- exit(1);
+ _exit(1);
}
// Calling into Qt directly from a signal handler is not safe,
@@ -1547,8 +1550,9 @@ void GMainWindow::AllowOSSleep() {
bool GMainWindow::LoadROM(const QString& filename, u64 program_id, std::size_t program_index) {
// Shutdown previous session if the emu thread is still active...
- if (emu_thread != nullptr)
+ if (emu_thread != nullptr) {
ShutdownGame();
+ }
if (!render_window->InitRenderTarget()) {
return false;
@@ -1707,8 +1711,10 @@ void GMainWindow::BootGame(const QString& filename, u64 program_id, std::size_t
system->RegisterExecuteProgramCallback(
[this](std::size_t program_index_) { render_window->ExecuteProgram(program_index_); });
- // Register an Exit callback such that Core can exit the currently running application.
- system->RegisterExitCallback([this]() { render_window->Exit(); });
+ system->RegisterExitCallback([this] {
+ emu_thread->ForceStop();
+ render_window->Exit();
+ });
connect(render_window, &GRenderWindow::Closed, this, &GMainWindow::OnStopGame);
connect(render_window, &GRenderWindow::MouseActivity, this, &GMainWindow::OnMouseActivity);
@@ -1779,9 +1785,9 @@ void GMainWindow::BootGame(const QString& filename, u64 program_id, std::size_t
OnStartGame();
}
-void GMainWindow::ShutdownGame() {
+bool GMainWindow::OnShutdownBegin() {
if (!emulation_running) {
- return;
+ return false;
}
if (ui->action_Fullscreen->isChecked()) {
@@ -1790,17 +1796,58 @@ void GMainWindow::ShutdownGame() {
AllowOSSleep();
+ // Disable unlimited frame rate
+ Settings::values.use_speed_limit.SetValue(true);
+
+ if (system->IsShuttingDown()) {
+ return false;
+ }
+
system->SetShuttingDown(true);
- system->DetachDebugger();
discord_rpc->Pause();
- emu_thread->RequestStop();
+
+ RequestGameExit();
+ emu_thread->disconnect();
+ emu_thread->SetRunning(true);
emit EmulationStopping();
- // Wait for emulation thread to complete and delete it
+ shutdown_timer.setSingleShot(true);
+ shutdown_timer.start(system->DebuggerEnabled() ? 0 : 5000);
+ connect(&shutdown_timer, &QTimer::timeout, this, &GMainWindow::OnEmulationStopTimeExpired);
+ connect(emu_thread.get(), &QThread::finished, this, &GMainWindow::OnEmulationStopped);
+
+ // Disable everything to prevent anything from being triggered here
+ ui->action_Pause->setEnabled(false);
+ ui->action_Restart->setEnabled(false);
+ ui->action_Stop->setEnabled(false);
+
+ return true;
+}
+
+void GMainWindow::OnShutdownBeginDialog() {
+ shutdown_dialog = new OverlayDialog(this, *system, QString{}, tr("Closing software..."),
+ QString{}, QString{}, Qt::AlignHCenter | Qt::AlignVCenter);
+ shutdown_dialog->open();
+}
+
+void GMainWindow::OnEmulationStopTimeExpired() {
+ if (emu_thread) {
+ emu_thread->ForceStop();
+ }
+}
+
+void GMainWindow::OnEmulationStopped() {
+ shutdown_timer.stop();
+ emu_thread->disconnect();
emu_thread->wait();
emu_thread = nullptr;
+ if (shutdown_dialog) {
+ shutdown_dialog->deleteLater();
+ shutdown_dialog = nullptr;
+ }
+
emulation_running = false;
discord_rpc->Update();
@@ -1846,6 +1893,20 @@ void GMainWindow::ShutdownGame() {
// When closing the game, destroy the GLWindow to clear the context after the game is closed
render_window->ReleaseRenderTarget();
+
+ Settings::RestoreGlobalState(system->IsPoweredOn());
+ system->HIDCore().ReloadInputDevices();
+ UpdateStatusButtons();
+}
+
+void GMainWindow::ShutdownGame() {
+ if (!emulation_running) {
+ return;
+ }
+
+ OnShutdownBegin();
+ OnEmulationStopTimeExpired();
+ OnEmulationStopped();
}
void GMainWindow::StoreRecentFile(const QString& filename) {
@@ -2375,6 +2436,152 @@ void GMainWindow::OnGameListNavigateToGamedbEntry(u64 program_id,
QDesktopServices::openUrl(QUrl(QStringLiteral("https://yuzu-emu.org/game/") + directory));
}
+void GMainWindow::OnGameListCreateShortcut(u64 program_id, const std::string& game_path,
+ GameListShortcutTarget target) {
+ // Get path to yuzu executable
+ const QStringList args = QApplication::arguments();
+ std::filesystem::path yuzu_command = args[0].toStdString();
+
+#if defined(__linux__) || defined(__FreeBSD__)
+ // If relative path, make it an absolute path
+ if (yuzu_command.c_str()[0] == '.') {
+ yuzu_command = Common::FS::GetCurrentDir() / yuzu_command;
+ }
+
+#if defined(__linux__)
+ // Warn once if we are making a shortcut to a volatile AppImage
+ const std::string appimage_ending =
+ std::string(Common::g_scm_rev).substr(0, 9).append(".AppImage");
+ if (yuzu_command.string().ends_with(appimage_ending) &&
+ !UISettings::values.shortcut_already_warned) {
+ if (QMessageBox::warning(this, tr("Create Shortcut"),
+ tr("This will create a shortcut to the current AppImage. This may "
+ "not work well if you update. Continue?"),
+ QMessageBox::StandardButton::Ok |
+ QMessageBox::StandardButton::Cancel) ==
+ QMessageBox::StandardButton::Cancel) {
+ return;
+ }
+ UISettings::values.shortcut_already_warned = true;
+ }
+#endif // __linux__
+#endif // __linux__ || __FreeBSD__
+
+ std::filesystem::path target_directory{};
+ // Determine target directory for shortcut
+#if defined(__linux__) || defined(__FreeBSD__)
+ 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");
+
+ if (target == GameListShortcutTarget::Desktop) {
+ target_directory = home_path / "Desktop";
+ if (!Common::FS::IsDir(target_directory)) {
+ QMessageBox::critical(
+ this, tr("Create Shortcut"),
+ tr("Cannot create shortcut on desktop. Path \"%1\" does not exist.")
+ .arg(QString::fromStdString(target_directory)),
+ QMessageBox::StandardButton::Ok);
+ return;
+ }
+ } else if (target == GameListShortcutTarget::Applications) {
+ target_directory = (xdg_data_home == nullptr ? home_path / ".local/share" : xdg_data_home) /
+ "applications";
+ if (!Common::FS::CreateDirs(target_directory)) {
+ QMessageBox::critical(this, tr("Create Shortcut"),
+ tr("Cannot create shortcut in applications menu. Path \"%1\" "
+ "does not exist and cannot be created.")
+ .arg(QString::fromStdString(target_directory)),
+ QMessageBox::StandardButton::Ok);
+ return;
+ }
+ }
+#endif
+
+ 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__)
+ std::filesystem::path system_icons_path =
+ (xdg_data_home == nullptr ? home_path / ".local/share/" : xdg_data_home) /
+ "icons/hicolor/256x256";
+ if (!Common::FS::CreateDirs(system_icons_path)) {
+ QMessageBox::critical(
+ this, tr("Create Icon"),
+ tr("Cannot create icon file. Path \"%1\" does not exist and cannot be created.")
+ .arg(QString::fromStdString(system_icons_path)),
+ QMessageBox::StandardButton::Ok);
+ return;
+ }
+ std::filesystem::path icon_path =
+ system_icons_path / (program_id == 0 ? fmt::format("yuzu-{}.png", game_file_name)
+ : fmt::format("yuzu-{:016X}.png", program_id));
+ const std::filesystem::path shortcut_path =
+ target_directory / (program_id == 0 ? fmt::format("yuzu-{}.desktop", game_file_name)
+ : fmt::format("yuzu-{:016X}.desktop", program_id));
+#else
+ const std::filesystem::path icon_path{};
+ const std::filesystem::path shortcut_path{};
+#endif
+
+ // Get title from game file
+ const FileSys::PatchManager pm{program_id, system->GetFileSystemController(),
+ system->GetContentProvider()};
+ const auto control = pm.GetControlMetadata();
+ const auto loader = Loader::GetLoader(*system, vfs->OpenFile(game_path, FileSys::Mode::Read));
+
+ std::string title{fmt::format("{:016X}", program_id)};
+
+ if (control.first != nullptr) {
+ title = control.first->GetApplicationName();
+ } else {
+ loader->ReadTitle(title);
+ }
+
+ // Get icon from game file
+ std::vector<u8> icon_image_file{};
+ if (control.second != nullptr) {
+ icon_image_file = control.second->ReadAllBytes();
+ } else if (loader->ReadIcon(icon_image_file) != Loader::ResultStatus::Success) {
+ LOG_WARNING(Frontend, "Could not read icon from {:s}", game_path);
+ }
+
+ QImage icon_jpeg =
+ QImage::fromData(icon_image_file.data(), static_cast<int>(icon_image_file.size()));
+#if defined(__linux__) || defined(__FreeBSD__)
+ // Convert and write the icon as a PNG
+ if (!icon_jpeg.save(QString::fromStdString(icon_path.string()))) {
+ LOG_ERROR(Frontend, "Could not write icon as PNG to file");
+ } else {
+ LOG_INFO(Frontend, "Wrote an icon to {}", icon_path.string());
+ }
+#endif // __linux__
+
+#if defined(__linux__) || defined(__FreeBSD__)
+ const std::string comment =
+ tr("Start %1 with the yuzu Emulator").arg(QString::fromStdString(title)).toStdString();
+ const std::string arguments = fmt::format("-g \"{:s}\"", game_path);
+ const std::string categories = "Game;Emulator;Qt;";
+ const std::string keywords = "Switch;Nintendo;";
+#else
+ const std::string comment{};
+ const std::string arguments{};
+ const std::string categories{};
+ const std::string keywords{};
+#endif
+ if (!CreateShortcut(shortcut_path.string(), title, comment, icon_path.string(),
+ yuzu_command.string(), arguments, categories, keywords)) {
+ QMessageBox::critical(this, tr("Create Shortcut"),
+ tr("Failed to create a shortcut at %1")
+ .arg(QString::fromStdString(shortcut_path.string())));
+ return;
+ }
+
+ LOG_INFO(Frontend, "Wrote a shortcut to {}", shortcut_path.string());
+ QMessageBox::information(
+ this, tr("Create Shortcut"),
+ tr("Successfully created a shortcut to %1").arg(QString::fromStdString(title)));
+}
+
void GMainWindow::OnGameListOpenDirectory(const QString& directory) {
std::filesystem::path fs_path;
if (directory == QStringLiteral("SDMC")) {
@@ -2508,6 +2715,9 @@ void GMainWindow::OnMenuInstallToNAND() {
return;
}
+ // Save folder location of the first selected file
+ UISettings::values.roms_path = QFileInfo(filenames[0]).path();
+
int remaining = filenames.size();
// This would only overflow above 2^43 bytes (8.796 TB)
@@ -2763,8 +2973,6 @@ void GMainWindow::OnStartGame() {
emu_thread->SetRunning(true);
- connect(emu_thread.get(), &EmuThread::ErrorThrown, this, &GMainWindow::OnCoreError);
-
UpdateMenuState();
OnTasStateChanged();
@@ -2801,11 +3009,9 @@ void GMainWindow::OnStopGame() {
return;
}
- ShutdownGame();
-
- Settings::RestoreGlobalState(system->IsPoweredOn());
- system->HIDCore().ReloadInputDevices();
- UpdateStatusButtons();
+ if (OnShutdownBegin()) {
+ OnShutdownBeginDialog();
+ }
}
void GMainWindow::OnLoadComplete() {
@@ -2912,9 +3118,15 @@ static QScreen* GuessCurrentScreen(QWidget* window) {
});
}
+bool GMainWindow::UsingExclusiveFullscreen() {
+ return Settings::values.fullscreen_mode.GetValue() == Settings::FullscreenMode::Exclusive ||
+ QGuiApplication::platformName() == QStringLiteral("wayland") ||
+ QGuiApplication::platformName() == QStringLiteral("wayland-egl");
+}
+
void GMainWindow::ShowFullscreen() {
- const auto show_fullscreen = [](QWidget* window) {
- if (Settings::values.fullscreen_mode.GetValue() == Settings::FullscreenMode::Exclusive) {
+ const auto show_fullscreen = [this](QWidget* window) {
+ if (UsingExclusiveFullscreen()) {
window->showFullScreen();
return;
}
@@ -2942,7 +3154,7 @@ void GMainWindow::ShowFullscreen() {
void GMainWindow::HideFullscreen() {
if (ui->action_Single_Window_Mode->isChecked()) {
- if (Settings::values.fullscreen_mode.GetValue() == Settings::FullscreenMode::Exclusive) {
+ if (UsingExclusiveFullscreen()) {
showNormal();
restoreGeometry(UISettings::values.geometry);
} else {
@@ -2956,7 +3168,7 @@ void GMainWindow::HideFullscreen() {
statusBar()->setVisible(ui->action_Show_Status_Bar->isChecked());
ui->menubar->show();
} else {
- if (Settings::values.fullscreen_mode.GetValue() == Settings::FullscreenMode::Exclusive) {
+ if (UsingExclusiveFullscreen()) {
render_window->showNormal();
render_window->restoreGeometry(UISettings::values.renderwindow_geometry);
} else {
@@ -3293,6 +3505,38 @@ void GMainWindow::OpenPerGameConfiguration(u64 title_id, const std::string& file
}
}
+bool GMainWindow::CreateShortcut(const std::string& shortcut_path, const std::string& title,
+ 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__)
+ // This desktop file template was writting referencing
+ // https://specifications.freedesktop.org/desktop-entry-spec/desktop-entry-spec-1.0.html
+ std::string shortcut_contents{};
+ shortcut_contents.append("[Desktop Entry]\n");
+ shortcut_contents.append("Type=Application\n");
+ shortcut_contents.append("Version=1.0\n");
+ shortcut_contents.append(fmt::format("Name={:s}\n", title));
+ shortcut_contents.append(fmt::format("Comment={:s}\n", comment));
+ shortcut_contents.append(fmt::format("Icon={:s}\n", icon_path));
+ shortcut_contents.append(fmt::format("TryExec={:s}\n", command));
+ shortcut_contents.append(fmt::format("Exec={:s} {:s}\n", command, arguments));
+ shortcut_contents.append(fmt::format("Categories={:s}\n", categories));
+ shortcut_contents.append(fmt::format("Keywords={:s}\n", keywords));
+
+ std::ofstream shortcut_stream(shortcut_path);
+ if (!shortcut_stream.is_open()) {
+ LOG_WARNING(Common, "Failed to create file {:s}", shortcut_path);
+ return false;
+ }
+ shortcut_stream << shortcut_contents;
+ shortcut_stream.close();
+
+ return true;
+#endif
+ return false;
+}
+
void GMainWindow::OnLoadAmiibo() {
if (emu_thread == nullptr || !emu_thread->IsRunning()) {
return;
@@ -3710,79 +3954,6 @@ void GMainWindow::OnMouseActivity() {
mouse_center_timer.stop();
}
-void GMainWindow::OnCoreError(Core::SystemResultStatus result, std::string details) {
- QMessageBox::StandardButton answer;
- QString status_message;
- const QString common_message =
- tr("The game you are trying to load requires additional files from your Switch to be "
- "dumped "
- "before playing.<br/><br/>For more information on dumping these files, please see the "
- "following wiki page: <a "
- "href='https://yuzu-emu.org/wiki/"
- "dumping-system-archives-and-the-shared-fonts-from-a-switch-console/'>Dumping System "
- "Archives and the Shared Fonts from a Switch Console</a>.<br/><br/>Would you like to "
- "quit "
- "back to the game list? Continuing emulation may result in crashes, corrupted save "
- "data, or other bugs.");
- switch (result) {
- case Core::SystemResultStatus::ErrorSystemFiles: {
- QString message;
- if (details.empty()) {
- message =
- tr("yuzu was unable to locate a Switch system archive. %1").arg(common_message);
- } else {
- message = tr("yuzu was unable to locate a Switch system archive: %1. %2")
- .arg(QString::fromStdString(details), common_message);
- }
-
- answer = QMessageBox::question(this, tr("System Archive Not Found"), message,
- QMessageBox::Yes | QMessageBox::No, QMessageBox::No);
- status_message = tr("System Archive Missing");
- break;
- }
-
- case Core::SystemResultStatus::ErrorSharedFont: {
- const QString message =
- tr("yuzu was unable to locate the Switch shared fonts. %1").arg(common_message);
- answer = QMessageBox::question(this, tr("Shared Fonts Not Found"), message,
- QMessageBox::Yes | QMessageBox::No, QMessageBox::No);
- status_message = tr("Shared Font Missing");
- break;
- }
-
- default:
- answer = QMessageBox::question(
- this, tr("Fatal Error"),
- tr("yuzu has encountered a fatal error, please see the log for more details. "
- "For more information on accessing the log, please see the following page: "
- "<a href='https://community.citra-emu.org/t/how-to-upload-the-log-file/296'>How "
- "to "
- "Upload the Log File</a>.<br/><br/>Would you like to quit back to the game "
- "list? "
- "Continuing emulation may result in crashes, corrupted save data, or other "
- "bugs."),
- QMessageBox::Yes | QMessageBox::No, QMessageBox::No);
- status_message = tr("Fatal Error encountered");
- break;
- }
-
- if (answer == QMessageBox::Yes) {
- if (emu_thread) {
- ShutdownGame();
-
- Settings::RestoreGlobalState(system->IsPoweredOn());
- system->HIDCore().ReloadInputDevices();
- UpdateStatusButtons();
- }
- } else {
- // Only show the message if the game is still running.
- if (emu_thread) {
- emu_thread->SetRunning(true);
- message_label->setText(status_message);
- }
- }
-}
-
void GMainWindow::OnReinitializeKeys(ReinitializeKeyBehavior behavior) {
if (behavior == ReinitializeKeyBehavior::Warning) {
const auto res = QMessageBox::information(
@@ -3927,10 +4098,6 @@ void GMainWindow::closeEvent(QCloseEvent* event) {
// Shutdown session if the emu thread is active...
if (emu_thread != nullptr) {
ShutdownGame();
-
- Settings::RestoreGlobalState(system->IsPoweredOn());
- system->HIDCore().ReloadInputDevices();
- UpdateStatusButtons();
}
render_window->close();
@@ -4023,6 +4190,10 @@ bool GMainWindow::ConfirmForceLockedExit() {
}
void GMainWindow::RequestGameExit() {
+ if (!system->IsPoweredOn()) {
+ return;
+ }
+
auto& sm{system->ServiceManager()};
auto applet_oe = sm.GetService<Service::AM::AppletOE>("appletOE");
auto applet_ae = sm.GetService<Service::AM::AppletAE>("appletAE");
diff --git a/src/yuzu/main.h b/src/yuzu/main.h
index 62d629973..db318485d 100644
--- a/src/yuzu/main.h
+++ b/src/yuzu/main.h
@@ -29,6 +29,7 @@ class GImageInfo;
class GRenderWindow;
class LoadingScreen;
class MicroProfileDialog;
+class OverlayDialog;
class ProfilerWidget;
class ControllerDialog;
class QLabel;
@@ -38,6 +39,7 @@ class QProgressDialog;
class WaitTreeWidget;
enum class GameListOpenTarget;
enum class GameListRemoveTarget;
+enum class GameListShortcutTarget;
enum class DumpRomFSTarget;
enum class InstalledEntryType;
class GameListPlaceholder;
@@ -293,6 +295,8 @@ private slots:
void OnGameListCopyTID(u64 program_id);
void OnGameListNavigateToGamedbEntry(u64 program_id,
const CompatibilityList& compatibility_list);
+ void OnGameListCreateShortcut(u64 program_id, const std::string& game_path,
+ GameListShortcutTarget target);
void OnGameListOpenDirectory(const QString& directory);
void OnGameListAddDirectory();
void OnGameListShowList(bool show);
@@ -320,6 +324,7 @@ private slots:
void OnDisplayTitleBars(bool);
void InitializeHotkeys();
void ToggleFullscreen();
+ bool UsingExclusiveFullscreen();
void ShowFullscreen();
void HideFullscreen();
void ToggleWindowMode();
@@ -328,10 +333,13 @@ private slots:
void ResetWindowSize900();
void ResetWindowSize1080();
void OnCaptureScreenshot();
- void OnCoreError(Core::SystemResultStatus, std::string);
void OnReinitializeKeys(ReinitializeKeyBehavior behavior);
void OnLanguageChanged(const QString& locale);
void OnMouseActivity();
+ bool OnShutdownBegin();
+ void OnShutdownBeginDialog();
+ void OnEmulationStopped();
+ void OnEmulationStopTimeExpired();
private:
QString GetGameListErrorRemoving(InstalledEntryType type) const;
@@ -365,6 +373,10 @@ private:
bool CheckDarkMode();
QString GetTasStateDescription() const;
+ bool CreateShortcut(const std::string& shortcut_path, const std::string& title,
+ 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);
std::unique_ptr<Ui::MainWindow> ui;
@@ -377,6 +389,8 @@ private:
GRenderWindow* render_window;
GameList* game_list;
LoadingScreen* loading_screen;
+ QTimer shutdown_timer;
+ OverlayDialog* shutdown_dialog{};
GameListPlaceholder* game_list_placeholder;
diff --git a/src/yuzu/startup_checks.cpp b/src/yuzu/startup_checks.cpp
index 563818362..9f702fe95 100644
--- a/src/yuzu/startup_checks.cpp
+++ b/src/yuzu/startup_checks.cpp
@@ -186,7 +186,7 @@ pid_t SpawnChild(const char* arg0) {
return pid;
} else if (pid == 0) {
// child
- execl(arg0, arg0, nullptr);
+ execlp(arg0, arg0, nullptr);
const int err = errno;
fmt::print(stderr, "execl failed with error {}\n", err);
_exit(0);
diff --git a/src/yuzu/uisettings.h b/src/yuzu/uisettings.h
index 452038cd9..2006b883e 100644
--- a/src/yuzu/uisettings.h
+++ b/src/yuzu/uisettings.h
@@ -138,6 +138,7 @@ struct Values {
bool configuration_applied;
bool reset_to_defaults;
+ bool shortcut_already_warned{false};
Settings::Setting<bool> disable_web_applet{true, "disable_web_applet"};
};
diff --git a/src/yuzu/util/overlay_dialog.cpp b/src/yuzu/util/overlay_dialog.cpp
index b27954512..796f5bf41 100644
--- a/src/yuzu/util/overlay_dialog.cpp
+++ b/src/yuzu/util/overlay_dialog.cpp
@@ -3,6 +3,7 @@
#include <QKeyEvent>
#include <QScreen>
+#include <QWindow>
#include "core/core.h"
#include "core/hid/hid_types.h"
@@ -42,7 +43,7 @@ OverlayDialog::OverlayDialog(QWidget* parent, Core::System& system, const QStrin
MoveAndResizeWindow();
// TODO (Morph): Remove this when InputInterpreter no longer relies on the HID backend
- if (system.IsPoweredOn()) {
+ if (system.IsPoweredOn() && !ui->buttonsDialog->isHidden()) {
input_interpreter = std::make_unique<InputInterpreter>(system);
StartInputThread();
@@ -83,6 +84,11 @@ void OverlayDialog::InitializeRegularTextDialog(const QString& title_text, const
ui->button_ok_label->setEnabled(false);
}
+ if (ui->button_cancel->isHidden() && ui->button_ok_label->isHidden()) {
+ ui->buttonsDialog->hide();
+ return;
+ }
+
connect(
ui->button_cancel, &QPushButton::clicked, this,
[this](bool) {
@@ -130,6 +136,11 @@ void OverlayDialog::InitializeRichTextDialog(const QString& title_text, const QS
ui->button_ok_rich->setEnabled(false);
}
+ if (ui->button_cancel_rich->isHidden() && ui->button_ok_rich->isHidden()) {
+ ui->buttonsRichDialog->hide();
+ return;
+ }
+
connect(
ui->button_cancel_rich, &QPushButton::clicked, this,
[this](bool) {
@@ -152,7 +163,7 @@ void OverlayDialog::MoveAndResizeWindow() {
const auto height = static_cast<float>(parentWidget()->height());
// High DPI
- const float dpi_scale = qApp->screenAt(pos)->logicalDotsPerInch() / 96.0f;
+ const float dpi_scale = parentWidget()->windowHandle()->screen()->logicalDotsPerInch() / 96.0f;
const auto title_text_font_size = BASE_TITLE_FONT_SIZE * (height / BASE_HEIGHT) / dpi_scale;
const auto body_text_font_size =
@@ -249,3 +260,9 @@ void OverlayDialog::InputThread() {
std::this_thread::sleep_for(std::chrono::milliseconds(50));
}
}
+
+void OverlayDialog::keyPressEvent(QKeyEvent* e) {
+ if (!ui->buttonsDialog->isHidden() || e->key() != Qt::Key_Escape) {
+ QDialog::keyPressEvent(e);
+ }
+}
diff --git a/src/yuzu/util/overlay_dialog.h b/src/yuzu/util/overlay_dialog.h
index 39c44393c..872283d61 100644
--- a/src/yuzu/util/overlay_dialog.h
+++ b/src/yuzu/util/overlay_dialog.h
@@ -94,6 +94,7 @@ private:
/// The thread where input is being polled and processed.
void InputThread();
+ void keyPressEvent(QKeyEvent* e) override;
std::unique_ptr<Ui::OverlayDialog> ui;