DPF

DISTRHO Plugin Framework
Log | Files | Refs | Submodules | README | LICENSE

commit a44de6c0b542258aa3aa512a19330edc8fb0c094
parent 50849162456c244deb4878fee21efbfae50ce3f5
Author: falkTX <falktx@falktx.com>
Date:   Sun, 23 May 2021 23:51:41 +0100

Get win32 file dialog working again

Signed-off-by: falkTX <falktx@falktx.com>

Diffstat:
Mdgl/Window.hpp | 4+++-
Mdgl/src/WindowPrivateData.cpp | 67+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++--
Mdgl/src/WindowPrivateData.hpp | 2+-
Mtests/FileBrowserDialog.cpp | 16+++++++++++++++-
4 files changed, 84 insertions(+), 5 deletions(-)

diff --git a/dgl/Window.hpp b/dgl/Window.hpp @@ -317,8 +317,10 @@ public: Open a file browser dialog with this window as parent. A few options can be specified to setup the dialog. - This function does not block. If a path is selected, onFileSelected() will be called with the user chosen path. + If the user cancels or does not pick a file, onFileSelected() will be called with nullptr as filename. + + This function does not block the event loop. */ bool openFileBrowser(const FileBrowserOptions& options); #endif diff --git a/dgl/src/WindowPrivateData.cpp b/dgl/src/WindowPrivateData.cpp @@ -23,6 +23,9 @@ #ifdef DISTRHO_OS_WINDOWS # include <direct.h> +# include <winsock2.h> +# include <windows.h> +# include <vector> #else # include <unistd.h> #endif @@ -50,6 +53,11 @@ START_NAMESPACE_DGL // ----------------------------------------------------------------------- +#ifdef DISTRHO_OS_WINDOWS +// static pointer used for direct comparisons +static const char* const kWin32SelectedFileCancelled = "__dpf_cancelled__"; +#endif + static double getDesktopScaleFactor() { if (const char* const scale = getenv("DPF_SCALE_FACTOR")) @@ -195,6 +203,11 @@ Window::PrivateData::~PrivateData() appData->idleCallbacks.remove(this); appData->windows.remove(self); +#ifdef DISTRHO_OS_WINDOWS + if (win32SelectedFile != nullptr && win32SelectedFile != kWin32SelectedFileCancelled) + std::free(const_cast<char*>(win32SelectedFile)); +#endif + if (view != nullptr) puglFreeView(view); } @@ -366,11 +379,13 @@ void Window::PrivateData::idleCallback() { #ifndef DGL_FILE_BROWSER_DISABLED # ifdef DISTRHO_OS_WINDOWS - if (char* const path = win32SelectedFile) + if (const char* path = win32SelectedFile) { win32SelectedFile = nullptr; + if (path == kWin32SelectedFileCancelled) + path = nullptr; self->onFileSelected(path); - std::free(path); + std::free(const_cast<char*>(path)); } # endif # ifdef HAVE_X11 @@ -465,6 +480,54 @@ bool Window::PrivateData::openFileBrowser(const Window::FileBrowserOptions& opti // -------------------------------------------------------------------------- // show +#ifdef DISTRHO_OS_WINDOWS + // the old and compatible dialog API + OPENFILENAMEW ofn; + memset(&ofn, 0, sizeof(ofn)); + if (win32SelectedFile != nullptr && win32SelectedFile != kWin32SelectedFileCancelled) + std::free(const_cast<char*>(win32SelectedFile)); + win32SelectedFile = nullptr; + + ofn.lStructSize = sizeof(ofn); + ofn.hwndOwner = (HWND)puglGetNativeWindow(view); + + // set start directory in UTF-16 encoding + std::vector<WCHAR> startDirW; + startDirW.resize(startDir.length() + 1); + if (MultiByteToWideChar(CP_UTF8, 0, startDir.buffer(), -1, startDirW.data(), startDirW.size())) + ofn.lpstrInitialDir = startDirW.data(); + + // set title in UTF-16 encoding + std::vector<WCHAR> titleW; + titleW.resize(title.length() + 1); + if (MultiByteToWideChar(CP_UTF8, 0, title.buffer(), -1, titleW.data(), titleW.size())) + ofn.lpstrTitle = titleW.data(); + + // prepare a buffer to receive the result + std::vector<WCHAR> fileNameW(32768); // the Unicode maximum + ofn.lpstrFile = fileNameW.data(); + ofn.nMaxFile = (DWORD)fileNameW.size(); + + // TODO synchronous only, can't do better with WinAPI native dialogs. + // threading might work, if someone is motivated to risk it. + if (GetOpenFileNameW(&ofn)) + { + // back to UTF-8 + std::vector<char> fileNameA(4 * 32768); + if (WideCharToMultiByte(CP_UTF8, 0, fileNameW.data(), -1, + fileNameA.data(), (int)fileNameA.size(), + nullptr, nullptr)) + { + // handle it during the next idle cycle (fake async) + win32SelectedFile = strdup(fileNameA.data()); + } + } + + if (win32SelectedFile == nullptr) + win32SelectedFile = kWin32SelectedFileCancelled; + + return true; +#endif #ifdef HAVE_X11 uint flags = 0x0; // TODO flags diff --git a/dgl/src/WindowPrivateData.hpp b/dgl/src/WindowPrivateData.hpp @@ -70,7 +70,7 @@ struct Window::PrivateData : IdleCallback { #ifdef DISTRHO_OS_WINDOWS /** Selected file for openFileBrowser on windows, stored for fake async operation. */ - char* win32SelectedFile; + const char* win32SelectedFile; #endif /** Modal window setup. */ diff --git a/tests/FileBrowserDialog.cpp b/tests/FileBrowserDialog.cpp @@ -116,7 +116,11 @@ protected: FileBrowserOptions opts; opts.title = "Look at me"; - openFileBrowser(opts); + if (! openFileBrowser(opts)) + { + selectedFile = "(Failed to start file browser)"; + repaint(); + } } return true; @@ -133,6 +137,16 @@ protected: buttonBounds = Rectangle<uint>(width - 120, height/2 - 20, 100, 40); } + void onFocus(const bool focus, CrossingMode) override + { + if (focus) + return; + + buttonClick = false; + buttonHover = false; + repaint(); + } + void onFileSelected(const char* filename) override { if (filename == nullptr)