mirror of
https://github.com/PCSX2/pcsx2.git
synced 2025-12-16 04:08:48 +00:00
CDVD: Synchronise access from different threads
Some checks failed
🐧 Linux Builds / AppImage (push) Has been cancelled
🐧 Linux Builds / Flatpak (push) Has been cancelled
🍎 MacOS Builds / Defaults (push) Has been cancelled
🖥️ Windows Builds / Lint VS Project Files (push) Has been cancelled
🖥️ Windows Builds / CMake (push) Has been cancelled
🖥️ Windows Builds / SSE4 (push) Has been cancelled
🖥️ Windows Builds / AVX2 (push) Has been cancelled
🏭 Update Controller Database / update-controller-db (push) Has been cancelled
Some checks failed
🐧 Linux Builds / AppImage (push) Has been cancelled
🐧 Linux Builds / Flatpak (push) Has been cancelled
🍎 MacOS Builds / Defaults (push) Has been cancelled
🖥️ Windows Builds / Lint VS Project Files (push) Has been cancelled
🖥️ Windows Builds / CMake (push) Has been cancelled
🖥️ Windows Builds / SSE4 (push) Has been cancelled
🖥️ Windows Builds / AVX2 (push) Has been cancelled
🏭 Update Controller Database / update-controller-db (push) Has been cancelled
This commit is contained in:
parent
d02f30ee62
commit
a98cfcf28c
@ -4,14 +4,17 @@
|
|||||||
#include "GameListRefreshThread.h"
|
#include "GameListRefreshThread.h"
|
||||||
|
|
||||||
#include "pcsx2/GameList.h"
|
#include "pcsx2/GameList.h"
|
||||||
|
#include "pcsx2/Host.h"
|
||||||
|
|
||||||
|
#include "common/Assertions.h"
|
||||||
|
#include "common/Console.h"
|
||||||
#include "common/ProgressCallback.h"
|
#include "common/ProgressCallback.h"
|
||||||
#include "common/Timer.h"
|
|
||||||
|
|
||||||
#include <QtWidgets/QMessageBox>
|
#include <QtWidgets/QMessageBox>
|
||||||
|
|
||||||
AsyncRefreshProgressCallback::AsyncRefreshProgressCallback(GameListRefreshThread* parent)
|
AsyncRefreshProgressCallback::AsyncRefreshProgressCallback(bool popup_on_error, GameListRefreshThread* parent)
|
||||||
: m_parent(parent)
|
: m_parent(parent)
|
||||||
|
, m_popup_on_error(popup_on_error)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -57,17 +60,20 @@ void AsyncRefreshProgressCallback::SetTitle(const char* title)
|
|||||||
|
|
||||||
void AsyncRefreshProgressCallback::DisplayError(const char* message)
|
void AsyncRefreshProgressCallback::DisplayError(const char* message)
|
||||||
{
|
{
|
||||||
QMessageBox::critical(nullptr, QStringLiteral("Error"), QString::fromUtf8(message));
|
if (m_popup_on_error)
|
||||||
|
Host::ReportErrorAsync(TRANSLATE_SV("GameListRefreshThread", "Error"), message);
|
||||||
|
else
|
||||||
|
ERROR_LOG("{}", message);
|
||||||
}
|
}
|
||||||
|
|
||||||
void AsyncRefreshProgressCallback::DisplayWarning(const char* message)
|
void AsyncRefreshProgressCallback::DisplayWarning(const char* message)
|
||||||
{
|
{
|
||||||
QMessageBox::warning(nullptr, QStringLiteral("Warning"), QString::fromUtf8(message));
|
pxFailRel("Not implemented.");
|
||||||
}
|
}
|
||||||
|
|
||||||
void AsyncRefreshProgressCallback::DisplayInformation(const char* message)
|
void AsyncRefreshProgressCallback::DisplayInformation(const char* message)
|
||||||
{
|
{
|
||||||
QMessageBox::information(nullptr, QStringLiteral("Information"), QString::fromUtf8(message));
|
pxFailRel("Not implemented.");
|
||||||
}
|
}
|
||||||
|
|
||||||
void AsyncRefreshProgressCallback::DisplayDebugMessage(const char* message)
|
void AsyncRefreshProgressCallback::DisplayDebugMessage(const char* message)
|
||||||
@ -77,17 +83,18 @@ void AsyncRefreshProgressCallback::DisplayDebugMessage(const char* message)
|
|||||||
|
|
||||||
void AsyncRefreshProgressCallback::ModalError(const char* message)
|
void AsyncRefreshProgressCallback::ModalError(const char* message)
|
||||||
{
|
{
|
||||||
QMessageBox::critical(nullptr, QStringLiteral("Error"), QString::fromUtf8(message));
|
pxFailRel("Not implemented.");
|
||||||
}
|
}
|
||||||
|
|
||||||
bool AsyncRefreshProgressCallback::ModalConfirmation(const char* message)
|
bool AsyncRefreshProgressCallback::ModalConfirmation(const char* message)
|
||||||
{
|
{
|
||||||
return QMessageBox::question(nullptr, QStringLiteral("Question"), QString::fromUtf8(message)) == QMessageBox::Yes;
|
pxFailRel("Not implemented.");
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void AsyncRefreshProgressCallback::ModalInformation(const char* message)
|
void AsyncRefreshProgressCallback::ModalInformation(const char* message)
|
||||||
{
|
{
|
||||||
QMessageBox::information(nullptr, QStringLiteral("Information"), QString::fromUtf8(message));
|
pxFailRel("Not implemented.");
|
||||||
}
|
}
|
||||||
|
|
||||||
void AsyncRefreshProgressCallback::fireUpdate()
|
void AsyncRefreshProgressCallback::fireUpdate()
|
||||||
@ -95,9 +102,9 @@ void AsyncRefreshProgressCallback::fireUpdate()
|
|||||||
m_parent->refreshProgress(m_status_text, m_last_value, m_last_range);
|
m_parent->refreshProgress(m_status_text, m_last_value, m_last_range);
|
||||||
}
|
}
|
||||||
|
|
||||||
GameListRefreshThread::GameListRefreshThread(bool invalidate_cache)
|
GameListRefreshThread::GameListRefreshThread(bool invalidate_cache, bool popup_on_error)
|
||||||
: QThread()
|
: QThread()
|
||||||
, m_progress(this)
|
, m_progress(popup_on_error, this)
|
||||||
, m_invalidate_cache(invalidate_cache)
|
, m_invalidate_cache(invalidate_cache)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|||||||
@ -14,7 +14,7 @@ class GameListRefreshThread;
|
|||||||
class AsyncRefreshProgressCallback : public BaseProgressCallback
|
class AsyncRefreshProgressCallback : public BaseProgressCallback
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
AsyncRefreshProgressCallback(GameListRefreshThread* parent);
|
AsyncRefreshProgressCallback(bool popup_on_error, GameListRefreshThread* parent);
|
||||||
|
|
||||||
void Cancel();
|
void Cancel();
|
||||||
|
|
||||||
@ -38,6 +38,7 @@ private:
|
|||||||
QString m_status_text;
|
QString m_status_text;
|
||||||
int m_last_range = 1;
|
int m_last_range = 1;
|
||||||
int m_last_value = 0;
|
int m_last_value = 0;
|
||||||
|
bool m_popup_on_error = false;
|
||||||
};
|
};
|
||||||
|
|
||||||
class GameListRefreshThread final : public QThread
|
class GameListRefreshThread final : public QThread
|
||||||
@ -45,7 +46,7 @@ class GameListRefreshThread final : public QThread
|
|||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
public:
|
public:
|
||||||
GameListRefreshThread(bool invalidate_cache);
|
GameListRefreshThread(bool invalidate_cache, bool popup_on_error);
|
||||||
~GameListRefreshThread();
|
~GameListRefreshThread();
|
||||||
|
|
||||||
void cancel();
|
void cancel();
|
||||||
@ -60,4 +61,5 @@ protected:
|
|||||||
private:
|
private:
|
||||||
AsyncRefreshProgressCallback m_progress;
|
AsyncRefreshProgressCallback m_progress;
|
||||||
bool m_invalidate_cache;
|
bool m_invalidate_cache;
|
||||||
|
bool m_popup_on_error;
|
||||||
};
|
};
|
||||||
|
|||||||
@ -294,7 +294,7 @@ void GameListWidget::initialize()
|
|||||||
m_empty_ui.setupUi(m_empty_widget);
|
m_empty_ui.setupUi(m_empty_widget);
|
||||||
m_empty_ui.supportedFormats->setText(qApp->translate("GameListWidget", SUPPORTED_FORMATS_STRING));
|
m_empty_ui.supportedFormats->setText(qApp->translate("GameListWidget", SUPPORTED_FORMATS_STRING));
|
||||||
connect(m_empty_ui.addGameDirectory, &QPushButton::clicked, this, [this]() { emit addGameDirectoryRequested(); });
|
connect(m_empty_ui.addGameDirectory, &QPushButton::clicked, this, [this]() { emit addGameDirectoryRequested(); });
|
||||||
connect(m_empty_ui.scanForNewGames, &QPushButton::clicked, this, [this]() { refresh(false); });
|
connect(m_empty_ui.scanForNewGames, &QPushButton::clicked, this, [this]() { refresh(false, true); });
|
||||||
connect(qApp, &QGuiApplication::applicationStateChanged, this, [this]() { GameListWidget::updateCustomBackgroundState(); });
|
connect(qApp, &QGuiApplication::applicationStateChanged, this, [this]() { GameListWidget::updateCustomBackgroundState(); });
|
||||||
m_ui.stack->insertWidget(2, m_empty_widget);
|
m_ui.stack->insertWidget(2, m_empty_widget);
|
||||||
|
|
||||||
@ -453,11 +453,11 @@ bool GameListWidget::getShowGridCoverTitles() const
|
|||||||
return m_model->getShowCoverTitles();
|
return m_model->getShowCoverTitles();
|
||||||
}
|
}
|
||||||
|
|
||||||
void GameListWidget::refresh(bool invalidate_cache)
|
void GameListWidget::refresh(bool invalidate_cache, bool popup_on_error)
|
||||||
{
|
{
|
||||||
cancelRefresh();
|
cancelRefresh();
|
||||||
|
|
||||||
m_refresh_thread = new GameListRefreshThread(invalidate_cache);
|
m_refresh_thread = new GameListRefreshThread(invalidate_cache, popup_on_error);
|
||||||
connect(m_refresh_thread, &GameListRefreshThread::refreshProgress, this, &GameListWidget::onRefreshProgress,
|
connect(m_refresh_thread, &GameListRefreshThread::refreshProgress, this, &GameListWidget::onRefreshProgress,
|
||||||
Qt::QueuedConnection);
|
Qt::QueuedConnection);
|
||||||
connect(m_refresh_thread, &GameListRefreshThread::refreshComplete, this, &GameListWidget::onRefreshComplete,
|
connect(m_refresh_thread, &GameListRefreshThread::refreshComplete, this, &GameListWidget::onRefreshComplete,
|
||||||
|
|||||||
@ -46,7 +46,7 @@ public:
|
|||||||
void initialize();
|
void initialize();
|
||||||
void resizeTableViewColumnsToFit();
|
void resizeTableViewColumnsToFit();
|
||||||
|
|
||||||
void refresh(bool invalidate_cache);
|
void refresh(bool invalidate_cache, bool popup_on_error);
|
||||||
void cancelRefresh();
|
void cancelRefresh();
|
||||||
void reloadThemeSpecificImages();
|
void reloadThemeSpecificImages();
|
||||||
void setCustomBackground(bool force = false);
|
void setCustomBackground(bool force = false);
|
||||||
|
|||||||
@ -357,8 +357,8 @@ void MainWindow::connectSignals()
|
|||||||
[this]() { doControllerSettings(ControllerSettingsWindow::Category::HotkeySettings); });
|
[this]() { doControllerSettings(ControllerSettingsWindow::Category::HotkeySettings); });
|
||||||
connect(m_ui.actionAddGameDirectory, &QAction::triggered,
|
connect(m_ui.actionAddGameDirectory, &QAction::triggered,
|
||||||
[this]() { getSettingsWindow()->getGameListSettingsWidget()->addSearchDirectory(this); });
|
[this]() { getSettingsWindow()->getGameListSettingsWidget()->addSearchDirectory(this); });
|
||||||
connect(m_ui.actionScanForNewGames, &QAction::triggered, [this]() { refreshGameList(false); });
|
connect(m_ui.actionScanForNewGames, &QAction::triggered, [this]() { refreshGameList(false, true); });
|
||||||
connect(m_ui.actionRescanAllGames, &QAction::triggered, [this]() { refreshGameList(true); });
|
connect(m_ui.actionRescanAllGames, &QAction::triggered, [this]() { refreshGameList(true, true); });
|
||||||
connect(m_ui.actionViewToolbar, &QAction::toggled, this, &MainWindow::onViewToolbarActionToggled);
|
connect(m_ui.actionViewToolbar, &QAction::toggled, this, &MainWindow::onViewToolbarActionToggled);
|
||||||
connect(m_ui.actionViewLockToolbar, &QAction::toggled, this, &MainWindow::onViewLockToolbarActionToggled);
|
connect(m_ui.actionViewLockToolbar, &QAction::toggled, this, &MainWindow::onViewLockToolbarActionToggled);
|
||||||
connect(m_ui.actionViewStatusBar, &QAction::toggled, this, &MainWindow::onViewStatusBarActionToggled);
|
connect(m_ui.actionViewStatusBar, &QAction::toggled, this, &MainWindow::onViewStatusBarActionToggled);
|
||||||
@ -547,7 +547,7 @@ void MainWindow::recreate()
|
|||||||
MainWindow* new_main_window = new MainWindow();
|
MainWindow* new_main_window = new MainWindow();
|
||||||
pxAssert(g_main_window == new_main_window);
|
pxAssert(g_main_window == new_main_window);
|
||||||
new_main_window->initialize();
|
new_main_window->initialize();
|
||||||
new_main_window->refreshGameList(false);
|
new_main_window->refreshGameList(false, false);
|
||||||
new_main_window->show();
|
new_main_window->show();
|
||||||
deleteLater();
|
deleteLater();
|
||||||
|
|
||||||
@ -1137,7 +1137,7 @@ bool MainWindow::shouldMouseLock() const
|
|||||||
if (!Host::GetBoolSettingValue("EmuCore", "EnableMouseLock", false))
|
if (!Host::GetBoolSettingValue("EmuCore", "EnableMouseLock", false))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
if(m_display_created == false || m_display_widget == nullptr && !isRenderingToMain())
|
if (m_display_created == false || m_display_widget == nullptr && !isRenderingToMain())
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
bool windowsHidden = (!g_debugger_window || g_debugger_window->isHidden()) &&
|
bool windowsHidden = (!g_debugger_window || g_debugger_window->isHidden()) &&
|
||||||
@ -1146,7 +1146,7 @@ bool MainWindow::shouldMouseLock() const
|
|||||||
|
|
||||||
auto* displayWindow = isRenderingToMain() ? window() : m_display_widget->window();
|
auto* displayWindow = isRenderingToMain() ? window() : m_display_widget->window();
|
||||||
|
|
||||||
if(displayWindow == nullptr)
|
if (displayWindow == nullptr)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
return windowsHidden && (displayWindow->isActiveWindow() || displayWindow->isFullScreen());
|
return windowsHidden && (displayWindow->isActiveWindow() || displayWindow->isFullScreen());
|
||||||
@ -1215,13 +1215,9 @@ void MainWindow::switchToEmulationView()
|
|||||||
m_display_widget->setFocus();
|
m_display_widget->setFocus();
|
||||||
}
|
}
|
||||||
|
|
||||||
void MainWindow::refreshGameList(bool invalidate_cache)
|
void MainWindow::refreshGameList(bool invalidate_cache, bool popup_on_error)
|
||||||
{
|
{
|
||||||
// can't do this while the VM is running because of CDVD
|
m_game_list_widget->refresh(invalidate_cache, popup_on_error);
|
||||||
if (s_vm_valid)
|
|
||||||
return;
|
|
||||||
|
|
||||||
m_game_list_widget->refresh(invalidate_cache);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void MainWindow::cancelGameListRefresh()
|
void MainWindow::cancelGameListRefresh()
|
||||||
@ -1466,8 +1462,7 @@ void MainWindow::onGameListEntryContextMenuRequested(const QPoint& point)
|
|||||||
const time_t entry_played_time = GameList::GetCachedPlayedTimeForSerial(entry->serial);
|
const time_t entry_played_time = GameList::GetCachedPlayedTimeForSerial(entry->serial);
|
||||||
// Best two options given zero play time are to grey this out or to not show it at all.
|
// Best two options given zero play time are to grey this out or to not show it at all.
|
||||||
if (entry_played_time)
|
if (entry_played_time)
|
||||||
connect(menu.addAction(tr("Reset Play Time")), &QAction::triggered, [this, entry, entry_played_time]()
|
connect(menu.addAction(tr("Reset Play Time")), &QAction::triggered, [this, entry, entry_played_time]() { clearGameListEntryPlayTime(entry, entry_played_time); });
|
||||||
{ clearGameListEntryPlayTime(entry, entry_played_time); });
|
|
||||||
|
|
||||||
// Check Wiki Page functionality is based on a serial redirect.
|
// Check Wiki Page functionality is based on a serial redirect.
|
||||||
if (!entry->serial.empty())
|
if (!entry->serial.empty())
|
||||||
@ -2102,7 +2097,7 @@ void MainWindow::onVMStopped()
|
|||||||
|
|
||||||
// reload played time
|
// reload played time
|
||||||
if (m_game_list_widget->isShowingGameList())
|
if (m_game_list_widget->isShowingGameList())
|
||||||
m_game_list_widget->refresh(false);
|
m_game_list_widget->refresh(false, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
void MainWindow::onGameChanged(const QString& title, const QString& elf_override, const QString& disc_path,
|
void MainWindow::onGameChanged(const QString& title, const QString& elf_override, const QString& disc_path,
|
||||||
@ -2932,12 +2927,12 @@ void MainWindow::clearGameListEntryPlayTime(const GameList::Entry* entry, const
|
|||||||
if (QMessageBox::question(this, tr("Confirm Reset"),
|
if (QMessageBox::question(this, tr("Confirm Reset"),
|
||||||
tr("Are you sure you want to reset the play time for '%1' (%2)?\n\nYour current play time is %3.\n\nThis action cannot be undone.")
|
tr("Are you sure you want to reset the play time for '%1' (%2)?\n\nYour current play time is %3.\n\nThis action cannot be undone.")
|
||||||
.arg(entry->title.empty() ? tr("empty title") : QString::fromStdString(entry->title),
|
.arg(entry->title.empty() ? tr("empty title") : QString::fromStdString(entry->title),
|
||||||
entry->serial.empty() ? tr("no serial") : QString::fromStdString(entry->serial),
|
entry->serial.empty() ? tr("no serial") : QString::fromStdString(entry->serial),
|
||||||
QString::fromStdString(GameList::FormatTimespan(entry_played_time, true))),
|
QString::fromStdString(GameList::FormatTimespan(entry_played_time, true))),
|
||||||
(QMessageBox::Yes | QMessageBox::No), QMessageBox::No) == QMessageBox::Yes)
|
(QMessageBox::Yes | QMessageBox::No), QMessageBox::No) == QMessageBox::Yes)
|
||||||
{
|
{
|
||||||
GameList::ClearPlayedTimeForSerial(entry->serial);
|
GameList::ClearPlayedTimeForSerial(entry->serial);
|
||||||
m_game_list_widget->refresh(false);
|
m_game_list_widget->refresh(false, false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -113,7 +113,7 @@ public:
|
|||||||
void checkMousePosition(int x, int y);
|
void checkMousePosition(int x, int y);
|
||||||
public Q_SLOTS:
|
public Q_SLOTS:
|
||||||
void checkForUpdates(bool display_message, bool force_check);
|
void checkForUpdates(bool display_message, bool force_check);
|
||||||
void refreshGameList(bool invalidate_cache);
|
void refreshGameList(bool invalidate_cache, bool popup_on_error);
|
||||||
void cancelGameListRefresh();
|
void cancelGameListRefresh();
|
||||||
void reportInfo(const QString& title, const QString& message);
|
void reportInfo(const QString& title, const QString& message);
|
||||||
void reportError(const QString& title, const QString& message);
|
void reportError(const QString& title, const QString& message);
|
||||||
|
|||||||
@ -1152,7 +1152,7 @@ void Host::OpenHostFileSelectorAsync(std::string_view title, bool select_directo
|
|||||||
if (!filters.empty())
|
if (!filters.empty())
|
||||||
{
|
{
|
||||||
filters_str.append(QStringLiteral("All File Types (%1)")
|
filters_str.append(QStringLiteral("All File Types (%1)")
|
||||||
.arg(QString::fromStdString(StringUtil::JoinString(filters.begin(), filters.end(), " "))));
|
.arg(QString::fromStdString(StringUtil::JoinString(filters.begin(), filters.end(), " "))));
|
||||||
for (const std::string& filter : filters)
|
for (const std::string& filter : filters)
|
||||||
{
|
{
|
||||||
filters_str.append(
|
filters_str.append(
|
||||||
@ -2385,7 +2385,7 @@ int main(int argc, char* argv[])
|
|||||||
|
|
||||||
// When running in batch mode, ensure game list is loaded, but don't scan for any new files.
|
// When running in batch mode, ensure game list is loaded, but don't scan for any new files.
|
||||||
if (!s_batch_mode)
|
if (!s_batch_mode)
|
||||||
g_main_window->refreshGameList(false);
|
g_main_window->refreshGameList(false, false);
|
||||||
else
|
else
|
||||||
GameList::Refresh(false, true);
|
GameList::Refresh(false, true);
|
||||||
|
|
||||||
|
|||||||
@ -63,7 +63,7 @@ bool GameListSettingsWidget::addExcludedPath(const std::string& path)
|
|||||||
|
|
||||||
Host::CommitBaseSettingChanges();
|
Host::CommitBaseSettingChanges();
|
||||||
m_ui.excludedPaths->addItem(QString::fromStdString(path));
|
m_ui.excludedPaths->addItem(QString::fromStdString(path));
|
||||||
g_main_window->refreshGameList(false);
|
g_main_window->refreshGameList(false, true);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -152,7 +152,7 @@ void GameListSettingsWidget::addSearchDirectory(const QString& path, bool recurs
|
|||||||
Host::AddBaseValueToStringList("GameList", recursive ? "RecursivePaths" : "Paths", spath.c_str());
|
Host::AddBaseValueToStringList("GameList", recursive ? "RecursivePaths" : "Paths", spath.c_str());
|
||||||
Host::CommitBaseSettingChanges();
|
Host::CommitBaseSettingChanges();
|
||||||
refreshDirectoryList();
|
refreshDirectoryList();
|
||||||
g_main_window->refreshGameList(false);
|
g_main_window->refreshGameList(false, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
void GameListSettingsWidget::removeSearchDirectory(const QString& path)
|
void GameListSettingsWidget::removeSearchDirectory(const QString& path)
|
||||||
@ -166,7 +166,7 @@ void GameListSettingsWidget::removeSearchDirectory(const QString& path)
|
|||||||
|
|
||||||
Host::CommitBaseSettingChanges();
|
Host::CommitBaseSettingChanges();
|
||||||
refreshDirectoryList();
|
refreshDirectoryList();
|
||||||
g_main_window->refreshGameList(false);
|
g_main_window->refreshGameList(false, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
void GameListSettingsWidget::onDirectoryListContextMenuRequested(const QPoint& point)
|
void GameListSettingsWidget::onDirectoryListContextMenuRequested(const QPoint& point)
|
||||||
@ -261,7 +261,7 @@ void GameListSettingsWidget::onRemoveExcludedPathButtonClicked()
|
|||||||
|
|
||||||
delete item;
|
delete item;
|
||||||
|
|
||||||
g_main_window->refreshGameList(false);
|
g_main_window->refreshGameList(false, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
void GameListSettingsWidget::onExcludedPathsSelectionChanged()
|
void GameListSettingsWidget::onExcludedPathsSelectionChanged()
|
||||||
@ -271,10 +271,10 @@ void GameListSettingsWidget::onExcludedPathsSelectionChanged()
|
|||||||
|
|
||||||
void GameListSettingsWidget::onRescanAllGamesClicked()
|
void GameListSettingsWidget::onRescanAllGamesClicked()
|
||||||
{
|
{
|
||||||
g_main_window->refreshGameList(true);
|
g_main_window->refreshGameList(true, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
void GameListSettingsWidget::onScanForNewGamesClicked()
|
void GameListSettingsWidget::onScanForNewGamesClicked()
|
||||||
{
|
{
|
||||||
g_main_window->refreshGameList(false);
|
g_main_window->refreshGameList(false, true);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -280,7 +280,8 @@ void GameSummaryWidget::onVerifyClicked()
|
|||||||
Error error;
|
Error error;
|
||||||
if (!hasher.Open(m_entry_path, &error))
|
if (!hasher.Open(m_entry_path, &error))
|
||||||
{
|
{
|
||||||
setVerifyResult(QString::fromStdString(error.GetDescription()));
|
QString message(QString::fromStdString(error.GetDescription()));
|
||||||
|
QMessageBox::critical(QtUtils::GetRootWidget(this), tr("Error"), message);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -21,6 +21,7 @@
|
|||||||
#include <ctype.h>
|
#include <ctype.h>
|
||||||
#include <exception>
|
#include <exception>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
#include <mutex>
|
||||||
#include <time.h>
|
#include <time.h>
|
||||||
|
|
||||||
#include "fmt/format.h"
|
#include "fmt/format.h"
|
||||||
@ -270,6 +271,23 @@ static void DetectDiskType()
|
|||||||
|
|
||||||
static std::string m_SourceFilename[3];
|
static std::string m_SourceFilename[3];
|
||||||
static CDVD_SourceType m_CurrentSourceType = CDVD_SourceType::NoDisc;
|
static CDVD_SourceType m_CurrentSourceType = CDVD_SourceType::NoDisc;
|
||||||
|
static std::mutex s_cdvd_lock;
|
||||||
|
|
||||||
|
bool cdvdLock(Error* error)
|
||||||
|
{
|
||||||
|
if (!s_cdvd_lock.try_lock())
|
||||||
|
{
|
||||||
|
Error::SetString(error, TRANSLATE_STR("CDVD", "The CDVD system is currently in use."));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void cdvdUnlock()
|
||||||
|
{
|
||||||
|
s_cdvd_lock.unlock();
|
||||||
|
}
|
||||||
|
|
||||||
void CDVDsys_SetFile(CDVD_SourceType srctype, std::string newfile)
|
void CDVDsys_SetFile(CDVD_SourceType srctype, std::string newfile)
|
||||||
{
|
{
|
||||||
@ -579,7 +597,7 @@ static s32 NODISCdummyS32()
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void NODISCnewDiskCB(void (*/* callback */)())
|
static void NODISCnewDiskCB(void (* /* callback */)())
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -20,7 +20,6 @@ struct cdvdTrackIndex
|
|||||||
u8 discM; // current minute location on the disc (BCD encoded)
|
u8 discM; // current minute location on the disc (BCD encoded)
|
||||||
u8 discS; // current sector location on the disc (BCD encoded)
|
u8 discS; // current sector location on the disc (BCD encoded)
|
||||||
u8 discF; // current frame location on the disc (BCD encoded)
|
u8 discF; // current frame location on the disc (BCD encoded)
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
struct cdvdTrack
|
struct cdvdTrack
|
||||||
@ -188,6 +187,13 @@ extern u8 strack;
|
|||||||
extern u8 etrack;
|
extern u8 etrack;
|
||||||
extern std::array<cdvdTrack, 100> tracks;
|
extern std::array<cdvdTrack, 100> tracks;
|
||||||
|
|
||||||
|
/// Try to take the CDVD lock, return false if it's already in use.
|
||||||
|
/// Must be called before your first CDVD call.
|
||||||
|
extern bool cdvdLock(Error* error = nullptr);
|
||||||
|
|
||||||
|
/// Release the CDVD lock. Must be called after you're done with CDVD.
|
||||||
|
extern void cdvdUnlock();
|
||||||
|
|
||||||
extern void CDVDsys_ChangeSource(CDVD_SourceType type);
|
extern void CDVDsys_ChangeSource(CDVD_SourceType type);
|
||||||
extern void CDVDsys_SetFile(CDVD_SourceType srctype, std::string newfile);
|
extern void CDVDsys_SetFile(CDVD_SourceType srctype, std::string newfile);
|
||||||
extern const std::string& CDVDsys_GetFile(CDVD_SourceType srctype);
|
extern const std::string& CDVDsys_GetFile(CDVD_SourceType srctype);
|
||||||
|
|||||||
@ -7,7 +7,6 @@
|
|||||||
|
|
||||||
#include "common/Error.h"
|
#include "common/Error.h"
|
||||||
#include "common/MD5Digest.h"
|
#include "common/MD5Digest.h"
|
||||||
#include "common/StringUtil.h"
|
|
||||||
|
|
||||||
#include "fmt/format.h"
|
#include "fmt/format.h"
|
||||||
|
|
||||||
@ -39,6 +38,10 @@ bool IsoHasher::Open(std::string iso_path, Error* error)
|
|||||||
{
|
{
|
||||||
Close();
|
Close();
|
||||||
|
|
||||||
|
m_is_locked = cdvdLock(error);
|
||||||
|
if (!m_is_locked)
|
||||||
|
return false;
|
||||||
|
|
||||||
CDVDsys_SetFile(CDVD_SourceType::Iso, std::move(iso_path));
|
CDVDsys_SetFile(CDVD_SourceType::Iso, std::move(iso_path));
|
||||||
CDVDsys_ChangeSource(CDVD_SourceType::Iso);
|
CDVDsys_ChangeSource(CDVD_SourceType::Iso);
|
||||||
|
|
||||||
@ -103,6 +106,12 @@ bool IsoHasher::Open(std::string iso_path, Error* error)
|
|||||||
|
|
||||||
void IsoHasher::Close()
|
void IsoHasher::Close()
|
||||||
{
|
{
|
||||||
|
if (!m_is_locked)
|
||||||
|
return;
|
||||||
|
|
||||||
|
cdvdUnlock();
|
||||||
|
m_is_locked = false;
|
||||||
|
|
||||||
if (!m_is_open)
|
if (!m_is_open)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
@ -151,7 +160,7 @@ bool IsoHasher::ComputeTrackHash(Track& track, ProgressCallback* callback)
|
|||||||
const u32 update_interval = std::max<u32>(track.sectors / 100u, 1u);
|
const u32 update_interval = std::max<u32>(track.sectors / 100u, 1u);
|
||||||
callback->SetStatusText(
|
callback->SetStatusText(
|
||||||
fmt::format(TRANSLATE_FS("CDVD", "Calculating checksum for track {}..."), track.number).c_str());
|
fmt::format(TRANSLATE_FS("CDVD", "Calculating checksum for track {}..."), track.number).c_str());
|
||||||
callback->SetProgressRange(track.sectors);
|
callback->SetProgressRange(track.sectors);
|
||||||
|
|
||||||
MD5Digest md5;
|
MD5Digest md5;
|
||||||
for (u32 i = 0; i < track.sectors; i++)
|
for (u32 i = 0; i < track.sectors; i++)
|
||||||
|
|||||||
@ -28,6 +28,9 @@ public:
|
|||||||
IsoHasher();
|
IsoHasher();
|
||||||
~IsoHasher();
|
~IsoHasher();
|
||||||
|
|
||||||
|
IsoHasher(const IsoHasher&) = delete;
|
||||||
|
IsoHasher& operator=(const IsoHasher&) = delete;
|
||||||
|
|
||||||
static std::string_view GetTrackTypeString(u32 type);
|
static std::string_view GetTrackTypeString(u32 type);
|
||||||
|
|
||||||
u32 GetTrackCount() const { return static_cast<u32>(m_tracks.size()); }
|
u32 GetTrackCount() const { return static_cast<u32>(m_tracks.size()); }
|
||||||
@ -44,6 +47,7 @@ private:
|
|||||||
bool ComputeTrackHash(Track& track, ProgressCallback* callback);
|
bool ComputeTrackHash(Track& track, ProgressCallback* callback);
|
||||||
|
|
||||||
std::vector<Track> m_tracks;
|
std::vector<Track> m_tracks;
|
||||||
|
bool m_is_locked = false;
|
||||||
bool m_is_open = false;
|
bool m_is_open = false;
|
||||||
bool m_is_cd = false;
|
bool m_is_cd = false;
|
||||||
};
|
};
|
||||||
|
|||||||
@ -163,6 +163,9 @@ void SymbolImporter::Reset()
|
|||||||
|
|
||||||
void SymbolImporter::LoadAndAnalyseElf(Pcsx2Config::DebugAnalysisOptions options)
|
void SymbolImporter::LoadAndAnalyseElf(Pcsx2Config::DebugAnalysisOptions options)
|
||||||
{
|
{
|
||||||
|
if (!VMManager::HasValidVM())
|
||||||
|
return;
|
||||||
|
|
||||||
const std::string& elf_path = VMManager::GetCurrentELF();
|
const std::string& elf_path = VMManager::GetCurrentELF();
|
||||||
|
|
||||||
Error error;
|
Error error;
|
||||||
@ -192,6 +195,9 @@ void SymbolImporter::AnalyseElf(
|
|||||||
Pcsx2Config::DebugAnalysisOptions options,
|
Pcsx2Config::DebugAnalysisOptions options,
|
||||||
bool wait_until_elf_is_loaded)
|
bool wait_until_elf_is_loaded)
|
||||||
{
|
{
|
||||||
|
if (!VMManager::HasValidVM())
|
||||||
|
return;
|
||||||
|
|
||||||
// Search for a .sym file to load symbols from.
|
// Search for a .sym file to load symbols from.
|
||||||
std::string nocash_path;
|
std::string nocash_path;
|
||||||
CDVD_SourceType source_type = CDVDsys_GetSourceType();
|
CDVD_SourceType source_type = CDVDsys_GetSourceType();
|
||||||
|
|||||||
@ -16,6 +16,7 @@
|
|||||||
#include "common/HeterogeneousContainers.h"
|
#include "common/HeterogeneousContainers.h"
|
||||||
#include "common/Path.h"
|
#include "common/Path.h"
|
||||||
#include "common/ProgressCallback.h"
|
#include "common/ProgressCallback.h"
|
||||||
|
#include "common/ScopedGuard.h"
|
||||||
#include "common/StringUtil.h"
|
#include "common/StringUtil.h"
|
||||||
|
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
@ -826,6 +827,15 @@ void GameList::Refresh(bool invalidate_cache, bool only_cache, ProgressCallback*
|
|||||||
if (!progress)
|
if (!progress)
|
||||||
progress = ProgressCallback::NullProgressCallback;
|
progress = ProgressCallback::NullProgressCallback;
|
||||||
|
|
||||||
|
Error cdvd_lock_error;
|
||||||
|
if (!cdvdLock(&cdvd_lock_error))
|
||||||
|
{
|
||||||
|
progress->DisplayError(cdvd_lock_error.GetDescription().c_str());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
ScopedGuard unlock_cdvd = &cdvdUnlock;
|
||||||
|
|
||||||
if (invalidate_cache)
|
if (invalidate_cache)
|
||||||
DeleteCacheFile();
|
DeleteCacheFile();
|
||||||
else
|
else
|
||||||
|
|||||||
@ -485,7 +485,7 @@ void VMManager::UpdateLoggingSettings(SettingsInterface& si)
|
|||||||
if (system_console_enabled != Log::IsConsoleOutputEnabled())
|
if (system_console_enabled != Log::IsConsoleOutputEnabled())
|
||||||
Log::SetConsoleOutputLevel(system_console_enabled ? level : LOGLEVEL_NONE);
|
Log::SetConsoleOutputLevel(system_console_enabled ? level : LOGLEVEL_NONE);
|
||||||
|
|
||||||
// Debug console only exists on Windows.
|
// Debug console only exists on Windows.
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
const bool debug_console_enabled = IsDebuggerPresent() && si.GetBoolValue("Logging", "EnableDebugConsole", false);
|
const bool debug_console_enabled = IsDebuggerPresent() && si.GetBoolValue("Logging", "EnableDebugConsole", false);
|
||||||
Log::SetDebugOutputLevel(debug_console_enabled ? level : LOGLEVEL_NONE);
|
Log::SetDebugOutputLevel(debug_console_enabled ? level : LOGLEVEL_NONE);
|
||||||
@ -776,8 +776,8 @@ std::string VMManager::GetGameSettingsPath(const std::string_view game_serial, u
|
|||||||
std::string sanitized_serial(Path::SanitizeFileName(game_serial));
|
std::string sanitized_serial(Path::SanitizeFileName(game_serial));
|
||||||
|
|
||||||
return game_serial.empty() ?
|
return game_serial.empty() ?
|
||||||
Path::Combine(EmuFolders::GameSettings, fmt::format("{:08X}.ini", game_crc)) :
|
Path::Combine(EmuFolders::GameSettings, fmt::format("{:08X}.ini", game_crc)) :
|
||||||
Path::Combine(EmuFolders::GameSettings, fmt::format("{}_{:08X}.ini", sanitized_serial, game_crc));
|
Path::Combine(EmuFolders::GameSettings, fmt::format("{}_{:08X}.ini", sanitized_serial, game_crc));
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string VMManager::GetDiscOverrideFromGameSettings(const std::string& elf_path)
|
std::string VMManager::GetDiscOverrideFromGameSettings(const std::string& elf_path)
|
||||||
@ -1324,6 +1324,15 @@ bool VMManager::Initialize(VMBootParameters boot_params)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Error cdvd_lock_error;
|
||||||
|
if (!cdvdLock(&cdvd_lock_error))
|
||||||
|
{
|
||||||
|
Host::ReportErrorAsync("Startup Error", cdvd_lock_error.GetDescription());
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
ScopedGuard unlock_cdvd = &cdvdUnlock;
|
||||||
|
|
||||||
// resolve source type
|
// resolve source type
|
||||||
if (boot_params.source_type.has_value())
|
if (boot_params.source_type.has_value())
|
||||||
{
|
{
|
||||||
@ -1355,12 +1364,14 @@ bool VMManager::Initialize(VMBootParameters boot_params)
|
|||||||
if (!LoadBIOS())
|
if (!LoadBIOS())
|
||||||
{
|
{
|
||||||
Host::ReportErrorAsync(TRANSLATE_SV("VMManager", "Error – No BIOS Present"),
|
Host::ReportErrorAsync(TRANSLATE_SV("VMManager", "Error – No BIOS Present"),
|
||||||
fmt::format(TRANSLATE_FS("VMManager",
|
fmt::format(
|
||||||
"PCSX2 requires a PlayStation 2 BIOS in order to run.\n\n"
|
TRANSLATE_FS("VMManager",
|
||||||
"For legal reasons, you will need to obtain this BIOS from a PlayStation 2 unit which you own.\n\n"
|
"PCSX2 requires a PlayStation 2 BIOS in order to run.\n\n"
|
||||||
"For step-by-step help with this process, please consult the setup guide at {}.\n\n"
|
"For legal reasons, you will need to obtain this BIOS from a PlayStation 2 unit which you own.\n\n"
|
||||||
"PCSX2 will be able to run once you've placed your BIOS image inside the folder named \"bios\" within the data directory "
|
"For step-by-step help with this process, please consult the setup guide at {}.\n\n"
|
||||||
"(Tools Menu -> Open Data Directory)."), PCSX2_DOCUMENTATION_BIOS_URL_SHORTENED));
|
"PCSX2 will be able to run once you've placed your BIOS image inside the folder named \"bios\" within the data directory "
|
||||||
|
"(Tools Menu -> Open Data Directory)."),
|
||||||
|
PCSX2_DOCUMENTATION_BIOS_URL_SHORTENED));
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1559,6 +1570,7 @@ bool VMManager::Initialize(VMBootParameters boot_params)
|
|||||||
close_memcards.Cancel();
|
close_memcards.Cancel();
|
||||||
close_cdvd.Cancel();
|
close_cdvd.Cancel();
|
||||||
close_cdvd_files.Cancel();
|
close_cdvd_files.Cancel();
|
||||||
|
unlock_cdvd.Cancel();
|
||||||
close_state.Cancel();
|
close_state.Cancel();
|
||||||
|
|
||||||
if (EmuConfig.CdvdPrecache)
|
if (EmuConfig.CdvdPrecache)
|
||||||
@ -1667,6 +1679,8 @@ void VMManager::Shutdown(bool save_resume_state)
|
|||||||
else
|
else
|
||||||
cdvdSaveNVRAM();
|
cdvdSaveNVRAM();
|
||||||
|
|
||||||
|
cdvdUnlock();
|
||||||
|
|
||||||
s_state.store(VMState::Shutdown, std::memory_order_release);
|
s_state.store(VMState::Shutdown, std::memory_order_release);
|
||||||
FullscreenUI::OnVMDestroyed();
|
FullscreenUI::OnVMDestroyed();
|
||||||
SaveStateSelectorUI::Clear();
|
SaveStateSelectorUI::Clear();
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user