system: resolve user-facing paths against the app root so a macOS bundle keeps them beside the .app
This commit is contained in:
parent
705b78f53e
commit
3e842e62a6
5 changed files with 42 additions and 5 deletions
|
|
@ -36,6 +36,14 @@ std::filesystem::path GetExecutablePath();
|
|||
// Get executable folder.
|
||||
std::filesystem::path GetExecutableFolder();
|
||||
|
||||
// Get the application's root folder: the executable folder, or, when the
|
||||
// executable lives inside a macOS application bundle
|
||||
// ("<root>/<name>.app/Contents/MacOS/<exe>"), the folder containing the
|
||||
// bundle. User-facing files (config, game data, saves, DLC, logs) resolve
|
||||
// against this so a bundled app keeps them beside the bundle rather than
|
||||
// inside it.
|
||||
std::filesystem::path GetAppRootFolder();
|
||||
|
||||
// Get user folder.
|
||||
std::filesystem::path GetUserFolder();
|
||||
|
||||
|
|
|
|||
|
|
@ -95,6 +95,21 @@ std::filesystem::path GetExecutableFolder() {
|
|||
return GetExecutablePath().parent_path();
|
||||
}
|
||||
|
||||
std::filesystem::path GetAppRootFolder() {
|
||||
auto folder = GetExecutableFolder();
|
||||
#if REX_PLATFORM_MAC
|
||||
// <root>/<name>.app/Contents/MacOS/<exe> -> <root>
|
||||
if (folder.filename() == "MacOS") {
|
||||
const auto contents = folder.parent_path();
|
||||
const auto bundle = contents.parent_path();
|
||||
if (contents.filename() == "Contents" && bundle.extension() == ".app") {
|
||||
return bundle.parent_path();
|
||||
}
|
||||
}
|
||||
#endif
|
||||
return folder;
|
||||
}
|
||||
|
||||
std::filesystem::path GetUserFolder() {
|
||||
// get preferred data home
|
||||
char* home = std::getenv("XDG_DATA_HOME");
|
||||
|
|
|
|||
|
|
@ -65,6 +65,12 @@ std::filesystem::path GetExecutableFolder() {
|
|||
return GetExecutablePath().parent_path();
|
||||
}
|
||||
|
||||
std::filesystem::path GetAppRootFolder() {
|
||||
// Application bundles are a macOS concept; the executable folder is the
|
||||
// application root everywhere else.
|
||||
return GetExecutableFolder();
|
||||
}
|
||||
|
||||
std::filesystem::path GetUserFolder() {
|
||||
std::filesystem::path result;
|
||||
PWSTR path;
|
||||
|
|
|
|||
|
|
@ -16,6 +16,7 @@
|
|||
#include <rex/assert.h>
|
||||
#include <rex/chrono/clock.h>
|
||||
#include <rex/cvar.h>
|
||||
#include <rex/filesystem.h>
|
||||
#include <rex/input/flags.h>
|
||||
#include <rex/input/sdl/sdl_input_driver.h>
|
||||
#include <rex/logging.h>
|
||||
|
|
@ -96,18 +97,23 @@ void SDLInputDriver::OnWindowAvailable(rex::ui::Window* window) {
|
|||
}
|
||||
SDL_Gamepad_initialized_ = true;
|
||||
|
||||
// Load custom controller mappings if available
|
||||
// Load custom controller mappings if available. A relative path is
|
||||
// resolved against the application root rather than the working
|
||||
// directory, which is undefined when launched from a bundle/Finder.
|
||||
if (!REXCVAR_GET(hid_mappings_file).empty()) {
|
||||
std::filesystem::path mappings_path(REXCVAR_GET(hid_mappings_file));
|
||||
if (mappings_path.is_relative()) {
|
||||
mappings_path = rex::filesystem::GetAppRootFolder() / mappings_path;
|
||||
}
|
||||
if (!std::filesystem::exists(mappings_path)) {
|
||||
REXLOG_WARN("SDL GameControllerDB: file '{}' does not exist.",
|
||||
REXCVAR_GET(hid_mappings_file));
|
||||
mappings_path.string());
|
||||
} else {
|
||||
auto mappings_result =
|
||||
SDL_AddGamepadMappingsFromFile(REXCVAR_GET(hid_mappings_file).c_str());
|
||||
SDL_AddGamepadMappingsFromFile(mappings_path.string().c_str());
|
||||
if (mappings_result < 0) {
|
||||
REXLOG_ERROR("SDL GameControllerDB: error loading file '{}': {}.",
|
||||
REXCVAR_GET(hid_mappings_file), mappings_result);
|
||||
mappings_path.string(), mappings_result);
|
||||
} else {
|
||||
REXLOG_INFO("SDL GameControllerDB: loaded {} mappings.", mappings_result);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -312,7 +312,9 @@ bool ReXApp::OnInitialize() {
|
|||
}
|
||||
|
||||
bool ReXApp::SetupEnvironment() {
|
||||
auto exe_dir = rex::filesystem::GetExecutableFolder();
|
||||
// App root, not executable folder: inside a macOS .app bundle the config
|
||||
// and logs stay next to the bundle, where users can find them.
|
||||
auto exe_dir = rex::filesystem::GetAppRootFolder();
|
||||
auto config_path = exe_dir / (std::string(GetName()) + ".toml");
|
||||
|
||||
// Load config before resolving cvar-backed paths such as game_data_root.
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue