mirror of
https://github.com/dolphin-emu/dolphin
synced 2024-06-28 22:46:42 +00:00
Compare commits
22 Commits
2e863b0569
...
fde7dc1c43
Author | SHA1 | Date | |
---|---|---|---|
|
fde7dc1c43 | ||
|
10a95a4d5b | ||
|
04b0ceedcd | ||
|
9c432e960b | ||
|
f8f117e599 | ||
|
c536754ffe | ||
|
e9e29daca4 | ||
|
2aec195ec8 | ||
|
c337ab6473 | ||
|
a75c65bde2 | ||
|
28692681ad | ||
|
bf230a9909 | ||
|
883195f171 | ||
|
ce2f4101f3 | ||
|
8e7d11d1a1 | ||
|
5c46716d28 | ||
|
0f659508ea | ||
|
aa393dfb6e | ||
|
e1a8dc65ce | ||
|
29f1b82f5e | ||
|
55ba014fed | ||
|
c0a1f5e123 |
|
@ -874,7 +874,7 @@ It can efficiently compress both junk data and encrypted Wii data.
|
|||
<string name="about_website"><a href="https://dolphin-emu.org/">Website</a></string>
|
||||
<string name="about_github"><a href="https://github.com/dolphin-emu/dolphin">GitHub</a></string>
|
||||
<string name="about_support"><a href="https://forums.dolphin-emu.org/">Support</a></string>
|
||||
<string name="about_copyright_warning">\u00A9 2003–2015+ Dolphin Team. \u201cGameCube\u201d and \u201cWii\u201d are trademarks of Nintendo. Dolphin is not affiliated with Nintendo in any way.</string>
|
||||
<string name="about_copyright_warning">\u00A9 2003–2024+ Dolphin Team. \u201cGameCube\u201d and \u201cWii\u201d are trademarks of Nintendo. Dolphin is not affiliated with Nintendo in any way.</string>
|
||||
<string name="system_driver">System driver</string>
|
||||
<string name="system_driver_desc">The GPU driver that is part of the OS.</string>
|
||||
|
||||
|
|
|
@ -13,6 +13,7 @@
|
|||
#include <rcheevos/include/rc_api_info.h>
|
||||
#include <rcheevos/include/rc_hash.h>
|
||||
|
||||
#include "Common/Assert.h"
|
||||
#include "Common/CommonPaths.h"
|
||||
#include "Common/FileUtil.h"
|
||||
#include "Common/Image.h"
|
||||
|
@ -22,6 +23,7 @@
|
|||
#include "Common/WorkQueueThread.h"
|
||||
#include "Core/Config/AchievementSettings.h"
|
||||
#include "Core/Core.h"
|
||||
#include "Core/HW/Memmap.h"
|
||||
#include "Core/PowerPC/MMU.h"
|
||||
#include "Core/System.h"
|
||||
#include "DiscIO/Blob.h"
|
||||
|
@ -44,7 +46,7 @@ void AchievementManager::Init()
|
|||
LoadDefaultBadges();
|
||||
if (!m_client && Config::Get(Config::RA_ENABLED))
|
||||
{
|
||||
m_client = rc_client_create(MemoryPeeker, Request);
|
||||
m_client = rc_client_create(MemoryVerifier, Request);
|
||||
std::string host_url = Config::Get(Config::RA_HOST_URL);
|
||||
if (!host_url.empty())
|
||||
rc_client_set_host(m_client, host_url.c_str());
|
||||
|
@ -120,6 +122,7 @@ void AchievementManager::LoadGame(const std::string& file_path, const DiscIO::Vo
|
|||
rc_client_set_unofficial_enabled(m_client, Config::Get(Config::RA_UNOFFICIAL_ENABLED));
|
||||
rc_client_set_encore_mode_enabled(m_client, Config::Get(Config::RA_ENCORE_ENABLED));
|
||||
rc_client_set_spectator_mode_enabled(m_client, Config::Get(Config::RA_SPECTATOR_ENABLED));
|
||||
rc_client_set_read_memory_function(m_client, MemoryVerifier);
|
||||
if (volume)
|
||||
{
|
||||
std::lock_guard lg{m_lock};
|
||||
|
@ -679,13 +682,14 @@ void AchievementManager::LoadGameCallback(int result, const char* error_message,
|
|||
}
|
||||
INFO_LOG_FMT(ACHIEVEMENTS, "Loaded data for game ID {}.", game->id);
|
||||
|
||||
AchievementManager::GetInstance().m_display_welcome_message = true;
|
||||
AchievementManager::GetInstance().FetchGameBadges();
|
||||
AchievementManager::GetInstance().m_system = &Core::System::GetInstance();
|
||||
AchievementManager::GetInstance().m_update_callback({.all = true});
|
||||
auto& instance = AchievementManager::GetInstance();
|
||||
rc_client_set_read_memory_function(instance.m_client, MemoryPeeker);
|
||||
instance.m_display_welcome_message = true;
|
||||
instance.FetchGameBadges();
|
||||
instance.m_system = &Core::System::GetInstance();
|
||||
instance.m_update_callback({.all = true});
|
||||
// Set this to a value that will immediately trigger RP
|
||||
AchievementManager::GetInstance().m_last_rp_time =
|
||||
std::chrono::steady_clock::now() - std::chrono::minutes{2};
|
||||
instance.m_last_rp_time = std::chrono::steady_clock::now() - std::chrono::minutes{2};
|
||||
}
|
||||
|
||||
void AchievementManager::ChangeMediaCallback(int result, const char* error_message,
|
||||
|
@ -706,6 +710,7 @@ void AchievementManager::ChangeMediaCallback(int result, const char* error_messa
|
|||
|
||||
ERROR_LOG_FMT(ACHIEVEMENTS, "RetroAchievements media change failed: {}", error_message);
|
||||
}
|
||||
rc_client_set_read_memory_function(AchievementManager::GetInstance().m_client, MemoryPeeker);
|
||||
}
|
||||
|
||||
void AchievementManager::DisplayWelcomeMessage()
|
||||
|
@ -914,11 +919,36 @@ void AchievementManager::Request(const rc_api_request_t* request,
|
|||
});
|
||||
}
|
||||
|
||||
// Currently, when rc_client calls the memory peek method provided in its constructor (or in
|
||||
// rc_client_set_read_memory_function) it will do so on the thread that calls DoFrame, which is
|
||||
// currently the host thread, with one exception: an asynchronous callback in the load game process.
|
||||
// This is done to validate/invalidate each memory reference in the downloaded assets, mark assets
|
||||
// as unsupported, and notify the player upon startup that there are unsupported assets and how
|
||||
// many. As such, all that call needs to do is return the number of bytes that can be read with this
|
||||
// call. As only the CPU and host threads are allowed to read from memory, I provide a separate
|
||||
// method for this verification. In lieu of a more convenient set of steps, I provide MemoryVerifier
|
||||
// to rc_client at construction, and in the Load Game callback, after the verification has been
|
||||
// complete, I call rc_client_set_read_memory_function to switch to the usual MemoryPeeker for all
|
||||
// future synchronous calls.
|
||||
u32 AchievementManager::MemoryVerifier(u32 address, u8* buffer, u32 num_bytes, rc_client_t* client)
|
||||
{
|
||||
auto& system = Core::System::GetInstance();
|
||||
u32 ram_size = system.GetMemory().GetRamSizeReal();
|
||||
if (address >= ram_size)
|
||||
return 0;
|
||||
return std::min(ram_size - address, num_bytes);
|
||||
}
|
||||
|
||||
u32 AchievementManager::MemoryPeeker(u32 address, u8* buffer, u32 num_bytes, rc_client_t* client)
|
||||
{
|
||||
if (buffer == nullptr)
|
||||
return 0u;
|
||||
auto& system = Core::System::GetInstance();
|
||||
if (!(Core::IsHostThread() || Core::IsCPUThread()))
|
||||
{
|
||||
ASSERT_MSG(ACHIEVEMENTS, false, "MemoryPeeker called from wrong thread");
|
||||
return 0;
|
||||
}
|
||||
Core::CPUThreadGuard threadguard(system);
|
||||
for (u32 num_read = 0; num_read < num_bytes; num_read++)
|
||||
{
|
||||
|
|
|
@ -177,6 +177,7 @@ private:
|
|||
|
||||
static void Request(const rc_api_request_t* request, rc_client_server_callback_t callback,
|
||||
void* callback_data, rc_client_t* client);
|
||||
static u32 MemoryVerifier(u32 address, u8* buffer, u32 num_bytes, rc_client_t* client);
|
||||
static u32 MemoryPeeker(u32 address, u8* buffer, u32 num_bytes, rc_client_t* client);
|
||||
void FetchBadge(Badge* badge, u32 badge_type, const BadgeNameFunction function,
|
||||
const UpdatedItems callback_data);
|
||||
|
|
|
@ -202,21 +202,27 @@ static void AnalyzeFunction2(PPCSymbolDB* func_db, Common::Symbol* func)
|
|||
func->flags = flags;
|
||||
}
|
||||
|
||||
static bool IsMfspr(UGeckoInstruction inst)
|
||||
{
|
||||
return inst.OPCD == 31 && inst.SUBOP10 == 339;
|
||||
}
|
||||
|
||||
static bool IsMtspr(UGeckoInstruction inst)
|
||||
{
|
||||
return inst.OPCD == 31 && inst.SUBOP10 == 467;
|
||||
}
|
||||
|
||||
static bool IsSprInstructionUsingMmcr(UGeckoInstruction inst)
|
||||
static u32 GetSPRIndex(UGeckoInstruction inst)
|
||||
{
|
||||
const u32 index = (inst.SPRU << 5) | (inst.SPRL & 0x1F);
|
||||
return index == SPR_MMCR0 || index == SPR_MMCR1;
|
||||
DEBUG_ASSERT(IsMfspr(inst) || IsMtspr(inst));
|
||||
return (inst.SPRU << 5) | (inst.SPRL & 0x1F);
|
||||
}
|
||||
|
||||
static bool InstructionCanEndBlock(const CodeOp& op)
|
||||
{
|
||||
return (op.opinfo->flags & FL_ENDBLOCK) &&
|
||||
(!IsMtspr(op.inst) || IsSprInstructionUsingMmcr(op.inst));
|
||||
(!IsMtspr(op.inst) || GetSPRIndex(op.inst) == SPR_MMCR0 ||
|
||||
GetSPRIndex(op.inst) == SPR_MMCR1);
|
||||
}
|
||||
|
||||
bool PPCAnalyzer::CanSwapAdjacentOps(const CodeOp& a, const CodeOp& b) const
|
||||
|
@ -637,10 +643,10 @@ void PPCAnalyzer::SetInstructionStats(CodeBlock* block, CodeOp* code,
|
|||
|
||||
// mfspr/mtspr can affect/use XER, so be super careful here
|
||||
// we need to note specifically that mfspr needs CA in XER, not in the x86 carry flag
|
||||
if (code->inst.OPCD == 31 && code->inst.SUBOP10 == 339) // mfspr
|
||||
code->wantsCA = ((code->inst.SPRU << 5) | (code->inst.SPRL & 0x1F)) == SPR_XER;
|
||||
if (code->inst.OPCD == 31 && code->inst.SUBOP10 == 467) // mtspr
|
||||
code->outputCA = ((code->inst.SPRU << 5) | (code->inst.SPRL & 0x1F)) == SPR_XER;
|
||||
if (IsMfspr(code->inst))
|
||||
code->wantsCA = GetSPRIndex(code->inst) == SPR_XER;
|
||||
if (IsMtspr(code->inst))
|
||||
code->outputCA = GetSPRIndex(code->inst) == SPR_XER;
|
||||
|
||||
code->regsIn = BitSet32(0);
|
||||
code->regsOut = BitSet32(0);
|
||||
|
@ -892,7 +898,7 @@ u32 PPCAnalyzer::Analyze(u32 address, CodeBlock* block, CodeBuffer* buffer,
|
|||
// Through it would be easy to track the upper level of call/return,
|
||||
// we can't guarantee the LR value. The PPC ABI forces all functions to push
|
||||
// the LR value on the stack as there are no spare registers. So we'd need
|
||||
// to check all store instruction to not alias with the stack.
|
||||
// to check all store instructions to not alias with the stack.
|
||||
follow = true;
|
||||
found_call = false;
|
||||
code[i].skip = true;
|
||||
|
@ -901,16 +907,10 @@ u32 PPCAnalyzer::Analyze(u32 address, CodeBlock* block, CodeBuffer* buffer,
|
|||
code[caller].skipLRStack = true;
|
||||
}
|
||||
}
|
||||
else if (inst.OPCD == 31 && inst.SUBOP10 == 467)
|
||||
else if (IsMtspr(inst) && GetSPRIndex(inst) == SPR_LR)
|
||||
{
|
||||
// mtspr, skip CALL/RET merging as LR is overwritten.
|
||||
const u32 index = (inst.SPRU << 5) | (inst.SPRL & 0x1F);
|
||||
if (index == SPR_LR)
|
||||
{
|
||||
// We give up to follow the return address
|
||||
// because we have to check the register usage.
|
||||
found_call = false;
|
||||
}
|
||||
// LR has been overwritten, so we give up on following the return address.
|
||||
found_call = false;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -962,8 +962,8 @@ u32 PPCAnalyzer::Analyze(u32 address, CodeBlock* block, CodeBuffer* buffer,
|
|||
}
|
||||
if (conditional_continue)
|
||||
{
|
||||
// If we skip any conditional branch, we can't garantee to get the matching CALL/RET pair.
|
||||
// So we stop inling the RET here and let the BLR optitmization handle this case.
|
||||
// If we skip any conditional branch, we can't guarantee to get the matching CALL/RET pair.
|
||||
// So we stop inlining the RET here and let the BLR optimization handle this case.
|
||||
found_call = false;
|
||||
}
|
||||
}
|
||||
|
@ -1142,9 +1142,9 @@ u32 PPCAnalyzer::Analyze(u32 address, CodeBlock* block, CodeBuffer* buffer,
|
|||
gqrUsed[gqr] = true;
|
||||
}
|
||||
|
||||
if (op.inst.OPCD == 31 && op.inst.SUBOP10 == 467) // mtspr
|
||||
if (IsMtspr(op.inst))
|
||||
{
|
||||
const int gqr = ((op.inst.SPRU << 5) | op.inst.SPRL) - SPR_GQR0;
|
||||
const int gqr = GetSPRIndex(op.inst) - SPR_GQR0;
|
||||
if (gqr >= 0 && gqr <= 7)
|
||||
gqrModified[gqr] = true;
|
||||
}
|
||||
|
|
|
@ -89,7 +89,7 @@ AboutDialog::AboutDialog(QWidget* parent) : QDialog(parent)
|
|||
// in your translation, please use the type of curly quotes that's appropriate for
|
||||
// your language. If you aren't sure which type is appropriate, see
|
||||
// https://en.wikipedia.org/wiki/Quotation_mark#Specific_language_features
|
||||
tr("\u00A9 2003-2015+ Dolphin Team. \u201cGameCube\u201d and \u201cWii\u201d are "
|
||||
tr("\u00A9 2003-2024+ Dolphin Team. \u201cGameCube\u201d and \u201cWii\u201d are "
|
||||
"trademarks of Nintendo. Dolphin is not affiliated with Nintendo in any way.")));
|
||||
|
||||
QLabel* logo = new QLabel();
|
||||
|
|
|
@ -4,10 +4,12 @@
|
|||
#ifdef USE_RETRO_ACHIEVEMENTS
|
||||
#include "DolphinQt/Achievements/AchievementBox.h"
|
||||
|
||||
#include <QByteArray>
|
||||
#include <QDateTime>
|
||||
#include <QHBoxLayout>
|
||||
#include <QLabel>
|
||||
#include <QProgressBar>
|
||||
#include <QSizePolicy>
|
||||
#include <QVBoxLayout>
|
||||
#include <QWidget>
|
||||
|
||||
|
@ -30,9 +32,11 @@ AchievementBox::AchievementBox(QWidget* parent, rc_client_achievement_t* achieve
|
|||
m_badge = new QLabel();
|
||||
QLabel* title = new QLabel(QString::fromUtf8(achievement->title, strlen(achievement->title)));
|
||||
title->setWordWrap(true);
|
||||
title->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Minimum);
|
||||
QLabel* description =
|
||||
new QLabel(QString::fromUtf8(achievement->description, strlen(achievement->description)));
|
||||
description->setWordWrap(true);
|
||||
description->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Minimum);
|
||||
QLabel* points = new QLabel(tr("%1 points").arg(achievement->points));
|
||||
m_status = new QLabel();
|
||||
m_progress_bar = new QProgressBar();
|
||||
|
@ -93,7 +97,9 @@ void AchievementBox::UpdateData()
|
|||
m_progress_bar->setRange(0, 100);
|
||||
m_progress_bar->setValue(m_achievement->measured_percent);
|
||||
m_progress_bar->setTextVisible(false);
|
||||
m_progress_label->setText(QString::fromUtf8(m_achievement->measured_progress, PROGRESS_LENGTH));
|
||||
m_progress_label->setText(
|
||||
QString::fromUtf8(m_achievement->measured_progress,
|
||||
qstrnlen(m_achievement->measured_progress, PROGRESS_LENGTH)));
|
||||
m_progress_bar->setVisible(true);
|
||||
}
|
||||
else
|
||||
|
|
|
@ -57,8 +57,10 @@ void AchievementLeaderboardWidget::UpdateData(bool clean_all)
|
|||
m_leaderboard_order[leaderboard->id] = row;
|
||||
QLabel* a_title = new QLabel(QString::fromUtf8(leaderboard->title));
|
||||
a_title->setWordWrap(true);
|
||||
a_title->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Minimum);
|
||||
QLabel* a_description = new QLabel(QString::fromUtf8(leaderboard->description));
|
||||
a_description->setWordWrap(true);
|
||||
a_description->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Minimum);
|
||||
QVBoxLayout* a_col_left = new QVBoxLayout();
|
||||
a_col_left->addWidget(a_title);
|
||||
a_col_left->addWidget(a_description);
|
||||
|
|
|
@ -236,7 +236,10 @@ void AchievementSettingsWidget::ToggleRAIntegration()
|
|||
else
|
||||
instance.Shutdown();
|
||||
if (Config::Get(Config::RA_HARDCORE_ENABLED))
|
||||
{
|
||||
emit Settings::Instance().EmulationStateChanged(Core::GetState(Core::System::GetInstance()));
|
||||
emit Settings::Instance().HardcoreStateChanged();
|
||||
}
|
||||
}
|
||||
|
||||
void AchievementSettingsWidget::Login()
|
||||
|
@ -266,6 +269,7 @@ void AchievementSettingsWidget::ToggleHardcore()
|
|||
Settings::Instance().SetDebugModeEnabled(false);
|
||||
}
|
||||
emit Settings::Instance().EmulationStateChanged(Core::GetState(Core::System::GetInstance()));
|
||||
emit Settings::Instance().HardcoreStateChanged();
|
||||
}
|
||||
|
||||
void AchievementSettingsWidget::ToggleUnofficial()
|
||||
|
|
|
@ -34,6 +34,8 @@ AchievementsWindow::AchievementsWindow(QWidget* parent) : QDialog(parent)
|
|||
});
|
||||
});
|
||||
connect(&Settings::Instance(), &Settings::EmulationStateChanged, this,
|
||||
[this] { m_settings_widget->UpdateData(); });
|
||||
connect(&Settings::Instance(), &Settings::HardcoreStateChanged, this,
|
||||
[this] { AchievementsWindow::UpdateData({.all = true}); });
|
||||
}
|
||||
|
||||
|
|
|
@ -59,8 +59,6 @@
|
|||
#include "InputCommon/ControllerInterface/CoreDevice.h"
|
||||
#include "InputCommon/InputConfig.h"
|
||||
|
||||
constexpr const char* PROFILES_DIR = "Profiles/";
|
||||
|
||||
MappingWindow::MappingWindow(QWidget* parent, Type type, int port_num)
|
||||
: QDialog(parent), m_port(port_num)
|
||||
{
|
||||
|
|
|
@ -299,16 +299,14 @@ void GameList::MakeEmptyView()
|
|||
size_policy.setRetainSizeWhenHidden(true);
|
||||
m_empty->setSizePolicy(size_policy);
|
||||
|
||||
connect(&Settings::Instance(), &Settings::GameListRefreshRequested, this,
|
||||
[this, refreshing_msg = refreshing_msg] {
|
||||
m_empty->setText(refreshing_msg);
|
||||
m_empty->setEnabled(false);
|
||||
});
|
||||
connect(&Settings::Instance(), &Settings::GameListRefreshCompleted, this,
|
||||
[this, empty_msg = empty_msg] {
|
||||
m_empty->setText(empty_msg);
|
||||
m_empty->setEnabled(true);
|
||||
});
|
||||
connect(&Settings::Instance(), &Settings::GameListRefreshRequested, this, [this, refreshing_msg] {
|
||||
m_empty->setText(refreshing_msg);
|
||||
m_empty->setEnabled(false);
|
||||
});
|
||||
connect(&Settings::Instance(), &Settings::GameListRefreshCompleted, this, [this, empty_msg] {
|
||||
m_empty->setText(empty_msg);
|
||||
m_empty->setEnabled(true);
|
||||
});
|
||||
}
|
||||
|
||||
void GameList::resizeEvent(QResizeEvent* event)
|
||||
|
|
|
@ -354,11 +354,6 @@ void Settings::NotifyRefreshGameListComplete()
|
|||
emit GameListRefreshCompleted();
|
||||
}
|
||||
|
||||
void Settings::RefreshMetadata()
|
||||
{
|
||||
emit MetadataRefreshRequested();
|
||||
}
|
||||
|
||||
void Settings::NotifyMetadataRefreshComplete()
|
||||
{
|
||||
emit MetadataRefreshCompleted();
|
||||
|
|
|
@ -104,7 +104,6 @@ public:
|
|||
void RefreshGameList();
|
||||
void NotifyRefreshGameListStarted();
|
||||
void NotifyRefreshGameListComplete();
|
||||
void RefreshMetadata();
|
||||
void NotifyMetadataRefreshComplete();
|
||||
void ReloadTitleDB();
|
||||
bool IsAutoRefreshEnabled() const;
|
||||
|
@ -224,6 +223,7 @@ signals:
|
|||
void SDCardInsertionChanged(bool inserted);
|
||||
void USBKeyboardConnectionChanged(bool connected);
|
||||
void EnableGfxModsChanged(bool enabled);
|
||||
void HardcoreStateChanged();
|
||||
|
||||
private:
|
||||
Settings();
|
||||
|
|
|
@ -100,7 +100,7 @@ void AdvancedPane::CreateLayout()
|
|||
clock_override_layout->addLayout(cpu_clock_override_slider_layout);
|
||||
|
||||
m_cpu_clock_override_slider = new QSlider(Qt::Horizontal);
|
||||
m_cpu_clock_override_slider->setRange(0, 150);
|
||||
m_cpu_clock_override_slider->setRange(1, 400);
|
||||
cpu_clock_override_slider_layout->addWidget(m_cpu_clock_override_slider);
|
||||
|
||||
m_cpu_clock_override_slider_label = new QLabel();
|
||||
|
@ -203,8 +203,7 @@ void AdvancedPane::ConnectLayout()
|
|||
});
|
||||
|
||||
connect(m_cpu_clock_override_slider, &QSlider::valueChanged, [this](int oc_factor) {
|
||||
// Vaguely exponential scaling?
|
||||
const float factor = std::exp2f((m_cpu_clock_override_slider->value() - 100.f) / 25.f);
|
||||
const float factor = m_cpu_clock_override_slider->value() / 100.f;
|
||||
Config::SetBaseOrCurrent(Config::MAIN_OVERCLOCK, factor);
|
||||
Update();
|
||||
});
|
||||
|
@ -271,8 +270,8 @@ void AdvancedPane::Update()
|
|||
|
||||
{
|
||||
const QSignalBlocker blocker(m_cpu_clock_override_slider);
|
||||
m_cpu_clock_override_slider->setValue(static_cast<int>(
|
||||
std::round(std::log2f(Config::Get(Config::MAIN_OVERCLOCK)) * 25.f + 100.f)));
|
||||
m_cpu_clock_override_slider->setValue(
|
||||
static_cast<int>(std::round(Config::Get(Config::MAIN_OVERCLOCK) * 100.f)));
|
||||
}
|
||||
|
||||
m_cpu_clock_override_slider_label->setText([] {
|
||||
|
|
|
@ -194,7 +194,7 @@ void GeneralPane::CreateAutoUpdate()
|
|||
auto_update_group_layout->addRow(tr("&Auto Update:"), m_combobox_update_track);
|
||||
|
||||
for (const QString& option :
|
||||
{tr("Don't Update"), tr("Beta (once a month)"), tr("Dev (multiple times a day)")})
|
||||
{tr("Don't Update"), tr("Releases (every few months)"), tr("Dev (multiple times a day)")})
|
||||
m_combobox_update_track->addItem(option);
|
||||
}
|
||||
|
||||
|
|
|
@ -235,15 +235,15 @@ void InterfacePane::ConnectLayout()
|
|||
connect(m_checkbox_use_builtin_title_database, &QCheckBox::toggled, &Settings::Instance(),
|
||||
&Settings::GameListRefreshRequested);
|
||||
connect(m_checkbox_use_covers, &QCheckBox::toggled, &Settings::Instance(),
|
||||
&Settings::RefreshMetadata);
|
||||
&Settings::MetadataRefreshRequested);
|
||||
connect(m_checkbox_show_debugging_ui, &QCheckBox::toggled, &Settings::Instance(),
|
||||
&Settings::SetDebugModeEnabled);
|
||||
connect(m_combobox_theme, &QComboBox::currentIndexChanged, this,
|
||||
[this](int index) { Settings::Instance().TriggerThemeChanged(); });
|
||||
connect(m_combobox_theme, &QComboBox::currentIndexChanged, &Settings::Instance(),
|
||||
&Settings::ThemeChanged);
|
||||
connect(m_combobox_userstyle, &QComboBox::currentIndexChanged, this,
|
||||
&InterfacePane::OnUserStyleChanged);
|
||||
connect(m_combobox_language, &QComboBox::currentIndexChanged, this,
|
||||
[this]() { OnLanguageChanged(); });
|
||||
&InterfacePane::OnLanguageChanged);
|
||||
connect(m_checkbox_top_window, &QCheckBox::toggled, &Settings::Instance(),
|
||||
&Settings::KeepWindowOnTopChanged);
|
||||
connect(m_radio_cursor_visible_movement, &ConfigRadioInt::OnSelected, &Settings::Instance(),
|
||||
|
@ -253,7 +253,7 @@ void InterfacePane::ConnectLayout()
|
|||
connect(m_radio_cursor_visible_always, &ConfigRadioInt::OnSelected, &Settings::Instance(),
|
||||
&Settings::CursorVisibilityChanged);
|
||||
connect(m_checkbox_lock_mouse, &QCheckBox::toggled, &Settings::Instance(),
|
||||
[this]() { Settings::Instance().LockCursorChanged(); });
|
||||
&Settings::LockCursorChanged);
|
||||
}
|
||||
|
||||
void InterfacePane::UpdateShowDebuggingCheckbox()
|
||||
|
|
|
@ -66,12 +66,15 @@ void VideoConfig::Refresh()
|
|||
CPUThreadConfigCallback::AddConfigChangedCallback([]() {
|
||||
auto& system = Core::System::GetInstance();
|
||||
|
||||
system.GetFifo().PauseAndLock(true, false);
|
||||
const bool lock_gpu_thread = Core::IsRunning(system);
|
||||
if (lock_gpu_thread)
|
||||
system.GetFifo().PauseAndLock(true, false);
|
||||
|
||||
g_Config.Refresh();
|
||||
g_Config.VerifyValidity();
|
||||
|
||||
system.GetFifo().PauseAndLock(false, true);
|
||||
if (lock_gpu_thread)
|
||||
system.GetFifo().PauseAndLock(false, true);
|
||||
});
|
||||
s_has_registered_callback = true;
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue
Block a user