You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
@@ -10,7 +10,7 @@ This library is based on Michael Labbe's Native File Dialog ([mlabbe/nativefiled
10
10
Features:
11
11
12
12
- Lean C API, static library — no C++/ObjC runtime needed
13
-
- Supports Windows (MSVC, MinGW, Clang), MacOS (Clang), and Linux (GTK, portal) (GCC, Clang)
13
+
- Supports Windows (MSVC, MinGW, Clang), macOS (Clang), and Linux (GTK, portal) (GCC, Clang)
14
14
- Zlib licensed
15
15
- Friendly names for filters (e.g. `C/C++ Source files (*.c;*.cpp)` instead of `(*.c;*.cpp)`) on platforms that support it
16
16
- Automatically append file extension on platforms where users expect it
@@ -19,7 +19,7 @@ Features:
19
19
- Consistent UTF-8 support on all platforms
20
20
- Native character set (UTF-16 `wchar_t`) support on Windows
21
21
- Initialization and de-initialization of platform library (e.g. COM (Windows) / GTK (Linux GTK) / D-Bus (Linux portal)) decoupled from dialog functions, so applications can choose when to initialize/de-initialize
22
-
- Multiple file selection support (for file open dialog)
22
+
- Multiple selection support (for file open and folder select dialogs)
23
23
- Support for Vista's modern `IFileDialog` on Windows
24
24
- No third party dependencies
25
25
- Modern CMake build system
@@ -37,6 +37,7 @@ Features added in Native File Dialog Extended:
37
37
- Support for setting a default file name
38
38
- Native character set (UTF-16 `wchar_t`) support on Windows
39
39
- xdg-desktop-portal support on Linux that opens the "native" file chooser (see "Usage" section below)
40
+
- Multiple folder selection support
40
41
- Initialization and de-initialization of platform library decoupled from file dialog functions
41
42
- Modern CMake build system
42
43
- Optional C++ wrapper with `unique_ptr` auto-freeing semantics and optional parameters
nfdresult_t result = NFD_OpenDialogU8_With(&outPath, &args);
63
67
if (result == NFD_OKAY)
64
68
{
65
69
puts("Success!");
66
70
puts(outPath);
67
-
NFD_FreePath(outPath);
71
+
NFD_FreePathU8(outPath);
68
72
}
69
73
else if (result == NFD_CANCEL)
70
74
{
@@ -80,16 +84,18 @@ int main(void)
80
84
}
81
85
```
82
86
83
-
See [NFD.h](src/include/nfd.h) for more options.
87
+
The `U8`/`u8` in NFDe refer to the API for UTF-8 characters (`char`), which most consumers probably want. An `N`/`n` version is also available, which uses the native character type (`wchar_t` on Windows and `char` on other platforms).
84
88
85
-
If you are using a platform abstraction framework such as SDL or GLFW, also see the "Usage" section below.
89
+
For the full list of arguments that you can set on the `args` struct, see the "All Options" section below.
90
+
91
+
If you are using a platform abstraction framework such as SDL or GLFW, also see the "Usage with a Platform Abstraction Framework" section below.

94
100

95
101
@@ -165,24 +171,78 @@ Make sure `libgtk-3-dev` is installed on your system.
165
171
#### Portal
166
172
Make sure `libdbus-1-dev` is installed on your system.
167
173
168
-
### MacOS
169
-
On MacOS, add `AppKit` and `UniformTypeIdentifiers` to the list of frameworks.
174
+
### macOS
175
+
On macOS, add `AppKit` and `UniformTypeIdentifiers` to the list of frameworks.
170
176
171
177
### Windows
172
178
On Windows (both MSVC and MinGW), ensure you are building against `ole32.lib`, `uuid.lib`, and `shell32.lib`.
173
179
174
180
# Usage
175
181
176
-
See `NFD.h` for API calls. See the `test` directory for example code (both C and C++).
182
+
## All Options
183
+
184
+
To open a dialog, you set options on a struct and then pass that struct to an NFDe function, e.g.:
185
+
```C
186
+
nfdopendialogu8args_t args = {0};
187
+
args.filterList = filters;
188
+
args.filterCount = 2;
189
+
nfdresult_t result = NFD_OpenDialogU8_With(&outPath, &args);
190
+
```
191
+
192
+
All options are optional and may be set individually (zero initialization sets all options to reasonable defaults), except for `filterList` and `filterCount` which must be either both set or both left unset.
193
+
194
+
**Future versions of NFDe may add additional options to the end of the arguments struct without bumping the major version number, so to ensure backward API compatibility, you should not assume that the struct has a specific length or number of fields.** You may assume that zero-initialization of the struct will continue to set all options to reasonable defaults, so assigning `{0}` to the struct is acceptable. For those building shared libraries of NFDe, backward ABI compatibility is ensured by an internal version index (`NFD_INTERFACE_VERSION`), which is expected to be transparent to consumers.
195
+
196
+
**OpenDialog**/**OpenDialogMultiple**:
197
+
```C
198
+
typedefstruct {
199
+
const nfdu8filteritem_t* filterList;
200
+
nfdfiltersize_t filterCount;
201
+
const nfdu8char_t* defaultPath;
202
+
nfdwindowhandle_t parentWindow;
203
+
} nfdopendialogu8args_t;
204
+
```
205
+
206
+
**SaveDialog**:
207
+
```C
208
+
typedefstruct {
209
+
const nfdu8filteritem_t* filterList;
210
+
nfdfiltersize_t filterCount;
211
+
const nfdu8char_t* defaultPath;
212
+
const nfdu8char_t* defaultName;
213
+
nfdwindowhandle_t parentWindow;
214
+
} nfdsavedialogu8args_t;
215
+
```
216
+
217
+
**PickFolder**/**PickFolderMultiple**:
218
+
```C
219
+
typedefstruct {
220
+
const nfdu8char_t* defaultPath;
221
+
nfdwindowhandle_t parentWindow;
222
+
} nfdpickfolderu8args_t;
223
+
```
224
+
225
+
-`filterList` and `filterCount`: Set these to customize the file filter (it appears as a dropdown menu on Windows and Linux, but simply hides files on macOS). Set `filterList` to a pointer to the start of the array of filter items and `filterCount` to the number of filter items in that array. See the "File Filter Syntax" section below for details.
226
+
-`defaultPath`: Set this to the default folder that the dialog should open to (on Windows, if there is a recently used folder, it opens to that folder instead of the folder you pass).
227
+
-`defaultName`: (For SaveDialog only) Set this to the file name that should be pre-filled on the dialog.
228
+
-`parentWindow`: Set this to the native window handle of the parent of this dialog. See the "Usage with a Platform Abstraction Framework" section for details. It is also possible to pass a handle even if you do not use a platform abstraction framework.
229
+
230
+
## Examples
231
+
232
+
See the `test` directory for example code (both C and C++).
177
233
178
234
If you turned on the option to build the `test` directory (`-DNFD_BUILD_TESTS=ON`), then `build/bin` will contain the compiled test programs.
179
235
236
+
There is also an SDL2 example, which needs to be enabled separately with `-DNFD_BUILD_SDL2_TESTS=ON`. It requires SDL2 to be installed on your machine.
237
+
238
+
Compiled examples (including the SDL2 example) are also uploaded as artefacts to GitHub Actions, and may be downloaded from there.
A file filter is a pair of strings comprising the friendly name and the specification (multiple file extensions are comma-separated).
@@ -191,7 +251,7 @@ A list of file filters can be passed as an argument when invoking the library.
191
251
192
252
A wildcard filter is always added to every dialog.
193
253
194
-
*Note: On MacOS, the file dialogs do not have friendly names and there is no way to switch between filters, so the filter specifications are combined (e.g. "c,cpp,cc,h,hpp"). The filter specification is also never explicitly shown to the user. This is usual MacOS behaviour and users expect it.*
254
+
*Note: On macOS, the file dialogs do not have friendly names and there is no way to switch between filters, so the filter specifications are combined (e.g. "c,cpp,cc,h,hpp"). The filter specification is also never explicitly shown to the user. This is usual macOS behaviour and users expect it.*
195
255
196
256
*Note 2: You must ensure that the specification string is non-empty and that every file extension has at least one character. Otherwise, bad things might ensue (i.e. undefined behaviour).*
197
257
@@ -234,7 +294,33 @@ Macros that might be defined by `nfd.h`:
234
294
235
295
## Usage with a Platform Abstraction Framework
236
296
237
-
NFDe is known to work with SDL2 and GLFW, and should also work with other platform abstraction framworks. However, you should initialize NFDe _after_ initializing the framework, and probably should deinitialize NFDe _before_ deinitializing the framework. This is because some frameworks expect to be initialized on a "clean slate", and they may configure the system in a different way from NFDe. `NFD_Init` is generally very careful not to disrupt the existing configuration unless necessary, and `NFD_Quit` restores the configuration back exactly to what it was before initialization.
297
+
NFDe is known to work with SDL2 and GLFW, and should also work with other platform abstraction framworks. This section explains how to use NFDe properly with such frameworks.
298
+
299
+
### Parent window handle
300
+
301
+
The `parentWindow` argument allows the user to give the dialog a parent.
302
+
303
+
If using SDL2, include `<nfd_sdl2.h>` and call the following function to set the parent window handle:
If using GLFW3, define the appropriate `GLFW_EXPOSE_NATIVE_*` macros described on the [GLFW native access page](https://www.glfw.org/docs/latest/group__native.html), and then include `<nfd_glfw3.h>` and call the following function to set the parent window handle:
If you are using another platform abstraction framework, or not using any such framework, you can set `args.parentWindow` manually.
314
+
315
+
Win32 (Windows), Cocoa (macOS), and X11 (Linux) windows are supported. Passing a Wayland (Linux) window currently does nothing (i.e. the dialog acts as if it has no parent), but support is likely to be added in the future.
316
+
317
+
#### Why pass a parent window handle?
318
+
319
+
To make a window (in this case the file dialog) stay above another window, we need to declare the bottom window as the parent of the top window. This keeps the dialog window from disappearing behind the parent window if the user clicks on the parent window while the dialog is open. Keeping the dialog above the window that invoked it is the expected behaviour on all supported operating systems, and so passing the parent window handle is recommended if possible.
320
+
321
+
### Initialization order
322
+
323
+
You should initialize NFDe _after_ initializing the framework, and probably should deinitialize NFDe _before_ deinitializing the framework. This is because some frameworks expect to be initialized on a "clean slate", and they may configure the system in a different way from NFDe. `NFD_Init` is generally very careful not to disrupt the existing configuration unless necessary, and `NFD_Quit` restores the configuration back exactly to what it was before initialization.
238
324
239
325
An example with SDL2:
240
326
@@ -270,15 +356,15 @@ To use the portal implementation, add `-DNFD_PORTAL=ON` to the build command.
270
356
271
357
### What is a portal?
272
358
273
-
Unlike Windows and MacOS, Linux does not have a file chooser baked into the operating system. Linux applications that want a file chooser usually link with a library that provides one (such as GTK, as in the Linux screenshot above). This is a mostly acceptable solution that many applications use, but may make the file chooser look foreign on non-GTK distros.
359
+
Unlike Windows and macOS, Linux does not have a file chooser baked into the operating system. Linux applications that want a file chooser usually link with a library that provides one (such as GTK, as in the Linux screenshot above). This is a mostly acceptable solution that many applications use, but may make the file chooser look foreign on non-GTK distros.
274
360
275
361
Flatpak was introduced in 2015, and with it came a standardized interface to open a file chooser. Applications using this interface did not need to come with a file chooser, and could use the one provided by Flatpak. This interface became known as the desktop portal, and its use expanded to non-Flatpak applications. Now, most major desktop Linux distros come with the desktop portal installed, with file choosers that fit the theme of the distro. Users can also install a different portal backend if desired. There are currently two known backends: GTK and KDE. (XFCE does not currently seem to have a portal backend.)
276
362
277
363
## Platform-specific Quirks
278
364
279
-
### MacOS
365
+
### macOS
280
366
281
-
- If the MacOS deployment target is ≥ 11.0, the [allowedContentTypes](https://developer.apple.com/documentation/appkit/nssavepanel/3566857-allowedcontenttypes?language=objc) property of NSSavePanel is used instead of the deprecated [allowedFileTypes](https://developer.apple.com/documentation/appkit/nssavepanel/1534419-allowedfiletypes?language=objc) property for file filters. Thus, if you are filtering by a custom file extension specific to your application, you will need to define the data type in your `Info.plist` file as per the [Apple documentation](https://developer.apple.com/documentation/uniformtypeidentifiers/defining_file_and_data_types_for_your_app). (It is possible to force NFDe to use allowedFileTypes by adding `-DNFD_USE_ALLOWEDCONTENTTYPES_IF_AVAILABLE=OFF` to your CMake build command, but this is not recommended. If you need to support older MacOS versions, you should be setting the correct deployment target instead.)
367
+
- If the macOS deployment target is ≥ 11.0, the [allowedContentTypes](https://developer.apple.com/documentation/appkit/nssavepanel/3566857-allowedcontenttypes?language=objc) property of NSSavePanel is used instead of the deprecated [allowedFileTypes](https://developer.apple.com/documentation/appkit/nssavepanel/1534419-allowedfiletypes?language=objc) property for file filters. Thus, if you are filtering by a custom file extension specific to your application, you will need to define the data type in your `Info.plist` file as per the [Apple documentation](https://developer.apple.com/documentation/uniformtypeidentifiers/defining_file_and_data_types_for_your_app). (It is possible to force NFDe to use allowedFileTypes by adding `-DNFD_USE_ALLOWEDCONTENTTYPES_IF_AVAILABLE=OFF` to your CMake build command, but this is not recommended. If you need to support older macOS versions, you should be setting the correct deployment target instead.)
282
368
283
369
# Known Limitations #
284
370
@@ -287,7 +373,7 @@ Flatpak was introduced in 2015, and with it came a standardized interface to ope
287
373
- GTK dialogs don't set the existing window as parent, so if users click the existing window while the dialog is open then the dialog will go behind it. GTK writes a warning to stdout or stderr about this.
288
374
- Portal dialogs (the alternative to GTK on Linux) don't support a default path. Any default path you supply will be ignored.
289
375
- This library is not compatible with the original Native File Dialog library. Things might break if you use both in the same project. (There are no plans to support this; you have to use one or the other.)
290
-
- This library does not explicitly dispatch calls to the UI thread. This may lead to crashes if you call functions from other threads when the platform does not support it (e.g. MacOS). Users are generally expected to call NFDe from an appropriate UI thread (i.e. the thread performing the UI event loop).
376
+
- This library does not explicitly dispatch calls to the UI thread. This may lead to crashes if you call functions from other threads when the platform does not support it (e.g. macOS). Users are generally expected to call NFDe from an appropriate UI thread (i.e. the thread performing the UI event loop).
0 commit comments