diff --git a/.github/workflows/canary.yml b/.github/workflows/canary.yml
index 1554b8f6b..fbd76a2d8 100644
--- a/.github/workflows/canary.yml
+++ b/.github/workflows/canary.yml
@@ -29,7 +29,7 @@ env:
jobs:
tag:
name: Create tag
- runs-on: ubuntu-20.04
+ runs-on: ubuntu-24.04
steps:
- name: Get version info
id: version_info
@@ -202,7 +202,7 @@ jobs:
macos_release:
name: Release MacOS universal
- runs-on: ubuntu-20.04
+ runs-on: ubuntu-24.04
steps:
- uses: actions/checkout@v4
diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml
index 072c6bf2f..d4292162a 100644
--- a/.github/workflows/release.yml
+++ b/.github/workflows/release.yml
@@ -18,7 +18,7 @@ env:
jobs:
tag:
name: Create tag
- runs-on: ubuntu-20.04
+ runs-on: ubuntu-24.04
steps:
- name: Get version info
id: version_info
@@ -183,7 +183,7 @@ jobs:
macos_release:
name: Release MacOS universal
- runs-on: ubuntu-20.04
+ runs-on: ubuntu-24.04
steps:
- uses: actions/checkout@v4
diff --git a/README.md b/README.md
index ef3e683e6..bb51dee13 100644
--- a/README.md
+++ b/README.md
@@ -39,12 +39,12 @@
Click below to join the Discord:
-
+
-
+
## Usage
diff --git a/docs/compatibility.csv b/docs/compatibility.csv
index 660c7a9b0..6cb10e8d8 100644
--- a/docs/compatibility.csv
+++ b/docs/compatibility.csv
@@ -1249,7 +1249,7 @@
0100A6B00D4EC000,"Furwind",,playable,2021-02-19 19:44:08
0100ECE00C0C4000,"Fury Unleashed",crash;services,ingame,2020-10-18 11:52:40
010070000ED9E000,"Fury Unleashed Demo",,playable,2020-10-08 20:09:21
-0100E1F013674000,"FUSER™",nvdec;UE4,playable,2022-10-17 20:58:32
+0100E1F013674000,"FUSER™",nvdec;UE4;slow;gpu,ingame,2025-02-12 16:03:00
0100A7A015E4C000,"Fushigi no Gensokyo Lotus Labyrinth",Needs Update;audio;gpu;nvdec,ingame,2021-01-20 15:30:02
01003C300B274000,"Futari de! Nyanko Daisensou",,playable,2024-01-05 22:26:52
010055801134E000,"FUZE Player",online-broken;vulkan-backend-bug,ingame,2022-10-18 12:23:53
diff --git a/src/Ryujinx/AppHost.cs b/src/Ryujinx/AppHost.cs
index f143d4e03..b26921e6a 100644
--- a/src/Ryujinx/AppHost.cs
+++ b/src/Ryujinx/AppHost.cs
@@ -517,7 +517,7 @@ namespace Ryujinx.Ava
Device?.System.ChangeDockedModeState(e.NewValue);
}
- private void UpdateAudioVolumeState(object sender, ReactiveEventArgs e)
+ public void UpdateAudioVolumeState(object sender, ReactiveEventArgs e)
{
Device?.SetVolume(e.NewValue);
diff --git a/src/Ryujinx/Assets/locales.json b/src/Ryujinx/Assets/locales.json
index 6d8449d41..685e50ee4 100644
--- a/src/Ryujinx/Assets/locales.json
+++ b/src/Ryujinx/Assets/locales.json
@@ -3447,6 +3447,156 @@
"zh_TW": ""
}
},
+ {
+ "ID": "SettingsTabGeneralFocusLossType",
+ "Translations": {
+ "ar_SA": "",
+ "de_DE": "",
+ "el_GR": "",
+ "en_US": "On Emulator Focus Lost:",
+ "es_ES": "",
+ "fr_FR": "",
+ "he_IL": "",
+ "it_IT": "",
+ "ja_JP": "",
+ "ko_KR": "",
+ "no_NO": "",
+ "pl_PL": "",
+ "pt_BR": "",
+ "ru_RU": "",
+ "sv_SE": "",
+ "th_TH": "",
+ "tr_TR": "",
+ "uk_UA": "",
+ "zh_CN": "",
+ "zh_TW": ""
+ }
+ },
+ {
+ "ID": "SettingsTabGeneralFocusLossTypeDoNothing",
+ "Translations": {
+ "ar_SA": "",
+ "de_DE": "",
+ "el_GR": "",
+ "en_US": "Do Nothing",
+ "es_ES": "",
+ "fr_FR": "",
+ "he_IL": "",
+ "it_IT": "",
+ "ja_JP": "",
+ "ko_KR": "",
+ "no_NO": "",
+ "pl_PL": "",
+ "pt_BR": "",
+ "ru_RU": "",
+ "sv_SE": "",
+ "th_TH": "",
+ "tr_TR": "",
+ "uk_UA": "",
+ "zh_CN": "",
+ "zh_TW": ""
+ }
+ },
+ {
+ "ID": "SettingsTabGeneralFocusLossTypeBlockInput",
+ "Translations": {
+ "ar_SA": "",
+ "de_DE": "",
+ "el_GR": "",
+ "en_US": "Block Input",
+ "es_ES": "",
+ "fr_FR": "",
+ "he_IL": "",
+ "it_IT": "",
+ "ja_JP": "",
+ "ko_KR": "",
+ "no_NO": "",
+ "pl_PL": "",
+ "pt_BR": "",
+ "ru_RU": "",
+ "sv_SE": "",
+ "th_TH": "",
+ "tr_TR": "",
+ "uk_UA": "",
+ "zh_CN": "",
+ "zh_TW": ""
+ }
+ },
+ {
+ "ID": "SettingsTabGeneralFocusLossTypeMuteAudio",
+ "Translations": {
+ "ar_SA": "",
+ "de_DE": "",
+ "el_GR": "",
+ "en_US": "Mute Volume",
+ "es_ES": "",
+ "fr_FR": "",
+ "he_IL": "",
+ "it_IT": "",
+ "ja_JP": "",
+ "ko_KR": "",
+ "no_NO": "",
+ "pl_PL": "",
+ "pt_BR": "",
+ "ru_RU": "",
+ "sv_SE": "",
+ "th_TH": "",
+ "tr_TR": "",
+ "uk_UA": "",
+ "zh_CN": "",
+ "zh_TW": ""
+ }
+ },
+ {
+ "ID": "SettingsTabGeneralFocusLossTypeBlockInputAndMuteAudio",
+ "Translations": {
+ "ar_SA": "",
+ "de_DE": "",
+ "el_GR": "",
+ "en_US": "Block Input & Mute Volume",
+ "es_ES": "",
+ "fr_FR": "",
+ "he_IL": "",
+ "it_IT": "",
+ "ja_JP": "",
+ "ko_KR": "",
+ "no_NO": "",
+ "pl_PL": "",
+ "pt_BR": "",
+ "ru_RU": "",
+ "sv_SE": "",
+ "th_TH": "",
+ "tr_TR": "",
+ "uk_UA": "",
+ "zh_CN": "",
+ "zh_TW": ""
+ }
+ },
+ {
+ "ID": "SettingsTabGeneralFocusLossTypePauseEmulation",
+ "Translations": {
+ "ar_SA": "",
+ "de_DE": "",
+ "el_GR": "",
+ "en_US": "Pause Emulation",
+ "es_ES": "",
+ "fr_FR": "",
+ "he_IL": "",
+ "it_IT": "",
+ "ja_JP": "",
+ "ko_KR": "",
+ "no_NO": "",
+ "pl_PL": "",
+ "pt_BR": "",
+ "ru_RU": "",
+ "sv_SE": "",
+ "th_TH": "",
+ "tr_TR": "",
+ "uk_UA": "",
+ "zh_CN": "",
+ "zh_TW": ""
+ }
+ },
{
"ID": "SettingsTabGeneralShowConfirmExitDialog",
"Translations": {
@@ -23923,4 +24073,4 @@
}
}
]
-}
+}
\ No newline at end of file
diff --git a/src/Ryujinx/Common/ThemeManager.cs b/src/Ryujinx/Common/ThemeManager.cs
deleted file mode 100644
index 6da01bfa7..000000000
--- a/src/Ryujinx/Common/ThemeManager.cs
+++ /dev/null
@@ -1,14 +0,0 @@
-using System;
-
-namespace Ryujinx.Ava.Common
-{
- public static class ThemeManager
- {
- public static event Action ThemeChanged;
-
- public static void OnThemeChanged()
- {
- ThemeChanged?.Invoke();
- }
- }
-}
diff --git a/src/Ryujinx/RyujinxApp.axaml.cs b/src/Ryujinx/RyujinxApp.axaml.cs
index 32318776a..90552cd16 100644
--- a/src/Ryujinx/RyujinxApp.axaml.cs
+++ b/src/Ryujinx/RyujinxApp.axaml.cs
@@ -22,6 +22,8 @@ namespace Ryujinx.Ava
{
public class RyujinxApp : Application
{
+ public static event Action ThemeChanged;
+
internal static string FormatTitle(LocaleKeys? windowTitleKey = null, bool includeVersion = true)
=> windowTitleKey is null
? $"{FullAppName}{(includeVersion ? $" {Program.Version}" : string.Empty)}"
@@ -112,7 +114,7 @@ namespace Ryujinx.Ava
baseStyle = ConfigurationState.Instance.UI.BaseStyle;
}
- ThemeManager.OnThemeChanged();
+ ThemeChanged?.Invoke();
RequestedThemeVariant = baseStyle switch
{
diff --git a/src/Ryujinx/UI/ViewModels/AboutWindowViewModel.cs b/src/Ryujinx/UI/ViewModels/AboutWindowViewModel.cs
index be0a5d644..7a63c3391 100644
--- a/src/Ryujinx/UI/ViewModels/AboutWindowViewModel.cs
+++ b/src/Ryujinx/UI/ViewModels/AboutWindowViewModel.cs
@@ -25,10 +25,10 @@ namespace Ryujinx.Ava.UI.ViewModels
Version = RyujinxApp.FullAppName + "\n" + Program.Version;
UpdateLogoTheme(ConfigurationState.Instance.UI.BaseStyle.Value);
- ThemeManager.ThemeChanged += ThemeManager_ThemeChanged;
+ RyujinxApp.ThemeChanged += Ryujinx_ThemeChanged;
}
- private void ThemeManager_ThemeChanged()
+ private void Ryujinx_ThemeChanged()
{
Dispatcher.UIThread.Post(() => UpdateLogoTheme(ConfigurationState.Instance.UI.BaseStyle.Value));
}
@@ -49,7 +49,7 @@ namespace Ryujinx.Ava.UI.ViewModels
public void Dispose()
{
- ThemeManager.ThemeChanged -= ThemeManager_ThemeChanged;
+ RyujinxApp.ThemeChanged -= Ryujinx_ThemeChanged;
GithubLogo.Dispose();
DiscordLogo.Dispose();
diff --git a/src/Ryujinx/UI/ViewModels/SettingsViewModel.cs b/src/Ryujinx/UI/ViewModels/SettingsViewModel.cs
index 017d68a28..1b1f8a2a5 100644
--- a/src/Ryujinx/UI/ViewModels/SettingsViewModel.cs
+++ b/src/Ryujinx/UI/ViewModels/SettingsViewModel.cs
@@ -128,6 +128,8 @@ namespace Ryujinx.Ava.UI.ViewModels
public bool EnableMouse { get; set; }
public bool DisableInputWhenOutOfFocus { get; set; }
+ public int FocusLostActionType { get; set; }
+
public VSyncMode VSyncMode
{
get => _vSyncMode;
@@ -481,6 +483,7 @@ namespace Ryujinx.Ava.UI.ViewModels
ShowTitleBar = config.ShowTitleBar;
HideCursor = (int)config.HideCursor.Value;
UpdateCheckerType = (int)config.UpdateCheckerType.Value;
+ FocusLostActionType = (int)config.FocusLostActionType.Value;
GameDirectories.Clear();
GameDirectories.AddRange(config.UI.GameDirs.Value);
@@ -589,6 +592,7 @@ namespace Ryujinx.Ava.UI.ViewModels
config.ShowTitleBar.Value = ShowTitleBar;
config.HideCursor.Value = (HideCursorMode)HideCursor;
config.UpdateCheckerType.Value = (UpdaterType)UpdateCheckerType;
+ config.FocusLostActionType.Value = (FocusLostType)FocusLostActionType;
if (GameDirectoryChanged)
{
diff --git a/src/Ryujinx/UI/Views/Settings/SettingsUIView.axaml b/src/Ryujinx/UI/Views/Settings/SettingsUIView.axaml
index 6aeff31f1..347f0fb51 100644
--- a/src/Ryujinx/UI/Views/Settings/SettingsUIView.axaml
+++ b/src/Ryujinx/UI/Views/Settings/SettingsUIView.axaml
@@ -37,12 +37,33 @@
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
/// The current version of the file format
///
- public const int CurrentVersion = 66;
+ public const int CurrentVersion = 67;
///
/// Version of the configuration file format
@@ -171,6 +171,11 @@ namespace Ryujinx.Ava.Utilities.Configuration
/// Checks for updates when Ryujinx starts when enabled, either prompting when an update is found or just showing a notification.
///
public UpdaterType UpdateCheckerType { get; set; }
+
+ ///
+ /// How the emulator should behave when you click off/on the window.
+ ///
+ public FocusLostType FocusLostActionType { get; set; }
///
/// Show "Confirm Exit" Dialog
diff --git a/src/Ryujinx/Utilities/Configuration/ConfigurationState.Migration.cs b/src/Ryujinx/Utilities/Configuration/ConfigurationState.Migration.cs
index b25de9318..6bca36340 100644
--- a/src/Ryujinx/Utilities/Configuration/ConfigurationState.Migration.cs
+++ b/src/Ryujinx/Utilities/Configuration/ConfigurationState.Migration.cs
@@ -46,6 +46,7 @@ namespace Ryujinx.Ava.Utilities.Configuration
EnableDiscordIntegration.Value = cff.EnableDiscordIntegration;
CheckUpdatesOnStart.Value = cff.CheckUpdatesOnStart;
UpdateCheckerType.Value = cff.UpdateCheckerType;
+ FocusLostActionType.Value = cff.FocusLostActionType;
ShowConfirmExit.Value = cff.ShowConfirmExit;
RememberWindowState.Value = cff.RememberWindowState;
ShowTitleBar.Value = cff.ShowTitleBar;
@@ -435,7 +436,8 @@ namespace Ryujinx.Ava.Utilities.Configuration
(63, static cff => cff.MatchSystemTime = false),
(64, static cff => cff.LoggingEnableAvalonia = false),
(65, static cff => cff.UpdateCheckerType = cff.CheckUpdatesOnStart ? UpdaterType.PromptAtStartup : UpdaterType.Off),
- (66, static cff => cff.DisableInputWhenOutOfFocus = false)
+ (66, static cff => cff.DisableInputWhenOutOfFocus = false),
+ (67, static cff => cff.FocusLostActionType = cff.DisableInputWhenOutOfFocus ? FocusLostType.BlockInput : FocusLostType.DoNothing)
);
}
}
diff --git a/src/Ryujinx/Utilities/Configuration/ConfigurationState.Model.cs b/src/Ryujinx/Utilities/Configuration/ConfigurationState.Model.cs
index 93496753b..51c40cc99 100644
--- a/src/Ryujinx/Utilities/Configuration/ConfigurationState.Model.cs
+++ b/src/Ryujinx/Utilities/Configuration/ConfigurationState.Model.cs
@@ -779,6 +779,11 @@ namespace Ryujinx.Ava.Utilities.Configuration
/// Checks for updates when Ryujinx starts when enabled, either prompting when an update is found or just showing a notification.
///
public ReactiveObject UpdateCheckerType { get; private set; }
+
+ ///
+ /// How the emulator should behave when you click off/on the window.
+ ///
+ public ReactiveObject FocusLostActionType { get; private set; }
///
/// Show "Confirm Exit" Dialog
@@ -817,6 +822,7 @@ namespace Ryujinx.Ava.Utilities.Configuration
EnableDiscordIntegration = new ReactiveObject();
CheckUpdatesOnStart = new ReactiveObject();
UpdateCheckerType = new ReactiveObject();
+ FocusLostActionType = new ReactiveObject();
ShowConfirmExit = new ReactiveObject();
RememberWindowState = new ReactiveObject();
ShowTitleBar = new ReactiveObject();
diff --git a/src/Ryujinx/Utilities/Configuration/ConfigurationState.cs b/src/Ryujinx/Utilities/Configuration/ConfigurationState.cs
index 0406219f6..774b9217e 100644
--- a/src/Ryujinx/Utilities/Configuration/ConfigurationState.cs
+++ b/src/Ryujinx/Utilities/Configuration/ConfigurationState.cs
@@ -57,6 +57,7 @@ namespace Ryujinx.Ava.Utilities.Configuration
EnableDiscordIntegration = EnableDiscordIntegration,
CheckUpdatesOnStart = CheckUpdatesOnStart,
UpdateCheckerType = UpdateCheckerType,
+ FocusLostActionType = FocusLostActionType,
ShowConfirmExit = ShowConfirmExit,
RememberWindowState = RememberWindowState,
ShowTitleBar = ShowTitleBar,
@@ -178,6 +179,7 @@ namespace Ryujinx.Ava.Utilities.Configuration
System.EnableDockedMode.Value = true;
EnableDiscordIntegration.Value = true;
UpdateCheckerType.Value = UpdaterType.PromptAtStartup;
+ FocusLostActionType.Value = FocusLostType.DoNothing;
ShowConfirmExit.Value = true;
RememberWindowState.Value = true;
ShowTitleBar.Value = !OperatingSystem.IsWindows();
diff --git a/src/Ryujinx/Utilities/Configuration/UI/FocusLostType.cs b/src/Ryujinx/Utilities/Configuration/UI/FocusLostType.cs
new file mode 100644
index 000000000..eea588539
--- /dev/null
+++ b/src/Ryujinx/Utilities/Configuration/UI/FocusLostType.cs
@@ -0,0 +1,15 @@
+using Ryujinx.Common.Utilities;
+using System.Text.Json.Serialization;
+
+namespace Ryujinx.Ava.Utilities.Configuration.UI
+{
+ [JsonConverter(typeof(TypedStringEnumConverter))]
+ public enum FocusLostType
+ {
+ DoNothing,
+ BlockInput,
+ MuteAudio,
+ BlockInputAndMuteAudio,
+ PauseEmulation
+ }
+}