forked from Ryubing/Ryujinx
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add "Create Shortcut" To app context menu (#4734)
* Added basic implementation for shortcut creation Currently bitmaps (.bmp) are used as the source file, colours are good (unlike .ico rn) but are scaled poorly on desktop. * Icons display properly in shortcut * code cleanup * Moved shortcut logic to specific file, added Ava UI for shortcuts * Added linux .desktop shortcut creation * fixes to .shortcut data * code issue fixes * Added basic implementation for shortcut creation Currently bitmaps (.bmp) are used as the source file, colours are good (unlike .ico rn) but are scaled poorly on desktop. * Icons display properly in shortcut * code cleanup * Moved shortcut logic to specific file, added Ava UI for shortcuts * Added linux .desktop shortcut creation * fixes to .shortcut data * code issue fixes * added back shortcut to new contextmenu file * Replaced COM reference with ComImport for shortcut functionality * remove specific platform values and regions * Move ShortcutHelper to Ryujinx.Ui.Common.Helpers * Adjust styling and structure * code feedback changes * Added MacOS support using .app folder * Added basic implementation for shortcut creation Currently bitmaps (.bmp) are used as the source file, colours are good (unlike .ico rn) but are scaled poorly on desktop. * Icons display properly in shortcut * code cleanup * Moved shortcut logic to specific file, added Ava UI for shortcuts * Added linux .desktop shortcut creation * fixes to .shortcut data * code issue fixes * Added basic implementation for shortcut creation Currently bitmaps (.bmp) are used as the source file, colours are good (unlike .ico rn) but are scaled poorly on desktop. * Icons display properly in shortcut * code cleanup * Moved shortcut logic to specific file, added Ava UI for shortcuts * Added linux .desktop shortcut creation * fixes to .shortcut data * code issue fixes * Replaced COM reference with ComImport for shortcut functionality * remove specific platform values and regions * Move ShortcutHelper to Ryujinx.Ui.Common.Helpers * Adjust styling and structure * code feedback changes * adjust tooltip message * added shortcut-template.desktop file * set shortcut icon location to .local/share/icons * Linux code feedback changes * change InteropServices to new securifybv.ShellLink Package * added ShellLink to readme, updated shortcut comment * Code feedback changes * Added MacOS Support (As per Jose Estrada's PR) * dotnet format * Small restructuring * Embed template files into Ryujinx.Ui.Common * Disable "CreateShortcut" option for flatpak builds --------- Co-authored-by: TSR Berry <[email protected]> Co-authored-by: Jose Estrada <[email protected]>
- Loading branch information
1 parent
b4bb22b
commit a42f0bb
Showing
17 changed files
with
316 additions
and
17 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
[Desktop Entry] | ||
Version=1.0 | ||
Name={0} | ||
Type=Application | ||
Icon={1} | ||
Exec={2} %f | ||
Comment=Nintendo Switch application | ||
GenericName=Nintendo Switch Emulator | ||
Terminal=false | ||
Categories=Game;Emulator; | ||
Keywords=Switch;Nintendo;Emulator; | ||
StartupWMClass=Ryujinx | ||
PrefersNonDefaultGPU=true |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,35 @@ | ||
<?xml version="1.0" encoding="UTF-8"?> | ||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> | ||
<plist version="1.0"> | ||
<dict> | ||
<key>CFBundleDevelopmentRegion</key> | ||
<string>English</string> | ||
<key>CFBundleExecutable</key> | ||
<string>{0}</string> | ||
<key>CFBundleGetInfoString</key> | ||
<string>{1}</string> | ||
<key>CFBundleIconFile</key> | ||
<string>{2}</string> | ||
<key>CFBundleInfoDictionaryVersion</key> | ||
<string>6.0</string> | ||
<key>CFBundleVersion</key> | ||
<string>1.0</string> | ||
<key>NSHighResolutionCapable</key> | ||
<true/> | ||
<key>CSResourcesFileMapped</key> | ||
<true/> | ||
<key>NSHumanReadableCopyright</key> | ||
<string>Copyright © 2018 - 2023 Ryujinx Team and Contributors.</string> | ||
<key>LSApplicationCategoryType</key> | ||
<string>public.app-category.games</string> | ||
<key>LSMinimumSystemVersion</key> | ||
<string>11.0</string> | ||
<key>UIPrerenderedIcon</key> | ||
<true/> | ||
<key>LSEnvironment</key> | ||
<dict> | ||
<key>DOTNET_DefaultStackSize</key> | ||
<string>200000</string> | ||
</dict> | ||
</dict> | ||
</plist> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -145,4 +145,4 @@ | |
<ItemGroup> | ||
<AdditionalFiles Include="Assets\Locales\en_US.json" /> | ||
</ItemGroup> | ||
</Project> | ||
</Project> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,171 @@ | ||
using Ryujinx.Common; | ||
using Ryujinx.Common.Configuration; | ||
using ShellLink; | ||
using SixLabors.ImageSharp; | ||
using SixLabors.ImageSharp.PixelFormats; | ||
using System; | ||
using System.Collections.Generic; | ||
using System.Drawing; | ||
using System.Drawing.Drawing2D; | ||
using System.Drawing.Imaging; | ||
using System.IO; | ||
using System.Runtime.Versioning; | ||
using Image = System.Drawing.Image; | ||
|
||
namespace Ryujinx.Ui.Common.Helper | ||
{ | ||
public static class ShortcutHelper | ||
{ | ||
[SupportedOSPlatform("windows")] | ||
private static void CreateShortcutWindows(string applicationFilePath, byte[] iconData, string iconPath, string cleanedAppName, string desktopPath) | ||
{ | ||
string basePath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, AppDomain.CurrentDomain.FriendlyName + ".exe"); | ||
iconPath += ".ico"; | ||
|
||
MemoryStream iconDataStream = new(iconData); | ||
using Image image = Image.FromStream(iconDataStream); | ||
using Bitmap bitmap = new(128, 128); | ||
using System.Drawing.Graphics graphic = System.Drawing.Graphics.FromImage(bitmap); | ||
graphic.InterpolationMode = InterpolationMode.HighQualityBicubic; | ||
graphic.DrawImage(image, 0, 0, 128, 128); | ||
SaveBitmapAsIcon(bitmap, iconPath); | ||
|
||
var shortcut = Shortcut.CreateShortcut(basePath, GetArgsString(basePath, applicationFilePath), iconPath, 0); | ||
shortcut.StringData.NameString = cleanedAppName; | ||
shortcut.WriteToFile(Path.Combine(desktopPath, cleanedAppName + ".lnk")); | ||
} | ||
|
||
[SupportedOSPlatform("linux")] | ||
private static void CreateShortcutLinux(string applicationFilePath, byte[] iconData, string iconPath, string desktopPath, string cleanedAppName) | ||
{ | ||
string basePath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Ryujinx.sh"); | ||
var desktopFile = EmbeddedResources.ReadAllText("Ryujinx.Ui.Common/shortcut-template.desktop"); | ||
iconPath += ".png"; | ||
|
||
var image = SixLabors.ImageSharp.Image.Load<Rgba32>(iconData); | ||
image.SaveAsPng(iconPath); | ||
|
||
using StreamWriter outputFile = new(Path.Combine(desktopPath, cleanedAppName + ".desktop")); | ||
outputFile.Write(desktopFile, cleanedAppName, iconPath, GetArgsString(basePath, applicationFilePath)); | ||
} | ||
|
||
[SupportedOSPlatform("macos")] | ||
private static void CreateShortcutMacos(string appFilePath, byte[] iconData, string desktopPath, string cleanedAppName) | ||
{ | ||
string basePath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, AppDomain.CurrentDomain.FriendlyName); | ||
var plistFile = EmbeddedResources.ReadAllText("Ryujinx.Ui.Common/shortcut-template.plist"); | ||
// Macos .App folder | ||
string contentFolderPath = Path.Combine(desktopPath, cleanedAppName + ".app", "Contents"); | ||
string scriptFolderPath = Path.Combine(contentFolderPath, "MacOS"); | ||
|
||
if (!Directory.Exists(scriptFolderPath)) | ||
{ | ||
Directory.CreateDirectory(scriptFolderPath); | ||
} | ||
|
||
// Runner script | ||
const string ScriptName = "runner.sh"; | ||
string scriptPath = Path.Combine(scriptFolderPath, ScriptName); | ||
using StreamWriter scriptFile = new(scriptPath); | ||
|
||
scriptFile.WriteLine("#!/bin/sh"); | ||
scriptFile.WriteLine(GetArgsString(basePath, appFilePath)); | ||
|
||
// Set execute permission | ||
FileInfo fileInfo = new(scriptPath); | ||
fileInfo.UnixFileMode |= UnixFileMode.UserExecute; | ||
|
||
// img | ||
string resourceFolderPath = Path.Combine(contentFolderPath, "Resources"); | ||
if (!Directory.Exists(resourceFolderPath)) | ||
{ | ||
Directory.CreateDirectory(resourceFolderPath); | ||
} | ||
|
||
const string IconName = "icon.png"; | ||
var image = SixLabors.ImageSharp.Image.Load<Rgba32>(iconData); | ||
image.SaveAsPng(Path.Combine(resourceFolderPath, IconName)); | ||
|
||
// plist file | ||
using StreamWriter outputFile = new(Path.Combine(contentFolderPath, "Info.plist")); | ||
outputFile.Write(plistFile, ScriptName, cleanedAppName, IconName); | ||
} | ||
|
||
public static void CreateAppShortcut(string applicationFilePath, string applicationName, string applicationId, byte[] iconData) | ||
{ | ||
string desktopPath = Environment.GetFolderPath(Environment.SpecialFolder.DesktopDirectory); | ||
string cleanedAppName = string.Join("_", applicationName.Split(Path.GetInvalidFileNameChars())); | ||
|
||
if (OperatingSystem.IsWindows()) | ||
{ | ||
string iconPath = Path.Combine(AppDataManager.BaseDirPath, "games", applicationId, "app"); | ||
|
||
CreateShortcutWindows(applicationFilePath, iconData, iconPath, cleanedAppName, desktopPath); | ||
|
||
return; | ||
} | ||
|
||
if (OperatingSystem.IsLinux()) | ||
{ | ||
string iconPath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.UserProfile), ".local", "share", "icons", "Ryujinx"); | ||
|
||
Directory.CreateDirectory(iconPath); | ||
CreateShortcutLinux(applicationFilePath, iconData, Path.Combine(iconPath, applicationId), desktopPath, cleanedAppName); | ||
|
||
return; | ||
} | ||
|
||
if (OperatingSystem.IsMacOS()) | ||
{ | ||
CreateShortcutMacos(applicationFilePath, iconData, desktopPath, cleanedAppName); | ||
|
||
return; | ||
} | ||
|
||
throw new NotImplementedException("Shortcut support has not been implemented yet for this OS."); | ||
} | ||
|
||
private static string GetArgsString(string basePath, string appFilePath) | ||
{ | ||
// args are first defined as a list, for easier adjustments in the future | ||
var argsList = new List<string> | ||
{ | ||
basePath, | ||
}; | ||
|
||
if (!string.IsNullOrEmpty(CommandLineState.BaseDirPathArg)) | ||
{ | ||
argsList.Add("--root-data-dir"); | ||
argsList.Add($"\"{CommandLineState.BaseDirPathArg}\""); | ||
} | ||
|
||
argsList.Add($"\"{appFilePath}\""); | ||
|
||
|
||
return String.Join(" ", argsList); | ||
} | ||
|
||
/// <summary> | ||
/// Creates a Icon (.ico) file using the source bitmap image at the specified file path. | ||
/// </summary> | ||
/// <param name="source">The source bitmap image that will be saved as an .ico file</param> | ||
/// <param name="filePath">The location that the new .ico file will be saved too (Make sure to include '.ico' in the path).</param> | ||
[SupportedOSPlatform("windows")] | ||
private static void SaveBitmapAsIcon(Bitmap source, string filePath) | ||
{ | ||
// Code Modified From https://stackoverflow.com/a/11448060/368354 by Benlitz | ||
byte[] header = { 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 1, 0, 32, 0, 0, 0, 0, 0, 22, 0, 0, 0 }; | ||
using FileStream fs = new(filePath, FileMode.Create); | ||
|
||
fs.Write(header); | ||
// Writing actual data | ||
source.Save(fs, ImageFormat.Png); | ||
// Getting data length (file length minus header) | ||
long dataLength = fs.Length - header.Length; | ||
// Write it in the correct place | ||
fs.Seek(14, SeekOrigin.Begin); | ||
fs.WriteByte((byte)dataLength); | ||
fs.WriteByte((byte)(dataLength >> 8)); | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.