diff --git a/src/Ryujinx.Common/Utilities/OsUtils.cs b/src/Ryujinx.Common/Utilities/OsUtils.cs
index a0791b092..29c6e187c 100644
--- a/src/Ryujinx.Common/Utilities/OsUtils.cs
+++ b/src/Ryujinx.Common/Utilities/OsUtils.cs
@@ -20,5 +20,21 @@ namespace Ryujinx.Common.Utilities
Debug.Assert(res != -1);
}
}
+
+ // "dumpable" attribute of the calling process
+ private const int PR_SET_DUMPABLE = 4;
+
+ [DllImport("libc", SetLastError = true)]
+ private static extern int prctl(int option, int arg2);
+
+ public static void SetCoreDumpable(bool dumpable)
+ {
+ if (OperatingSystem.IsLinux())
+ {
+ int dumpableInt = dumpable ? 1 : 0;
+ int result = prctl(PR_SET_DUMPABLE, dumpableInt);
+ Debug.Assert(result == 0);
+ }
+ }
}
}
diff --git a/src/Ryujinx.HLE/HOS/Services/Am/AppletAE/AllSystemAppletProxiesService/SystemAppletProxy/ISelfController.cs b/src/Ryujinx.HLE/HOS/Services/Am/AppletAE/AllSystemAppletProxiesService/SystemAppletProxy/ISelfController.cs
index 8e0f515ba..7aac6f3ea 100644
--- a/src/Ryujinx.HLE/HOS/Services/Am/AppletAE/AllSystemAppletProxiesService/SystemAppletProxy/ISelfController.cs
+++ b/src/Ryujinx.HLE/HOS/Services/Am/AppletAE/AllSystemAppletProxiesService/SystemAppletProxy/ISelfController.cs
@@ -416,7 +416,7 @@ namespace Ryujinx.HLE.HOS.Services.Am.AppletAE.AllSystemAppletProxiesService.Sys
return ResultCode.InvalidParameters;
}
- Logger.Stub?.PrintStub(LogClass.ServiceAm, new { albumReportOption });
+ context.Device.UIHandler.TakeScreenshot();
return ResultCode.Success;
}
diff --git a/src/Ryujinx.HLE/UI/IHostUIHandler.cs b/src/Ryujinx.HLE/UI/IHostUIHandler.cs
index b5c5cb168..79b479d8a 100644
--- a/src/Ryujinx.HLE/UI/IHostUIHandler.cs
+++ b/src/Ryujinx.HLE/UI/IHostUIHandler.cs
@@ -68,5 +68,10 @@ namespace Ryujinx.HLE.UI
/// Displays the player select dialog and returns the selected profile.
///
UserProfile ShowPlayerSelectDialog();
+
+ ///
+ /// Takes a screenshot from the current renderer and saves it in the screenshots folder.
+ ///
+ void TakeScreenshot();
}
}
diff --git a/src/Ryujinx/Headless/Windows/WindowBase.cs b/src/Ryujinx/Headless/Windows/WindowBase.cs
index 8e06a3f20..49b2a389a 100644
--- a/src/Ryujinx/Headless/Windows/WindowBase.cs
+++ b/src/Ryujinx/Headless/Windows/WindowBase.cs
@@ -580,5 +580,10 @@ namespace Ryujinx.Headless
{
return AccountSaveDataManager.GetLastUsedUser();
}
+
+ public void TakeScreenshot()
+ {
+ throw new NotImplementedException();
+ }
}
}
diff --git a/src/Ryujinx/Program.cs b/src/Ryujinx/Program.cs
index 4904b8464..d77e79756 100644
--- a/src/Ryujinx/Program.cs
+++ b/src/Ryujinx/Program.cs
@@ -17,6 +17,7 @@ using Ryujinx.Common.Configuration;
using Ryujinx.Common.GraphicsDriver;
using Ryujinx.Common.Logging;
using Ryujinx.Common.SystemInterop;
+using Ryujinx.Common.Utilities;
using Ryujinx.Graphics.Vulkan.MoltenVK;
using Ryujinx.Headless;
using Ryujinx.SDL3.Common;
@@ -46,7 +47,7 @@ namespace Ryujinx.Ava
public static int Main(string[] args)
{
Version = ReleaseInformation.Version;
-
+
if (OperatingSystem.IsWindows())
{
if (!OperatingSystem.IsWindowsVersionAtLeast(10, 0, 19041))
@@ -55,8 +56,11 @@ namespace Ryujinx.Ava
return 0;
}
- if (Environment.CurrentDirectory.StartsWithIgnoreCase("C:\\Program Files") ||
- Environment.CurrentDirectory.StartsWithIgnoreCase("C:\\Program Files (x86)"))
+ var programFiles = Environment.GetFolderPath(Environment.SpecialFolder.ProgramFiles);
+ var programFilesX86 = Environment.GetFolderPath(Environment.SpecialFolder.ProgramFilesX86);
+
+ if (Environment.CurrentDirectory.StartsWithIgnoreCase(programFiles) ||
+ Environment.CurrentDirectory.StartsWithIgnoreCase(programFilesX86))
{
_ = Win32NativeInterop.MessageBoxA(nint.Zero, "Ryujinx is not intended to be run from the Program Files folder. Please move it out and relaunch.", $"Ryujinx {Version}", MbIconwarning);
return 0;
@@ -73,11 +77,23 @@ namespace Ryujinx.Ava
}
}
+ bool noGuiArg = ConsumeCommandLineArgument(ref args, "--no-gui") || ConsumeCommandLineArgument(ref args, "nogui");
+ bool coreDumpArg = ConsumeCommandLineArgument(ref args, "--core-dumps");
+
+ // TODO: Ryujinx causes core dumps on Linux when it exits "uncleanly", eg. through an unhandled exception.
+ // This is undesirable and causes very odd behavior during development (the process stops responding,
+ // the .NET debugger freezes or suddenly detaches, /tmp/ gets filled etc.), unless explicitly requested by the user.
+ // This needs to be investigated, but calling prctl() is better than modifying system-wide settings or leaving this be.
+ if (!coreDumpArg)
+ {
+ OsUtils.SetCoreDumpable(false);
+ }
+
PreviewerDetached = true;
- if (args.Length > 0 && args[0] is "--no-gui" or "nogui")
+ if (noGuiArg)
{
- HeadlessRyujinx.Entrypoint(args[1..]);
+ HeadlessRyujinx.Entrypoint(args);
return 0;
}
@@ -112,6 +128,14 @@ namespace Ryujinx.Ava
: [Win32RenderingMode.Software]
});
+ private static bool ConsumeCommandLineArgument(ref string[] args, string targetArgument)
+ {
+ List argList = [.. args];
+ bool found = argList.Remove(targetArgument);
+ args = argList.ToArray();
+ return found;
+ }
+
private static void Initialize(string[] args)
{
// Ensure Discord presence timestamp begins at the absolute start of when Ryujinx is launched
@@ -177,7 +201,6 @@ namespace Ryujinx.Ava
}
}
-
public static string GetDirGameUserConfig(string gameId, bool changeFolderForGame = false)
{
if (string.IsNullOrEmpty(gameId))
diff --git a/src/Ryujinx/UI/Applet/AvaHostUIHandler.cs b/src/Ryujinx/UI/Applet/AvaHostUIHandler.cs
index 38670e5d5..45235ee3f 100644
--- a/src/Ryujinx/UI/Applet/AvaHostUIHandler.cs
+++ b/src/Ryujinx/UI/Applet/AvaHostUIHandler.cs
@@ -327,5 +327,10 @@ namespace Ryujinx.Ava.UI.Applet
return profile;
}
+
+ public void TakeScreenshot()
+ {
+ _parent.ViewModel.AppHost.ScreenshotRequested = true;
+ }
}
}
diff --git a/src/Ryujinx/UI/ViewModels/MainWindowViewModel.cs b/src/Ryujinx/UI/ViewModels/MainWindowViewModel.cs
index 6ad14905e..58bf3a043 100644
--- a/src/Ryujinx/UI/ViewModels/MainWindowViewModel.cs
+++ b/src/Ryujinx/UI/ViewModels/MainWindowViewModel.cs
@@ -1333,7 +1333,10 @@ namespace Ryujinx.Ava.UI.ViewModels
}
}
- public void TakeScreenshot() => AppHost.ScreenshotRequested = true;
+ public void TakeScreenshot()
+ {
+ AppHost.ScreenshotRequested = true;
+ }
public void HideUi() => ShowMenuAndStatusBar = false;