mirror of https://github.com/PCSX2/pcsx2.git
Qt: Ensure settings are writable before running setup wizard
This commit is contained in:
parent
332be6c771
commit
f8b18d406f
|
@ -88,7 +88,8 @@ static u32 s_total_drawn_frames = 0;
|
|||
|
||||
bool GSRunner::InitializeConfig()
|
||||
{
|
||||
if (!EmuFolders::InitializeCriticalFolders())
|
||||
EmuFolders::SetAppRoot();
|
||||
if (!EmuFolders::SetResourcesDirectory() || !EmuFolders::SetDataDirectory(nullptr))
|
||||
return false;
|
||||
|
||||
const char* error;
|
||||
|
|
|
@ -34,6 +34,7 @@
|
|||
#include "common/Assertions.h"
|
||||
#include "common/Console.h"
|
||||
#include "common/CrashHandler.h"
|
||||
#include "common/Error.h"
|
||||
#include "common/FileSystem.h"
|
||||
#include "common/HTTPDownloader.h"
|
||||
#include "common/Path.h"
|
||||
|
@ -1197,23 +1198,41 @@ void Host::OnCaptureStopped()
|
|||
|
||||
bool QtHost::InitializeConfig()
|
||||
{
|
||||
if (!EmuFolders::InitializeCriticalFolders())
|
||||
Error error;
|
||||
|
||||
EmuFolders::SetAppRoot();
|
||||
|
||||
if (!EmuFolders::SetResourcesDirectory())
|
||||
{
|
||||
QMessageBox::critical(nullptr, QStringLiteral("PCSX2"),
|
||||
QStringLiteral("One or more critical directories are missing, your installation may be incomplete."));
|
||||
QStringLiteral("Resources directory is missing, your installation is incomplete."));
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!EmuFolders::SetDataDirectory(&error))
|
||||
{
|
||||
// no point translating, config isn't loaded
|
||||
QMessageBox::critical(
|
||||
nullptr, QStringLiteral("PCSX2"),
|
||||
QStringLiteral("Failed to create data directory at path\n\n%1\n\n"
|
||||
"The error was: %2\n"
|
||||
"Please ensure this directory is writable. You can also try portable mode "
|
||||
"by creating portable.txt in the same directory you installed PCSX2 into.")
|
||||
.arg(QString::fromStdString(EmuFolders::DataRoot))
|
||||
.arg(QString::fromStdString(error.GetDescription())));
|
||||
return false;
|
||||
}
|
||||
|
||||
// Write crash dumps to the data directory, since that'll be accessible for certain.
|
||||
CrashHandler::SetWriteDirectory(EmuFolders::DataRoot);
|
||||
|
||||
const std::string path(Path::Combine(EmuFolders::Settings, "PCSX2.ini"));
|
||||
s_run_setup_wizard = s_run_setup_wizard || !FileSystem::FileExists(path.c_str());
|
||||
Console.WriteLn("Loading config from %s.", path.c_str());
|
||||
const std::string path = Path::Combine(EmuFolders::Settings, "PCSX2.ini");
|
||||
const bool settings_exists = FileSystem::FileExists(path.c_str());
|
||||
Console.WriteLnFmt("Loading config from {}.", path);
|
||||
|
||||
s_base_settings_interface = std::make_unique<INISettingsInterface>(std::move(path));
|
||||
Host::Internal::SetBaseSettingsLayer(s_base_settings_interface.get());
|
||||
if (!s_base_settings_interface->Load() || !VMManager::Internal::CheckSettingsVersion())
|
||||
if (!settings_exists || !s_base_settings_interface->Load() || !VMManager::Internal::CheckSettingsVersion())
|
||||
{
|
||||
// If the config file doesn't exist, assume this is a new install and don't prompt to overwrite.
|
||||
if (FileSystem::FileExists(s_base_settings_interface->GetFileName().c_str()) &&
|
||||
|
@ -1226,6 +1245,22 @@ bool QtHost::InitializeConfig()
|
|||
|
||||
VMManager::SetDefaultSettings(*s_base_settings_interface, true, true, true, true, true);
|
||||
|
||||
// Flag for running the setup wizard if this is our first run. We want to run it next time if they don't finish it.
|
||||
s_base_settings_interface->SetBoolValue("UI", "SetupWizardIncomplete", true);
|
||||
|
||||
// Make sure we can actually save the config, and the user doesn't have some permission issue.
|
||||
if (!s_base_settings_interface->Save(&error))
|
||||
{
|
||||
QMessageBox::critical(
|
||||
nullptr, QStringLiteral("PCSX2"),
|
||||
QStringLiteral(
|
||||
"Failed to save configuration to\n\n%1\n\nThe error was: %2\n\nPlease ensure this directory is writable. You "
|
||||
"can also try portable mode by creating portable.txt in the same directory you installed PCSX2 into.")
|
||||
.arg(QString::fromStdString(s_base_settings_interface->GetFileName()))
|
||||
.arg(QString::fromStdString(error.GetDescription())));
|
||||
return false;
|
||||
}
|
||||
|
||||
// Don't save if we're running the setup wizard. We want to run it next time if they don't finish it.
|
||||
if (!s_run_setup_wizard)
|
||||
SaveSettings();
|
||||
|
@ -1379,8 +1414,7 @@ std::optional<bool> QtHost::DownloadFile(QWidget* parent, const QString& title,
|
|||
const std::string::size_type url_file_part_pos = url.rfind('/');
|
||||
QtModalProgressCallback progress(parent);
|
||||
progress.GetDialog().setLabelText(
|
||||
qApp->translate("EmuThread", "Downloading %1...").arg(QtUtils::StringViewToQString(
|
||||
std::string_view(url).substr((url_file_part_pos != std::string::npos) ? (url_file_part_pos + 1) : 0))));
|
||||
qApp->translate("EmuThread", "Downloading %1...").arg(QtUtils::StringViewToQString(std::string_view(url).substr((url_file_part_pos != std::string::npos) ? (url_file_part_pos + 1) : 0))));
|
||||
progress.GetDialog().setWindowTitle(title);
|
||||
progress.GetDialog().setWindowIcon(GetAppIcon());
|
||||
progress.SetCancellable(true);
|
||||
|
@ -1403,8 +1437,8 @@ std::optional<bool> QtHost::DownloadFile(QWidget* parent, const QString& title,
|
|||
QMessageBox::critical(parent, qApp->translate("EmuThread", "Error"),
|
||||
qApp->translate("EmuThread", "Download failed: Data is empty.").arg(status_code));
|
||||
|
||||
download_result = false;
|
||||
return;
|
||||
download_result = false;
|
||||
return;
|
||||
}
|
||||
|
||||
*data = std::move(hdata);
|
||||
|
@ -1851,10 +1885,6 @@ void QtHost::RegisterTypes()
|
|||
|
||||
bool QtHost::RunSetupWizard()
|
||||
{
|
||||
// Set a flag in the config so that even though we created the ini, we'll run the wizard next time.
|
||||
Host::SetBaseBoolSettingValue("UI", "SetupWizardIncomplete", true);
|
||||
Host::CommitBaseSettingChanges();
|
||||
|
||||
SetupWizardDialog dialog;
|
||||
if (dialog.exec() == QDialog::Rejected)
|
||||
return false;
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
// SPDX-FileCopyrightText: 2002-2023 PCSX2 Dev Team
|
||||
// SPDX-FileCopyrightText: 2002-2024 PCSX2 Dev Team
|
||||
// SPDX-License-Identifier: LGPL-3.0+
|
||||
|
||||
#pragma once
|
||||
|
@ -24,6 +24,7 @@
|
|||
} \
|
||||
;
|
||||
|
||||
class Error;
|
||||
class SettingsInterface;
|
||||
class SettingsWrapper;
|
||||
|
||||
|
@ -1226,7 +1227,9 @@ namespace EmuFolders
|
|||
extern std::string Videos;
|
||||
|
||||
/// Initializes critical folders (AppRoot, DataRoot, Settings). Call once on startup.
|
||||
bool InitializeCriticalFolders();
|
||||
void SetAppRoot();
|
||||
bool SetResourcesDirectory();
|
||||
bool SetDataDirectory(Error* error);
|
||||
|
||||
// Assumes that AppRoot and DataRoot have been initialized.
|
||||
void SetDefaults(SettingsInterface& si);
|
||||
|
|
|
@ -167,10 +167,7 @@ namespace EmuFolders
|
|||
std::string InputProfiles;
|
||||
std::string Videos;
|
||||
|
||||
static void SetAppRoot();
|
||||
static void SetResourcesDirectory();
|
||||
static bool ShouldUsePortableMode();
|
||||
static void SetDataDirectory();
|
||||
} // namespace EmuFolders
|
||||
|
||||
TraceFiltersEE::TraceFiltersEE()
|
||||
|
@ -1845,26 +1842,28 @@ void Pcsx2Config::ClearConfiguration(SettingsInterface* dest_si)
|
|||
temp.LoadSaveCore(wrapper);
|
||||
}
|
||||
|
||||
bool EmuFolders::InitializeCriticalFolders()
|
||||
void EmuFolders::SetAppRoot()
|
||||
{
|
||||
SetAppRoot();
|
||||
SetResourcesDirectory();
|
||||
SetDataDirectory();
|
||||
const std::string program_path = FileSystem::GetProgramPath();
|
||||
Console.WriteLnFmt("Program Path: {}", program_path);
|
||||
|
||||
AppRoot = Path::Canonicalize(Path::GetDirectory(program_path));
|
||||
|
||||
// logging of directories in case something goes wrong super early
|
||||
Console.WriteLn("AppRoot Directory: %s", AppRoot.c_str());
|
||||
Console.WriteLn("DataRoot Directory: %s", DataRoot.c_str());
|
||||
Console.WriteLn("Resources Directory: %s", Resources.c_str());
|
||||
Console.WriteLnFmt("AppRoot Directory: {}", AppRoot);
|
||||
}
|
||||
|
||||
// allow SetDataDirectory() to change settings directory (if we want to split config later on)
|
||||
if (Settings.empty())
|
||||
{
|
||||
Settings = Path::Combine(DataRoot, "inis");
|
||||
bool EmuFolders::SetResourcesDirectory()
|
||||
{
|
||||
#ifndef __APPLE__
|
||||
// On Windows/Linux, these are in the binary directory.
|
||||
Resources = Path::Combine(AppRoot, "resources");
|
||||
#else
|
||||
// On macOS, this is in the bundle resources directory.
|
||||
Resources = Path::Canonicalize(Path::Combine(AppRoot, "../Resources"));
|
||||
#endif
|
||||
|
||||
// Create settings directory if it doesn't exist. If we're not using portable mode, it won't.
|
||||
if (!FileSystem::DirectoryExists(Settings.c_str()))
|
||||
FileSystem::CreateDirectoryPath(Settings.c_str(), false);
|
||||
}
|
||||
Console.WriteLnFmt("Resources Directory: {}", Resources);
|
||||
|
||||
// the resources directory should exist, bail out if not
|
||||
if (!FileSystem::DirectoryExists(Resources.c_str()))
|
||||
|
@ -1876,87 +1875,65 @@ bool EmuFolders::InitializeCriticalFolders()
|
|||
return true;
|
||||
}
|
||||
|
||||
void EmuFolders::SetAppRoot()
|
||||
{
|
||||
const std::string program_path = FileSystem::GetProgramPath();
|
||||
Console.WriteLn("Program Path: %s", program_path.c_str());
|
||||
|
||||
AppRoot = Path::Canonicalize(Path::GetDirectory(program_path));
|
||||
}
|
||||
|
||||
void EmuFolders::SetResourcesDirectory()
|
||||
{
|
||||
#ifndef __APPLE__
|
||||
// On Windows/Linux, these are in the binary directory.
|
||||
Resources = Path::Combine(AppRoot, "resources");
|
||||
#else
|
||||
// On macOS, this is in the bundle resources directory.
|
||||
Resources = Path::Canonicalize(Path::Combine(AppRoot, "../Resources"));
|
||||
#endif
|
||||
}
|
||||
|
||||
bool EmuFolders::ShouldUsePortableMode()
|
||||
{
|
||||
// Check whether portable.ini exists in the program directory.
|
||||
return FileSystem::FileExists(Path::Combine(AppRoot, "portable.ini").c_str()) || FileSystem::FileExists(Path::Combine(AppRoot, "portable.txt").c_str());
|
||||
}
|
||||
|
||||
void EmuFolders::SetDataDirectory()
|
||||
bool EmuFolders::SetDataDirectory(Error* error)
|
||||
{
|
||||
if (ShouldUsePortableMode())
|
||||
if (!ShouldUsePortableMode())
|
||||
{
|
||||
DataRoot = AppRoot;
|
||||
return;
|
||||
}
|
||||
|
||||
#if defined(_WIN32)
|
||||
// On Windows, use My Documents\PCSX2 to match old installs.
|
||||
PWSTR documents_directory;
|
||||
if (SUCCEEDED(SHGetKnownFolderPath(FOLDERID_Documents, 0, NULL, &documents_directory)))
|
||||
{
|
||||
if (std::wcslen(documents_directory) > 0)
|
||||
DataRoot = Path::Combine(StringUtil::WideStringToUTF8String(documents_directory), "PCSX2");
|
||||
CoTaskMemFree(documents_directory);
|
||||
}
|
||||
// On Windows, use My Documents\PCSX2 to match old installs.
|
||||
PWSTR documents_directory;
|
||||
if (SUCCEEDED(SHGetKnownFolderPath(FOLDERID_Documents, 0, NULL, &documents_directory)))
|
||||
{
|
||||
if (std::wcslen(documents_directory) > 0)
|
||||
DataRoot = Path::Combine(StringUtil::WideStringToUTF8String(documents_directory), "PCSX2");
|
||||
CoTaskMemFree(documents_directory);
|
||||
}
|
||||
#elif defined(__linux__) || defined(__FreeBSD__)
|
||||
// Use $XDG_CONFIG_HOME/PCSX2 if it exists.
|
||||
const char* xdg_config_home = getenv("XDG_CONFIG_HOME");
|
||||
if (xdg_config_home && Path::IsAbsolute(xdg_config_home))
|
||||
{
|
||||
DataRoot = Path::RealPath(Path::Combine(xdg_config_home, "PCSX2"));
|
||||
}
|
||||
else
|
||||
{
|
||||
// Use ~/PCSX2 for non-XDG, and ~/.config/PCSX2 for XDG.
|
||||
// Use $XDG_CONFIG_HOME/PCSX2 if it exists.
|
||||
const char* xdg_config_home = getenv("XDG_CONFIG_HOME");
|
||||
if (xdg_config_home && Path::IsAbsolute(xdg_config_home))
|
||||
{
|
||||
DataRoot = Path::RealPath(Path::Combine(xdg_config_home, "PCSX2"));
|
||||
}
|
||||
else
|
||||
{
|
||||
// Use ~/PCSX2 for non-XDG, and ~/.config/PCSX2 for XDG.
|
||||
const char* home_dir = getenv("HOME");
|
||||
if (home_dir)
|
||||
{
|
||||
// ~/.config should exist, but just in case it doesn't and this is a fresh profile..
|
||||
const std::string config_dir(Path::Combine(home_dir, ".config"));
|
||||
if (!FileSystem::DirectoryExists(config_dir.c_str()))
|
||||
FileSystem::CreateDirectoryPath(config_dir.c_str(), false);
|
||||
|
||||
DataRoot = Path::RealPath(Path::Combine(config_dir, "PCSX2"));
|
||||
}
|
||||
}
|
||||
#elif defined(__APPLE__)
|
||||
static constexpr char MAC_DATA_DIR[] = "Library/Application Support/PCSX2";
|
||||
const char* home_dir = getenv("HOME");
|
||||
if (home_dir)
|
||||
{
|
||||
// ~/.config should exist, but just in case it doesn't and this is a fresh profile..
|
||||
const std::string config_dir(Path::Combine(home_dir, ".config"));
|
||||
if (!FileSystem::DirectoryExists(config_dir.c_str()))
|
||||
FileSystem::CreateDirectoryPath(config_dir.c_str(), false);
|
||||
|
||||
DataRoot = Path::RealPath(Path::Combine(config_dir, "PCSX2"));
|
||||
}
|
||||
}
|
||||
#elif defined(__APPLE__)
|
||||
static constexpr char MAC_DATA_DIR[] = "Library/Application Support/PCSX2";
|
||||
const char* home_dir = getenv("HOME");
|
||||
if (home_dir)
|
||||
DataRoot = Path::RealPath(Path::Combine(home_dir, MAC_DATA_DIR));
|
||||
DataRoot = Path::RealPath(Path::Combine(home_dir, MAC_DATA_DIR));
|
||||
#endif
|
||||
|
||||
// make sure it exists
|
||||
if (!DataRoot.empty() && !FileSystem::DirectoryExists(DataRoot.c_str()))
|
||||
{
|
||||
// we're in trouble if we fail to create this directory... but try to hobble on with portable
|
||||
if (!FileSystem::CreateDirectoryPath(DataRoot.c_str(), false))
|
||||
DataRoot.clear();
|
||||
}
|
||||
|
||||
// couldn't determine the data directory? fallback to portable.
|
||||
// couldn't determine the data directory, or using portable mode? fallback to portable.
|
||||
if (DataRoot.empty())
|
||||
DataRoot = AppRoot;
|
||||
|
||||
// inis is always below the data root
|
||||
Settings = Path::Combine(DataRoot, "inis");
|
||||
|
||||
// make sure it exists
|
||||
Console.WriteLnFmt("DataRoot Directory: {}", DataRoot);
|
||||
return (FileSystem::EnsureDirectoryExists(DataRoot.c_str(), false, error) &&
|
||||
FileSystem::EnsureDirectoryExists(Settings.c_str(), false, error));
|
||||
}
|
||||
|
||||
void EmuFolders::SetDefaults(SettingsInterface& si)
|
||||
|
|
Loading…
Reference in New Issue