From f7653a5cc2288156d9579c039928a9fba53df8a6 Mon Sep 17 00:00:00 2001 From: Alexander Yee Date: Thu, 13 Aug 2026 20:53:53 -0700 Subject: [PATCH 1/3] Finish yeeting Qt from GlobalAutoPaths. --- Common/Cpp/Filesystem/FilePath.h | 2 +- Common/Cpp/Filesystem/Filesystem.cpp | 6 ++ Common/Cpp/Filesystem/Filesystem.h | 2 + Common/Cpp/Filesystem/Filesystem_Linux.h | 6 +- Common/Cpp/Filesystem/Filesystem_Mac.h | 79 ++++++++++++++++++- Common/Cpp/Filesystem/Filesystem_Qt.h | 6 +- Common/Cpp/Filesystem/Filesystem_Windows.h | 6 +- .../CommonFramework/GlobalAutoPaths.cpp | 60 ++------------ .../Source/CommonFramework/Main.cpp | 2 +- 9 files changed, 99 insertions(+), 70 deletions(-) diff --git a/Common/Cpp/Filesystem/FilePath.h b/Common/Cpp/Filesystem/FilePath.h index b6e1e28bbe..476b9ce36b 100644 --- a/Common/Cpp/Filesystem/FilePath.h +++ b/Common/Cpp/Filesystem/FilePath.h @@ -117,7 +117,7 @@ class Path{ public: - Path& replace_extension(const Path& replacement){ + Path& replace_extension(const Path& replacement = Path()){ m_path.replace_extension(replacement); return *this; } diff --git a/Common/Cpp/Filesystem/Filesystem.cpp b/Common/Cpp/Filesystem/Filesystem.cpp index aa0c5ff454..8b97e3b1ba 100644 --- a/Common/Cpp/Filesystem/Filesystem.cpp +++ b/Common/Cpp/Filesystem/Filesystem.cpp @@ -70,6 +70,12 @@ Path current_path(){ return std::filesystem::current_path(); } +Path application_binary_name(){ + return application_binary_path().filename(); +} +Path application_binary_directory(){ + return application_binary_path().parent_path(); +} diff --git a/Common/Cpp/Filesystem/Filesystem.h b/Common/Cpp/Filesystem/Filesystem.h index f68f73a59c..b7a6dcd8eb 100644 --- a/Common/Cpp/Filesystem/Filesystem.h +++ b/Common/Cpp/Filesystem/Filesystem.h @@ -66,7 +66,9 @@ void rename(const Path& old_path, const Path& new_path, std::error_code& ec); Path current_path(); // The path to the actual binary that is running. +Path application_binary_name(); Path application_binary_path(); +Path application_binary_directory(); // Path to where the application is installed. // All immutable resources are relative to this. diff --git a/Common/Cpp/Filesystem/Filesystem_Linux.h b/Common/Cpp/Filesystem/Filesystem_Linux.h index 7c58d37cce..d18c4792cc 100644 --- a/Common/Cpp/Filesystem/Filesystem_Linux.h +++ b/Common/Cpp/Filesystem/Filesystem_Linux.h @@ -21,7 +21,7 @@ Path application_binary_path(){ char buffer[PATH_MAX]; ssize_t count = readlink("/proc/self/exe", buffer, PATH_MAX); if (count != -1) { - return Path(std::string(buffer, count)).parent_path(); + return Path(std::string(buffer, count)); } return Path(); } @@ -94,10 +94,10 @@ Path application_install_path(){ } // Fallback - return application_binary_path(); + return application_binary_directory(); } Path application_scratch_path(){ - return current_path(); + return current_path().string_slash_normalized() + "/"; } diff --git a/Common/Cpp/Filesystem/Filesystem_Mac.h b/Common/Cpp/Filesystem/Filesystem_Mac.h index e6cbc614f4..5ecb93b007 100644 --- a/Common/Cpp/Filesystem/Filesystem_Mac.h +++ b/Common/Cpp/Filesystem/Filesystem_Mac.h @@ -6,6 +6,8 @@ #include #include +#include +#include #include #include #include @@ -16,11 +18,58 @@ namespace PokemonAutomation{ namespace Filesystem{ + +static std::string g_startup_profile; + +void set_startup_profile(int& argc, char* argv[]){ + for (int i = 1; i + 1 < argc; i++){ + if (strcmp(argv[i], "--profile") == 0){ + std::string profile = argv[i + 1]; + for (char c : profile){ + if (!(std::isalpha(c) || std::isdigit(c)) && c != u'_' && c != u'-') c = u'_'; + } + g_startup_profile = std::move(profile); + // Shift everything after --profile down by 2. + for (int j = i; j + 2 < argc; j++){ + argv[j] = argv[j + 2]; + } + argc -= 2; + return; + } + } +} + +const std::string& STARTUP_PROFILE(){ + return g_startup_profile; +} + + +// Helper function to safely get the current executable's name on macOS +std::string get_macos_executable_name() { + char path_buffer[PROC_PIDPATHINFO_MAXSIZE]; + pid_t pid = getpid(); + + if (proc_pidpath(pid, path_buffer, sizeof(path_buffer)) > 0) { + Filesystem::Path full_path(path_buffer); + return full_path.filename().string(); // Returns the binary name (e.g., "SerialPrograms") + } + + return "UnknownApp"; // Worst-case fallback +} + + + + + + + + + Path application_binary_path(){ char buffer[PATH_MAX]; uint32_t size = sizeof(buffer); if (_NSGetExecutablePath(buffer, &size) == 0) { - return std::filesystem::canonical(std::filesystem::path(buffer)).parent_path(); + return std::filesystem::canonical(std::filesystem::path(buffer)); } return Path(); } @@ -71,11 +120,33 @@ Path application_install_path(){ } // Fallback - return application_binary_path(); + return application_binary_directory(); } Path application_scratch_path(){ - // TODO: This is just a placeholder. - return current_path(); + // 1. Replicate Home folder resolution (~/) + const char* home_env = std::getenv("HOME"); + Filesystem::Path app_support_path; + + if (home_env != nullptr) { + app_support_path = Filesystem::Path(home_env); + } else { + app_support_path = Filesystem::current_path(); + } + + // 2. Replicate standard macOS AppDataLocation structure programmatically + std::string app_name = get_macos_executable_name(); + app_support_path = app_support_path / "Library" / "Application Support" / app_name; + + // 3. Append your profile path + if (!g_startup_profile.empty()) { + app_support_path /= "Profiles"; + app_support_path /= g_startup_profile; + } + + // 4. Create directory structure + Filesystem::create_directories(app_support_path); + + return app_support_path.string() + "/"; } diff --git a/Common/Cpp/Filesystem/Filesystem_Qt.h b/Common/Cpp/Filesystem/Filesystem_Qt.h index 08c907780c..ca575f807d 100644 --- a/Common/Cpp/Filesystem/Filesystem_Qt.h +++ b/Common/Cpp/Filesystem/Filesystem_Qt.h @@ -13,14 +13,14 @@ namespace Filesystem{ Path application_binary_path(){ - QString application_dir_path = qApp->applicationDirPath(); + QString application_dir_path = qApp->applicationFilePath(); return Path(application_dir_path.toStdString()); } Path application_install_path(){ - return application_binary_path(); + return application_binary_directory(); } Path application_scratch_path(){ - return current_path(); + return current_path().string_slash_normalized() + "/"; } diff --git a/Common/Cpp/Filesystem/Filesystem_Windows.h b/Common/Cpp/Filesystem/Filesystem_Windows.h index ff504c5778..5d9481055a 100644 --- a/Common/Cpp/Filesystem/Filesystem_Windows.h +++ b/Common/Cpp/Filesystem/Filesystem_Windows.h @@ -15,13 +15,13 @@ namespace Filesystem{ Path application_binary_path(){ wchar_t buffer[MAX_PATH]; GetModuleFileNameW(nullptr, buffer, MAX_PATH); - return std::filesystem::path(buffer).parent_path(); + return std::filesystem::path(buffer); } Path application_install_path(){ - return application_binary_path(); + return application_binary_directory(); } Path application_scratch_path(){ - return current_path(); + return current_path().string_slash_normalized() + "/"; } diff --git a/SerialPrograms/Source/CommonFramework/GlobalAutoPaths.cpp b/SerialPrograms/Source/CommonFramework/GlobalAutoPaths.cpp index 3e24bb81ff..3729840dcf 100644 --- a/SerialPrograms/Source/CommonFramework/GlobalAutoPaths.cpp +++ b/SerialPrograms/Source/CommonFramework/GlobalAutoPaths.cpp @@ -4,13 +4,6 @@ * */ -#include -#include -#include -#include -#include -#include -#include #include "Common/Cpp/Filesystem/Filesystem.h" #include "GlobalAutoPaths.h" @@ -21,40 +14,9 @@ namespace PokemonAutomation{ - - - -#if defined(__APPLE__) -static std::string g_startup_profile; - -void set_startup_profile(int& argc, char* argv[]){ - for (int i = 1; i + 1 < argc; i++){ - if (strcmp(argv[i], "--profile") == 0){ - std::string profile = argv[i + 1]; - for (char c : profile){ - if (!(std::isalpha(c) || std::isdigit(c)) && c != u'_' && c != u'-') c = u'_'; - } - g_startup_profile = std::move(profile); - // Shift everything after --profile down by 2. - for (int j = i; j + 2 < argc; j++){ - argv[j] = argv[j + 2]; - } - argc -= 2; - return; - } - } -} - -const std::string& STARTUP_PROFILE(){ - return g_startup_profile; -} -#endif - namespace{ - - std::string get_resource_path(){ // Find the resource directory. Filesystem::Path base = Filesystem::application_install_path(); @@ -110,21 +72,6 @@ std::string get_training_path(){ return (base / "TrainingData/").string_slash_normalized(); } -std::string get_runtime_base_path(){ -#if defined(__APPLE__) - // QStandardPaths::writableLocation(QStandardPaths::AppDataLocation) returns - // "/Users/$USERNAME/Library/Application Support/SerialPrograms" - QString appSupportPath = QStandardPaths::writableLocation(QStandardPaths::AppDataLocation); - if (!g_startup_profile.empty()){ - appSupportPath += "/Profiles/" + QString::fromStdString(g_startup_profile); - } - QDir().mkpath(appSupportPath); - return appSupportPath.toStdString() + "/"; -#else - return Filesystem::application_scratch_path().string_slash_normalized() + "/"; -#endif -} - std::string get_setting_path(){ return RUNTIME_BASE_PATH() + "UserSettings/"; } @@ -143,8 +90,11 @@ std::string get_user_file_path(){ } // anonymous namespace + + + const std::string& RUNTIME_BASE_PATH(){ - static std::string path = get_runtime_base_path(); + static std::string path = Filesystem::application_scratch_path().string(); return path; } @@ -153,7 +103,7 @@ const std::string& SETTINGS_PATH(){ return path; } const std::string& PROGRAM_SETTING_JSON_PATH(){ - static std::string path = SETTINGS_PATH() + QCoreApplication::applicationName().toStdString() + "-Settings.json"; + static std::string path = SETTINGS_PATH() + Filesystem::application_binary_name().replace_extension().string() + "-Settings.json"; return path; } const std::string& SCREENSHOTS_PATH(){ diff --git a/SerialPrograms/Source/CommonFramework/Main.cpp b/SerialPrograms/Source/CommonFramework/Main.cpp index 744f84f9b2..623acfabe1 100644 --- a/SerialPrograms/Source/CommonFramework/Main.cpp +++ b/SerialPrograms/Source/CommonFramework/Main.cpp @@ -109,7 +109,7 @@ int run_program(int argc, char *argv[]){ logger.log("================================================================================"); logger.log("Starting Program..."); logger.log("Current path: " + Filesystem::current_path().string_slash_normalized()); - logger.log("Executable path: " + Filesystem::application_binary_path().string_slash_normalized()); + logger.log("Executable path: " + Filesystem::application_binary_directory().string_slash_normalized()); logger.log("Program setting folder: " + SETTINGS_PATH()); logger.log("Program resources folder: " + RESOURCE_PATH()); From f0b3caa4de712a46ea0457d41f4e278686ad27d7 Mon Sep 17 00:00:00 2001 From: Alexander Yee Date: Thu, 13 Aug 2026 21:41:46 -0700 Subject: [PATCH 2/3] fix --- Common/Cpp/Filesystem/Filesystem.h | 9 +++++++++ SerialPrograms/Source/CommonFramework/GlobalAutoPaths.h | 9 --------- .../Source/CommonFramework/Windows/MainWindow.cpp | 3 ++- 3 files changed, 11 insertions(+), 10 deletions(-) diff --git a/Common/Cpp/Filesystem/Filesystem.h b/Common/Cpp/Filesystem/Filesystem.h index b7a6dcd8eb..4f6df4db57 100644 --- a/Common/Cpp/Filesystem/Filesystem.h +++ b/Common/Cpp/Filesystem/Filesystem.h @@ -78,6 +78,15 @@ Path application_install_path(); Path application_scratch_path(); +// Set a profile for program settings (/UserSettings/PROFILE_NAME/) on MacOS. +// Have to run the program with command-line argument "open -n PATH_TO_APP --args --profile PROFILE_NAME" to set the profile and launch a new window. +// This allows multiple instances of the program to run since settings are no longer shared. +#if defined(__APPLE__) +void set_startup_profile(int& argc, char* argv[]); +const std::string& STARTUP_PROFILE(); +#endif + + } } diff --git a/SerialPrograms/Source/CommonFramework/GlobalAutoPaths.h b/SerialPrograms/Source/CommonFramework/GlobalAutoPaths.h index f78dd89967..46d8526f51 100644 --- a/SerialPrograms/Source/CommonFramework/GlobalAutoPaths.h +++ b/SerialPrograms/Source/CommonFramework/GlobalAutoPaths.h @@ -12,15 +12,6 @@ namespace PokemonAutomation{ - -// Set a profile for program settings (/UserSettings/PROFILE_NAME/) on MacOS. -// Have to run the program with command-line argument "open -n PATH_TO_APP --args --profile PROFILE_NAME" to set the profile and launch a new window. -// This allows multiple instances of the program to run since settings are no longer shared. -#if defined(__APPLE__) -void set_startup_profile(int& argc, char* argv[]); -const std::string& STARTUP_PROFILE(); -#endif - // Path to the parent folder that holds all other folders, e.g. settings folder, screenshot folder, etc. const std::string& RUNTIME_BASE_PATH(); diff --git a/SerialPrograms/Source/CommonFramework/Windows/MainWindow.cpp b/SerialPrograms/Source/CommonFramework/Windows/MainWindow.cpp index b40eccca88..ad4454e93b 100644 --- a/SerialPrograms/Source/CommonFramework/Windows/MainWindow.cpp +++ b/SerialPrograms/Source/CommonFramework/Windows/MainWindow.cpp @@ -14,9 +14,10 @@ #include #include #include "Common/Cpp/ScopeExit.h" +#include "Common/Cpp/Exceptions.h" #include "Common/Cpp/Logging/MultiOutputLogger.h" +#include "Common/Cpp/Filesystem/Filesystem.h" #include "Common/Cpp/CpuId/CpuId.h" -#include "Common/Cpp/Exceptions.h" #include "CommonFramework/Globals.h" #include "CommonFramework/GlobalAutoPaths.h" #include "CommonFramework/GlobalSettingsPanel.h" From b1f958cf9321200f6e8140e950871b83530865f2 Mon Sep 17 00:00:00 2001 From: Alexander Yee Date: Thu, 13 Aug 2026 22:00:04 -0700 Subject: [PATCH 3/3] fix --- SerialPrograms/Source/CommonFramework/Main.cpp | 5 +++-- SerialPrograms/Source/CommonFramework/Windows/MainWindow.cpp | 4 ++-- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/SerialPrograms/Source/CommonFramework/Main.cpp b/SerialPrograms/Source/CommonFramework/Main.cpp index 623acfabe1..b4e94eb794 100644 --- a/SerialPrograms/Source/CommonFramework/Main.cpp +++ b/SerialPrograms/Source/CommonFramework/Main.cpp @@ -89,7 +89,7 @@ FileLogger& global_file_logger(){ int run_program(int argc, char *argv[]){ #if defined(__APPLE__) - PokemonAutomation::set_startup_profile(argc, argv); + Filesystem::set_startup_profile(argc, argv); QApplication application(argc, argv); #else QApplication application(argc, argv); @@ -240,8 +240,9 @@ int main(int argc, char *argv[]){ // Qt multimedia, default to gstreamer to prevent flickering // Easier than the alternative which is compiling qt6multimedia with QT_DEFAULT_MEDIA_BACKEND // See: https://doc.qt.io/qt-6.5/qtmultimedia-index.html - if (qEnvironmentVariableIsEmpty("QT_MEDIA_BACKEND")) + if (qEnvironmentVariableIsEmpty("QT_MEDIA_BACKEND")){ qputenv("QT_MEDIA_BACKEND", "gstreamer"); + } #endif // So far, this is only needed on Mac where static initialization is fucked up. diff --git a/SerialPrograms/Source/CommonFramework/Windows/MainWindow.cpp b/SerialPrograms/Source/CommonFramework/Windows/MainWindow.cpp index ad4454e93b..8f587a0540 100644 --- a/SerialPrograms/Source/CommonFramework/Windows/MainWindow.cpp +++ b/SerialPrograms/Source/CommonFramework/Windows/MainWindow.cpp @@ -73,8 +73,8 @@ MainWindow::MainWindow(QWidget* parent) // setStatusBar(statusbar); std::string title = PROGRAM_NAME + " Computer-Control Programs (" + PROGRAM_VERSION + ")"; #if defined(__APPLE__) - if (!STARTUP_PROFILE().empty()){ - setWindowTitle(QString::fromStdString(title + " [Profile: " + STARTUP_PROFILE() + "]")); + if (!Filesystem::STARTUP_PROFILE().empty()){ + setWindowTitle(QString::fromStdString(title + " [Profile: " + Filesystem::STARTUP_PROFILE() + "]")); }else{ setWindowTitle(QString::fromStdString(title)); }