Skip to content

Fix lookup in XDG locations#77

Merged
slouken merged 1 commit into
libsdl-org:mainfrom
pinotree:fix-xdg-lookup
May 31, 2026
Merged

Fix lookup in XDG locations#77
slouken merged 1 commit into
libsdl-org:mainfrom
pinotree:fix-xdg-lookup

Conversation

@pinotree

Copy link
Copy Markdown
Contributor

Make use of the existing project name to lookup resources, matching what is used to install them. Additionally, user resources are "namespaced" using the organization name too.

This makes it possible to provide own data & mods in the user local directory without changing the system installation.

@slouken

slouken commented May 23, 2026

Copy link
Copy Markdown
Contributor

@smcv, is this expected usage?

@smcv

smcv commented May 26, 2026

Copy link
Copy Markdown

is this expected usage?

I'm not sure what you're asking me. @pinotree, perhaps you could give a solution-neutral problem statement for the bug you're fixing, or the enhancement you're asking for? That would make it easier to assess whether this PR is the right implementation.

The canonical spec for the XDG locations is: https://specifications.freedesktop.org/basedir-spec/basedir-spec-latest.html

The main thing that people sometimes miss is that if a particular sort of data is looked up in $XDG_DATA_HOME/maelstrom or ~/.local/share/maelstrom, then to be consistent with other apps, it should be looked up in all XDG locations:

  • when reading, first try $XDG_DATA_HOME/maelstrom or ~/.local/share/maelstrom, then split $XDG_DATA_DIRS or /usr/local/share:/usr/share at colons, and try $dir/maelstrom for each one, in decreasing order of importance
  • it's also OK to try reading implementation-specific locations before or after doing this search, for example next to the executable, or a hard-coded compile-time path
  • if a data file is found in more than one place, it's the app author's choice whether to take the first/most-important location, or merge them somehow
  • normally you'd install to ${datadir}/maelstrom in Autotools, or other build systems' equivalents
  • when writing (if that's applicable for your app), only write to $XDG_DATA_HOME/maelstrom or ~/.local/share/maelstrom

And the config "stack" is very similar to the data "stack", but with different environment variable names and defaults. A few specifications like Vulkan use both "stacks", one after the other.

It's also OK for resources to only be looked up in the app's installed directory (conventionally hard-coded at build time on Unix, but might also be looked up relative to the executable), for example perhaps in /usr/share/maelstrom or /usr/lib/Maelstrom/Data, without having anything to do with the XDG variables - although that will make it less convenient to install per-user mods, so for resources that make sense to mod, users might prefer it if the game would search the XDG data stack first, falling back to a hard-coded or executable-relative location if it can't find resources that way.

The subdirectory can be anything you want, within reason. I'd normally expect maelstrom or Maelstrom (the most common), or occasionally a reversed-DNS name like org.libsdl.Maelstrom (some GNOME apps use that naming convention). It's unusual to use a path like ~/.local/share/Ambrosia Software/Maelstrom on "freedesktop" platforms, even if that's the closest to a 1:1 match for what you'd do on Windows - I think SDL's default is to ignore the organization name and use only the app name in this case, and that's often the most appropriate.

@pinotree

Copy link
Copy Markdown
Contributor Author

The main thing that people sometimes miss is that if a particular sort of data is looked up in $XDG_DATA_HOME/maelstrom or ~/.local/share/maelstrom

As I mentioned, there is a mismatch between what GetXDGDataPath() checks and where things are installed/saved.

Regarding the system locations:

set(GAME_INSTALL_DATADIR "${CMAKE_INSTALL_DATAROOTDIR}/${PROJECT_NAME}")

Considering that ${PROJECT_NAME} is "Maelstrom", then the current lookup of a lowercase "maelstrom" done by GetXDGDataPath() does not find any resources in $XDG_DATA_DIRS at all. This can be easily checked with strace over a system installation of Maelstrom (installed in /usr, so that /usr/share/Maelstrom/Data/ exists):

newfstatat(AT_FDCWD, "/home/pino/.local/share/maelstrom/Data", 0x7fffd619bdb0, 0) = -1 ENOENT (No such file or directory)
newfstatat(AT_FDCWD, "/usr/local/share/maelstrom/Data", 0x7fffd619bdb0, 0) = -1 ENOENT (No such file or directory)
newfstatat(AT_FDCWD, "/usr/share/maelstrom/Data", 0x7fffd619bdb0, 0) = -1 ENOENT (No such file or directory)
newfstatat(AT_FDCWD, "/home/pino/.local/share/maelstrom/mods", 0x7fffd619bdb0, 0) = -1 ENOENT (No such file or directory)
newfstatat(AT_FDCWD, "/usr/local/share/maelstrom/mods", 0x7fffd619bdb0, 0) = -1 ENOENT (No such file or directory)
newfstatat(AT_FDCWD, "/usr/share/maelstrom/mods", 0x7fffd619bdb0, 0) = -1 ENOENT (No such file or directory)

Using the predefined name (passed to InitFilesystem()) fixes this:

Maelstrom/game/main.cpp

Lines 52 to 53 in 0d7a850

#define MAELSTROM_ORGANIZATION "Ambrosia Software"
#define MAELSTROM_NAME "Maelstrom"

Regarding the user local directory:

It's unusual to use a path like ~/.local/share/Ambrosia Software/Maelstrom on "freedesktop" platforms, even if that's the closest to a 1:1 match for what you'd do on Windows - I think SDL's default is to ignore the organization name and use only the app name in this case, and that's often the most appropriate.

May seem unusual, however that is what SDL (at least in v3) does. Maelstrom calls SDL_OpenUserStorage() with the above name & organization mentioned above, and in the end the filesystem implementation for "common" Unix OSes (e.g. Linux, BSDs, etc) does use the organization:

https://github.com/libsdl-org/SDL/blob/main/src/filesystem/unix/SDL_sysfilesystem.c#L274-L335

Indeed, my scores and preferences are in /home/pino/.local/share/Ambrosia Software/Maelstrom/ since Maelstrom 3 (which started to use the user local storage for scores). Since Maelstrom 3 is a SDL 2 application, then I guess we can say this behaviour was also in SDL 2 too.

Make use of the existing project name to lookup resources, matching
what is used to install them. Additionally, user resources are
"namespaced" using the organization name too.

This makes it possible to provide own data & mods in the user local
directory without changing the system installation.
@slouken

slouken commented May 31, 2026

Copy link
Copy Markdown
Contributor

It seems reasonable for the Data override to share the same directory as the scores and preferences. I'll go ahead and accept this PR, thanks!

@slouken slouken merged commit 01f829a into libsdl-org:main May 31, 2026
3 checks passed
@pinotree pinotree deleted the fix-xdg-lookup branch May 31, 2026 22:05
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants