From cbaa845f5d51fe61a46d1a57950aa76a0a976d3e Mon Sep 17 00:00:00 2001
From: RMED24 <81475204+RMED24@users.noreply.github.com>
Date: Sat, 7 Jan 2023 08:06:13 +0000
Subject: [PATCH] Include a start.sh file with correct launch options (#4013)

* Include reference to start.sh to be bundled

* Add start.sh

* Fix silly mistake I made on windows-x64

* ... I cannot read properly

* Make same changes for avalonia csproj

* Remove notice from start.sh

Co-authored-by: Mary-nyan <thog@protonmail.com>

* Update Ryujinx/Ryujinx.csproj

Co-authored-by: Mary-nyan <thog@protonmail.com>

* Update Ryujinx.Ava/Ryujinx.Ava.csproj

Co-authored-by: Mary-nyan <thog@protonmail.com>

* Update distribution/linux/start.sh

Co-authored-by: TSRBerry <20988865+TSRBerry@users.noreply.github.com>

* Update distribution/linux/start.sh

Co-authored-by: TSRBerry <20988865+TSRBerry@users.noreply.github.com>

* Update Ryujinx.Ava/Ryujinx.Ava.csproj

Co-authored-by: TSRBerry <20988865+TSRBerry@users.noreply.github.com>

* Update Ryujinx.csproj

* Update Ryujinx.Ava.csproj

* Rename start.sh to Ryujinx.sh

* Update Ryujinx.csproj

* Update Ryujinx.Ava.csproj

* Update Ryujinx.Ava.csproj

* Update Ryujinx.Ava/Ryujinx.Ava.csproj

Co-authored-by: TSRBerry <20988865+TSRBerry@users.noreply.github.com>

* Add `GDK_BACKEND` variable

* Update Ryujinx.Ava.csproj

* Update Program.cs

* Update Program.cs

* Update Ryujinx.sh

* Update Program.cs

* linux: Register mime types on launch

* Add DOTNET_EnableAlternateStackCheck=1 to desktop file

* linux: Add exclusion for RegisterMimeTypes for flathub builds

* Update logo path

* Cleanup Ryujinx.sh

* Fix typo in ReleaseInformation

* gha: Fix permissions for linux release binaries

* ava: Rename output assembly to Ryujinx

* Update mime database after installing new types

Wait until logging is available before registering mime types

* Copy mime types to output directory

Co-authored-by: Mary-nyan <thog@protonmail.com>
Co-authored-by: TSRBerry <20988865+TSRBerry@users.noreply.github.com>
---
 .github/workflows/release.yml                 | 25 ++++++---
 Ryujinx.Ava/Modules/Updater/Updater.cs        |  8 +--
 Ryujinx.Ava/Program.cs                        | 54 ++++++++++++++++++-
 Ryujinx.Ava/Ryujinx.Ava.csproj                | 11 ++++
 .../UI/ViewModels/MainWindowViewModel.cs      |  2 +-
 .../Logging/Targets/FileLogTarget.cs          |  2 +-
 ...eInformations.cs => ReleaseInformation.cs} |  4 +-
 Ryujinx.Headless.SDL2/Program.cs              |  4 +-
 Ryujinx.SDL2.Common/SDL2Driver.cs             |  2 +-
 .../Configuration/LoggerModule.cs             |  2 +-
 Ryujinx/Modules/Updater/Updater.cs            |  6 +--
 Ryujinx/Program.cs                            | 53 +++++++++++++++++-
 Ryujinx/Ryujinx.csproj                        | 10 ++++
 Ryujinx/Ui/MainWindow.cs                      |  2 +-
 .../{ryujinx.desktop => Ryujinx.desktop}      |  8 +--
 distribution/linux/Ryujinx.sh                 |  5 ++
 .../{ryujinx-mime.xml => mime/Ryujinx.xml}    | 10 ++++
 .../{linux/ryujinx-logo.svg => misc/Logo.svg} |  0
 18 files changed, 177 insertions(+), 31 deletions(-)
 rename Ryujinx.Common/{ReleaseInformations.cs => ReleaseInformation.cs} (97%)
 rename distribution/linux/{ryujinx.desktop => Ryujinx.desktop} (78%)
 create mode 100644 distribution/linux/Ryujinx.sh
 rename distribution/linux/{ryujinx-mime.xml => mime/Ryujinx.xml} (62%)
 rename distribution/{linux/ryujinx-logo.svg => misc/Logo.svg} (100%)

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 @@
     <RuntimeIdentifiers>win10-x64;osx-x64;linux-x64</RuntimeIdentifiers>
     <OutputType>Exe</OutputType>
     <AllowUnsafeBlocks>true</AllowUnsafeBlocks>
+    <AssemblyName>Ryujinx</AssemblyName>
     <Version>1.0.0-dirty</Version>
     <DefineConstants Condition=" '$(ExtraDefineConstants)' != '' ">$(DefineConstants);$(ExtraDefineConstants)</DefineConstants>
     <RootNamespace>Ryujinx.Ava</RootNamespace>
@@ -76,6 +77,16 @@
     </Content>
   </ItemGroup>
 
+  <ItemGroup Condition="'$(RuntimeIdentifier)' == 'linux-x64'">
+    <Content Include="..\distribution\linux\Ryujinx.sh">
+      <CopyToOutputDirectory>Always</CopyToOutputDirectory>
+    </Content>
+    <Content Include="..\distribution\linux\mime\Ryujinx.xml">
+      <CopyToOutputDirectory>Always</CopyToOutputDirectory>
+      <TargetPath>mime\Ryujinx.xml</TargetPath>
+    </Content>
+  </ItemGroup>
+
   <ItemGroup>
     <AvaloniaResource Include="Ui\**\*.xaml">
       <SubType>Designer</SubType>
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 @@
     </Content>
   </ItemGroup>
 
+   <ItemGroup Condition="'$(RuntimeIdentifier)' == 'linux-x64'">
+     <Content Include="..\distribution\linux\Ryujinx.sh">
+      <CopyToOutputDirectory>Always</CopyToOutputDirectory>
+     </Content>
+     <Content Include="..\distribution\linux\mime\Ryujinx.xml">
+       <CopyToOutputDirectory>Always</CopyToOutputDirectory>
+       <TargetPath>mime\Ryujinx.xml</TargetPath>
+     </Content>
+   </ItemGroup>
+
   <!-- Due to .net core 3.1 embedded resource loading -->
   <PropertyGroup>
     <EmbeddedResourceUseDependentUponConvention>false</EmbeddedResourceUseDependentUponConvention>
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 @@
 <mime-info xmlns="http://www.freedesktop.org/standards/shared-mime-info">
     <mime-type type="application/x-nx-nca">
         <comment>Nintendo Content Archive</comment>
+        <acronym>NCA</acronym>
         <glob pattern="*.nca"/>
+        <magic><match value="NCA" type="string" offset="512"/></magic>
     </mime-type>
     <mime-type type="application/x-nx-nro">
         <comment>Nintendo Relocatable Object</comment>
+        <acronym>NRO</acronym>
         <glob pattern="*.nro"/>
+        <magic><match value="NRO0" type="string" offset="16"/></magic>
     </mime-type>
     <mime-type type="application/x-nx-nso">
         <comment>Nintendo Shared Object</comment>
+        <acronym>NSO</acronym>
         <glob pattern="*.nso"/>
+        <magic><match value="NSO0" type="string" offset="0"/></magic>
     </mime-type>
     <mime-type type="application/x-nx-nsp">
         <comment>Nintendo Submission Package</comment>
+        <acronym>NSP</acronym>
         <glob pattern="*.nsp"/>
+        <magic><match value="PFS0" type="string" offset="0"/></magic>
     </mime-type>
     <mime-type type="application/x-nx-xci">
         <comment>Nintendo Switch Cartridge</comment>
+        <acronym>XCI</acronym>
         <glob pattern="*.xci"/>
+        <magic><match value="HEAD" type="string" offset="4352"/></magic>
     </mime-type>
 </mime-info>
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