Skip to content
21 changes: 21 additions & 0 deletions src/XIVLauncher.Core/CoreEnvironmentSettings.cs
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,27 @@ public static class CoreEnvironmentSettings
public static bool IsSteamCompatTool => CheckEnvBool("XL_SCT");
public static uint SteamAppId => GetAppId(Environment.GetEnvironmentVariable("SteamAppId"));
public static uint AltAppID => GetAppId(Environment.GetEnvironmentVariable("XL_APPID"));

private static string? userDir = null;
public static string UserDir
{
get
{
if (userDir != null)
return userDir;

var uDir = Environment.GetEnvironmentVariable("XL_USERDIR") ?? "";
var uDir2 = Environment.GetEnvironmentVariable("XL_USER_DIR") ?? "";
var xlPath = Environment.GetEnvironmentVariable("XL_PATH") ?? "";
if (!string.IsNullOrEmpty(uDir))
userDir = uDir;
else if (!string.IsNullOrEmpty(uDir2))
userDir = uDir2;
else
userDir = xlPath;
return userDir;
}
}

private static bool CheckEnvBool(string key)
{
Expand Down
4 changes: 3 additions & 1 deletion src/XIVLauncher.Core/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -181,7 +181,9 @@ private static DalamudUpdater CreateDalamudUpdater()
private static void Main(string[] args)
{
mainArgs = args;
storage = new Storage(APP_NAME);
// XDG will handle the storage path for Linux and Mac. It will fall back to the old ~/.xlcore path on Linux and Mac if it exists and the XDG path does not.
var userDir = XDG.GetStoragePath(APP_NAME, CoreEnvironmentSettings.UserDir);
storage = new Storage(APP_NAME, userDir);

@marzent marzent May 20, 2026

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why are we not packing all that logic into the Storage class, where it makes sense to be?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Here's a PR for that: goatcorp/FFXIVQuickLauncher#1867

In the mean time, I'd still like to get this added, since it can take a very long time to get anything linux-related merged into XL.


if (CoreEnvironmentSettings.ClearAll)
{
Expand Down
59 changes: 59 additions & 0 deletions src/XIVLauncher.Core/XDG.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
using System.IO;

using XIVLauncher.Common;

namespace XIVLauncher.Core;

public static class XDG
{
private static Platform platform;

static XDG()
{
if (Environment.OSVersion.Platform == PlatformID.Win32NT)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

XDG as a concept mostly makes sense on Linux...

{
platform = Platform.Win32;
}
else if (Environment.OSVersion.Platform == PlatformID.Unix)
{
platform = Platform.Linux;
}
else if (Environment.OSVersion.Platform == PlatformID.MacOSX)
{
platform = Platform.Mac;
}
else
{
throw new PlatformNotSupportedException("Unsupported platform");
}
}
public static string? GetStoragePath(string appName, string? overridePath = null)
{
if (!string.IsNullOrEmpty(overridePath))
{
return overridePath;
}
if (platform == Platform.Win32)
{
return null; // Let Storage class handle it. Windows works fine.
}
else if (platform == Platform.Linux || platform == Platform.Mac)
{
if (Directory.Exists(Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), appName)))

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

On macOS Environment.SpecialFolder doesn't give you XDG paths, but rather system native locations, such as $HOME/Library/Application Support etc.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

According to the documentation I was reading, $HOME/Library/Application Support/{appName} (or just $HOME/Library/{appname})is the closest there is to XDG_DATA_HOME, and this at least doesn't pollute the ~/Library folder directly. I could switch to using environment variables directly, and that would create ~/.local/share/dev.goats.xlcore for Mac users. Not sure if xlcore even compiles for macos, though.

{
return Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), appName); // Use XDG Base Directory spec path if it exists.
// This is ~/.local/share/xlcore on Linux and ~/Library/Application Support/xlcore on Mac.
// This can be overridden with the XL_USERDIR environment variable, which will take precedence over both the old path and the XDG path.
}
if (Directory.Exists(Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.UserProfile), $".{appName}")))
{
return null; // Let Storage class handle it and use the old ~/.xlcore path if it exists, and the XDG_DATA_HOME/xlcore directory does not exist.
}
return Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), appName); // Use XDG Base Directory spec path for new installs on Linux and Mac.
}
else
{
throw new PlatformNotSupportedException("Unsupported platform");
}
}
}
Loading