1
0
mirror of https://github.com/RPCS3/rpcs3.git synced 2024-11-22 02:32:36 +01:00

UX: Option to pause emulation when RPCS3 is not focused

This commit is contained in:
Eladash 2023-07-07 10:31:35 +03:00 committed by Elad Ashkenazi
parent b3b680f073
commit 05824e6acd
8 changed files with 97 additions and 1 deletions

View File

@ -106,7 +106,7 @@ class Emulator final
atomic_t<u64> m_pause_start_time{0}; // set when paused
atomic_t<u64> m_pause_amend_time{0}; // increased when resumed
atomic_t<u64> m_stop_ctr{0}; // Increments when emulation is stopped
atomic_t<u64> m_stop_ctr{1}; // Increments when emulation is stopped
games_config m_games_config;

View File

@ -326,6 +326,7 @@ struct cfg_root : cfg::node
cfg::_bool autostart{ this, "Automatically start games after boot", true, true };
cfg::_bool autoexit{ this, "Exit RPCS3 when process finishes", false, true };
cfg::_bool autopause{ this, "Pause emulation on RPCS3 focus loss", false, true };
cfg::_bool start_fullscreen{ this, "Start games in fullscreen mode", false, true };
cfg::_bool prevent_display_sleep{ this, "Prevent display sleep while running games", true, true };
cfg::_bool show_trophy_popups{ this, "Show trophy popups", true, true };

View File

@ -162,6 +162,7 @@ enum class emu_settings_type
// Misc
ExitRPCS3OnFinish,
StartOnBoot,
PauseOnFocusLoss,
StartGameFullscreen,
PreventDisplaySleep,
ShowTrophyPopups,
@ -346,6 +347,7 @@ inline static const QMap<emu_settings_type, cfg_location> settings_location =
// Misc
{ emu_settings_type::ExitRPCS3OnFinish, { "Miscellaneous", "Exit RPCS3 when process finishes" }},
{ emu_settings_type::StartOnBoot, { "Miscellaneous", "Automatically start games after boot" }},
{ emu_settings_type::PauseOnFocusLoss, { "Miscellaneous", "Pause emulation on RPCS3 focus loss" }},
{ emu_settings_type::StartGameFullscreen, { "Miscellaneous", "Start games in fullscreen mode"}},
{ emu_settings_type::PreventDisplaySleep, { "Miscellaneous", "Prevent display sleep while running games"}},
{ emu_settings_type::ShowTrophyPopups, { "Miscellaneous", "Show trophy popups"}},

View File

@ -270,6 +270,7 @@ void gui_application::InitializeConnects()
connect(this, &gui_application::OnEmulatorStop, this, &gui_application::StopPlaytime);
connect(this, &gui_application::OnEmulatorPause, this, &gui_application::StopPlaytime);
connect(this, &gui_application::OnEmulatorResume, this, &gui_application::StartPlaytime);
connect(this, &QGuiApplication::applicationStateChanged, this, &gui_application::OnAppStateChanged);
if (m_main_window)
{
@ -798,3 +799,76 @@ void gui_application::CallFromMainThread(const std::function<void()>& func, atom
wake_up->notify_one();
}
}
void gui_application::OnAppStateChanged(Qt::ApplicationState state)
{
// Invalidate previous delayed pause call (even when the setting is off because it is dynamic)
m_pause_delayed_tag++;
if (!g_cfg.misc.autopause)
{
return;
}
const auto emu_state = Emu.GetStatus();
const bool is_active = state == Qt::ApplicationActive;
if (emu_state != system_state::paused && emu_state != system_state::running)
{
return;
}
const bool is_paused = emu_state == system_state::paused;
if (is_active != is_paused)
{
// Nothing to do (either paused and this is focus-out event or running and this is a focus-in event)
// Invalidate data
m_is_pause_on_focus_loss_active = false;
m_emu_focus_out_emulation_id = Emulator::stop_counter_t{};
return;
}
if (is_paused)
{
// Check if Emu.Resume() or Emu.Kill() has not been called since
if (m_is_pause_on_focus_loss_active && m_pause_amend_time_on_focus_loss == Emu.GetPauseTime() && m_emu_focus_out_emulation_id == Emu.GetEmulationIdentifier())
{
m_is_pause_on_focus_loss_active = false;
Emu.Resume();
}
return;
}
// Gather validation data
m_emu_focus_out_emulation_id = Emu.GetEmulationIdentifier();
auto pause_callback = [this, delayed_tag = m_pause_delayed_tag]()
{
// Check if Emu.Kill() has not been called since
if (applicationState() != Qt::ApplicationActive && Emu.IsRunning() &&
m_emu_focus_out_emulation_id == Emu.GetEmulationIdentifier() &&
delayed_tag == m_pause_delayed_tag &&
!m_is_pause_on_focus_loss_active)
{
if (Emu.Pause())
{
// Gather validation data
m_pause_amend_time_on_focus_loss = Emu.GetPauseTime();
m_emu_focus_out_emulation_id = Emu.GetEmulationIdentifier();
m_is_pause_on_focus_loss_active = true;
}
}
};
if (state == Qt::ApplicationSuspended)
{
// Must be invoked now (otherwise it may not happen later)
pause_callback();
return;
}
// Delay pause so it won't immediately pause the emulated application
QTimer::singleShot(1000, this, pause_callback);
}

View File

@ -10,6 +10,8 @@
#include "main_application.h"
#include "Emu/System.h"
#include <memory>
#include <functional>
@ -95,8 +97,14 @@ private:
bool m_start_games_fullscreen = false;
int m_game_screen_index = -1;
u64 m_pause_amend_time_on_focus_loss = umax;
u64 m_pause_delayed_tag = 0;
typename Emulator::stop_counter_t m_emu_focus_out_emulation_id{};
bool m_is_pause_on_focus_loss_active = false;
private Q_SLOTS:
void OnChangeStyleSheetRequest();
void OnAppStateChanged(Qt::ApplicationState state);
Q_SIGNALS:
void OnEmulatorRun(bool start_playtime);

View File

@ -1734,6 +1734,9 @@ settings_dialog::settings_dialog(std::shared_ptr<gui_settings> gui_settings, std
m_emu_settings->EnhanceCheckBox(ui->exitOnStop, emu_settings_type::ExitRPCS3OnFinish);
SubscribeTooltip(ui->exitOnStop, tooltips.settings.exit_on_stop);
m_emu_settings->EnhanceCheckBox(ui->pauseOnFocusLoss, emu_settings_type::PauseOnFocusLoss);
SubscribeTooltip(ui->pauseOnFocusLoss, tooltips.settings.pause_on_focus_loss);
m_emu_settings->EnhanceCheckBox(ui->startGameFullscreen, emu_settings_type::StartGameFullscreen);
SubscribeTooltip(ui->startGameFullscreen, tooltips.settings.start_game_fullscreen);

View File

@ -2878,6 +2878,13 @@
</property>
</widget>
</item>
<item>
<widget class="QCheckBox" name="pauseOnFocusLoss">
<property name="text">
<string>Pause emulation on RPCS3 focus loss</string>
</property>
</widget>
</item>
<item>
<widget class="QCheckBox" name="pausedSavestates">
<property name="text">

View File

@ -122,6 +122,7 @@ public:
// emulator
const QString exit_on_stop = tr("Automatically close RPCS3 when closing a game, or when a game closes itself.");
const QString pause_on_focus_loss = tr("Automatically pause emulation when RPCS3 loses its focus or the application is inactive in order to save power and reduce CPU usage.\nDo note that emulation pausing in general is not perfect and may not be compatible with all games.\nAlthough it currently also pauses gameplay, it is not recommended to rely on it as this behavior may be changed in the future and it is not the purpose of this setting.");
const QString start_game_fullscreen = tr("Automatically puts the game window in fullscreen.\nDouble click on the game window or press Alt+Enter to toggle fullscreen and windowed mode.");
const QString prevent_display_sleep = tr("Prevent the display from sleeping while a game is running.\nThis requires the org.freedesktop.ScreenSaver D-Bus service on Linux.\nThis option will be disabled if the current platform does not support display sleep control.");
const QString game_window_title_format = tr("Configure the game window title.\nChanging this and/or adding the framerate may cause buggy or outdated recording software to not notice RPCS3.");