diff --git a/include/wx/stdpaths.h b/include/wx/stdpaths.h index d048888ddb..5cadcf1a8b 100644 --- a/include/wx/stdpaths.h +++ b/include/wx/stdpaths.h @@ -60,10 +60,11 @@ public: Dir_Videos }; - enum + // Layout to use for user config/data files under Unix. + enum FileLayout { - FileLayout_Classic = 0, - FileLayout_XDG = 1 + FileLayout_Classic, // Default: use home directory. + FileLayout_XDG // Recommended: use XDG specification. }; // return the global standard paths object @@ -174,14 +175,14 @@ public: bool UsesAppInfo(int info) const { return (m_usedAppInfo & info) != 0; } - void SetFileLayout(int layout) + void SetFileLayout(FileLayout layout) { - m_usedFileLayout = layout; + m_fileLayout = layout; } - int GetFileLayout() const + FileLayout GetFileLayout() const { - return m_usedFileLayout; + return m_fileLayout; } protected: @@ -199,7 +200,9 @@ protected: // combination of AppInfo_XXX flags used by AppendAppInfo() int m_usedAppInfo; - int m_usedFileLayout; + + // The file layout to use, currently only used under Unix. + FileLayout m_fileLayout; }; #if wxUSE_STDPATHS diff --git a/interface/wx/stdpaths.h b/interface/wx/stdpaths.h index 81f218f4a0..e148cf7749 100644 --- a/interface/wx/stdpaths.h +++ b/interface/wx/stdpaths.h @@ -135,16 +135,34 @@ public: Dir_Videos }; - enum + /** + Possible values for SetFileLayout() argument. + + The elements of this enum correspond to the different file layout + standards under Unix systems. + + @since 3.1.1 + */ + enum FileLayout { - /** - Use the classic file layout - */ + /** + Use the classic file layout. + + User configuration and data files are located directly in the home + directory. + + This is the default behaviour for compatibility reasons. + */ FileLayout_Classic, - /** - Use a XDG styled file layout (Unix) - */ + /** + Use a XDG styled file layout. + + File layout follows the XDG Base Directory Specification (see + https://standards.freedesktop.org/basedir-spec/basedir-spec-latest.html). + + This is the recommended layout for new applications. + */ FileLayout_XDG }; @@ -313,8 +331,11 @@ public: virtual wxString GetTempDir() const; /** - Return the directory for the user config files: - - Unix: @c ~ (the home directory) + Return the directory for the user config files. + + This directory is: + - Unix: @c ~ (the home directory) or @c XDG_CONFIG_HOME depending on + GetFileLayout() return value - Windows: @c "C:\Users\username\AppData\Roaming" or @c "C:\Documents and Settings\username\Application Data" - Mac: @c ~/Library/Preferences @@ -339,7 +360,8 @@ public: If the value could not be determined the users home directory is returned. - @note On Unix this supports the xdg user dirs specification. + @note On Unix this method respects the XDG base directory specification + only if SetFileLayout() with @c FileLayout_XDG had been called. @since 3.1.0 */ @@ -458,17 +480,24 @@ public: void UseAppInfo(int info); /** - Returns the current file layout - Valid values for @a are: - - @c FileLayout_Classic, - - @c FileLayout_XDG + Returns the current file layout. + + The default layout is @c FileLayout_Classic for compatibility, however + newer applications are encouraged to set it to @c FileLayout_XDG on + program startup. + + @since 3.1.1 */ - void SetFileLayout(int layout); + void SetFileLayout(FileLayout layout); /** - Returns the current file layout + Returns the current file layout. + + @see SetFileLayout() + + @since 3.1.1 */ - int GetFileLayout() const; + FileLayout GetFileLayout() const; /** Return the file name which would be used by wxFileConfig as local, diff --git a/src/common/stdpbase.cpp b/src/common/stdpbase.cpp index e29bae8d14..6f776c30d4 100644 --- a/src/common/stdpbase.cpp +++ b/src/common/stdpbase.cpp @@ -97,6 +97,8 @@ wxStandardPathsBase::wxStandardPathsBase() // Derived classes can call this in their constructors // to set the platform-specific settings UseAppInfo(AppInfo_AppName); + + // Default for compatibility with the existing config files. SetFileLayout(FileLayout_Classic); } diff --git a/src/unix/stdpaths.cpp b/src/unix/stdpaths.cpp index ec59b30e43..c72b47a6f8 100644 --- a/src/unix/stdpaths.cpp +++ b/src/unix/stdpaths.cpp @@ -53,17 +53,23 @@ void wxStandardPaths::SetInstallPrefix(const wxString& prefix) wxString wxStandardPaths::GetUserConfigDir() const { - if (GetFileLayout() & FileLayout_XDG) + wxString dir; + + switch ( GetFileLayout() ) { - wxString configPath; - if (wxGetenv(wxT("XDG_CONFIG_HOME"))) - configPath = wxGetenv(wxT("XDG_CONFIG_HOME")); - else - configPath = wxFileName::GetHomeDir() + wxT("/.config"); - return configPath; + case FileLayout_Classic: + dir = wxFileName::GetHomeDir(); + break; + + case FileLayout_XDG: + if ( !wxGetEnv(wxS("XDG_CONFIG_HOME"), &dir) || dir.empty() ) + dir = wxFileName::GetHomeDir() + wxS("/.config"); + break; } - return wxFileName::GetHomeDir(); + wxASSERT_MSG( !dir.empty(), wxS("unsupported file layout") ); + + return dir; } @@ -246,73 +252,81 @@ wxStandardPaths::GetLocalizedResourcesDir(const wxString& lang, wxString wxStandardPaths::GetUserDir(Dir userDir) const { - if (GetFileLayout() & FileLayout_XDG) + switch ( GetFileLayout() ) { - wxLogNull logNull; - wxString homeDir = wxFileName::GetHomeDir(); - if (userDir == Dir_Cache) - { - if (wxGetenv(wxT("XDG_CACHE_HOME"))) - return wxGetenv(wxT("XDG_CACHE_HOME")); - else - return homeDir + wxT("/.cache"); - } + case FileLayout_Classic: + // Fall back to the base class below. + break; - wxString configPath; - if (wxGetenv(wxT("XDG_CONFIG_HOME"))) - configPath = wxGetenv(wxT("XDG_CONFIG_HOME")); - else - configPath = homeDir + wxT("/.config"); - wxString dirsFile = configPath + wxT("/user-dirs.dirs"); - if (wxFileExists(dirsFile)) - { - wxString userDirId; - switch (userDir) + case FileLayout_XDG: { - case Dir_Desktop: - userDirId = "XDG_DESKTOP_DIR"; - break; - case Dir_Downloads: - userDirId = "XDG_DOWNLOAD_DIR"; - break; - case Dir_Music: - userDirId = "XDG_MUSIC_DIR"; - break; - case Dir_Pictures: - userDirId = "XDG_PICTURES_DIR"; - break; - case Dir_Videos: - userDirId = "XDG_VIDEOS_DIR"; - break; - default: - userDirId = "XDG_DOCUMENTS_DIR"; - break; - } - - wxTextFile textFile; - if (textFile.Open(dirsFile)) - { - size_t i; - for (i = 0; i < textFile.GetLineCount(); i++) + wxLogNull logNull; + wxString homeDir = wxFileName::GetHomeDir(); + if (userDir == Dir_Cache) { - wxString line(textFile[i]); - int pos = line.Find(userDirId); - if (pos != wxNOT_FOUND) + if (wxGetenv(wxT("XDG_CACHE_HOME"))) + return wxGetenv(wxT("XDG_CACHE_HOME")); + else + return homeDir + wxT("/.cache"); + } + + wxString configPath; + if (wxGetenv(wxT("XDG_CONFIG_HOME"))) + configPath = wxGetenv(wxT("XDG_CONFIG_HOME")); + else + configPath = homeDir + wxT("/.config"); + wxString dirsFile = configPath + wxT("/user-dirs.dirs"); + if (wxFileExists(dirsFile)) + { + wxString userDirId; + switch (userDir) { - wxString value = line.AfterFirst(wxT('=')); - value.Replace(wxT("$HOME"), homeDir); - value.Trim(true); - value.Trim(false); - // Remove quotes - value.Replace("\"", "", true /* replace all */); - if (!value.IsEmpty() && wxDirExists(value)) - return value; - else + case Dir_Desktop: + userDirId = "XDG_DESKTOP_DIR"; break; + case Dir_Downloads: + userDirId = "XDG_DOWNLOAD_DIR"; + break; + case Dir_Music: + userDirId = "XDG_MUSIC_DIR"; + break; + case Dir_Pictures: + userDirId = "XDG_PICTURES_DIR"; + break; + case Dir_Videos: + userDirId = "XDG_VIDEOS_DIR"; + break; + default: + userDirId = "XDG_DOCUMENTS_DIR"; + break; + } + + wxTextFile textFile; + if (textFile.Open(dirsFile)) + { + size_t i; + for (i = 0; i < textFile.GetLineCount(); i++) + { + wxString line(textFile[i]); + int pos = line.Find(userDirId); + if (pos != wxNOT_FOUND) + { + wxString value = line.AfterFirst(wxT('=')); + value.Replace(wxT("$HOME"), homeDir); + value.Trim(true); + value.Trim(false); + // Remove quotes + value.Replace("\"", "", true /* replace all */); + if (!value.IsEmpty() && wxDirExists(value)) + return value; + else + break; + } + } } } } - } + break; } return wxStandardPathsBase::GetUserDir(userDir); @@ -323,10 +337,27 @@ wxString wxStandardPaths::GetUserDir(Dir userDir) const wxString wxStandardPaths::MakeConfigFileName(const wxString& basename, int style) const { wxFileName fn(wxEmptyString, basename); - if (style & wxCONFIG_USE_SUBDIR || GetFileLayout() & FileLayout_XDG) - fn.SetExt(wxT("conf")); - else - fn.SetName(wxT('.') + fn.GetName()); + switch ( GetFileLayout() ) + { + case FileLayout_Classic: + if ( !(style & wxCONFIG_USE_SUBDIR) ) + { + // The standard convention is to not use the extensions for the + // config files in the home directory and just prepend a dot to + // them instead. + fn.SetName(wxT('.') + fn.GetName()); + break; + } + //else: fall through to add the extension + wxFALLTHROUGH; + + case FileLayout_XDG: + // We always use the extension for the config files when using XDG + // layout as they don't go to the home directory anyhow. + fn.SetExt(wxS("conf")); + break; + } + return fn.GetFullName(); }