mirror of
https://github.com/RPCS3/rpcs3.git
synced 2025-08-12 02:59:51 +00:00
Qt: Exit And Save Log - toolbar action (#14212)
Fixup main_window::IsValidFile
This commit is contained in:
parent
db029ed29f
commit
ba988f1d3f
6 changed files with 230 additions and 1 deletions
|
@ -135,6 +135,7 @@ namespace gui
|
||||||
const gui_save fd_insert_disc = gui_save(main_window, "lastExplorePathDISC", "");
|
const gui_save fd_insert_disc = gui_save(main_window, "lastExplorePathDISC", "");
|
||||||
const gui_save fd_cfg_check = gui_save(main_window, "lastExplorePathCfgChk", "");
|
const gui_save fd_cfg_check = gui_save(main_window, "lastExplorePathCfgChk", "");
|
||||||
const gui_save fd_save_elf = gui_save(main_window, "lastExplorePathSaveElf", "");
|
const gui_save fd_save_elf = gui_save(main_window, "lastExplorePathSaveElf", "");
|
||||||
|
const gui_save fd_save_log = gui_save(main_window, "lastExplorePathSaveLog", "");
|
||||||
|
|
||||||
const gui_save mw_debugger = gui_save(main_window, "debuggerVisible", false);
|
const gui_save mw_debugger = gui_save(main_window, "debuggerVisible", false);
|
||||||
const gui_save mw_logger = gui_save(main_window, "loggerVisible", true);
|
const gui_save mw_logger = gui_save(main_window, "loggerVisible", true);
|
||||||
|
|
|
@ -2347,6 +2347,124 @@ void main_window::CreateConnects()
|
||||||
|
|
||||||
connect(ui->bootInstallPkgAct, &QAction::triggered, this, [this] {InstallPackages(); });
|
connect(ui->bootInstallPkgAct, &QAction::triggered, this, [this] {InstallPackages(); });
|
||||||
connect(ui->bootInstallPupAct, &QAction::triggered, this, [this] {InstallPup(); });
|
connect(ui->bootInstallPupAct, &QAction::triggered, this, [this] {InstallPup(); });
|
||||||
|
|
||||||
|
connect(this, &main_window::NotifyWindowCloseEvent, this, [this](bool closed)
|
||||||
|
{
|
||||||
|
if (!closed)
|
||||||
|
{
|
||||||
|
// Cancel the request
|
||||||
|
m_requested_show_logs_on_exit = false;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!m_requested_show_logs_on_exit)
|
||||||
|
{
|
||||||
|
// Not requested
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const std::string archived_path = fs::get_cache_dir() + "RPCS3.log.gz";
|
||||||
|
const std::string raw_file_path = fs::get_cache_dir() + "RPCS3.log";
|
||||||
|
|
||||||
|
fs::stat_t raw_stat{};
|
||||||
|
fs::stat_t archived_stat{};
|
||||||
|
|
||||||
|
if ((!fs::stat(raw_file_path, raw_stat) || raw_stat.is_directory) || (!fs::stat(archived_path, archived_stat) || archived_stat.is_directory) || (raw_stat.size == 0 && archived_stat.size == 0))
|
||||||
|
{
|
||||||
|
QMessageBox::warning(this, tr("Failed to locate log"), tr("Failed to locate log files.\nMake sure that RPCS3.log and RPCS3.log.gz are writable and can be created without permission issues."));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get new filename from title and title ID but simplified
|
||||||
|
std::string log_filename = Emu.GetTitleID().empty() ? "RPCS3" : Emu.GetTitleAndTitleID();
|
||||||
|
log_filename.erase(std::remove_if(log_filename.begin(), log_filename.end(), [](u8 c){ return !std::isalnum(c) && c != ' ' && c != '[' && ']'; }), log_filename.end());
|
||||||
|
fmt::trim_back(log_filename);
|
||||||
|
|
||||||
|
QString path_last_log = m_gui_settings->GetValue(gui::fd_save_log).toString();
|
||||||
|
|
||||||
|
auto move_log = [](const std::string& from, const std::string& to)
|
||||||
|
{
|
||||||
|
if (from == to)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Test writablity here to avoid closing the log with no *chance* of success
|
||||||
|
if (fs::file test_writable{to, fs::write + fs::create}; !test_writable)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Close and flush log file handle (!)
|
||||||
|
// Cannot rename the file due to file management design
|
||||||
|
logs::listener::close_all_prematurely();
|
||||||
|
|
||||||
|
// Try to move it
|
||||||
|
if (fs::rename(from, to, true))
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Try to copy it if fails
|
||||||
|
if (fs::copy_file(from, to, true))
|
||||||
|
{
|
||||||
|
fs::remove_file(from);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
};
|
||||||
|
|
||||||
|
if (archived_stat.size)
|
||||||
|
{
|
||||||
|
const QString dir_path = QFileDialog::getExistingDirectory(this, tr("Select RPCS3's log saving location (saving %0)").arg(qstr(log_filename + ".log.gz")), path_last_log, QFileDialog::ShowDirsOnly | QFileDialog::DontResolveSymlinks);
|
||||||
|
|
||||||
|
if (dir_path.isEmpty())
|
||||||
|
{
|
||||||
|
// Aborted - view the current location
|
||||||
|
gui::utils::open_dir(archived_path);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const std::string dest_archived_path = dir_path.toStdString() + "/" + log_filename + ".log.gz";
|
||||||
|
|
||||||
|
if (!Emu.GetTitleID().empty() && !dest_archived_path.empty() && move_log(archived_path, dest_archived_path))
|
||||||
|
{
|
||||||
|
m_gui_settings->SetValue(gui::fd_save_log, dir_path);
|
||||||
|
gui_log.success("Moved log file to '%s'!", dest_archived_path);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
gui::utils::open_dir(archived_path);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const QString dir_path = QFileDialog::getExistingDirectory(this, tr("Select RPCS3's log saving location (saving %0)").arg(qstr(log_filename + ".log")), path_last_log, QFileDialog::ShowDirsOnly | QFileDialog::DontResolveSymlinks);
|
||||||
|
|
||||||
|
if (dir_path.isEmpty())
|
||||||
|
{
|
||||||
|
// Aborted - view the current location
|
||||||
|
gui::utils::open_dir(raw_file_path);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const std::string dest_raw_file_path = dir_path.toStdString() + "/" + log_filename + ".log";
|
||||||
|
|
||||||
|
if (!Emu.GetTitleID().empty() && !dest_raw_file_path.empty() && move_log(raw_file_path, dest_raw_file_path))
|
||||||
|
{
|
||||||
|
m_gui_settings->SetValue(gui::fd_save_log, dir_path);
|
||||||
|
gui_log.success("Moved log file to '%s'!", dest_raw_file_path);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
gui::utils::open_dir(raw_file_path);
|
||||||
|
});
|
||||||
|
|
||||||
|
connect(ui->exitAndSaveLogAct, &QAction::triggered, this, [this]()
|
||||||
|
{
|
||||||
|
m_requested_show_logs_on_exit = true;
|
||||||
|
close();
|
||||||
|
});
|
||||||
connect(ui->exitAct, &QAction::triggered, this, &QWidget::close);
|
connect(ui->exitAct, &QAction::triggered, this, &QWidget::close);
|
||||||
|
|
||||||
connect(ui->batchCreatePPUCachesAct, &QAction::triggered, m_game_list_frame, &game_list_frame::BatchCreatePPUCaches);
|
connect(ui->batchCreatePPUCachesAct, &QAction::triggered, m_game_list_frame, &game_list_frame::BatchCreatePPUCaches);
|
||||||
|
@ -3212,6 +3330,7 @@ void main_window::closeEvent(QCloseEvent* closeEvent)
|
||||||
{
|
{
|
||||||
if (!m_gui_settings->GetBootConfirmation(this, gui::ib_confirm_exit))
|
if (!m_gui_settings->GetBootConfirmation(this, gui::ib_confirm_exit))
|
||||||
{
|
{
|
||||||
|
Q_EMIT NotifyWindowCloseEvent(false);
|
||||||
closeEvent->ignore();
|
closeEvent->ignore();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -3223,6 +3342,12 @@ void main_window::closeEvent(QCloseEvent* closeEvent)
|
||||||
}
|
}
|
||||||
|
|
||||||
SaveWindowState();
|
SaveWindowState();
|
||||||
|
|
||||||
|
// Flush logs here as well
|
||||||
|
logs::listener::sync_all();
|
||||||
|
|
||||||
|
Q_EMIT NotifyWindowCloseEvent(true);
|
||||||
|
|
||||||
Emu.Quit(true);
|
Emu.Quit(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3248,6 +3373,11 @@ Check data for valid file types and cache their paths if necessary
|
||||||
*/
|
*/
|
||||||
main_window::drop_type main_window::IsValidFile(const QMimeData& md, QStringList* drop_paths)
|
main_window::drop_type main_window::IsValidFile(const QMimeData& md, QStringList* drop_paths)
|
||||||
{
|
{
|
||||||
|
if (drop_paths)
|
||||||
|
{
|
||||||
|
drop_paths->clear();
|
||||||
|
}
|
||||||
|
|
||||||
drop_type type = drop_type::drop_error;
|
drop_type type = drop_type::drop_error;
|
||||||
|
|
||||||
QList<QUrl> list = md.urls(); // get list of all the dropped file urls
|
QList<QUrl> list = md.urls(); // get list of all the dropped file urls
|
||||||
|
@ -3255,6 +3385,14 @@ main_window::drop_type main_window::IsValidFile(const QMimeData& md, QStringList
|
||||||
// Try to cache the data for half a second
|
// Try to cache the data for half a second
|
||||||
if (m_drop_file_timestamp != umax && m_drop_file_url_list == list && get_system_time() - m_drop_file_timestamp < 500'000)
|
if (m_drop_file_timestamp != umax && m_drop_file_url_list == list && get_system_time() - m_drop_file_timestamp < 500'000)
|
||||||
{
|
{
|
||||||
|
if (drop_paths)
|
||||||
|
{
|
||||||
|
for (auto&& url : m_drop_file_url_list)
|
||||||
|
{
|
||||||
|
drop_paths->append(url.toLocalFile());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return m_drop_file_cached_drop_type;
|
return m_drop_file_cached_drop_type;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -50,6 +50,7 @@ class main_window : public QMainWindow
|
||||||
|
|
||||||
bool m_is_list_mode = true;
|
bool m_is_list_mode = true;
|
||||||
bool m_save_slider_pos = false;
|
bool m_save_slider_pos = false;
|
||||||
|
bool m_requested_show_logs_on_exit = false;
|
||||||
int m_other_slider_pos = 0;
|
int m_other_slider_pos = 0;
|
||||||
|
|
||||||
QIcon m_app_icon;
|
QIcon m_app_icon;
|
||||||
|
@ -95,6 +96,7 @@ Q_SIGNALS:
|
||||||
void RequestGlobalStylesheetChange();
|
void RequestGlobalStylesheetChange();
|
||||||
void RequestTrophyManagerRepaint();
|
void RequestTrophyManagerRepaint();
|
||||||
void NotifyEmuSettingsChange();
|
void NotifyEmuSettingsChange();
|
||||||
|
void NotifyWindowCloseEvent(bool closed);
|
||||||
|
|
||||||
public Q_SLOTS:
|
public Q_SLOTS:
|
||||||
void OnEmuStop();
|
void OnEmuStop();
|
||||||
|
|
|
@ -213,6 +213,7 @@
|
||||||
<addaction name="menuBatch"/>
|
<addaction name="menuBatch"/>
|
||||||
<addaction name="menuFirmware"/>
|
<addaction name="menuFirmware"/>
|
||||||
<addaction name="separator"/>
|
<addaction name="separator"/>
|
||||||
|
<addaction name="exitAndSaveLogAct"/>
|
||||||
<addaction name="exitAct"/>
|
<addaction name="exitAct"/>
|
||||||
</widget>
|
</widget>
|
||||||
<widget class="QMenu" name="menuEmulation">
|
<widget class="QMenu" name="menuEmulation">
|
||||||
|
@ -588,6 +589,17 @@
|
||||||
<string>Configure Auto Pause</string>
|
<string>Configure Auto Pause</string>
|
||||||
</property>
|
</property>
|
||||||
</action>
|
</action>
|
||||||
|
<action name="exitAndSaveLogAct">
|
||||||
|
<property name="text">
|
||||||
|
<string>Exit And Save Log</string>
|
||||||
|
</property>
|
||||||
|
<property name="toolTip">
|
||||||
|
<string>Exit RPCS3, move the log file to a custom location</string>
|
||||||
|
</property>
|
||||||
|
<property name="statusTip">
|
||||||
|
<string>Exit the application and save the log to a user-defined location</string>
|
||||||
|
</property>
|
||||||
|
</action>
|
||||||
<action name="exitAct">
|
<action name="exitAct">
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>Exit</string>
|
<string>Exit</string>
|
||||||
|
|
|
@ -107,6 +107,9 @@ namespace logs
|
||||||
|
|
||||||
// Ensure written to disk
|
// Ensure written to disk
|
||||||
void sync();
|
void sync();
|
||||||
|
|
||||||
|
// Close file handle after flushing to disk
|
||||||
|
void close_prematurely();
|
||||||
};
|
};
|
||||||
|
|
||||||
struct file_listener final : file_writer, public listener
|
struct file_listener final : file_writer, public listener
|
||||||
|
@ -121,6 +124,11 @@ namespace logs
|
||||||
{
|
{
|
||||||
file_writer::sync();
|
file_writer::sync();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void close_prematurely() override
|
||||||
|
{
|
||||||
|
file_writer::close_prematurely();
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
struct root_listener final : public listener
|
struct root_listener final : public listener
|
||||||
|
@ -353,6 +361,10 @@ void logs::listener::sync()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void logs::listener::close_prematurely()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
void logs::listener::sync_all()
|
void logs::listener::sync_all()
|
||||||
{
|
{
|
||||||
for (listener* lis = get_logger(); lis; lis = lis->m_next)
|
for (listener* lis = get_logger(); lis; lis = lis->m_next)
|
||||||
|
@ -361,6 +373,14 @@ void logs::listener::sync_all()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void logs::listener::close_all_prematurely()
|
||||||
|
{
|
||||||
|
for (listener* lis = get_logger(); lis; lis = lis->m_next)
|
||||||
|
{
|
||||||
|
lis->close_prematurely();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
logs::registerer::registerer(channel& _ch)
|
logs::registerer::registerer(channel& _ch)
|
||||||
{
|
{
|
||||||
std::lock_guard lock(g_mutex);
|
std::lock_guard lock(g_mutex);
|
||||||
|
@ -535,7 +555,7 @@ logs::file_writer::~file_writer()
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
// Cancel compressed log file autodeletion
|
// Cancel compressed log file auto-deletion
|
||||||
FILE_DISPOSITION_INFO disp;
|
FILE_DISPOSITION_INFO disp;
|
||||||
disp.DeleteFileW = false;
|
disp.DeleteFileW = false;
|
||||||
SetFileInformationByHandle(m_fout2.get_handle(), FileDispositionInfo, &disp, sizeof(disp));
|
SetFileInformationByHandle(m_fout2.get_handle(), FileDispositionInfo, &disp, sizeof(disp));
|
||||||
|
@ -691,6 +711,56 @@ void logs::file_writer::sync()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void logs::file_writer::close_prematurely()
|
||||||
|
{
|
||||||
|
if (!m_fptr)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Ensure written to disk
|
||||||
|
sync();
|
||||||
|
|
||||||
|
std::lock_guard lock(m_m);
|
||||||
|
|
||||||
|
if (m_fout2)
|
||||||
|
{
|
||||||
|
m_zs.avail_in = 0;
|
||||||
|
m_zs.next_in = nullptr;
|
||||||
|
|
||||||
|
do
|
||||||
|
{
|
||||||
|
m_zs.avail_out = sizeof(m_zout);
|
||||||
|
m_zs.next_out = m_zout;
|
||||||
|
|
||||||
|
if (deflate(&m_zs, Z_FINISH) == Z_STREAM_ERROR || m_fout2.write(m_zout, sizeof(m_zout) - m_zs.avail_out) != sizeof(m_zout) - m_zs.avail_out)
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
while (m_zs.avail_out == 0);
|
||||||
|
|
||||||
|
deflateEnd(&m_zs);
|
||||||
|
|
||||||
|
#ifdef _WIN32
|
||||||
|
// Cancel compressed log file auto-deletion
|
||||||
|
FILE_DISPOSITION_INFO disp;
|
||||||
|
disp.DeleteFileW = false;
|
||||||
|
SetFileInformationByHandle(m_fout2.get_handle(), FileDispositionInfo, &disp, sizeof(disp));
|
||||||
|
#else
|
||||||
|
// Restore compressed log file permissions
|
||||||
|
::fchmod(m_fout2.get_handle(), S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
m_fout2.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (m_fout)
|
||||||
|
{
|
||||||
|
m_fout.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
logs::file_listener::file_listener(const std::string& path, u64 max_size)
|
logs::file_listener::file_listener(const std::string& path, u64 max_size)
|
||||||
: file_writer(path, max_size)
|
: file_writer(path, max_size)
|
||||||
, listener()
|
, listener()
|
||||||
|
|
|
@ -84,6 +84,9 @@ namespace logs
|
||||||
// Flush contents (file writer)
|
// Flush contents (file writer)
|
||||||
virtual void sync();
|
virtual void sync();
|
||||||
|
|
||||||
|
// Close file handle after flushing to disk (hazardous)
|
||||||
|
virtual void close_prematurely();
|
||||||
|
|
||||||
// Add new listener
|
// Add new listener
|
||||||
static void add(listener*);
|
static void add(listener*);
|
||||||
|
|
||||||
|
@ -92,6 +95,9 @@ namespace logs
|
||||||
|
|
||||||
// Flush log to disk
|
// Flush log to disk
|
||||||
static void sync_all();
|
static void sync_all();
|
||||||
|
|
||||||
|
// Close file handle after flushing to disk (hazardous)
|
||||||
|
static void close_all_prematurely();
|
||||||
};
|
};
|
||||||
|
|
||||||
struct alignas(16) channel : private message
|
struct alignas(16) channel : private message
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue