Qt: Work around broken dialogs in MacOS 26

pull/3575/head
Stenzek 2 months ago
parent 1e41408753
commit ceb6757524
No known key found for this signature in database

@ -20,6 +20,7 @@ AchievementLoginDialog::AchievementLoginDialog(QWidget* parent, Achievements::Lo
title_font.setPixelSize(20);
m_ui.titleLabel->setFont(title_font);
setWindowFlags(windowFlags() & ~Qt::WindowContextHelpButtonHint);
setAttribute(Qt::WA_DeleteOnClose, true);
// Adjust text if needed based on reason.
if (reason == Achievements::LoginRequestReason::TokenInvalid)

@ -237,10 +237,13 @@ void AchievementSettingsWidget::onLoginLogoutPressed()
return;
}
AchievementLoginDialog login(this, Achievements::LoginRequestReason::UserInitiated);
if (login.exec() == QDialog::Rejected)
return;
AchievementLoginDialog* login = new AchievementLoginDialog(this, Achievements::LoginRequestReason::UserInitiated);
connect(login, &AchievementLoginDialog::accepted, this, &AchievementSettingsWidget::onLoginCompleted);
login->show();
}
void AchievementSettingsWidget::onLoginCompleted()
{
updateLoginState();
// Login can enable achievements/hardcore.

@ -23,6 +23,7 @@ private:
void onAchievementsNotificationDurationSliderChanged();
void onLeaderboardsNotificationDurationSliderChanged();
void onLoginLogoutPressed();
void onLoginCompleted();
void onViewProfilePressed();
void onAchievementsRefreshed(quint32 id, const QString& game_info_string);

@ -189,15 +189,14 @@ void ConsoleSettingsWidget::onEnableCPUClockSpeedControlChecked(int state)
"system requirements.\n\nBy enabling this option you are agreeing to not create any bug reports unless you "
"have confirmed the bug also occurs with overclocking disabled.\n\nThis warning will only be shown once.");
QMessageBox mb(QMessageBox::Warning, tr("CPU Overclocking Warning"), message, QMessageBox::NoButton, this);
mb.setWindowModality(Qt::WindowModal);
const QAbstractButton* const yes_button =
mb.addButton(tr("Yes, I will confirm bugs without overclocking before reporting."), QMessageBox::YesRole);
mb.addButton(tr("No, take me back to safety."), QMessageBox::NoRole);
mb.exec();
if (mb.clickedButton() != yes_button)
{
QMessageBox* mb =
new QMessageBox(QMessageBox::Warning, tr("CPU Overclocking Warning"), message, QMessageBox::NoButton, this);
mb->setAttribute(Qt::WA_DeleteOnClose, true);
mb->setWindowModality(Qt::WindowModal);
const QPushButton* const yes_button =
mb->addButton(tr("Yes, I will confirm bugs without overclocking before reporting."), QMessageBox::YesRole);
const QPushButton* const no_button = mb->addButton(tr("No, take me back to safety."), QMessageBox::NoRole);
connect(no_button, &QPushButton::clicked, this, [this]() {
QSignalBlocker sb(m_ui.enableCPUClockSpeedControl);
if (m_dialog->isPerGameSettings())
{
@ -210,11 +209,14 @@ void ConsoleSettingsWidget::onEnableCPUClockSpeedControlChecked(int state)
m_dialog->setBoolSettingValue("CPU", "OverclockEnable", false);
}
return;
}
Host::SetBaseBoolSettingValue("UI", "CPUOverclockingWarningShown", true);
Host::CommitBaseSettingChanges();
m_ui.cpuClockSpeed->setEnabled(m_dialog->getEffectiveBoolValue("CPU", "OverclockEnable", false));
updateCPUClockSpeedLabel();
});
connect(yes_button, &QPushButton::clicked, this, []() {
Host::SetBaseBoolSettingValue("UI", "CPUOverclockingWarningShown", true);
Host::CommitBaseSettingChanges();
});
mb->show();
}
m_ui.cpuClockSpeed->setEnabled(m_dialog->getEffectiveBoolValue("CPU", "OverclockEnable", false));

@ -373,22 +373,23 @@ void GameSummaryWidget::populateTracksInfo()
void GameSummaryWidget::onCompatibilityCommentsClicked()
{
QDialog dlg(QtUtils::GetRootWidget(this));
dlg.resize(QSize(700, 400));
dlg.setWindowModality(Qt::WindowModal);
dlg.setWindowTitle(tr("Compatibility Report"));
QDialog* dlg = new QDialog(QtUtils::GetRootWidget(this));
dlg->resize(QSize(700, 400));
dlg->setWindowModality(Qt::WindowModal);
dlg->setWindowTitle(tr("Compatibility Report"));
dlg->setAttribute(Qt::WA_DeleteOnClose, true);
QVBoxLayout* layout = new QVBoxLayout(&dlg);
QVBoxLayout* layout = new QVBoxLayout(dlg);
QTextBrowser* tb = new QTextBrowser(&dlg);
QTextBrowser* tb = new QTextBrowser(dlg);
tb->setMarkdown(m_compatibility_comments);
layout->addWidget(tb, 1);
QDialogButtonBox* bb = new QDialogButtonBox(QDialogButtonBox::Close, &dlg);
connect(bb, &QDialogButtonBox::rejected, &dlg, &QDialog::accept);
QDialogButtonBox* bb = new QDialogButtonBox(QDialogButtonBox::Close, dlg);
connect(bb, &QDialogButtonBox::rejected, dlg, &QDialog::accept);
layout->addWidget(bb);
dlg.exec();
dlg->show();
}
void GameSummaryWidget::onInputProfileChanged(int index)

@ -401,10 +401,11 @@ void InputBindingWidget::unhookInputManager()
void InputBindingWidget::openDialog()
{
InputBindingDialog binding_dialog(m_sif, m_bind_type, m_section_name, m_key_name, m_bindings,
QtUtils::GetRootWidget(this));
binding_dialog.exec();
reloadBinding();
InputBindingDialog* dlg =
new InputBindingDialog(m_sif, m_bind_type, m_section_name, m_key_name, m_bindings, QtUtils::GetRootWidget(this));
dlg->setAttribute(Qt::WA_DeleteOnClose, true);
connect(dlg, &InputBindingDialog::finished, this, &InputBindingWidget::reloadBinding);
dlg->show();
}
InputVibrationBindingWidget::InputVibrationBindingWidget(QWidget* parent)

@ -1141,51 +1141,47 @@ std::shared_ptr<SystemBootParameters> MainWindow::getSystemBootParameters(std::s
return ret;
}
std::optional<bool> MainWindow::promptForResumeState(const std::string& save_state_path)
bool MainWindow::openResumeStateDialog(const std::string& path, const std::string& serial)
{
System::FlushSaveStates();
FILESYSTEM_STAT_DATA sd;
std::string save_state_path = System::GetGameSaveStatePath(serial, -1);
if (save_state_path.empty() || !FileSystem::StatFile(save_state_path.c_str(), &sd))
return false;
QMessageBox msgbox(this);
msgbox.setIcon(QMessageBox::Question);
msgbox.setWindowTitle(tr("Load Resume State"));
msgbox.setWindowModality(Qt::WindowModal);
msgbox.setText(
QMessageBox* msgbox = new QMessageBox(this);
msgbox->setIcon(QMessageBox::Question);
msgbox->setWindowTitle(tr("Load Resume State"));
msgbox->setWindowModality(Qt::WindowModal);
msgbox->setAttribute(Qt::WA_DeleteOnClose, true);
msgbox->setText(
tr("A resume save state was found for this game, saved at:\n\n%1.\n\nDo you want to load this state, "
"or start from a fresh boot?")
.arg(QtHost::FormatNumber(Host::NumberFormatType::LongDateTime, static_cast<s64>(sd.ModificationTime))));
QPushButton* load = msgbox.addButton(tr("Load State"), QMessageBox::AcceptRole);
QPushButton* boot = msgbox.addButton(tr("Fresh Boot"), QMessageBox::RejectRole);
QPushButton* delboot = msgbox.addButton(tr("Delete And Boot"), QMessageBox::RejectRole);
msgbox.addButton(QMessageBox::Cancel);
msgbox.setDefaultButton(load);
msgbox.exec();
QPushButton* load = msgbox->addButton(tr("Load State"), QMessageBox::AcceptRole);
QPushButton* boot = msgbox->addButton(tr("Fresh Boot"), QMessageBox::RejectRole);
QPushButton* delboot = msgbox->addButton(tr("Delete And Boot"), QMessageBox::RejectRole);
msgbox->addButton(QMessageBox::Cancel);
msgbox->setDefaultButton(load);
QAbstractButton* clicked = msgbox.clickedButton();
if (load == clicked)
{
return true;
}
else if (boot == clicked)
{
return false;
}
else if (delboot == clicked)
{
connect(load, &QPushButton::clicked, [this, path, save_state_path]() mutable {
startFile(std::move(path), std::move(save_state_path), std::nullopt);
});
connect(boot, &QPushButton::clicked,
[this, path]() mutable { startFile(std::move(path), std::nullopt, std::nullopt); });
connect(delboot, &QPushButton::clicked, [this, path, save_state_path]() mutable {
if (!FileSystem::DeleteFile(save_state_path.c_str()))
{
QMessageBox::critical(this, tr("Error"),
tr("Failed to delete save state file '%1'.").arg(QString::fromStdString(save_state_path)));
}
startFile(std::move(path), std::nullopt, std::nullopt);
});
return false;
}
return std::nullopt;
msgbox->show();
return true;
}
void MainWindow::startFile(std::string path, std::optional<std::string> save_path, std::optional<bool> fast_boot)
@ -1198,34 +1194,24 @@ void MainWindow::startFile(std::string path, std::optional<std::string> save_pat
g_emu_thread->bootSystem(std::move(params));
}
void MainWindow::startFileOrChangeDisc(const QString& path)
void MainWindow::startFileOrChangeDisc(const QString& qpath)
{
if (s_system_valid)
{
// this is a disc change
promptForDiscChange(path);
promptForDiscChange(qpath);
return;
}
// try to find the serial for the game
std::string path_str(path.toStdString());
std::string serial(GameDatabase::GetSerialForPath(path_str.c_str()));
std::optional<std::string> save_path;
if (!serial.empty())
std::string path = qpath.toStdString();
{
std::string resume_path(System::GetGameSaveStatePath(serial.c_str(), -1));
std::optional<bool> resume = promptForResumeState(resume_path);
if (!resume.has_value())
{
// cancelled
const auto lock = GameList::GetLock();
const GameList::Entry* entry = GameList::GetEntryForPath(path);
if (entry && !entry->serial.empty() && openResumeStateDialog(entry->path, entry->serial))
return;
}
else if (resume.value())
save_path = std::move(resume_path);
}
// only resume if the option is enabled, and we have one for this game
startFile(std::move(path_str), std::move(save_path), std::nullopt);
startFile(std::move(path), std::nullopt, std::nullopt);
}
void MainWindow::promptForDiscChange(const QString& path)
@ -1557,22 +1543,11 @@ void MainWindow::onGameListEntryActivated()
return;
}
std::optional<std::string> save_path;
if (!entry->serial.empty())
{
std::string resume_path(System::GetGameSaveStatePath(entry->serial.c_str(), -1));
std::optional<bool> resume = promptForResumeState(resume_path);
if (!resume.has_value())
{
// cancelled
return;
}
else if (resume.value())
save_path = std::move(resume_path);
}
if (!entry->serial.empty() && openResumeStateDialog(entry->path, entry->serial))
return;
// only resume if the option is enabled, and we have one for this game
startFile(entry->path, std::move(save_path), std::nullopt);
startFile(entry->path, std::nullopt, std::nullopt);
}
void MainWindow::onGameListEntryContextMenuRequested(const QPoint& point)
@ -2991,27 +2966,36 @@ void MainWindow::requestShutdown(bool allow_confirm, bool allow_save_to_state, b
SystemLock lock(pauseAndLockSystem());
QMessageBox msgbox(lock.getDialogParent());
msgbox.setIcon(QMessageBox::Question);
msgbox.setWindowTitle(tr("Confirm Shutdown"));
msgbox.setWindowModality(Qt::WindowModal);
msgbox.setText(tr("Are you sure you want to shut down the virtual machine?"));
QMessageBox* msgbox = new QMessageBox(lock.getDialogParent());
msgbox->setWindowTitle(tr("Confirm Shutdown"));
msgbox->setWindowModality(Qt::WindowModal);
msgbox->setAttribute(Qt::WA_DeleteOnClose, true);
msgbox->setIcon(QMessageBox::Question);
msgbox->setText(tr("Are you sure you want to shut down the virtual machine?"));
QCheckBox* save_cb = new QCheckBox(tr("Save State For Resume"), &msgbox);
QCheckBox* const save_cb = new QCheckBox(tr("Save State For Resume"), msgbox);
save_cb->setChecked(allow_save_to_state && save_state);
save_cb->setEnabled(allow_save_to_state);
msgbox.setCheckBox(save_cb);
msgbox.addButton(QMessageBox::Yes);
msgbox.addButton(QMessageBox::No);
msgbox.setDefaultButton(QMessageBox::Yes);
if (msgbox.exec() != QMessageBox::Yes)
return;
save_state = save_cb->isChecked();
// Don't switch back to fullscreen when we're shutting down anyway.
if (!QtHost::IsFullscreenUIStarted())
lock.cancelResume();
msgbox->setCheckBox(save_cb);
msgbox->addButton(QMessageBox::Yes);
msgbox->addButton(QMessageBox::No);
msgbox->setDefaultButton(QMessageBox::Yes);
connect(msgbox, &QMessageBox::finished, this,
[this, lock = std::move(lock), save_cb, allow_save_to_state, check_safety, check_pause, exit_fullscreen_ui,
quit_afterwards](int result) mutable {
if (result != QMessageBox::Yes)
return;
// Don't switch back to fullscreen when we're shutting down anyway.
if (!QtHost::IsFullscreenUIStarted())
lock.cancelResume();
const bool save_state = save_cb->isChecked();
requestShutdown(false, allow_save_to_state, save_state, check_safety, check_pause, exit_fullscreen_ui,
quit_afterwards);
});
msgbox->show();
return;
}
// If we're running in batch mode, don't show the main window after shutting down.
@ -3134,10 +3118,11 @@ void MainWindow::openMemoryCardEditor(const QString& card_a_path, const QString&
void MainWindow::onAchievementsLoginRequested(Achievements::LoginRequestReason reason)
{
const auto lock = pauseAndLockSystem();
auto lock = pauseAndLockSystem();
AchievementLoginDialog dlg(lock.getDialogParent(), reason);
dlg.exec();
AchievementLoginDialog* dlg = new AchievementLoginDialog(lock.getDialogParent(), reason);
connect(dlg, &AchievementLoginDialog::finished, this, [lock = std::move(lock)]() {});
dlg->show();
}
void MainWindow::onAchievementsLoginSuccess(const QString& username, quint32 points, quint32 sc_points,
@ -3335,7 +3320,6 @@ void MainWindow::checkForUpdates(bool display_message)
{
QMessageBox mbox(this);
mbox.setWindowTitle(tr("Updater Error"));
mbox.setWindowModality(Qt::WindowModal);
mbox.setTextFormat(Qt::RichText);
QString message;
@ -3440,20 +3424,26 @@ MainWindow::SystemLock MainWindow::pauseAndLockSystem()
}
MainWindow::SystemLock::SystemLock(QWidget* dialog_parent, bool was_paused, bool was_fullscreen)
: m_dialog_parent(dialog_parent), m_was_paused(was_paused), m_was_fullscreen(was_fullscreen)
: m_dialog_parent(dialog_parent), m_was_paused(was_paused), m_was_fullscreen(was_fullscreen), m_valid(true)
{
}
MainWindow::SystemLock::SystemLock(SystemLock&& lock)
: m_dialog_parent(lock.m_dialog_parent), m_was_paused(lock.m_was_paused), m_was_fullscreen(lock.m_was_fullscreen)
: m_dialog_parent(lock.m_dialog_parent), m_was_paused(lock.m_was_paused), m_was_fullscreen(lock.m_was_fullscreen),
m_valid(true)
{
Assert(lock.m_valid);
lock.m_dialog_parent = nullptr;
lock.m_was_paused = true;
lock.m_was_fullscreen = false;
lock.m_valid = false;
}
MainWindow::SystemLock::~SystemLock()
{
if (!m_valid)
return;
DebugAssert(s_system_locked.load(std::memory_order_relaxed) > 0);
s_system_locked.fetch_sub(1, std::memory_order_release);
if (m_was_fullscreen)

@ -73,6 +73,7 @@ public:
QWidget* m_dialog_parent;
bool m_was_paused;
bool m_was_fullscreen;
bool m_valid;
};
public:
@ -214,9 +215,9 @@ private:
const GameList::Entry* resolveDiscSetEntry(const GameList::Entry* entry,
std::unique_lock<std::recursive_mutex>& lock);
std::shared_ptr<SystemBootParameters> getSystemBootParameters(std::string file);
std::optional<bool> promptForResumeState(const std::string& save_state_path);
bool openResumeStateDialog(const std::string& path, const std::string& serial);
void startFile(std::string path, std::optional<std::string> save_path, std::optional<bool> fast_boot);
void startFileOrChangeDisc(const QString& path);
void startFileOrChangeDisc(const QString& qpath);
void promptForDiscChange(const QString& path);
std::optional<WindowInfo> acquireRenderWindow(RenderAPI render_api, bool fullscreen, bool exclusive_fullscreen,

@ -651,11 +651,13 @@ void SetupWizardDialog::onAchievementsLoginLogoutClicked()
return;
}
AchievementLoginDialog login(this, Achievements::LoginRequestReason::UserInitiated);
int res = login.exec();
if (res == QDialog::Rejected)
return;
AchievementLoginDialog* login = new AchievementLoginDialog(this, Achievements::LoginRequestReason::UserInitiated);
connect(login, &AchievementLoginDialog::accepted, this, &SetupWizardDialog::onAchievementsLoginCompleted);
login->show();
}
void SetupWizardDialog::onAchievementsLoginCompleted()
{
updateAchievementsEnableState();
updateAchievementsLoginState();

@ -74,6 +74,7 @@ private:
void onGraphicsAspectRatioChanged();
void onAchievementsLoginLogoutClicked();
void onAchievementsLoginCompleted();
void onAchievementsViewProfileClicked();
void updateAchievementsEnableState();
void updateAchievementsLoginState();

Loading…
Cancel
Save