Merge branch 'config-xdg'

Make it easier to use wxFileConfig in XDG-compliant way.

See #24180.
This commit is contained in:
Vadim Zeitlin 2024-01-07 16:13:15 +01:00
commit b294a6b2bc
15 changed files with 372 additions and 40 deletions

View file

@ -168,6 +168,10 @@ Currently the following symbols exist:
implemented in a generic way, using a critical section.} implemented in a generic way, using a critical section.}
@itemdef{wxHAS_BITMAPTOGGLEBUTTON, Defined in @c wx/tglbtn.h if @itemdef{wxHAS_BITMAPTOGGLEBUTTON, Defined in @c wx/tglbtn.h if
wxBitmapToggleButton class is available in addition to wxToggleButton.} wxBitmapToggleButton class is available in addition to wxToggleButton.}
@itemdef{wxHAS_CONFIG_AS_FILECONFIG, Defined if wxConfig is defined as
wxFileConfig. This constant is available since wxWidgets 3.3.0.}
@itemdef{wxHAS_CONFIG_AS_REGCONFIG, Defined if wxConfig is defined as
wxRegConfig. This constant is available since wxWidgets 3.3.0.}
@itemdef{wxHAS_CONFIG_TEMPLATE_RW, Defined if the currently used compiler @itemdef{wxHAS_CONFIG_TEMPLATE_RW, Defined if the currently used compiler
supports template Read() and Write() methods in wxConfig.} supports template Read() and Write() methods in wxConfig.}
@itemdef{wxHAS_DEPRECATED_ATTR, Defined if C++14 @c [[deprecated]] attribute is @itemdef{wxHAS_DEPRECATED_ATTR, Defined if C++14 @c [[deprecated]] attribute is

View file

@ -62,7 +62,8 @@ enum
wxCONFIG_USE_GLOBAL_FILE = 2, wxCONFIG_USE_GLOBAL_FILE = 2,
wxCONFIG_USE_RELATIVE_PATH = 4, wxCONFIG_USE_RELATIVE_PATH = 4,
wxCONFIG_USE_NO_ESCAPE_CHARACTERS = 8, wxCONFIG_USE_NO_ESCAPE_CHARACTERS = 8,
wxCONFIG_USE_SUBDIR = 16 wxCONFIG_USE_SUBDIR = 16,
wxCONFIG_USE_XDG = 32
}; };
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------

View file

@ -23,9 +23,11 @@
#if defined(__WINDOWS__) && wxUSE_CONFIG_NATIVE #if defined(__WINDOWS__) && wxUSE_CONFIG_NATIVE
#include "wx/msw/regconf.h" #include "wx/msw/regconf.h"
#define wxConfig wxRegConfig #define wxConfig wxRegConfig
#define wxHAS_CONFIG_AS_REGCONFIG
#else // either we're under Unix or wish to always use config files #else // either we're under Unix or wish to always use config files
#include "wx/fileconf.h" #include "wx/fileconf.h"
#define wxConfig wxFileConfig #define wxConfig wxFileConfig
#define wxHAS_CONFIG_AS_FILECONFIG
#endif #endif
#endif // wxUSE_CONFIG #endif // wxUSE_CONFIG

View file

@ -123,6 +123,22 @@ public:
return GetLocalFile(szFile, style).GetFullPath(); return GetLocalFile(szFile, style).GetFullPath();
} }
// Function to migrate, i.e. move, an existing local config file to another
// location. Old and new style determine the existing and new file paths.
struct MigrationResult
{
// If empty, it means the old file wasn't found and nothing was done.
wxString oldPath;
// The name of the new file.
wxString newPath;
// If empty, means the file was successfully migrated.
wxString error;
};
static MigrationResult
MigrateLocalFile(const wxString& name, int newStyle, int oldStyle = 0);
// ctor & dtor // ctor & dtor
// New constructor: one size fits all. Specify wxCONFIG_USE_LOCAL_FILE or // New constructor: one size fits all. Specify wxCONFIG_USE_LOCAL_FILE or
// wxCONFIG_USE_GLOBAL_FILE to say which files should be used. // wxCONFIG_USE_GLOBAL_FILE to say which files should be used.

View file

@ -51,6 +51,7 @@ public:
enum Dir enum Dir
{ {
Dir_Cache, Dir_Cache,
Dir_Config,
Dir_Documents, Dir_Documents,
Dir_Desktop, Dir_Desktop,
Dir_Downloads, Dir_Downloads,
@ -184,6 +185,11 @@ public:
bool UsesAppInfo(int info) const { return (m_usedAppInfo & info) != 0; } bool UsesAppInfo(int info) const { return (m_usedAppInfo & info) != 0; }
// append application information determined by m_usedAppInfo to dir
wxNODISCARD
wxString AppendAppInfo(const wxString& dir) const;
void SetFileLayout(FileLayout layout) void SetFileLayout(FileLayout layout)
{ {
m_fileLayout = layout; m_fileLayout = layout;
@ -203,10 +209,6 @@ protected:
// path separator or dot (.) is not already at the end of dir // path separator or dot (.) is not already at the end of dir
static wxString AppendPathComponent(const wxString& dir, const wxString& component); static wxString AppendPathComponent(const wxString& dir, const wxString& component);
// append application information determined by m_usedAppInfo to dir
wxString AppendAppInfo(const wxString& dir) const;
// combination of AppInfo_XXX flags used by AppendAppInfo() // combination of AppInfo_XXX flags used by AppendAppInfo()
int m_usedAppInfo; int m_usedAppInfo;

View file

@ -6,14 +6,41 @@
///////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////
// Flags for constructor style parameter /// Flags for wxConfig constructor style parameter.
enum enum
{ {
wxCONFIG_USE_LOCAL_FILE = 1, wxCONFIG_USE_LOCAL_FILE = 1,
wxCONFIG_USE_GLOBAL_FILE = 2, wxCONFIG_USE_GLOBAL_FILE = 2,
wxCONFIG_USE_RELATIVE_PATH = 4, wxCONFIG_USE_RELATIVE_PATH = 4,
wxCONFIG_USE_NO_ESCAPE_CHARACTERS = 8, wxCONFIG_USE_NO_ESCAPE_CHARACTERS = 8,
wxCONFIG_USE_SUBDIR = 16
/**
Use subdirectory for the local configuration file location.
Specifying this flag changes the default local configuration file
location to `~/.appname/appname.conf`. Please note that this path is
_not_ affected by layout set using wxStandardPaths::SetFileLayout() and
it is recommended to use wxCONFIG_USE_XDG flag in addition to this file
on contemporary Linux systems.
@since 2.8.2
*/
wxCONFIG_USE_SUBDIR = 16,
/**
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
wxStandardPaths::FileLayout_XDG, i.e. it changes the default local
configuration file location to `~/.config/appname.conf`.
In combination with wxCONFIG_USE_SUBDIR, this flag changes the default
configuration file location to ~/.config/appname/appname.conf`.
@since 3.3.0
*/
wxCONFIG_USE_XDG = 32
}; };
@ -30,7 +57,9 @@ enum
with the registry under Windows or text-based config files under Unix. with the registry under Windows or text-based config files under Unix.
To make writing the portable code even easier, wxWidgets provides a typedef To make writing the portable code even easier, wxWidgets provides a typedef
wxConfig which is mapped onto the native wxConfigBase implementation on the wxConfig which is mapped onto the native wxConfigBase implementation on the
given platform: i.e. wxRegConfig under Windows and wxFileConfig otherwise. given platform: i.e. wxRegConfig under Windows (in this case
`wxHAS_CONFIG_AS_REGCONFIG` preprocessor symbol is defined) and
wxFileConfig otherwise (in this case `wxHAS_CONFIG_AS_FILECONFIG` is).
See @ref overview_config for a description of all features of this class. See @ref overview_config for a description of all features of this class.
@ -296,14 +325,16 @@ public:
@n For wxFileConfig you can also add @c wxCONFIG_USE_RELATIVE_PATH by @n For wxFileConfig you can also add @c wxCONFIG_USE_RELATIVE_PATH by
logically or'ing it to either of the _FILE options to tell logically or'ing it to either of the _FILE options to tell
wxFileConfig to use relative instead of absolute paths. wxFileConfig to use relative instead of absolute paths.
@n On non-VMS Unix systems, the default local configuration file is @n On Unix-like systems, the default local configuration file is
"~/.appname". However, this path may be also used as user data `~/.appname` unless wxStandardPaths::SetFileLayout() is called with
wxStandardPaths::FileLayout_XDG parameter in which case the default
becomes `~/.config/appname.conf`.
@n Note that this default path may be also used as user data
directory (see wxStandardPaths::GetUserDataDir()) if the directory (see wxStandardPaths::GetUserDataDir()) if the
application has several data files. In this case application has several data files. In this case it is recommended
@c wxCONFIG_USE_SUBDIR flag, which changes the default local to use ::wxCONFIG_USE_XDG flag (available since wxWidgets 3.3.0)
configuration file to "~/.appname/appname" should be used. Notice and/or older ::wxCONFIG_USE_SUBDIR (available since 2.8.2) to
that this flag is ignored if @a localFilename is provided. change the default local configuration file location.
@c wxCONFIG_USE_SUBDIR is new since wxWidgets version 2.8.2.
@n For wxFileConfig, you can also add @n For wxFileConfig, you can also add
@c wxCONFIG_USE_NO_ESCAPE_CHARACTERS which will turn off character @c wxCONFIG_USE_NO_ESCAPE_CHARACTERS which will turn off character
escaping for the values of entries stored in the config file: for escaping for the values of entries stored in the config file: for

View file

@ -18,6 +18,25 @@
used explicitly if you want to use files and not the registry even under used explicitly if you want to use files and not the registry even under
Windows. Windows.
@section fileconf_paths Configuration Files Paths
The default path for local (or user) configuration file is `~/.appname`,
i.e. it is stored directly in the user home directory. This default
path is backwards-compatible but not recommended any more and it is advised
to call wxStandardPaths::SetFileLayout() with
wxStandardPaths::FileLayout_XDG parameter to change the default path to
`~/.config/appname.conf`. MigrateLocalFile() may be helpful for moving the
existing configuration file to the new location.
Alternatively, it is possible to specify ::wxCONFIG_USE_XDG flag in the
style parameter of the constructor to use this XDG-compliant path without
changing the global file layout.
And for the programs using multiple configuration files it is recommended
to use both ::wxCONFIG_USE_XDG and ::wxCONFIG_USE_SUBDIR which change the
default file path to `~/.config/appname/appname.conf` -- and allow the
program to store other files in the same `~/.config/appname` directory.
@library{wxbase} @library{wxbase}
@category{cfg} @category{cfg}
@ -71,8 +90,8 @@ public:
parameter in the constructor. parameter in the constructor.
@a style has the same meaning as in @ref wxConfigBase::wxConfigBase "wxConfig 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 bit is and can contain any combination of styles but only wxCONFIG_USE_SUBDIR
examined by this function. and wxCONFIG_USE_XDG are really used by this function.
Notice that this function cannot be used if @a basename is already a full path name. Notice that this function cannot be used if @a basename is already a full path name.
*/ */
@ -81,6 +100,70 @@ public:
static wxString GetGlobalFileName(const wxString& szFile); static wxString GetGlobalFileName(const wxString& szFile);
static wxString GetLocalFileName(const wxString& szFile, int style = 0); static wxString GetLocalFileName(const wxString& szFile, int style = 0);
/**
Contains return value of MigrateLocalFile().
@since 3.3.0
*/
struct MigrationResult
{
/// If empty, it means the old file wasn't found and nothing was done.
wxString oldPath;
/// The name of the new file.
wxString newPath;
/// If empty, means the file was successfully migrated.
wxString error;
};
/**
Move the existing configuration file to a new location.
This function is useful for moving legacy configuration files in
`~/.appname` or `~/.appname/appname.conf` to the XDG-compliant location
under `~/.config`. To do this, simply specify ::wxCONFIG_USE_XDG as
part of @a newStyle.
The returned MigrationResult object describes what, if anything, was
done: if its `oldPath` member is empty, it means that the file
corresponding to @a oldStyle was not found and nothing was done.
Otherwise, if its `error` member is empty, the old file was found and
moved to `newPath`. And if `error` is not empty, it contains the
user-readable error message describing why moving the file failed.
Typical example of using this function is shown in the widgets sample:
@code
// Execute this early during the application startup, before the
// global wxConfig object is created.
const auto res = wxFileConfig::MigrateLocalFile("app", wxCONFIG_USE_XDG);
if ( !res.oldPath.empty() ) {
if ( res.error.empty() ) {
wxLogMessage("Config file was migrated from \"%s\" to \"%s\"",
res.oldPath, res.newPath);
} else {
wxLogWarning("Migrating old config failed: %s.", res.error);
}
}
// 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.
wxStandardPaths::Get().SetFileLayout(wxStandardPaths::FileLayout_XDG);
@endcode
@param name Name of the configuration file.
@param newStyle Style which is used by the current version of the
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.
@since 3.3.0
*/
static MigrationResult
MigrateLocalFile(const wxString& name, int newStyle, int oldStyle = 0);
/** /**
Saves all config data to the given stream, returns @true if data was saved Saves all config data to the given stream, returns @true if data was saved
successfully or @false on error. successfully or @false on error.

View file

@ -79,6 +79,18 @@ public:
*/ */
Dir_Cache, Dir_Cache,
/**
Directory containing configuration information.
Example return values:
- Unix: `~/.config`
- Windows: `C:\Users\username\AppData\Roaming`
- Mac: @c `~/Library/Preferences`
@since 3.3.0
*/
Dir_Config,
/** /**
Directory containing user documents. Directory containing user documents.
@ -195,6 +207,20 @@ public:
ConfigFileConv_Ext ConfigFileConv_Ext
}; };
/**
Append application and/or vendor name to the given directory.
By default, appends the subdirectory with the application name, as
returned by wxApp::GetAppName(), to the given directory.
This behaviour is affected by UseAppInfo(), e.g. if this function is
called with `AppInfo_VendorName` then the vendor name would be appended
instead of the application name.
@since 3.3.0
*/
wxString AppendAppInfo(const wxString& dir) const;
/** /**
MSW-specific function undoing the effect of IgnoreAppSubDir() calls. MSW-specific function undoing the effect of IgnoreAppSubDir() calls.
@ -370,17 +396,25 @@ public:
- Mac: @c ~/Library/Preferences - Mac: @c ~/Library/Preferences
Only use this method if you have a single configuration file to put in this Only use this method if you have a single configuration file to put in this
directory, otherwise GetUserDataDir() is more appropriate as the latter directory, otherwise calling AppendAppInfo() with the value returned by
adds @c appinfo to the path, unlike this function. GetDir() with wxStandardPaths::Dir_Config is more appropriate.
*/ */
virtual wxString GetUserConfigDir() const; virtual wxString GetUserConfigDir() const;
/** /**
Return the directory for the user-dependent application data files: Return the directory for the user-dependent application data files.
The returned path is:
- Unix: @c ~/.appinfo - Unix: @c ~/.appinfo
- Windows: @c "C:\Users\username\AppData\Roaming\appinfo" or - Windows: @c "C:\Users\username\AppData\Roaming\appinfo" or
@c "C:\Documents and Settings\username\Application Data\appinfo" @c "C:\Documents and Settings\username\Application Data\appinfo"
- Mac: @c "~/Library/Application Support/appinfo" - Mac: @c "~/Library/Application Support/appinfo"
Please note that under Unix this function return value doesn't depend
on the file layout, and so returns a possibly unexpected value when
wxStandardPaths::FileLayout_XDG is used. Consider using GetUserDir()
instead if you use XDG layout, as this function does respect it.
*/ */
virtual wxString GetUserDataDir() const; virtual wxString GetUserDataDir() const;
@ -505,6 +539,8 @@ public:
By default, only the application name is used. By default, only the application name is used.
@see AppendAppInfo()
@since 2.9.0 @since 2.9.0
*/ */
void UseAppInfo(int info); void UseAppInfo(int info);

View file

@ -37,6 +37,9 @@
#include "wx/msgdlg.h" #include "wx/msgdlg.h"
#endif #endif
#include "wx/config.h"
#include "wx/stdpaths.h"
#include "wx/sysopt.h" #include "wx/sysopt.h"
#include "wx/bookctrl.h" #include "wx/bookctrl.h"
#include "wx/treebook.h" #include "wx/treebook.h"
@ -141,6 +144,30 @@ public:
#if USE_LOG #if USE_LOG
m_logTarget = nullptr; m_logTarget = nullptr;
#endif // USE_LOG #endif // USE_LOG
#ifdef wxHAS_CONFIG_AS_FILECONFIG
// We want to put our config file (implicitly created for persistent
// controls settings) in XDG-compliant location, so we want to change
// the default file layout, but before doing this migrate any existing
// config files to the new location as the previous versions of this
// sample didn't use XDG layout.
const auto
res = wxFileConfig::MigrateLocalFile("widgets", wxCONFIG_USE_XDG);
if ( !res.oldPath.empty() )
{
if ( res.error.empty() )
{
wxLogMessage("Config file was migrated from \"%s\" to \"%s\"",
res.oldPath, res.newPath);
}
else
{
wxLogWarning("Migrating old config failed: %s.", res.error);
}
}
wxStandardPaths::Get().SetFileLayout(wxStandardPaths::FileLayout_XDG);
#endif // wxHAS_CONFIG_AS_FILECONFIG
} }
WidgetsApp(const WidgetsApp&) = delete; WidgetsApp(const WidgetsApp&) = delete;
WidgetsApp& operator=(const WidgetsApp&) = delete; WidgetsApp& operator=(const WidgetsApp&) = delete;

View file

@ -56,12 +56,13 @@ bool wxConfigBase::ms_bAutoCreate = true;
wxConfigBase *wxAppTraitsBase::CreateConfig() wxConfigBase *wxAppTraitsBase::CreateConfig()
{ {
return new #if defined(wxHAS_CONFIG_AS_REGCONFIG)
#if defined(__WINDOWS__) && wxUSE_CONFIG_NATIVE return new wxRegConfig(wxTheApp->GetAppName(), wxTheApp->GetVendorName());
wxRegConfig(wxTheApp->GetAppName(), wxTheApp->GetVendorName()); #elif defined(wxHAS_CONFIG_AS_FILECONFIG)
#else // either we're under Unix or wish to use files even under Windows return new wxFileConfig(wxTheApp->GetAppName());
wxFileConfig(wxTheApp->GetAppName()); #else
#endif #error No wxConfig implementation defined.
#endif
} }
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------

View file

@ -247,42 +247,154 @@ wxString wxFileConfig::GetGlobalDir()
wxString wxFileConfig::GetLocalDir(int style) wxString wxFileConfig::GetLocalDir(int style)
{ {
wxUnusedVar(style); const wxStandardPathsBase& stdp = wxStandardPaths::Get();
wxStandardPathsBase& stdp = wxStandardPaths::Get(); if ( style & wxCONFIG_USE_XDG )
{
// When XDG-compliant layout is requested, we need to use this function
// as GetUserDataDir() doesn't support it.
wxString dir = stdp.GetUserDir(wxStandardPaths::Dir_Config);
// it so happens that user data directory is a subdirectory of user config if ( style & wxCONFIG_USE_SUBDIR )
// directory on all supported platforms, which explains why we use it here 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
// these functions already, so return the same values as we always did.
return style & wxCONFIG_USE_SUBDIR ? stdp.GetUserDataDir() return style & wxCONFIG_USE_SUBDIR ? stdp.GetUserDataDir()
: stdp.GetUserConfigDir(); : stdp.GetUserConfigDir();
} }
wxFileName wxFileConfig::GetGlobalFile(const wxString& szFile) wxFileName wxFileConfig::GetGlobalFile(const wxString& szFile)
{ {
wxStandardPathsBase& stdp = wxStandardPaths::Get(); const wxStandardPathsBase& stdp = wxStandardPaths::Get();
return wxFileName(GetGlobalDir(), stdp.MakeConfigFileName(szFile)); return wxFileName(GetGlobalDir(), stdp.MakeConfigFileName(szFile));
} }
wxFileName wxFileConfig::GetLocalFile(const wxString& szFile, int style) wxFileName wxFileConfig::GetLocalFile(const wxString& szFile, int style)
{ {
wxStandardPathsBase& stdp = wxStandardPaths::Get(); const wxStandardPathsBase& stdp = wxStandardPaths::Get();
// If the config file is located in a subdirectory, we always use an // If the config file is located in a subdirectory, we always use an
// extension for it, but we use just the leading dot if it is located // extension for it, but we use just the leading dot if it is located
// directly in the home directory. Note that if wxStandardPaths is // directly in the home directory. Note that if wxStandardPaths is
// configured to follow XDG specification, all config files go to a // configured to follow XDG specification, all config files go to a
// subdirectory of XDG_CONFIG_HOME anyhow, so in this case we'll still end // subdirectory of XDG_CONFIG_HOME anyhow, so in this case we'll still end
// up using the extension even if wxCONFIG_USE_SUBDIR is not set, but this // up using the extension even if neither wxCONFIG_USE_SUBDIR nor
// is the correct and expected (if a little confusing) behaviour. // wxCONFIG_USE_XDG is set, but this is the correct and expected (if a
// little confusing) behaviour.
const wxStandardPaths::ConfigFileConv const wxStandardPaths::ConfigFileConv
conv = style & wxCONFIG_USE_SUBDIR conv = style & (wxCONFIG_USE_SUBDIR | wxCONFIG_USE_XDG)
? wxStandardPaths::ConfigFileConv_Ext ? wxStandardPaths::ConfigFileConv_Ext
: wxStandardPaths::ConfigFileConv_Dot; : wxStandardPaths::ConfigFileConv_Dot;
return wxFileName(GetLocalDir(style), stdp.MakeConfigFileName(szFile, conv)); return wxFileName(GetLocalDir(style), stdp.MakeConfigFileName(szFile, conv));
} }
wxFileConfig::MigrationResult
wxFileConfig::MigrateLocalFile(const wxString& name, int newStyle, int oldStyle)
{
MigrationResult res;
const auto oldPath = GetLocalFile(name, oldStyle);
if ( !oldPath.FileExists() )
return res;
const auto newPath = GetLocalFile(name, newStyle);
if ( newPath == oldPath )
return res;
res.oldPath = oldPath.GetFullPath();
res.newPath = newPath.GetFullPath();
// This class ensures that we (at least try to) rename the existing config
// file back to its original name if we fail with an error.
class RenameBackOnError
{
public:
explicit RenameBackOnError(wxFileConfig::MigrationResult& res)
: m_res(res)
{
}
void Init(const wxString& tempPath)
{
m_tempPath = tempPath;
}
void Dismiss()
{
m_tempPath.clear();
}
~RenameBackOnError()
{
if ( !m_tempPath.empty() )
{
if ( !wxRenameFile(m_tempPath, m_res.oldPath) )
{
// This should never happen, but if it does, do at least
// let the user know that we moved their file to a wrong
// place and couldn't put it back.
m_res.error += wxString::Format(
_(" and additionally, the existing configuration file"
" was renamed to \"%s\" and couldn't be renamed back,"
" please rename it to its original path \"%s\""),
m_tempPath,
m_res.oldPath
);
}
}
}
private:
MigrationResult& m_res;
wxString m_tempPath;
} renameBackOnError{res};
wxString currentPath = res.oldPath;
const auto newDir = newPath.GetPath();
if ( !wxFileName::DirExists(newDir) )
{
// There is an annoying failure mode here when the new directory can't
// be created because its name is the same as the name of the existing
// file, e.g. when oldStyle==0 and newStyle==wxCONFIG_USE_SUBDIR and
// XDG layout is not used, so check for this specially.
if ( newDir == res.oldPath )
{
currentPath = wxFileName::CreateTempFileName(currentPath);
if ( !wxRenameFile(res.oldPath, currentPath) )
{
res.error = _("failed to rename the existing file");
return res;
}
renameBackOnError.Init(currentPath);
}
if ( !wxFileName::Mkdir(newDir, wxS_DIR_DEFAULT, wxPATH_MKDIR_FULL) )
{
res.error = _("failed to create the new file directory");
return res;
}
}
if ( !wxRenameFile(currentPath, res.newPath) )
{
res.error = _("failed to move the file to the new location");
return res;
}
return res;
}
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
// ctor // ctor
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------

View file

@ -488,14 +488,18 @@ static void DoCommonPostCleanup()
void wxEntryCleanup() void wxEntryCleanup()
{ {
DoCommonPreCleanup();
// delete the application object // delete the application object
if ( wxTheApp ) if ( wxTheApp )
{ {
wxTheApp->CleanUp(); wxTheApp->CleanUp();
}
// It's important to call this after wxApp::CleanUp() as it can log some
// messages that will be flushed inside DoCommonPreCleanup().
DoCommonPreCleanup();
if ( wxTheApp )
{
// reset the global pointer to it to nullptr before destroying it as in // reset the global pointer to it to nullptr before destroying it as in
// some circumstances this can result in executing the code using // some circumstances this can result in executing the code using
// wxTheApp and using half-destroyed object is no good // wxTheApp and using half-destroyed object is no good

View file

@ -189,6 +189,9 @@ wxString wxStandardPaths::GetUserDir(Dir userDir) const
case Dir_Cache: case Dir_Cache:
csidl = CSIDL_LOCAL_APPDATA; csidl = CSIDL_LOCAL_APPDATA;
break; break;
case Dir_Config:
csidl = CSIDL_APPDATA;
break;
case Dir_Desktop: case Dir_Desktop:
csidl = CSIDL_DESKTOPDIRECTORY; csidl = CSIDL_DESKTOPDIRECTORY;
break; break;

View file

@ -101,12 +101,18 @@ wxStandardPaths::GetLocalizedResourcesDir(const wxString& lang,
wxString wxStandardPaths::GetUserDir(Dir userDir) const wxString wxStandardPaths::GetUserDir(Dir userDir) const
{ {
wxString subdir;
NSSearchPathDirectory dirType; NSSearchPathDirectory dirType;
switch (userDir) switch (userDir)
{ {
case Dir_Cache: case Dir_Cache:
dirType = NSCachesDirectory; dirType = NSCachesDirectory;
break; break;
case Dir_Config:
dirType = NSLibraryDirectory;
subdir = "/Preferences";
break;
case Dir_Desktop: case Dir_Desktop:
dirType = NSDesktopDirectory; dirType = NSDesktopDirectory;
break; break;
@ -127,7 +133,7 @@ wxString wxStandardPaths::GetUserDir(Dir userDir) const
break; break;
} }
return GetFMDirectory(dirType, NSUserDomainMask); return GetFMDirectory(dirType, NSUserDomainMask) + subdir;
} }
wxString wxString

View file

@ -274,7 +274,11 @@ wxString wxStandardPaths::GetUserDir(Dir userDir) const
return cacheDir; return cacheDir;
} }
const wxFileName dirsFile(GetXDGConfigHome(), wxS("user-dirs.dirs")); const wxString configDir = GetXDGConfigHome();
if (userDir == Dir_Config)
return configDir;
const wxFileName dirsFile(configDir, wxS("user-dirs.dirs"));
if ( dirsFile.FileExists() ) if ( dirsFile.FileExists() )
{ {
wxString userDirId; wxString userDirId;