|
|
|
@ -1,6 +1,7 @@ |
|
|
|
#include "qt_common.h"
|
|
|
|
#include "common/fs/fs.h"
|
|
|
|
#include "common/fs/path_util.h"
|
|
|
|
#include "core/hle/service/filesystem/filesystem.h"
|
|
|
|
#include "uisettings.h"
|
|
|
|
|
|
|
|
#include <QGuiApplication>
|
|
|
|
@ -21,17 +22,18 @@ MetadataResult ResetMetadata() |
|
|
|
{ |
|
|
|
if (!Common::FS::Exists(Common::FS::GetEdenPath(Common::FS::EdenPath::CacheDir) |
|
|
|
/ "game_list/")) { |
|
|
|
return Empty; |
|
|
|
return MetadataResult::Empty; |
|
|
|
} else if (Common::FS::RemoveDirRecursively( |
|
|
|
Common::FS::GetEdenPath(Common::FS::EdenPath::CacheDir) / "game_list")) { |
|
|
|
return Success; |
|
|
|
return MetadataResult::Success; |
|
|
|
UISettings::values.is_game_list_reload_pending.exchange(true); |
|
|
|
} else { |
|
|
|
return Failure; |
|
|
|
return MetadataResult::Failure; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
Core::Frontend::WindowSystemType GetWindowSystemType() { |
|
|
|
Core::Frontend::WindowSystemType GetWindowSystemType() |
|
|
|
{ |
|
|
|
// Determine WSI type based on Qt platform.
|
|
|
|
QString platform_name = QGuiApplication::platformName(); |
|
|
|
if (platform_name == QStringLiteral("windows")) |
|
|
|
@ -51,7 +53,8 @@ Core::Frontend::WindowSystemType GetWindowSystemType() { |
|
|
|
return Core::Frontend::WindowSystemType::Windows; |
|
|
|
} // namespace Core::Frontend::WindowSystemType
|
|
|
|
|
|
|
|
Core::Frontend::EmuWindow::WindowSystemInfo GetWindowSystemInfo(QWindow* window) { |
|
|
|
Core::Frontend::EmuWindow::WindowSystemInfo GetWindowSystemInfo(QWindow* window) |
|
|
|
{ |
|
|
|
Core::Frontend::EmuWindow::WindowSystemInfo wsi; |
|
|
|
wsi.type = GetWindowSystemType(); |
|
|
|
|
|
|
|
@ -59,8 +62,8 @@ Core::Frontend::EmuWindow::WindowSystemInfo GetWindowSystemInfo(QWindow* window) |
|
|
|
// Our Win32 Qt external doesn't have the private API.
|
|
|
|
wsi.render_surface = reinterpret_cast<void*>(window->winId()); |
|
|
|
#elif defined(__APPLE__)
|
|
|
|
wsi.render_surface = reinterpret_cast<void* (*)(id, SEL)>(objc_msgSend)( |
|
|
|
reinterpret_cast<id>(window->winId()), sel_registerName("layer")); |
|
|
|
wsi.render_surface = reinterpret_cast<void* (*) (id, SEL)>( |
|
|
|
objc_msgSend)(reinterpret_cast<id>(window->winId()), sel_registerName("layer")); |
|
|
|
#else
|
|
|
|
QPlatformNativeInterface* pni = QGuiApplication::platformNativeInterface(); |
|
|
|
wsi.display_connection = pni->nativeResourceForWindow("display", window); |
|
|
|
@ -74,4 +77,92 @@ Core::Frontend::EmuWindow::WindowSystemInfo GetWindowSystemInfo(QWindow* window) |
|
|
|
return wsi; |
|
|
|
} |
|
|
|
|
|
|
|
FirmwareInstallResult InstallFirmware(const QString& location, |
|
|
|
bool recursive, |
|
|
|
std::function<bool(size_t, size_t)> QtProgressCallback, |
|
|
|
Core::System* system, |
|
|
|
FileSys::VfsFilesystem* vfs) |
|
|
|
{ |
|
|
|
LOG_INFO(Frontend, "Installing firmware from {}", location.toStdString()); |
|
|
|
|
|
|
|
// Check for a reasonable number of .nca files (don't hardcode them, just see if there's some in
|
|
|
|
// there.)
|
|
|
|
std::filesystem::path firmware_source_path = location.toStdString(); |
|
|
|
if (!Common::FS::IsDir(firmware_source_path)) { |
|
|
|
return FirmwareInstallResult::NoOp; |
|
|
|
} |
|
|
|
|
|
|
|
std::vector<std::filesystem::path> out; |
|
|
|
const Common::FS::DirEntryCallable callback = |
|
|
|
[&out](const std::filesystem::directory_entry& entry) { |
|
|
|
if (entry.path().has_extension() && entry.path().extension() == ".nca") { |
|
|
|
out.emplace_back(entry.path()); |
|
|
|
} |
|
|
|
|
|
|
|
return true; |
|
|
|
}; |
|
|
|
|
|
|
|
QtProgressCallback(100, 10); |
|
|
|
|
|
|
|
if (recursive) { |
|
|
|
Common::FS::IterateDirEntriesRecursively(firmware_source_path, |
|
|
|
callback, |
|
|
|
Common::FS::DirEntryFilter::File); |
|
|
|
} else { |
|
|
|
Common::FS::IterateDirEntries(firmware_source_path, |
|
|
|
callback, |
|
|
|
Common::FS::DirEntryFilter::File); |
|
|
|
} |
|
|
|
|
|
|
|
if (out.size() <= 0) { |
|
|
|
return FirmwareInstallResult::NoNCAs; |
|
|
|
} |
|
|
|
|
|
|
|
// Locate and erase the content of nand/system/Content/registered/*.nca, if any.
|
|
|
|
auto sysnand_content_vdir = system->GetFileSystemController().GetSystemNANDContentDirectory(); |
|
|
|
if (!sysnand_content_vdir->CleanSubdirectoryRecursive("registered")) { |
|
|
|
return FirmwareInstallResult::FailedDelete; |
|
|
|
} |
|
|
|
|
|
|
|
LOG_INFO(Frontend, |
|
|
|
"Cleaned nand/system/Content/registered folder in preparation for new firmware."); |
|
|
|
|
|
|
|
QtProgressCallback(100, 20); |
|
|
|
|
|
|
|
auto firmware_vdir = sysnand_content_vdir->GetDirectoryRelative("registered"); |
|
|
|
|
|
|
|
bool success = true; |
|
|
|
int i = 0; |
|
|
|
for (const auto& firmware_src_path : out) { |
|
|
|
i++; |
|
|
|
auto firmware_src_vfile = vfs->OpenFile(firmware_src_path.generic_string(), |
|
|
|
FileSys::OpenMode::Read); |
|
|
|
auto firmware_dst_vfile = firmware_vdir |
|
|
|
->CreateFileRelative(firmware_src_path.filename().string()); |
|
|
|
|
|
|
|
if (!VfsRawCopy(firmware_src_vfile, firmware_dst_vfile)) { |
|
|
|
LOG_ERROR(Frontend, |
|
|
|
"Failed to copy firmware file {} to {} in registered folder!", |
|
|
|
firmware_src_path.generic_string(), |
|
|
|
firmware_src_path.filename().string()); |
|
|
|
success = false; |
|
|
|
} |
|
|
|
|
|
|
|
if (QtProgressCallback(100, |
|
|
|
20 |
|
|
|
+ static_cast<int>(((i) / static_cast<float>(out.size())) |
|
|
|
* 70.0))) { |
|
|
|
return FirmwareInstallResult::FailedCorrupted; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
if (!success) { |
|
|
|
return FirmwareInstallResult::FailedCopy; |
|
|
|
} |
|
|
|
|
|
|
|
// Re-scan VFS for the newly placed firmware files.
|
|
|
|
system->GetFileSystemController().CreateFactories(*vfs); |
|
|
|
return FirmwareInstallResult::Success; |
|
|
|
} |
|
|
|
|
|
|
|
} |