From 8ed244ee658eaa169d34557facea18247a8aae76 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Sat, 7 Nov 2026 10:57:46 +0100 Subject: [PATCH] UI: Only list disc images on the UMD switch screen Both its lists offered everything bootable, the XMB, homebrew and PS1 games included, though only what UmdMount takes can go in the drive. The new UMDS_ONLY browse flag keeps PSP disc images and disc folders. ISOs and CSOs are trusted by extension so big folders stay quick to list; CHDs and PBPs are identified, since they can be PS1 games. Co-Authored-By: Claude Opus 5.5 --- UI/GameBrowser.cpp | 43 ++++++++++++++++++++++++++++++++++++++++--- UI/GameBrowser.h | 1 + UI/MainScreen.cpp | 4 ++-- 3 files changed, 43 insertions(+), 5 deletions(-) diff --git a/UI/GameBrowser.cpp b/UI/GameBrowser.cpp index d752af6314..b40a08612d 100644 --- a/UI/GameBrowser.cpp +++ b/UI/GameBrowser.cpp @@ -38,6 +38,7 @@ #include "Core/HLE/sceCtrl.h" #include "Core/ELF/PBPReader.h" #include "Core/FileLoaders/PS1EbootFileLoader.h" +#include "Core/Loaders.h" #include "Core/MemMap.h" #include "UI/GameBrowser.h" @@ -277,11 +278,42 @@ void GameBrowser::PinToggleClick(UI::EventParams &e) { refreshPending_ = true; } +// Whether UmdMount takes it: a PSP disc image (also a UMD video, or a PSN game's ISO in an EBOOT.PBP), +// or a disc's files in a directory. +static bool IsUmdPath(const Path &path, bool isDirectory) { + if (!isDirectory) { + const std::string ext = path.GetFileExtension(); + // Trusted by name, since opening every image would make big folders slow to list. + if (ext == ".iso" || ext == ".cso") { + return true; + } + // A CHD can hold a PS1 disc, and a PBP can be homebrew or a PS1 game. + if (ext != ".chd" && ext != ".pbp") { + return false; + } + } + std::unique_ptr loader(ConstructFileLoader(path)); + std::string error; + switch (Identify_File(loader.get(), &error)) { + case IdentifiedFileType::PSP_ISO: + case IdentifiedFileType::PSP_ISO_NP: + case IdentifiedFileType::PSP_DISC_DIRECTORY: + case IdentifiedFileType::PSP_UMD_VIDEO_ISO: + return true; + default: + return false; + } +} + bool GameBrowser::HasSpecialFiles(std::vector &filenames) { if (path_.GetPath().ToString() == "!RECENT") { filenames.clear(); for (auto &str : g_recentFiles.GetRecentFiles()) { - filenames.emplace_back(str); + Path path(str); + if ((browseFlags_ & BrowseFlags::UMDS_ONLY) && !IsUmdPath(path, File::IsDirectory(path))) { + continue; + } + filenames.push_back(path); } return true; } @@ -524,8 +556,9 @@ void GameBrowser::Refresh() { gameButtons.push_back(new GameButton(GameButtonType::Game, filenames[i], lastViewMode_, new UI::LinearLayoutParams(gridStyle ? UI::WRAP_CONTENT : UI::FILL_PARENT, UI::WRAP_CONTENT))); } } else if (!listingPending_) { + const bool umdsOnly = browseFlags_ & BrowseFlags::UMDS_ONLY; std::vector fileInfo; - path_.GetListing(fileInfo, "iso:cso:chd:pbp:elf:prx:ppdmp:cue:ccd:mds:bin:img:"); + path_.GetListing(fileInfo, umdsOnly ? "iso:cso:chd:pbp:" : "iso:cso:chd:pbp:elf:prx:ppdmp:cue:ccd:mds:bin:img:"); // PS1 discs: a .bin or .img shows up as its cue sheet or .ccd, when it has one. RemoveDescribedDiscImages(&fileInfo); // Drives and servers aren't games, and probing a server that's gone away can take seconds. @@ -543,6 +576,10 @@ void GameBrowser::Refresh() { else if (!isGame && File::Exists(path_.GetPath() / fileInfo[i].name / "PARAM.SFO")) isSaveData = true; + if (umdsOnly && (isSaveData || (isGame && !IsUmdPath(fileInfo[i].fullName, fileInfo[i].isDirectory)))) { + continue; + } + if (!isGame && !isSaveData) { if (browseFlags_ & BrowseFlags::NAVIGATE) { dirButtons.push_back(new GameButton(GameButtonType::Dir, fileInfo[i].fullName, lastViewMode_, new UI::LinearLayoutParams(UI::FILL_PARENT, UI::FILL_PARENT))); @@ -558,7 +595,7 @@ void GameBrowser::Refresh() { // Put RAR/ZIP files at the end to get them out of the way. Game update packages go here // too - they're not something to boot, they're something to install. // We do support unpacking some of them automatically. - if (browseFlags_ & BrowseFlags::ARCHIVES) { + if ((browseFlags_ & BrowseFlags::ARCHIVES) && !umdsOnly) { fileInfo.clear(); path_.GetListing(fileInfo, "zip:rar:r00:r01:7z:pkg:"); if (!fileInfo.empty()) { diff --git a/UI/GameBrowser.h b/UI/GameBrowser.h index 0f429ac243..49c4f87229 100644 --- a/UI/GameBrowser.h +++ b/UI/GameBrowser.h @@ -28,6 +28,7 @@ enum class BrowseFlags { PIN = 8, HOMEBREW_STORE = 16, UPLOAD_BUTTON = 32, + UMDS_ONLY = 64, // Only what can go in the UMD drive (see UmdMount). STANDARD = 1 | 2 | 4 | 8 | 32, }; ENUM_CLASS_BITOPS(BrowseFlags); diff --git a/UI/MainScreen.cpp b/UI/MainScreen.cpp index 044a1a1957..169521831d 100644 --- a/UI/MainScreen.cpp +++ b/UI/MainScreen.cpp @@ -959,7 +959,7 @@ void UmdReplaceScreen::CreateContentViews(UI::ViewGroup *parent) { ScrollView *scrollRecentGames = new ScrollView(ORIENT_VERTICAL, new LinearLayoutParams(FILL_PARENT, WRAP_CONTENT)); scrollRecentGames->SetTag("UmdReplaceRecentGames"); GameBrowser *tabRecentGames = new GameBrowser(GetRequesterToken(), - Path("!RECENT"), BrowseFlags::NONE, portrait, &g_Config.iGameBrowserView1, screenManager(), "", "", + Path("!RECENT"), BrowseFlags::UMDS_ONLY, portrait, &g_Config.iGameBrowserView1, screenManager(), "", "", new LinearLayoutParams(FILL_PARENT, FILL_PARENT)); scrollRecentGames->Add(tabRecentGames); tabs->AddTab(mm->T("Recent"), ImageID::invalid(), scrollRecentGames); @@ -969,7 +969,7 @@ void UmdReplaceScreen::CreateContentViews(UI::ViewGroup *parent) { ScrollView *scrollAllGames = new ScrollView(ORIENT_VERTICAL, new LinearLayoutParams(FILL_PARENT, WRAP_CONTENT)); scrollAllGames->SetTag("UmdReplaceAllGames"); - GameBrowser *tabAllGames = new GameBrowser(GetRequesterToken(), Path(g_Config.currentDirectory), BrowseFlags::STANDARD, portrait, &g_Config.iGameBrowserView2, screenManager(), + GameBrowser *tabAllGames = new GameBrowser(GetRequesterToken(), Path(g_Config.currentDirectory), BrowseFlags::STANDARD | BrowseFlags::UMDS_ONLY, portrait, &g_Config.iGameBrowserView2, screenManager(), mm->T("How to get games"), "https://www.ppsspp.org/getgames.html", new LinearLayoutParams(FILL_PARENT, FILL_PARENT));