move disk usage dialog box to game list's context menu (#17977)
Some checks are pending
Generate Translation Template / Generate Translation Template (push) Waiting to run
Build RPCS3 / RPCS3 Linux ${{ matrix.os }} ${{ matrix.compiler }} (/rpcs3/.ci/build-linux-aarch64.sh, gcc, rpcs3/rpcs3-ci-jammy-aarch64:1.7, ubuntu-24.04-arm) (push) Waiting to run
Build RPCS3 / RPCS3 Linux ${{ matrix.os }} ${{ matrix.compiler }} (/rpcs3/.ci/build-linux.sh, gcc, rpcs3/rpcs3-ci-jammy:1.7, ubuntu-24.04) (push) Waiting to run
Build RPCS3 / RPCS3 Linux ${{ matrix.os }} ${{ matrix.compiler }} (a1d35836e8d45bfc6f63c26f0a3e5d46ef622fe1, rpcs3/rpcs3-binaries-linux-arm64, /rpcs3/.ci/build-linux-aarch64.sh, clang, rpcs3/rpcs3-ci-jammy-aarch64:1.7, ubuntu-24.04-arm) (push) Waiting to run
Build RPCS3 / RPCS3 Linux ${{ matrix.os }} ${{ matrix.compiler }} (d812f1254a1157c80fd402f94446310560f54e5f, rpcs3/rpcs3-binaries-linux, /rpcs3/.ci/build-linux.sh, clang, rpcs3/rpcs3-ci-jammy:1.7, ubuntu-24.04) (push) Waiting to run
Build RPCS3 / RPCS3 Mac ${{ matrix.name }} (0, 51ae32f468089a8169aaf1567de355ff4a3e0842, rpcs3/rpcs3-binaries-mac, Intel) (push) Waiting to run
Build RPCS3 / RPCS3 Mac ${{ matrix.name }} (1, 8e21bdbc40711a3fccd18fbf17b742348b0f4281, rpcs3/rpcs3-binaries-mac-arm64, Apple Silicon) (push) Waiting to run
Build RPCS3 / RPCS3 Windows (push) Waiting to run
Build RPCS3 / RPCS3 Windows Clang (win64, clang, clang64) (push) Waiting to run
Build RPCS3 / RPCS3 FreeBSD (push) Waiting to run

This commit is contained in:
Antonino Di Guardo 2026-01-07 08:22:40 +01:00 committed by GitHub
parent 90df8baa5f
commit 27033ee0cb
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
5 changed files with 207 additions and 202 deletions

View file

@ -25,6 +25,7 @@
#include <QTimer>
LOG_CHANNEL(game_list_log, "GameList");
LOG_CHANNEL(sys_log, "SYS");
extern atomic_t<bool> g_system_progress_canceled;
@ -340,7 +341,7 @@ void game_list_actions::ShowRemoveGameDialog(const std::vector<game_info>& games
if (content_info.is_single_selection) // Single selection
{
if (!RemoveContentList(games[0]->info.serial, true))
if (!RemoveContentList(games[0]->info.serial))
{
QMessageBox::critical(m_game_list_frame, tr("Failure!"), caches->isChecked()
? tr("Failed to remove %0 from drive!\nCaches and custom configs have been left intact.").arg(QString::fromStdString(games[0]->info.name))
@ -351,7 +352,7 @@ void game_list_actions::ShowRemoveGameDialog(const std::vector<game_info>& games
}
else // Multi selection
{
BatchRemoveContentLists(games, true);
BatchRemoveContentLists(games);
}
}
@ -363,6 +364,41 @@ void game_list_actions::ShowGameInfoDialog(const std::vector<game_info>& games)
QMessageBox::information(m_game_list_frame, tr("Game Info"), GetContentInfo(games).info);
}
void game_list_actions::ShowDiskUsageDialog()
{
if (m_disk_usage_future.isRunning()) // Still running the last request
return;
// Disk usage calculation can take a while (in particular on non ssd/m.2 disks)
// so run it on a concurrent thread avoiding to block the entire GUI
m_disk_usage_future = QtConcurrent::run([this]()
{
const std::vector<std::pair<std::string, u64>> vfs_disk_usage = rpcs3::utils::get_vfs_disk_usage();
const u64 cache_disk_usage = rpcs3::utils::get_cache_disk_usage();
QString text;
u64 tot_data_size = 0;
for (const auto& [dev, data_size] : vfs_disk_usage)
{
text += tr("\n %0: %1").arg(QString::fromStdString(dev)).arg(gui::utils::format_byte_size(data_size));
tot_data_size += data_size;
}
if (!text.isEmpty())
text = tr("\n VFS disk usage: %0%1").arg(gui::utils::format_byte_size(tot_data_size)).arg(text);
text += tr("\n Cache disk usage: %0").arg(gui::utils::format_byte_size(cache_disk_usage));
sys_log.success("%s", text);
Emu.CallFromMainThread([this, text]()
{
QMessageBox::information(m_game_list_frame, tr("Disk usage"), text);
}, nullptr, false);
});
}
bool game_list_actions::IsGameRunning(const std::string& serial)
{
return !Emu.IsStopped(true) && (serial == Emu.GetTitleID() || (serial == "vsh.self" && Emu.IsVsh()));
@ -1063,6 +1099,128 @@ void game_list_actions::BatchCreateCPUCaches(const std::vector<game_info>& games
});
}
void game_list_actions::BatchRemoveCustomConfigurations(const std::vector<game_info>& games, bool is_interactive)
{
if (is_interactive && QMessageBox::question(m_game_list_frame, tr("Confirm Removal"), tr("Remove custom configuration?")) != QMessageBox::Yes)
{
return;
}
std::set<std::string> serials;
for (const auto& game : (games.empty() ? m_game_list_frame->GetGameInfo() : games))
{
if (game->has_custom_config && !serials.count(game->info.serial))
{
serials.emplace(game->info.serial);
}
}
const u32 total = ::size32(serials);
if (total == 0)
{
QMessageBox::information(m_game_list_frame, tr("Custom Configuration Batch Removal"), tr("No files found"), QMessageBox::Ok);
return;
}
progress_dialog* pdlg = new progress_dialog(tr("Custom Configuration Batch Removal"), tr("Removing all custom configurations"), tr("Cancel"), 0, total, false, m_game_list_frame);
pdlg->setAutoClose(false);
pdlg->setAutoReset(false);
pdlg->open();
BatchActionBySerials(pdlg, serials, tr("%0/%1 custom configurations cleared"), [this](const std::string& serial)
{
return !serial.empty() && Emu.IsStopped(true) && RemoveCustomConfiguration(serial);
},
[](u32 removed, u32 total)
{
game_list_log.notice("Custom Configuration Batch Removal was canceled. %d/%d custom configurations cleared", removed, total);
}, nullptr, true);
}
void game_list_actions::BatchRemoveCustomPadConfigurations(const std::vector<game_info>& games, bool is_interactive)
{
if (is_interactive && QMessageBox::question(m_game_list_frame, tr("Confirm Removal"), tr("Remove custom gamepad configuration?")) != QMessageBox::Yes)
{
return;
}
std::set<std::string> serials;
for (const auto& game : (games.empty() ? m_game_list_frame->GetGameInfo() : games))
{
if (game->has_custom_pad_config && !serials.count(game->info.serial))
{
serials.emplace(game->info.serial);
}
}
const u32 total = ::size32(serials);
if (total == 0)
{
QMessageBox::information(m_game_list_frame, tr("Custom Gamepad Configuration Batch Removal"), tr("No files found"), QMessageBox::Ok);
return;
}
progress_dialog* pdlg = new progress_dialog(tr("Custom Gamepad Configuration Batch Removal"), tr("Removing all custom gamepad configurations"), tr("Cancel"), 0, total, false, m_game_list_frame);
pdlg->setAutoClose(false);
pdlg->setAutoReset(false);
pdlg->open();
BatchActionBySerials(pdlg, serials, tr("%0/%1 custom gamepad configurations cleared"), [this](const std::string& serial)
{
return !serial.empty() && Emu.IsStopped(true) && RemoveCustomPadConfiguration(serial);
},
[](u32 removed, u32 total)
{
game_list_log.notice("Custom Gamepad Configuration Batch Removal was canceled. %d/%d custom gamepad configurations cleared", removed, total);
}, nullptr, true);
}
void game_list_actions::BatchRemoveShaderCaches(const std::vector<game_info>& games, bool is_interactive)
{
if (!ValidateBatchRemoval("shader cache", is_interactive))
{
return;
}
std::set<std::string> serials;
if (games.empty())
{
serials.emplace("vsh.self");
}
for (const auto& game : (games.empty() ? m_game_list_frame->GetGameInfo() : games))
{
serials.emplace(game->info.serial);
}
const u32 total = ::size32(serials);
if (total == 0)
{
QMessageBox::information(m_game_list_frame, tr("Shader Cache Batch Removal"), tr("No files found"), QMessageBox::Ok);
return;
}
progress_dialog* pdlg = new progress_dialog(tr("Shader Cache Batch Removal"), tr("Removing all shader caches"), tr("Cancel"), 0, total, false, m_game_list_frame);
pdlg->setAutoClose(false);
pdlg->setAutoReset(false);
pdlg->open();
BatchActionBySerials(pdlg, serials, tr("%0/%1 shader caches cleared"), [this](const std::string& serial)
{
return !serial.empty() && Emu.IsStopped(true) && RemoveShaderCache(serial);
},
[](u32 removed, u32 total)
{
game_list_log.notice("Shader Cache Batch Removal was canceled. %d/%d caches cleared", removed, total);
}, nullptr, false);
}
void game_list_actions::BatchRemovePPUCaches(const std::vector<game_info>& games, bool is_interactive)
{
if (!ValidateBatchRemoval("PPU cache", is_interactive))
@ -1288,131 +1446,6 @@ void game_list_actions::BatchRemoveContentLists(const std::vector<game_info>& ga
}, false);
}
void game_list_actions::BatchRemoveCustomConfigurations(const std::vector<game_info>& games, bool is_interactive)
{
if (is_interactive && QMessageBox::question(m_game_list_frame, tr("Confirm Removal"), tr("Remove custom configuration?")) != QMessageBox::Yes)
{
return;
}
std::set<std::string> serials;
for (const auto& game : (games.empty() ? m_game_list_frame->GetGameInfo() : games))
{
if (game->has_custom_config && !serials.count(game->info.serial))
{
serials.emplace(game->info.serial);
}
}
const u32 total = ::size32(serials);
if (total == 0)
{
QMessageBox::information(m_game_list_frame, tr("Custom Configuration Batch Removal"), tr("No files found"), QMessageBox::Ok);
return;
}
progress_dialog* pdlg = new progress_dialog(tr("Custom Configuration Batch Removal"), tr("Removing all custom configurations"), tr("Cancel"), 0, total, false, m_game_list_frame);
pdlg->setAutoClose(false);
pdlg->setAutoReset(false);
pdlg->open();
BatchActionBySerials(pdlg, serials, tr("%0/%1 custom configurations cleared"),
[this](const std::string& serial)
{
return !serial.empty() && Emu.IsStopped(true) && RemoveCustomConfiguration(serial);
},
[](u32 removed, u32 total)
{
game_list_log.notice("Custom Configuration Batch Removal was canceled. %d/%d custom configurations cleared", removed, total);
}, nullptr, true);
}
void game_list_actions::BatchRemoveCustomPadConfigurations(const std::vector<game_info>& games, bool is_interactive)
{
if (is_interactive && QMessageBox::question(m_game_list_frame, tr("Confirm Removal"), tr("Remove custom gamepad configuration?")) != QMessageBox::Yes)
{
return;
}
std::set<std::string> serials;
for (const auto& game : (games.empty() ? m_game_list_frame->GetGameInfo() : games))
{
if (game->has_custom_pad_config && !serials.count(game->info.serial))
{
serials.emplace(game->info.serial);
}
}
const u32 total = ::size32(serials);
if (total == 0)
{
QMessageBox::information(m_game_list_frame, tr("Custom Gamepad Configuration Batch Removal"), tr("No files found"), QMessageBox::Ok);
return;
}
progress_dialog* pdlg = new progress_dialog(tr("Custom Gamepad Configuration Batch Removal"), tr("Removing all custom gamepad configurations"), tr("Cancel"), 0, total, false, m_game_list_frame);
pdlg->setAutoClose(false);
pdlg->setAutoReset(false);
pdlg->open();
BatchActionBySerials(pdlg, serials, tr("%0/%1 custom gamepad configurations cleared"),
[this](const std::string& serial)
{
return !serial.empty() && Emu.IsStopped(true) && RemoveCustomPadConfiguration(serial);
},
[](u32 removed, u32 total)
{
game_list_log.notice("Custom Gamepad Configuration Batch Removal was canceled. %d/%d custom gamepad configurations cleared", removed, total);
}, nullptr, true);
}
void game_list_actions::BatchRemoveShaderCaches(const std::vector<game_info>& games, bool is_interactive)
{
if (!ValidateBatchRemoval("shader cache", is_interactive))
{
return;
}
std::set<std::string> serials;
if (games.empty())
{
serials.emplace("vsh.self");
}
for (const auto& game : (games.empty() ? m_game_list_frame->GetGameInfo() : games))
{
serials.emplace(game->info.serial);
}
const u32 total = ::size32(serials);
if (total == 0)
{
QMessageBox::information(m_game_list_frame, tr("Shader Cache Batch Removal"), tr("No files found"), QMessageBox::Ok);
return;
}
progress_dialog* pdlg = new progress_dialog(tr("Shader Cache Batch Removal"), tr("Removing all shader caches"), tr("Cancel"), 0, total, false, m_game_list_frame);
pdlg->setAutoClose(false);
pdlg->setAutoReset(false);
pdlg->open();
BatchActionBySerials(pdlg, serials, tr("%0/%1 shader caches cleared"),
[this](const std::string& serial)
{
return !serial.empty() && Emu.IsStopped(true) && RemoveShaderCache(serial);
},
[](u32 removed, u32 total)
{
game_list_log.notice("Shader Cache Batch Removal was canceled. %d/%d caches cleared", removed, total);
}, nullptr, false);
}
void game_list_actions::CreateShortcuts(const std::vector<game_info>& games, const std::set<gui::utils::shortcut_location>& locations)
{
if (games.empty())

View file

@ -3,6 +3,7 @@
#include "gui_game_info.h"
#include "shortcut_utils.h"
#include <QFuture>
#include <QObject>
class progress_dialog;
@ -53,15 +54,7 @@ public:
void ShowRemoveGameDialog(const std::vector<game_info>& games);
void ShowGameInfoDialog(const std::vector<game_info>& games);
void BatchCreateCPUCaches(const std::vector<game_info>& games = {}, bool is_fast_compilation = false, bool is_interactive = false);
void BatchRemoveCustomConfigurations(const std::vector<game_info>& games = {}, bool is_interactive = false);
void BatchRemoveCustomPadConfigurations(const std::vector<game_info>& games = {}, bool is_interactive = false);
void BatchRemoveShaderCaches(const std::vector<game_info>& games = {}, bool is_interactive = false);
void BatchRemovePPUCaches(const std::vector<game_info>& games = {}, bool is_interactive = false);
void BatchRemoveSPUCaches(const std::vector<game_info>& games = {}, bool is_interactive = false);
void BatchRemoveHDD1Caches(const std::vector<game_info>& games = {}, bool is_interactive = false);
void BatchRemoveAllCaches(const std::vector<game_info>& games = {}, bool is_interactive = false);
void ShowDiskUsageDialog();
// NOTES:
// - SetContentList() MUST always be called to set the content's info to be removed by:
@ -69,8 +62,6 @@ public:
// - BatchRemoveContentLists()
//
void SetContentList(u16 content_types, const content_info& content_info);
void BatchRemoveContentLists(const std::vector<game_info>& games = {}, bool is_interactive = false);
void ClearContentList(bool refresh = false);
content_info GetContentInfo(const std::vector<game_info>& games);
@ -88,6 +79,16 @@ public:
bool RemoveAllCaches(const std::string& serial, bool is_interactive = false);
bool RemoveContentList(const std::string& serial, bool is_interactive = false);
void BatchCreateCPUCaches(const std::vector<game_info>& games = {}, bool is_fast_compilation = false, bool is_interactive = false);
void BatchRemoveCustomConfigurations(const std::vector<game_info>& games = {}, bool is_interactive = false);
void BatchRemoveCustomPadConfigurations(const std::vector<game_info>& games = {}, bool is_interactive = false);
void BatchRemoveShaderCaches(const std::vector<game_info>& games = {}, bool is_interactive = false);
void BatchRemovePPUCaches(const std::vector<game_info>& games = {}, bool is_interactive = false);
void BatchRemoveSPUCaches(const std::vector<game_info>& games = {}, bool is_interactive = false);
void BatchRemoveHDD1Caches(const std::vector<game_info>& games = {}, bool is_interactive = false);
void BatchRemoveAllCaches(const std::vector<game_info>& games = {}, bool is_interactive = false);
void BatchRemoveContentLists(const std::vector<game_info>& games = {}, bool is_interactive = false);
static bool RemoveContentPath(const std::string& path, const std::string& desc);
static u32 RemoveContentPathList(const std::set<std::string>& path_list, const std::string& desc);
static bool RemoveContentBySerial(const std::string& base_dir, const std::string& serial, const std::string& desc);
@ -95,6 +96,7 @@ public:
private:
game_list_frame* m_game_list_frame = nullptr;
std::shared_ptr<gui_settings> m_gui_settings;
QFuture<void> m_disk_usage_future;
// NOTE:
// m_content_info is used by:

View file

@ -303,13 +303,6 @@ void game_list_context_menu::show_single_selection_context_menu(const game_info&
QAction* remove_game = manage_game_menu->addAction(tr("&Remove %1").arg(gameinfo->localized_category));
remove_game->setEnabled(!is_current_running_game);
// Game info
QAction* game_info = manage_game_menu->addAction(tr("&Game Info"));
connect(game_info, &QAction::triggered, this, [this, gameinfo]()
{
m_game_list_actions->ShowGameInfoDialog({gameinfo});
});
// Custom Images menu
QMenu* icon_menu = addMenu(tr("&Custom Images"));
const std::array<QAction*, 3> custom_icon_actions =
@ -457,8 +450,6 @@ void game_list_context_menu::show_single_selection_context_menu(const game_info&
icon_menu->setEnabled(false);
}
addSeparator();
// Open Folder menu
QMenu* open_folder_menu = addMenu(tr("&Open Folder"));
@ -575,6 +566,22 @@ void game_list_context_menu::show_single_selection_context_menu(const game_info&
QAction* check_compat = addAction(tr("&Check Game Compatibility"));
QAction* download_compat = addAction(tr("&Download Compatibility Database"));
addSeparator();
// Disk usage
QAction* disk_usage = addAction(tr("&Disk Usage"));
connect(disk_usage, &QAction::triggered, this, [this]()
{
m_game_list_actions->ShowDiskUsageDialog();
});
// Game info
QAction* game_info = addAction(tr("&Game Info"));
connect(game_info, &QAction::triggered, this, [this, gameinfo]()
{
m_game_list_actions->ShowGameInfoDialog({gameinfo});
});
connect(boot, &QAction::triggered, m_game_list_frame, [this, gameinfo]()
{
sys_log.notice("Booting from gamelist per context menu...");
@ -896,8 +903,25 @@ void game_list_context_menu::show_multi_selection_context_menu(const std::vector
m_game_list_actions->ShowRemoveGameDialog(games);
});
addSeparator();
QAction* download_compat = addAction(tr("&Download Compatibility Database"));
connect(download_compat, &QAction::triggered, m_game_list_frame, [this]
{
ensure(m_game_list_frame->GetGameCompatibility())->RequestCompatibility(true);
});
addSeparator();
// Disk usage
QAction* disk_usage = addAction(tr("&Disk Usage"));
connect(disk_usage, &QAction::triggered, this, [this]()
{
m_game_list_actions->ShowDiskUsageDialog();
});
// Game info
QAction* game_info = manage_game_menu->addAction(tr("&Game Info"));
QAction* game_info = addAction(tr("&Game Info"));
connect(game_info, &QAction::triggered, this, [this, games]()
{
m_game_list_actions->ShowGameInfoDialog(games);

View file

@ -4,14 +4,10 @@
#include "hex_validator.h"
#include "memory_viewer_panel.h"
#include "Emu/System.h"
#include "Emu/system_utils.hpp"
#include "Utilities/lockless.h"
#include "util/asm.hpp"
#include <QtConcurrent>
#include <QMenu>
#include <QMessageBox>
#include <QActionGroup>
#include <QScrollBar>
#include <QVBoxLayout>
@ -21,8 +17,6 @@
#include <deque>
#include <mutex>
LOG_CHANNEL(sys_log, "SYS");
extern fs::file g_tty;
extern atomic_t<s64> g_tty_size;
extern std::array<std::deque<std::string>, 16> g_tty_input;
@ -171,28 +165,6 @@ log_frame::log_frame(std::shared_ptr<gui_settings> _gui_settings, QWidget* paren
connect(m_timer, &QTimer::timeout, this, &log_frame::UpdateUI);
}
void log_frame::show_disk_usage(const std::vector<std::pair<std::string, u64>>& vfs_disk_usage, u64 cache_disk_usage)
{
QString text;
u64 tot_data_size = 0;
for (const auto& [dev, data_size] : vfs_disk_usage)
{
text += tr("\n %0: %1").arg(QString::fromStdString(dev)).arg(gui::utils::format_byte_size(data_size));
tot_data_size += data_size;
}
if (!text.isEmpty())
{
text = tr("\n VFS disk usage: %0%1").arg(gui::utils::format_byte_size(tot_data_size)).arg(text);
}
text += tr("\n Cache disk usage: %0").arg(gui::utils::format_byte_size(cache_disk_usage));
sys_log.success("%s", text);
QMessageBox::information(this, tr("Disk usage"), text);
}
void log_frame::SetLogLevel(logs::level lev) const
{
switch (lev)
@ -273,26 +245,6 @@ void log_frame::CreateAndConnectActions()
m_tty->clear();
});
m_show_disk_usage_act = new QAction(tr("Show Disk Usage"), this);
connect(m_show_disk_usage_act, &QAction::triggered, [this]()
{
if (m_disk_usage_future.isRunning())
{
return; // Still running the last request
}
m_disk_usage_future = QtConcurrent::run([this]()
{
const std::vector<std::pair<std::string, u64>> vfs_disk_usage = rpcs3::utils::get_vfs_disk_usage();
const u64 cache_disk_usage = rpcs3::utils::get_cache_disk_usage();
Emu.CallFromMainThread([this, vfs_disk_usage, cache_disk_usage]()
{
show_disk_usage(vfs_disk_usage, cache_disk_usage);
}, nullptr, false);
});
});
m_perform_goto_on_debugger = new QAction(tr("Go-To on Debugger"), this);
connect(m_perform_goto_on_debugger, &QAction::triggered, [this]()
{
@ -418,8 +370,6 @@ void log_frame::CreateAndConnectActions()
QMenu* menu = m_log->createStandardContextMenu();
menu->addAction(m_clear_act);
menu->addSeparator();
menu->addAction(m_show_disk_usage_act);
menu->addSeparator();
menu->addAction(m_perform_goto_on_debugger);
menu->addAction(m_perform_goto_thread_on_debugger);
menu->addAction(m_perform_show_in_mem_viewer);

View file

@ -8,7 +8,6 @@
#include <memory>
#include <QFuture>
#include <QTabWidget>
#include <QPlainTextEdit>
#include <QActionGroup>
@ -39,7 +38,6 @@ protected:
private Q_SLOTS:
void UpdateUI();
private:
void show_disk_usage(const std::vector<std::pair<std::string, u64>>& vfs_disk_usage, u64 cache_disk_usage);
void SetLogLevel(logs::level lev) const;
void SetTTYLogging(bool val) const;
@ -50,7 +48,6 @@ private:
std::unique_ptr<find_dialog> m_find_dialog;
QTimer* m_timer = nullptr;
QFuture<void> m_disk_usage_future;
std::vector<QColor> m_color;
QColor m_color_stack;
@ -75,7 +72,6 @@ private:
QAction* m_clear_act = nullptr;
QAction* m_clear_tty_act = nullptr;
QAction* m_show_disk_usage_act = nullptr;
QAction* m_perform_goto_on_debugger = nullptr;
QAction* m_perform_goto_thread_on_debugger = nullptr;
QAction* m_perform_show_in_mem_viewer = nullptr;