From 6586afb0a58b1c3b59ca6efa8613f4e0b52a8c7a Mon Sep 17 00:00:00 2001 From: Vadim Zeitlin Date: Mon, 8 Jan 2024 00:43:26 +0100 Subject: [PATCH 1/2] Use XDG-compliant location by default in wxFileConfig Still use the traditional dot file if it already exists, but prefer using the new location otherwise, i.e. for the new program installation. Add wxCONFIG_USE_HOME to allow forcing the use of the old location if really necessary. Also use the new style as default "old style" of MigrateLocalFile() so that calling it even when using XDG layout in wxStandardPaths still works as expected. --- docs/changes.txt | 6 ++++++ include/wx/confbase.h | 3 ++- include/wx/fileconf.h | 4 +++- interface/wx/config.h | 24 ++++++++++++++++++++++-- interface/wx/fileconf.h | 16 +++++++++------- src/common/fileconf.cpp | 26 ++++++++++++++++++++++++++ 6 files changed, 68 insertions(+), 11 deletions(-) diff --git a/docs/changes.txt b/docs/changes.txt index e20e6429ac..e813684a3a 100644 --- a/docs/changes.txt +++ b/docs/changes.txt @@ -31,6 +31,12 @@ Changes in behaviour not resulting in compilation errors wxGLAttributes::Samplers(1).SampleBuffers(4) explicitly if you need to keep using the same attributes that were previously used by default. +- Default location of file used by wxFileConfig under Unix has changed to + XDG-compliant ~/.config/appname.conf instead of ~/.appname but note that + any existing files at the old location will still continue to be used. + See wxCONFIG_USE_XDG and wxCONFIG_USE_HOME for how to customize this + behaviour. You may also find wxFileConfig::MigrateLocalFile() useful. + - As first mentioned in 3.0 release notes, the value of wxTHREAD_WAIT_DEFAULT, used by wxThread::Delete() and Wait() by default, has changed from wxTHREAD_WAIT_YIELD to wxTHREAD_WAIT_BLOCK for safety and consistency. diff --git a/include/wx/confbase.h b/include/wx/confbase.h index bc00ec1413..34e250ce90 100644 --- a/include/wx/confbase.h +++ b/include/wx/confbase.h @@ -63,7 +63,8 @@ enum wxCONFIG_USE_RELATIVE_PATH = 4, wxCONFIG_USE_NO_ESCAPE_CHARACTERS = 8, wxCONFIG_USE_SUBDIR = 16, - wxCONFIG_USE_XDG = 32 + wxCONFIG_USE_XDG = 32, + wxCONFIG_USE_HOME = 64 }; // ---------------------------------------------------------------------------- diff --git a/include/wx/fileconf.h b/include/wx/fileconf.h index 4229820cf8..31971df83e 100644 --- a/include/wx/fileconf.h +++ b/include/wx/fileconf.h @@ -137,7 +137,9 @@ public: wxString error; }; static MigrationResult - MigrateLocalFile(const wxString& name, int newStyle, int oldStyle = 0); + MigrateLocalFile(const wxString& name, + int newStyle, + int oldStyle = wxCONFIG_USE_HOME); // ctor & dtor // New constructor: one size fits all. Specify wxCONFIG_USE_LOCAL_FILE or diff --git a/interface/wx/config.h b/interface/wx/config.h index 3be4368c66..f0169b693e 100644 --- a/interface/wx/config.h +++ b/interface/wx/config.h @@ -28,7 +28,7 @@ enum wxCONFIG_USE_SUBDIR = 16, /** - Use XDG-compliant file location on Unix systems. + Always use XDG-compliant file location on Unix systems. If wxCONFIG_USE_SUBDIR is not specified, using this flag has the same effect as calling wxStandardPaths::SetFileLayout() with @@ -38,9 +38,29 @@ enum In combination with wxCONFIG_USE_SUBDIR, this flag changes the default configuration file location to ~/.config/appname/appname.conf`. + If neither this flag nor wxCONFIG_USE_HOME is specified, XDG-compliant + configuration file path will be used by default, but if there is an + existing file in the home directory, then it will continue to be used + instead. + @since 3.3.0 */ - wxCONFIG_USE_XDG = 32 + wxCONFIG_USE_XDG = 32, + + /** + Use home directory for the local file location on Unix systems. + + Using this flag is not recommended, it exists only for compatibility + with the previous wxWidgets versions which created configuration files + in the home directory (i.e. `~/.appname`) by default. + + Note that any already existing files in the home directory will still + be used, even if this file is not specified, unless wxCONFIG_USE_XDG is + used. + + @since 3.3.0 + */ + wxCONFIG_USE_HOME = 64 }; diff --git a/interface/wx/fileconf.h b/interface/wx/fileconf.h index 05f3c14b21..95ae264a50 100644 --- a/interface/wx/fileconf.h +++ b/interface/wx/fileconf.h @@ -90,8 +90,8 @@ public: parameter in the constructor. @a style has the same meaning as in @ref wxConfigBase::wxConfigBase "wxConfig constructor" - and can contain any combination of styles but only wxCONFIG_USE_SUBDIR - and wxCONFIG_USE_XDG are really used by this function. + and can contain any combination of styles but only wxCONFIG_USE_SUBDIR, + wxCONFIG_USE_XDG and wxCONFIG_USE_HOME are really used by this function. Notice that this function cannot be used if @a basename is already a full path name. */ @@ -146,9 +146,8 @@ public: } } - // Note that this must be done after calling MigrateLocalFile(), - // otherwise the old style would use XDG layout already and the actual - // file at non-XDG-compliant location wouldn't be migrated. + // Prefer doing it only after successfully calling MigrateLocalFile(), + // otherwise, i.e. if it failed, the old config file wouldn't be used. wxStandardPaths::Get().SetFileLayout(wxStandardPaths::FileLayout_XDG); @endcode @@ -157,12 +156,15 @@ public: program, typically including ::wxCONFIG_USE_XDG and possibly also including ::wxCONFIG_USE_SUBDIR. @param oldStyle Style which was used by the previous versions of the - program, possibly including ::wxCONFIG_USE_SUBDIR. + program, possibly including ::wxCONFIG_USE_SUBDIR and typically + including ::wxCONFIG_USE_HOME. @since 3.3.0 */ static MigrationResult - MigrateLocalFile(const wxString& name, int newStyle, int oldStyle = 0); + MigrateLocalFile(const wxString& name, + int newStyle, + int oldStyle = wxCONFIG_USE_HOME); /** Saves all config data to the given stream, returns @true if data was saved diff --git a/src/common/fileconf.cpp b/src/common/fileconf.cpp index 17e6b6469e..097bd551eb 100644 --- a/src/common/fileconf.cpp +++ b/src/common/fileconf.cpp @@ -261,6 +261,18 @@ wxString wxFileConfig::GetLocalDir(int style) return dir; } + if ( style & wxCONFIG_USE_HOME ) + { + // When traditional layout is requested, don't use wxStandardPaths as + // it could be using XDG layout. + wxString dir = wxGetHomeDir(); + + if ( style & wxCONFIG_USE_HOME ) + dir = stdp.AppendAppInfo(dir); + + return dir; + } + // Normally we'd like to use GetUserConfigDir() and just append app info // subdirectories to it, but we can't do it for compatibility reasons: // there are existing configuration files in the locations returned by @@ -469,8 +481,22 @@ wxFileConfig::wxFileConfig(const wxString& appName, const wxString& vendorName, { // Make up names for files if empty if ( !m_fnLocalFile.IsOk() && (style & wxCONFIG_USE_LOCAL_FILE) ) + { m_fnLocalFile = GetLocalFile(GetAppName(), style); + // If none of the styles explicitly selecting the location to use is + // specified, default to XDG unless the file already exists in the + // traditional location in the home directory: + if ( !(style & (wxCONFIG_USE_XDG | wxCONFIG_USE_HOME)) ) + { + if ( !m_fnLocalFile.FileExists() ) + { + style |= wxCONFIG_USE_XDG; + m_fnLocalFile = GetLocalFile(GetAppName(), style); + } + } + } + if ( !m_fnGlobalFile.IsOk() && (style & wxCONFIG_USE_GLOBAL_FILE) ) m_fnGlobalFile = GetGlobalFile(GetAppName()); From d7b9548c19c3f1d1a243d4afbaeb0b3f7bba6aa4 Mon Sep 17 00:00:00 2001 From: Vadim Zeitlin Date: Mon, 8 Jan 2024 02:02:18 +0100 Subject: [PATCH 2/2] Create output directory in wxFileConfig if it doesn't exist This seems like the most sensible thing to do. Alternative would be to not use XDG directories if ~/.config doesn't exist yet, but this doesn't seem right, especially if wxCONFIG_USE_XDG is explicitly specified. --- src/common/fileconf.cpp | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/src/common/fileconf.cpp b/src/common/fileconf.cpp index 097bd551eb..2f2a2d182a 100644 --- a/src/common/fileconf.cpp +++ b/src/common/fileconf.cpp @@ -1108,6 +1108,21 @@ bool wxFileConfig::Flush(bool /* bCurrentOnly */) if ( !IsDirty() || !m_fnLocalFile.GetFullPath() ) return true; + // Create the directory containing the file if it doesn't exist. Although we + // don't always use XDG, it seems sensible to follow the XDG specification + // and create it with permissions 700 if it doesn't exist. + const wxString& outPath = m_fnLocalFile.GetPath(); + if ( !wxFileName::DirExists(outPath) ) + { + if ( !wxFileName::Mkdir(outPath, + wxS_IRUSR | wxS_IWUSR | wxS_IXUSR, + wxPATH_MKDIR_FULL) ) + { + wxLogWarning(_("Failed to create configuration file directory.")); + return false; + } + } + // set the umask if needed wxCHANGE_UMASK(m_umask);