diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 7bcd57417..3a4b4e205 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -38,11 +38,11 @@ jobs: shell: bash - name: Configure for release run: | - sed -r --in-place 's/\%\%RYUJINX_BUILD_VERSION\%\%/${{ steps.version_info.outputs.build_version }}/g;' Ryujinx.Common/ReleaseInformations.cs - sed -r --in-place 's/\%\%RYUJINX_BUILD_GIT_HASH\%\%/${{ steps.version_info.outputs.git_short_hash }}/g;' Ryujinx.Common/ReleaseInformations.cs - sed -r --in-place 's/\%\%RYUJINX_TARGET_RELEASE_CHANNEL_NAME\%\%/${{ env.RYUJINX_TARGET_RELEASE_CHANNEL_NAME }}/g;' Ryujinx.Common/ReleaseInformations.cs - sed -r --in-place 's/\%\%RYUJINX_TARGET_RELEASE_CHANNEL_OWNER\%\%/${{ env.RYUJINX_TARGET_RELEASE_CHANNEL_OWNER }}/g;' Ryujinx.Common/ReleaseInformations.cs - sed -r --in-place 's/\%\%RYUJINX_TARGET_RELEASE_CHANNEL_REPO\%\%/${{ env.RYUJINX_TARGET_RELEASE_CHANNEL_REPO }}/g;' Ryujinx.Common/ReleaseInformations.cs + sed -r --in-place 's/\%\%RYUJINX_BUILD_VERSION\%\%/${{ steps.version_info.outputs.build_version }}/g;' Ryujinx.Common/ReleaseInformation.cs + sed -r --in-place 's/\%\%RYUJINX_BUILD_GIT_HASH\%\%/${{ steps.version_info.outputs.git_short_hash }}/g;' Ryujinx.Common/ReleaseInformation.cs + sed -r --in-place 's/\%\%RYUJINX_TARGET_RELEASE_CHANNEL_NAME\%\%/${{ env.RYUJINX_TARGET_RELEASE_CHANNEL_NAME }}/g;' Ryujinx.Common/ReleaseInformation.cs + sed -r --in-place 's/\%\%RYUJINX_TARGET_RELEASE_CHANNEL_OWNER\%\%/${{ env.RYUJINX_TARGET_RELEASE_CHANNEL_OWNER }}/g;' Ryujinx.Common/ReleaseInformation.cs + sed -r --in-place 's/\%\%RYUJINX_TARGET_RELEASE_CHANNEL_REPO\%\%/${{ env.RYUJINX_TARGET_RELEASE_CHANNEL_REPO }}/g;' Ryujinx.Common/ReleaseInformation.cs shell: bash - name: Create output dir run: "mkdir release_output" @@ -75,15 +75,24 @@ jobs: - name: Packing Linux builds run: | pushd publish_linux - tar -czvf ../release_output/ryujinx-${{ steps.version_info.outputs.build_version }}-linux_x64.tar.gz publish + tar --exclude "publish/Ryujinx" -cvf ../release_output/ryujinx-${{ steps.version_info.outputs.build_version }}-linux_x64.tar publish + python3 ../distribution/misc/add_tar_exec.py ../release_output/ryujinx-${{ steps.version_info.outputs.build_version }}-linux_x64.tar "publish/Ryujinx" "publish/Ryujinx" + gzip -9 < ../release_output/ryujinx-${{ steps.version_info.outputs.build_version }}-linux_x64.tar > ../release_output/ryujinx-${{ steps.version_info.outputs.build_version }}-linux_x64.tar.gz + rm ../release_output/ryujinx-${{ steps.version_info.outputs.build_version }}-linux_x64.tar popd pushd publish_linux_sdl2_headless - tar -czvf ../release_output/sdl2-ryujinx-headless-${{ steps.version_info.outputs.build_version }}-linux_x64.tar.gz publish + tar --exclude "publish/Ryujinx.Headless.SDL2" -cvf ../release_output/sdl2-ryujinx-headless-${{ steps.version_info.outputs.build_version }}-linux_x64.tar publish + python3 ../distribution/misc/add_tar_exec.py ../release_output/sdl2-ryujinx-headless-${{ steps.version_info.outputs.build_version }}-linux_x64.tar "publish/Ryujinx.Headless.SDL2" "publish/Ryujinx.Headless.SDL2" + gzip -9 < ../release_output/sdl2-ryujinx-headless-${{ steps.version_info.outputs.build_version }}-linux_x64.tar > ../release_output/sdl2-ryujinx-headless-${{ steps.version_info.outputs.build_version }}-linux_x64.tar.gz + rm ../release_output/sdl2-ryujinx-headless-${{ steps.version_info.outputs.build_version }}-linux_x64.tar popd pushd publish_linux_ava - tar -czvf ../release_output/test-ava-ryujinx-${{ steps.version_info.outputs.build_version }}-linux_x64.tar.gz publish + tar --exclude "publish/Ryujinx" -cvf ../release_output/test-ava-ryujinx-${{ steps.version_info.outputs.build_version }}-linux_x64.tar publish + python3 ../distribution/misc/add_tar_exec.py ../release_output/test-ava-ryujinx-${{ steps.version_info.outputs.build_version }}-linux_x64.tar "publish/Ryujinx" "publish/Ryujinx" + gzip -9 < ../release_output/test-ava-ryujinx-${{ steps.version_info.outputs.build_version }}-linux_x64.tar > ../release_output/test-ava-ryujinx-${{ steps.version_info.outputs.build_version }}-linux_x64.tar.gz + rm ../release_output/test-ava-ryujinx-${{ steps.version_info.outputs.build_version }}-linux_x64.tar popd shell: bash diff --git a/Ryujinx.Ava/Modules/Updater/Updater.cs b/Ryujinx.Ava/Modules/Updater/Updater.cs index 7bf147fe4..bc4760bae 100644 --- a/Ryujinx.Ava/Modules/Updater/Updater.cs +++ b/Ryujinx.Ava/Modules/Updater/Updater.cs @@ -95,7 +95,7 @@ namespace Ryujinx.Modules { using (HttpClient jsonClient = ConstructHttpClient()) { - string buildInfoURL = $"{GitHubApiURL}/repos/{ReleaseInformations.ReleaseChannelOwner}/{ReleaseInformations.ReleaseChannelRepo}/releases/latest"; + string buildInfoURL = $"{GitHubApiURL}/repos/{ReleaseInformation.ReleaseChannelOwner}/{ReleaseInformation.ReleaseChannelRepo}/releases/latest"; string fetchedJson = await jsonClient.GetStringAsync(buildInfoURL); JObject jsonRoot = JObject.Parse(fetchedJson); @@ -625,7 +625,7 @@ namespace Ryujinx.Modules return false; } - if (Program.Version.Contains("dirty") || !ReleaseInformations.IsValid()) + if (Program.Version.Contains("dirty") || !ReleaseInformation.IsValid()) { if (showWarnings) { @@ -640,7 +640,7 @@ namespace Ryujinx.Modules #else if (showWarnings) { - if (ReleaseInformations.IsFlatHubBuild()) + if (ReleaseInformation.IsFlatHubBuild()) { ContentDialogHelper.CreateWarningDialog(LocaleManager.Instance[LocaleKeys.UpdaterDisabledWarningTitle], LocaleManager.Instance[LocaleKeys.DialogUpdaterFlatpakNotSupportedMessage]); } @@ -711,4 +711,4 @@ namespace Ryujinx.Modules } } } -} +} \ No newline at end of file diff --git a/Ryujinx.Ava/Program.cs b/Ryujinx.Ava/Program.cs index 836801c88..5d88466e8 100644 --- a/Ryujinx.Ava/Program.cs +++ b/Ryujinx.Ava/Program.cs @@ -13,8 +13,10 @@ using Ryujinx.Ui.Common; using Ryujinx.Ui.Common.Configuration; using Ryujinx.Ui.Common.Helper; using System; +using System.Diagnostics; using System.IO; using System.Runtime.InteropServices; +using System.Runtime.Versioning; using System.Threading.Tasks; namespace Ryujinx.Ava @@ -32,9 +34,51 @@ namespace Ryujinx.Ava private const uint MB_ICONWARNING = 0x30; + [SupportedOSPlatform("linux")] + static void RegisterMimeTypes() + { + if (ReleaseInformation.IsFlatHubBuild()) + { + return; + } + + string mimeDbPath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.UserProfile), ".local", "share", "mime"); + + if (!File.Exists(Path.Combine(mimeDbPath, "packages", "Ryujinx.xml"))) + { + string mimeTypesFile = Path.Combine(ReleaseInformation.GetBaseApplicationDirectory(), "mime", "Ryujinx.xml"); + using Process mimeProcess = new(); + + mimeProcess.StartInfo.FileName = "xdg-mime"; + mimeProcess.StartInfo.Arguments = $"install --novendor --mode user {mimeTypesFile}"; + + mimeProcess.Start(); + mimeProcess.WaitForExit(); + + if (mimeProcess.ExitCode != 0) + { + Logger.Error?.PrintMsg(LogClass.Application, $"Unable to install mime types. Make sure xdg-utils is installed. Process exited with code: {mimeProcess.ExitCode}"); + return; + } + + using Process updateMimeProcess = new(); + + updateMimeProcess.StartInfo.FileName = "update-mime-database"; + updateMimeProcess.StartInfo.Arguments = mimeDbPath; + + updateMimeProcess.Start(); + updateMimeProcess.WaitForExit(); + + if (updateMimeProcess.ExitCode != 0) + { + Logger.Error?.PrintMsg(LogClass.Application, $"Could not update local mime database. Process exited with code: {updateMimeProcess.ExitCode}"); + } + } + } + public static void Main(string[] args) { - Version = ReleaseInformations.GetVersion(); + Version = ReleaseInformation.GetVersion(); if (OperatingSystem.IsWindows() && !OperatingSystem.IsWindowsVersionAtLeast(10, 0, 17134)) { @@ -93,6 +137,12 @@ namespace Ryujinx.Ava // Initialize the logger system. LoggerModule.Initialize(); + // Register mime types on linux. + if (OperatingSystem.IsLinux()) + { + RegisterMimeTypes(); + } + // Initialize Discord integration. DiscordIntegrationModule.Initialize(); @@ -218,4 +268,4 @@ namespace Ryujinx.Ava Logger.Shutdown(); } } -} +} \ No newline at end of file diff --git a/Ryujinx.Ava/Ryujinx.Ava.csproj b/Ryujinx.Ava/Ryujinx.Ava.csproj index 3e3bdc8c7..e63360d47 100644 --- a/Ryujinx.Ava/Ryujinx.Ava.csproj +++ b/Ryujinx.Ava/Ryujinx.Ava.csproj @@ -4,6 +4,7 @@ win10-x64;osx-x64;linux-x64 Exe true + Ryujinx 1.0.0-dirty $(DefineConstants);$(ExtraDefineConstants) Ryujinx.Ava @@ -76,6 +77,16 @@ + + + Always + + + Always + mime\Ryujinx.xml + + + Designer diff --git a/Ryujinx.Ava/UI/ViewModels/MainWindowViewModel.cs b/Ryujinx.Ava/UI/ViewModels/MainWindowViewModel.cs index 888e227c0..514a8bb35 100644 --- a/Ryujinx.Ava/UI/ViewModels/MainWindowViewModel.cs +++ b/Ryujinx.Ava/UI/ViewModels/MainWindowViewModel.cs @@ -940,7 +940,7 @@ namespace Ryujinx.Ava.UI.ViewModels public static void OpenLogsFolder() { - string logPath = Path.Combine(ReleaseInformations.GetBaseApplicationDirectory(), "Logs"); + string logPath = Path.Combine(ReleaseInformation.GetBaseApplicationDirectory(), "Logs"); new DirectoryInfo(logPath).Create(); diff --git a/Ryujinx.Common/Logging/Targets/FileLogTarget.cs b/Ryujinx.Common/Logging/Targets/FileLogTarget.cs index 401fe91ba..24dd6d179 100644 --- a/Ryujinx.Common/Logging/Targets/FileLogTarget.cs +++ b/Ryujinx.Common/Logging/Targets/FileLogTarget.cs @@ -29,7 +29,7 @@ namespace Ryujinx.Common.Logging files[i].Delete(); } - string version = ReleaseInformations.GetVersion(); + string version = ReleaseInformation.GetVersion(); // Get path for the current time path = Path.Combine(logDir.FullName, $"Ryujinx_{version}_{DateTime.Now.ToString("yyyy-MM-dd_HH-mm-ss")}.log"); diff --git a/Ryujinx.Common/ReleaseInformations.cs b/Ryujinx.Common/ReleaseInformation.cs similarity index 97% rename from Ryujinx.Common/ReleaseInformations.cs rename to Ryujinx.Common/ReleaseInformation.cs index 35890406e..d0e013282 100644 --- a/Ryujinx.Common/ReleaseInformations.cs +++ b/Ryujinx.Common/ReleaseInformation.cs @@ -5,7 +5,7 @@ using System.Reflection; namespace Ryujinx.Common { // DO NOT EDIT, filled by CI - public static class ReleaseInformations + public static class ReleaseInformation { private const string FlatHubChannelOwner = "flathub"; @@ -50,4 +50,4 @@ namespace Ryujinx.Common return AppDomain.CurrentDomain.BaseDirectory; } } -} +} \ No newline at end of file diff --git a/Ryujinx.Headless.SDL2/Program.cs b/Ryujinx.Headless.SDL2/Program.cs index b0c29e561..84363e1fb 100644 --- a/Ryujinx.Headless.SDL2/Program.cs +++ b/Ryujinx.Headless.SDL2/Program.cs @@ -59,7 +59,7 @@ namespace Ryujinx.Headless.SDL2 static void Main(string[] args) { - Version = ReleaseInformations.GetVersion(); + Version = ReleaseInformation.GetVersion(); Console.Title = $"Ryujinx Console {Version} (Headless SDL2)"; @@ -419,7 +419,7 @@ namespace Ryujinx.Headless.SDL2 if ((bool)option.EnableFileLog) { Logger.AddTarget(new AsyncLogTargetWrapper( - new FileLogTarget(ReleaseInformations.GetBaseApplicationDirectory(), "file"), + new FileLogTarget(ReleaseInformation.GetBaseApplicationDirectory(), "file"), 1000, AsyncLogTargetOverflowAction.Block )); diff --git a/Ryujinx.SDL2.Common/SDL2Driver.cs b/Ryujinx.SDL2.Common/SDL2Driver.cs index 7aa2d5840..970e287de 100644 --- a/Ryujinx.SDL2.Common/SDL2Driver.cs +++ b/Ryujinx.SDL2.Common/SDL2Driver.cs @@ -91,7 +91,7 @@ namespace Ryujinx.SDL2.Common SDL_EventState(SDL_EventType.SDL_CONTROLLERSENSORUPDATE, SDL_DISABLE); - string gamepadDbPath = Path.Combine(ReleaseInformations.GetBaseApplicationDirectory(), "SDL_GameControllerDB.txt"); + string gamepadDbPath = Path.Combine(ReleaseInformation.GetBaseApplicationDirectory(), "SDL_GameControllerDB.txt"); if (File.Exists(gamepadDbPath)) { diff --git a/Ryujinx.Ui.Common/Configuration/LoggerModule.cs b/Ryujinx.Ui.Common/Configuration/LoggerModule.cs index 174f056d8..f4712213e 100644 --- a/Ryujinx.Ui.Common/Configuration/LoggerModule.cs +++ b/Ryujinx.Ui.Common/Configuration/LoggerModule.cs @@ -80,7 +80,7 @@ namespace Ryujinx.Ui.Common.Configuration if (e.NewValue) { Logger.AddTarget(new AsyncLogTargetWrapper( - new FileLogTarget(ReleaseInformations.GetBaseApplicationDirectory(), "file"), + new FileLogTarget(ReleaseInformation.GetBaseApplicationDirectory(), "file"), 1000, AsyncLogTargetOverflowAction.Block )); diff --git a/Ryujinx/Modules/Updater/Updater.cs b/Ryujinx/Modules/Updater/Updater.cs index 0a1cb53bc..2a25e78f5 100644 --- a/Ryujinx/Modules/Updater/Updater.cs +++ b/Ryujinx/Modules/Updater/Updater.cs @@ -103,7 +103,7 @@ namespace Ryujinx.Modules { using (HttpClient jsonClient = ConstructHttpClient()) { - string buildInfoURL = $"{GitHubApiURL}/repos/{ReleaseInformations.ReleaseChannelOwner}/{ReleaseInformations.ReleaseChannelRepo}/releases/latest"; + string buildInfoURL = $"{GitHubApiURL}/repos/{ReleaseInformation.ReleaseChannelOwner}/{ReleaseInformation.ReleaseChannelRepo}/releases/latest"; // Fetch latest build information string fetchedJson = await jsonClient.GetStringAsync(buildInfoURL); @@ -556,7 +556,7 @@ namespace Ryujinx.Modules return false; } - if (Program.Version.Contains("dirty") || !ReleaseInformations.IsValid()) + if (Program.Version.Contains("dirty") || !ReleaseInformation.IsValid()) { if (showWarnings) { @@ -570,7 +570,7 @@ namespace Ryujinx.Modules #else if (showWarnings) { - if (ReleaseInformations.IsFlatHubBuild()) + if (ReleaseInformation.IsFlatHubBuild()) { GtkDialog.CreateWarningDialog("Updater Disabled!", "Please update Ryujinx via FlatHub."); } diff --git a/Ryujinx/Program.cs b/Ryujinx/Program.cs index 787a8ad5f..b1fedaade 100644 --- a/Ryujinx/Program.cs +++ b/Ryujinx/Program.cs @@ -18,6 +18,7 @@ using System.Collections.Generic; using System.Diagnostics; using System.IO; using System.Runtime.InteropServices; +using System.Runtime.Versioning; using System.Threading.Tasks; namespace Ryujinx @@ -72,9 +73,51 @@ namespace Ryujinx } } + [SupportedOSPlatform("linux")] + static void RegisterMimeTypes() + { + if (ReleaseInformation.IsFlatHubBuild()) + { + return; + } + + string mimeDbPath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.UserProfile), ".local", "share", "mime"); + + if (!File.Exists(Path.Combine(mimeDbPath, "packages", "Ryujinx.xml"))) + { + string mimeTypesFile = Path.Combine(ReleaseInformation.GetBaseApplicationDirectory(), "mime", "Ryujinx.xml"); + using Process mimeProcess = new(); + + mimeProcess.StartInfo.FileName = "xdg-mime"; + mimeProcess.StartInfo.Arguments = $"install --novendor --mode user {mimeTypesFile}"; + + mimeProcess.Start(); + mimeProcess.WaitForExit(); + + if (mimeProcess.ExitCode != 0) + { + Logger.Error?.PrintMsg(LogClass.Application, $"Unable to install mime types. Make sure xdg-utils is installed. Process exited with code: {mimeProcess.ExitCode}"); + return; + } + + using Process updateMimeProcess = new(); + + updateMimeProcess.StartInfo.FileName = "update-mime-database"; + updateMimeProcess.StartInfo.Arguments = mimeDbPath; + + updateMimeProcess.Start(); + updateMimeProcess.WaitForExit(); + + if (updateMimeProcess.ExitCode != 0) + { + Logger.Error?.PrintMsg(LogClass.Application, $"Could not update local mime database. Process exited with code: {updateMimeProcess.ExitCode}"); + } + } + } + static void Main(string[] args) { - Version = ReleaseInformations.GetVersion(); + Version = ReleaseInformation.GetVersion(); if (OperatingSystem.IsWindows() && !OperatingSystem.IsWindowsVersionAtLeast(10, 0, 17134)) { @@ -101,6 +144,8 @@ namespace Ryujinx if (OperatingSystem.IsLinux()) { XInitThreads(); + Environment.SetEnvironmentVariable("GDK_BACKEND", "x11"); + setenv("GDK_BACKEND", "x11", 1); } if (OperatingSystem.IsMacOS()) @@ -144,6 +189,12 @@ namespace Ryujinx // Initialize the logger system. LoggerModule.Initialize(); + // Register mime types on linux. + if (OperatingSystem.IsLinux()) + { + RegisterMimeTypes(); + } + // Initialize Discord integration. DiscordIntegrationModule.Initialize(); diff --git a/Ryujinx/Ryujinx.csproj b/Ryujinx/Ryujinx.csproj index d8176ee35..6aae6296f 100644 --- a/Ryujinx/Ryujinx.csproj +++ b/Ryujinx/Ryujinx.csproj @@ -62,6 +62,16 @@ + + + Always + + + Always + mime\Ryujinx.xml + + + false diff --git a/Ryujinx/Ui/MainWindow.cs b/Ryujinx/Ui/MainWindow.cs index 495f66519..688e2f522 100644 --- a/Ryujinx/Ui/MainWindow.cs +++ b/Ryujinx/Ui/MainWindow.cs @@ -1294,7 +1294,7 @@ namespace Ryujinx.Ui private void OpenLogsFolder_Pressed(object sender, EventArgs args) { - string logPath = System.IO.Path.Combine(ReleaseInformations.GetBaseApplicationDirectory(), "Logs"); + string logPath = System.IO.Path.Combine(ReleaseInformation.GetBaseApplicationDirectory(), "Logs"); new DirectoryInfo(logPath).Create(); diff --git a/distribution/linux/ryujinx.desktop b/distribution/linux/Ryujinx.desktop similarity index 78% rename from distribution/linux/ryujinx.desktop rename to distribution/linux/Ryujinx.desktop index dbfc43e41..19cc5d6cc 100644 --- a/distribution/linux/ryujinx.desktop +++ b/distribution/linux/Ryujinx.desktop @@ -1,13 +1,13 @@ [Desktop Entry] Version=1.0 Name=Ryujinx -Comment=A Nintendo Switch Emulator Type=Application +Icon=Ryujinx +Exec=env DOTNET_EnableAlternateStackCheck=1 Ryujinx %f +Comment=A Nintendo Switch Emulator GenericName=Nintendo Switch Emulator -Icon=ryujinx Terminal=false -Exec=Ryujinx %f -Categories=Game;Emulator;GTK; +Categories=Game;Emulator; MimeType=application/x-nx-nca;application/x-nx-nro;application/x-nx-nso;application/x-nx-nsp;application/x-nx-xci; Keywords=Switch;Nintendo;Emulator; StartupWMClass=Ryujinx diff --git a/distribution/linux/Ryujinx.sh b/distribution/linux/Ryujinx.sh new file mode 100644 index 000000000..57a75b1d1 --- /dev/null +++ b/distribution/linux/Ryujinx.sh @@ -0,0 +1,5 @@ +#!/bin/sh + +SCRIPT_DIR=$(dirname $(realpath $0)) + +env DOTNET_EnableAlternateStackCheck=1 "$SCRIPT_DIR/Ryujinx" "$@" diff --git a/distribution/linux/ryujinx-mime.xml b/distribution/linux/mime/Ryujinx.xml similarity index 62% rename from distribution/linux/ryujinx-mime.xml rename to distribution/linux/mime/Ryujinx.xml index 6ec35c848..bd9df0edf 100644 --- a/distribution/linux/ryujinx-mime.xml +++ b/distribution/linux/mime/Ryujinx.xml @@ -2,22 +2,32 @@ Nintendo Content Archive + NCA + Nintendo Relocatable Object + NRO + Nintendo Shared Object + NSO + Nintendo Submission Package + NSP + Nintendo Switch Cartridge + XCI + diff --git a/distribution/linux/ryujinx-logo.svg b/distribution/misc/Logo.svg similarity index 100% rename from distribution/linux/ryujinx-logo.svg rename to distribution/misc/Logo.svg