How to store preferences (and user settings) in a cross-platform application?
Asked Answered
B

2

8

I'm working on a GUI desktop application that should run natively on Windows, Mac OS X and Linux. What is the preferred way to store preferences in a cross-platform application? I'm using C++, but the question (and its answers) should be valid for any natively compiled language. (Solutions for dynamic languages and Java can be seen here.)

My research so far tells me, that there are at least two strategies:
(A) Use the OS-specific API preferences functions.
(B) Store the preferences in a file within an appropriate (OS-specific) folder.

Let's consider method (A): I assume NSUserDefaults is the correct method for Mac OS X. On Windows systems, I'd write to the registry via RegOpenKeyEx. But there arise some questions: Is there any comparable and portable Linux API for that? Is writing to the Windows registry really a future-proof solution?

To keep things simple, I'm inclined to follow method (B). Thus I just have OS-specific code to get the appropriate directory where I can store my data in a format of my choice. On Windows, I've learned SHGetFolderPath (or SHGetKnownFolderPath for recent Windows systems) and CSIDL_LOCAL_APPDATA is the way to go. On Macs, the NSSearchPathForDirectoriesInDomains API call should do the same; it's an Objective-C API though making things more complicated. Finally, for the Linux version using getenv("HOME") (and getpwuid() as a fallback solution) seems to be recommend.

To summarize my questions:
1. Are there any patterns considered as best-practice for this task?
2. Is there any C++ class abstracting all the dirty things like finding the correct folder away out there? (I came across QSetting, but I'm using FLTK and I don't want to change my GUI toolkit.)

Edit:
By "preferences" I mean data that may be changed by the application and the user, e.g. a list of recent files, the preferred window size and so on.

Barretter answered 27/9, 2013 at 13:35 Comment(5)
Use JSON or XML. Another option is to use property lists: native on OS X, easy to handle on Linux and Windows using libplist.Fraley
@H2CO3 The format of the files to store is not my problem. The problem is where to store these files?Barretter
You could always store them in the directory along with the executable and prepend the config file name with "." to hide it. Means the user doesn't see a cluttered directory but that its easy to find and stops your program inserting stuff all over the filesystem.Lornalorne
Storing the preference file along the executable prohibits changing the preferences by the application, at least on modern Windows and Max OS X systems, I thought. (Perhaps the term "preferences" is misleading, so I edited my question to make it clearer what usage I intend.)Barretter
If you're installing your program into Program Files on Windows then it would need to be run with admin rights to alter the preferences file, should you put choose to have the .exe live with the prefs. If that's your plan then putting the prefs elsewhere does seem smart. I've used QStandardPaths(qt-project.org/doc/qt-5.0/qtcore/qstandardpaths.html) before, you wouldn't have to use the rest of the Qt framework though. Not sure what kind of overhead building with Qt would cause though, if any.Lornalorne
D
3

Since z80crew says he's using Fltk in his project, I think the best way to store small amounts of user data is through the Fltk Fl_Preferences class. (http://www.fltk.org/doc-1.3/classFl__Preferences.html).

That way, you don't have to care about where the user data is actually stored in the filesystem. You just create a Fl_Preferences object identified by the name of the application and its vendor (e.g., "CoolApp" and "AuthorOfCoolApp") and Fltk stores the data somewhere.

Under Linux, the preferences are stored in ~/.fltk/{vendor}/{application}.prefs where {vendor} and {application} are the same strings you've passed the constructor of Fl_Preferences. But you aren't supposed to worry about that.

Distance answered 3/11, 2013 at 10:33 Comment(1)
+1 for pointing me to Fl_Preferences, which indeed should come handy for doing the storage part. But I took a quick look into its source code and it's hardcoding the the path where it stores the preferences: sprintf(filename, "%s/Library/Preferences", fl_getenv("HOME")); While Apple is advising against doing it, there seem to be a lot of applications going this way.Barretter
P
2

I'm also developing a set of cross-platform plugins and did exactly what you describe in method (B):

  1. Find the proper folder using platform specific code.
  2. Write the preferences to that folder with cross-platform code.

I would also note that:

  1. Using the Windows registry is very limited and problematic. I try to avoid that as much as possible.
  2. Lately apple has a new song: that you should not access the ~/Library/Preferences folder directly but rather use their API for saving preferences value. In effect this turns the preferences into registry like mechanism. I very much resent this approach.

I do not know of any library that implements finding the currect folder in cross-platform manner. Such function is not very hard to write using SHGetKnownFolderPath and NSSearchPathForDirectoriesInDomains, as you described.

Phan answered 31/10, 2013 at 12:5 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.