Skip to content

Commit

Permalink
New feature: Accept native parent window handle
Browse files Browse the repository at this point in the history
This is necessary for platforms to present the dialog properly, e.g. ensuring that the dialog never goes behind the parent window.
  • Loading branch information
btzy committed May 12, 2024
1 parent edd69c3 commit d5bdfeb
Show file tree
Hide file tree
Showing 2 changed files with 46 additions and 11 deletions.
25 changes: 25 additions & 0 deletions src/include/nfd.h
Original file line number Diff line number Diff line change
Expand Up @@ -93,19 +93,40 @@ typedef struct {
typedef nfdu8filteritem_t nfdnfilteritem_t;
#endif // _WIN32

// The native window handle type.
enum {
NFD_WINDOW_HANDLE_TYPE_UNSET = 0,
// Windows: handle is HWND (the Windows API typedefs this to void*)
NFD_WINDOW_HANDLE_TYPE_WINDOWS = 1,
// Cocoa: handle is NSWindow*
NFD_WINDOW_HANDLE_TYPE_COCOA = 2,
// X11: handle is Window
NFD_WINDOW_HANDLE_TYPE_X11 = 3,
// Wayland: handle is wl_surface*
NFD_WINDOW_HANDLE_TYPE_WAYLAND = 4,
};
// The native window handle. If using a platform abstraction framework (e.g. SDL), this should be
// obtained using the corresponding NFD glue header (e.g. nfd_sdl.h).
typedef struct {
size_t type; // this is one of the values of the enum above
void* handle;
} nfdwindowhandle_t;

typedef size_t nfdversion_t;

typedef struct {
const nfdu8filteritem_t* filterList;
nfdfiltersize_t filterCount;
const nfdu8char_t* defaultPath;
nfdwindowhandle_t parentWindow;
} nfdopendialogu8args_t;

#ifdef _WIN32
typedef struct {
const nfdnfilteritem_t* filterList;
nfdfiltersize_t filterCount;
const nfdnchar_t* defaultPath;
nfdwindowhandle_t parentWindow;
} nfdopendialognargs_t;
#else
typedef nfdopendialogu8args_t nfdopendialognargs_t;
Expand All @@ -116,6 +137,7 @@ typedef struct {
nfdfiltersize_t filterCount;
const nfdu8char_t* defaultPath;
const nfdu8char_t* defaultName;
nfdwindowhandle_t parentWindow;
} nfdsavedialogu8args_t;

#ifdef _WIN32
Expand All @@ -124,18 +146,21 @@ typedef struct {
nfdfiltersize_t filterCount;
const nfdnchar_t* defaultPath;
const nfdnchar_t* defaultName;
nfdwindowhandle_t parentWindow;
} nfdsavedialognargs_t;
#else
typedef nfdsavedialogu8args_t nfdsavedialognargs_t;
#endif // _WIN32

typedef struct {
const nfdu8char_t* defaultPath;
nfdwindowhandle_t parentWindow;
} nfdpickfolderu8args_t;

#ifdef _WIN32
typedef struct {
const nfdnchar_t* defaultPath;
nfdwindowhandle_t parentWindow;
} nfdpickfoldernargs_t;
#else
typedef nfdpickfolderu8args_t nfdpickfoldernargs_t;
Expand Down
32 changes: 21 additions & 11 deletions src/nfd_win.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -284,6 +284,13 @@ nfdresult_t AddOptions(IFileDialog* dialog, FILEOPENDIALOGOPTIONS options) {
}
return NFD_OKAY;
}

HWND GetNativeWindowHandle(const nfdwindowhandle_t& nfd_handle) {
if (nfd_handle.type != NFD_WINDOW_HANDLE_TYPE_WINDOWS) {
return nullptr;
}
return static_cast<HWND>(nfd_handle.handle);
}
} // namespace

const char* NFD_GetError(void) {
Expand Down Expand Up @@ -382,7 +389,7 @@ nfdresult_t NFD_OpenDialogN_With_Impl(nfdversion_t version,
}

// Show the dialog.
result = fileOpenDialog->Show(nullptr);
result = fileOpenDialog->Show(GetNativeWindowHandle(args->parentWindow));
if (SUCCEEDED(result)) {
// Get the file name
::IShellItem* psiResult;
Expand Down Expand Up @@ -463,7 +470,7 @@ nfdresult_t NFD_OpenDialogMultipleN_With_Impl(nfdversion_t version,
}

// Show the dialog.
result = fileOpenDialog->Show(nullptr);
result = fileOpenDialog->Show(GetNativeWindowHandle(args->parentWindow));
if (SUCCEEDED(result)) {
::IShellItemArray* shellItems;
result = fileOpenDialog->GetResults(&shellItems);
Expand Down Expand Up @@ -542,7 +549,7 @@ nfdresult_t NFD_SaveDialogN_With_Impl(nfdversion_t version,
}

// Show the dialog.
result = fileSaveDialog->Show(nullptr);
result = fileSaveDialog->Show(GetNativeWindowHandle(args->parentWindow));
if (SUCCEEDED(result)) {
// Get the file name
::IShellItem* psiResult;
Expand Down Expand Up @@ -607,7 +614,7 @@ nfdresult_t NFD_PickFolderN_With_Impl(nfdversion_t version,
}

// Show the dialog to the user
const HRESULT result = fileOpenDialog->Show(nullptr);
const HRESULT result = fileOpenDialog->Show(GetNativeWindowHandle(args->parentWindow));
if (result == HRESULT_FROM_WIN32(ERROR_CANCELLED)) {
return NFD_CANCEL;
} else if (!SUCCEEDED(result)) {
Expand Down Expand Up @@ -673,7 +680,7 @@ nfdresult_t NFD_PickFolderMultipleN_With_Impl(nfdversion_t version,
}

// Show the dialog.
const HRESULT result = fileOpenDialog->Show(nullptr);
const HRESULT result = fileOpenDialog->Show(GetNativeWindowHandle(args->parentWindow));
if (SUCCEEDED(result)) {
::IShellItemArray* shellItems;
if (!SUCCEEDED(fileOpenDialog->GetResults(&shellItems))) {
Expand Down Expand Up @@ -933,7 +940,7 @@ nfdresult_t NFD_OpenDialogU8_With_Impl(nfdversion_t version,
// call the native function
nfdnchar_t* outPathN;
const nfdopendialognargs_t argsN{
filterItemsNGuard.data, args->filterCount, defaultPathNGuard.data};
filterItemsNGuard.data, args->filterCount, defaultPathNGuard.data, args->parentWindow};
nfdresult_t res = NFD_OpenDialogN_With_Impl(NFD_INTERFACE_VERSION, &outPathN, &argsN);

if (res != NFD_OKAY) {
Expand Down Expand Up @@ -978,7 +985,7 @@ nfdresult_t NFD_OpenDialogMultipleU8_With_Impl(nfdversion_t version,

// call the native function
const nfdopendialognargs_t argsN{
filterItemsNGuard.data, args->filterCount, defaultPathNGuard.data};
filterItemsNGuard.data, args->filterCount, defaultPathNGuard.data, args->parentWindow};
return NFD_OpenDialogMultipleN_With_Impl(NFD_INTERFACE_VERSION, outPaths, &argsN);
}

Expand Down Expand Up @@ -1017,8 +1024,11 @@ nfdresult_t NFD_SaveDialogU8_With_Impl(nfdversion_t version,

// call the native function
nfdnchar_t* outPathN;
const nfdsavedialognargs_t argsN{
filterItemsNGuard.data, args->filterCount, defaultPathNGuard.data, defaultNameNGuard.data};
const nfdsavedialognargs_t argsN{filterItemsNGuard.data,
args->filterCount,
defaultPathNGuard.data,
defaultNameNGuard.data,
args->parentWindow};
nfdresult_t res = NFD_SaveDialogN_With_Impl(NFD_INTERFACE_VERSION, &outPathN, &argsN);

if (res != NFD_OKAY) {
Expand Down Expand Up @@ -1054,7 +1064,7 @@ nfdresult_t NFD_PickFolderU8_With_Impl(nfdversion_t version,

// call the native function
nfdnchar_t* outPathN;
const nfdpickfoldernargs_t argsN{defaultPathNGuard.data};
const nfdpickfoldernargs_t argsN{defaultPathNGuard.data, args->parentWindow};
nfdresult_t res = NFD_PickFolderN_With_Impl(NFD_INTERFACE_VERSION, &outPathN, &argsN);

if (res != NFD_OKAY) {
Expand Down Expand Up @@ -1090,7 +1100,7 @@ nfdresult_t NFD_PickFolderMultipleU8_With_Impl(nfdversion_t version,
NormalizePathSeparator(defaultPathNGuard.data);

// call the native function
const nfdpickfoldernargs_t argsN{defaultPathNGuard.data};
const nfdpickfoldernargs_t argsN{defaultPathNGuard.data, args->parentWindow};
return NFD_PickFolderMultipleN_With_Impl(NFD_INTERFACE_VERSION, outPaths, &argsN);
}

Expand Down

0 comments on commit d5bdfeb

Please sign in to comment.