DPF

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

commit d7abd3e1d5287f0dc023340d424270fd5069c8ab
parent a5952348cdb9baefe1564e9e0c096ce4237dbc5e
Author: falkTX <falktx@falktx.com>
Date:   Thu, 28 Oct 2021 18:12:01 +0100

Use win32 thread API for file browser, not pthreads; Cleanup

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

Diffstat:
MMakefile.base.mk | 1+
Mdgl/src/WindowPrivateData.cpp | 127++++++++++++++++++++++++++++++++++++++++++++++++++++++++-----------------------
Mdgl/src/WindowPrivateData.hpp | 140++++---------------------------------------------------------------------------
3 files changed, 97 insertions(+), 171 deletions(-)

diff --git a/Makefile.base.mk b/Makefile.base.mk @@ -280,6 +280,7 @@ endif ifeq ($(WINDOWS),true) DGL_SYSTEM_LIBS += -lgdi32 -lcomdlg32 +# -lole32 endif ifneq ($(HAIKU_OR_MACOS_OR_WINDOWS),true) diff --git a/dgl/src/WindowPrivateData.cpp b/dgl/src/WindowPrivateData.cpp @@ -23,6 +23,7 @@ #ifdef DISTRHO_OS_WINDOWS # include <direct.h> +# include <process.h> # include <winsock2.h> # include <windows.h> # include <vector> @@ -30,7 +31,7 @@ # include <unistd.h> #endif -#define DGL_DEBUG_EVENTS +// #define DGL_DEBUG_EVENTS #if defined(DEBUG) && defined(DGL_DEBUG_EVENTS) # ifdef DISTRHO_PROPER_CPP11_SUPPORT @@ -82,15 +83,23 @@ static double getDesktopScaleFactor(const PuglView* const view) // ----------------------------------------------------------------------- -#if defined(DISTRHO_OS_WINDOWS) && !defined(_MSC_VER) +#ifdef DISTRHO_OS_WINDOWS struct FileBrowserThread::PrivateData { OPENFILENAMEW ofn; + volatile bool threadCancelled; + uintptr_t threadHandle; std::vector<WCHAR> fileNameW; std::vector<WCHAR> startDirW; std::vector<WCHAR> titleW; - - PrivateData() - : fileNameW(32768) + const bool isEmbed; + const char*& win32SelectedFile; + + PrivateData(const bool embed, const char*& file) + : threadCancelled(false), + threadHandle(0), + fileNameW(32768), + isEmbed(embed), + win32SelectedFile(file) { std::memset(&ofn, 0, sizeof(ofn)); ofn.lStructSize = sizeof(ofn); @@ -105,7 +114,7 @@ struct FileBrowserThread::PrivateData { { ofn.hwndOwner = (HWND)winId; - ofn.Flags = OFN_PATHMUSTEXIST; + ofn.Flags = OFN_EXPLORER | OFN_PATHMUSTEXIST | OFN_FILEMUSTEXIST | OFN_NOCHANGEDIR; if (options.buttons.showHidden == Window::FileBrowserOptions::kButtonVisibleChecked) ofn.Flags |= OFN_FORCESHOWHIDDEN; @@ -122,56 +131,102 @@ struct FileBrowserThread::PrivateData { ofn.lpstrTitle = titleW.data(); } - const char* run() + void run() { + const char* nextFile = nullptr; + if (GetOpenFileNameW(&ofn)) { + if (threadCancelled) + { + threadHandle = 0; + return; + } + // 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)) { - return strdup(fileNameA.data()); + nextFile = strdup(fileNameA.data()); } } - return nullptr; + if (threadCancelled) + { + threadHandle = 0; + return; + } + + if (nextFile == nullptr) + nextFile = kWin32SelectedFileCancelled; + + win32SelectedFile = nextFile; + threadHandle = 0; } }; -FileBrowserThread::FileBrowserThread(const char*& file) - : pData(new PrivateData()), - win32SelectedFile(file) {} +FileBrowserThread::FileBrowserThread(const bool isEmbed, const char*& file) + : pData(new PrivateData(isEmbed, file)) {} FileBrowserThread::~FileBrowserThread() { - stopThread(5000); + stop(); delete pData; } +unsigned __stdcall FileBrowserThread__run(void* const arg) +{ + // CoInitializeEx(nullptr, COINIT_MULTITHREADED); + static_cast<FileBrowserThread*>(arg)->pData->run(); + // CoUninitialize(); + _endthreadex(0); + return 0; +} + void FileBrowserThread::start(const char* const startDir, const char* const title, const uintptr_t winId, const Window::FileBrowserOptions options) { pData->setup(startDir, title, winId, options); - startThread(); + + uint threadId; + pData->threadCancelled = false; + pData->threadHandle = _beginthreadex(nullptr, 0, FileBrowserThread__run, this, 0, &threadId); } -void FileBrowserThread::run() +void FileBrowserThread::stop() { - const char* nextFile = pData->run(); + pData->threadCancelled = true; - if (shouldThreadExit()) + if (pData->threadHandle == 0) return; - if (nextFile == nullptr) - nextFile = kWin32SelectedFileCancelled; + // if previous dialog running, carefully close its window + const HWND owner = pData->isEmbed ? GetParent(pData->ofn.hwndOwner) : pData->ofn.hwndOwner; - d_stdout("WThread finished, final file '%s'", nextFile); - win32SelectedFile = nextFile; + if (owner != nullptr && owner != INVALID_HANDLE_VALUE) + { + const HWND window = GetWindow(owner, GW_HWNDFIRST); + + if (window != nullptr && window != INVALID_HANDLE_VALUE) + { + SendMessage(window, WM_SYSCOMMAND, SC_CLOSE, 0); + SendMessage(window, WM_CLOSE, 0, 0); + WaitForSingleObject((HANDLE)pData->threadHandle, 5000); + } + } + + // not good if thread still running, but let's close the handle anyway + if (pData->threadHandle != 0) + { + CloseHandle((HANDLE)pData->threadHandle); + pData->threadHandle = 0; + } } + #endif // DISTRHO_OS_WINDOWS && !_MSC_VER // ----------------------------------------------------------------------- @@ -194,9 +249,9 @@ Window::PrivateData::PrivateData(Application& a, Window* const s) keepAspectRatio(false), ignoreIdleCallbacks(false), filenameToRenderInto(nullptr), -#if defined(DISTRHO_OS_WINDOWS) && !defined(_MSC_VER) +#ifdef DISTRHO_OS_WINDOWS win32SelectedFile(nullptr), - win32FileThread(win32SelectedFile), + win32FileThread(false, win32SelectedFile), #endif modal() { @@ -221,9 +276,9 @@ Window::PrivateData::PrivateData(Application& a, Window* const s, PrivateData* c keepAspectRatio(false), ignoreIdleCallbacks(false), filenameToRenderInto(nullptr), -#if defined(DISTRHO_OS_WINDOWS) && !defined(_MSC_VER) +#ifdef DISTRHO_OS_WINDOWS win32SelectedFile(nullptr), - win32FileThread(win32SelectedFile), + win32FileThread(false, win32SelectedFile), #endif modal(ppData) { @@ -252,9 +307,9 @@ Window::PrivateData::PrivateData(Application& a, Window* const s, keepAspectRatio(false), ignoreIdleCallbacks(false), filenameToRenderInto(nullptr), -#if defined(DISTRHO_OS_WINDOWS) && !defined(_MSC_VER) +#ifdef DISTRHO_OS_WINDOWS win32SelectedFile(nullptr), - win32FileThread(win32SelectedFile), + win32FileThread(isEmbed, win32SelectedFile), #endif modal() { @@ -285,9 +340,9 @@ Window::PrivateData::PrivateData(Application& a, Window* const s, keepAspectRatio(false), ignoreIdleCallbacks(false), filenameToRenderInto(nullptr), -#if defined(DISTRHO_OS_WINDOWS) && !defined(_MSC_VER) +#ifdef DISTRHO_OS_WINDOWS win32SelectedFile(nullptr), - win32FileThread(win32SelectedFile), + win32FileThread(isEmbed, win32SelectedFile), #endif modal() { @@ -317,9 +372,8 @@ Window::PrivateData::~PrivateData() isVisible = false; } -#if defined(DISTRHO_OS_WINDOWS) && !defined(_MSC_VER) - if (win32FileThread.isThreadRunning()) - win32FileThread.stopThread(2000); +#ifdef DISTRHO_OS_WINDOWS + win32FileThread.stop(); if (win32SelectedFile != nullptr && win32SelectedFile != kWin32SelectedFileCancelled) std::free(const_cast<char*>(win32SelectedFile)); @@ -512,7 +566,7 @@ void Window::PrivateData::setResizable(const bool resizable) void Window::PrivateData::idleCallback() { #ifndef DGL_FILE_BROWSER_DISABLED -# if defined(DISTRHO_OS_WINDOWS) && !defined(_MSC_VER) +# ifdef DISTRHO_OS_WINDOWS if (const char* path = win32SelectedFile) { win32SelectedFile = nullptr; @@ -637,10 +691,9 @@ bool Window::PrivateData::openFileBrowser(const Window::FileBrowserOptions& opti return puglMacOSFilePanelOpen(view, startDir, title, flags, openPanelCallback); # endif -# if defined(DISTRHO_OS_WINDOWS) && !defined(_MSC_VER) - // TODO signal to close - if (win32FileThread.isThreadRunning()) - win32FileThread.stopThread(1000); +# ifdef DISTRHO_OS_WINDOWS + // only one possible at a time + DISTRHO_SAFE_ASSERT_RETURN(win32FileThread.pData->threadHandle == 0, false); if (win32SelectedFile != nullptr && win32SelectedFile != kWin32SelectedFileCancelled) std::free(const_cast<char*>(win32SelectedFile)); diff --git a/dgl/src/WindowPrivateData.hpp b/dgl/src/WindowPrivateData.hpp @@ -25,30 +25,22 @@ #include <list> -#if defined(DISTRHO_OS_WINDOWS) && !defined(_MSC_VER) -# include "../distrho/extra/Thread.hpp" -#endif - START_NAMESPACE_DGL class TopLevelWidget; // ----------------------------------------------------------------------- -#if defined(DISTRHO_OS_WINDOWS) && !defined(_MSC_VER) -class FileBrowserThread : public Thread +#ifdef DISTRHO_OS_WINDOWS +struct FileBrowserThread { struct PrivateData; PrivateData* const pData; - const char*& win32SelectedFile; -public: - FileBrowserThread(const char*& win32SelectedFile); - ~FileBrowserThread() override; + FileBrowserThread(bool isEmbed, const char*& win32SelectedFile); + ~FileBrowserThread(); void start(const char* startDir, const char* title, uintptr_t winId, Window::FileBrowserOptions options); - -protected: - void run() override; + void stop(); }; #endif @@ -103,7 +95,7 @@ struct Window::PrivateData : IdleCallback { /** Render to a picture file when non-null, automatically free+unset after saving. */ char* filenameToRenderInto; -#if defined(DISTRHO_OS_WINDOWS) && !defined(_MSC_VER) +#ifdef DISTRHO_OS_WINDOWS /** Selected file for openFileBrowser on windows, stored for fake async operation. */ const char* win32SelectedFile; /** Thread where the openFileBrowser runs. */ @@ -218,124 +210,4 @@ struct Window::PrivateData : IdleCallback { END_NAMESPACE_DGL -#if 0 -// #if defined(DISTRHO_OS_HAIKU) -// BApplication* bApplication; -// BView* bView; -// BWindow* bWindow; -#if defined(DISTRHO_OS_MAC) -// NSView<PuglGenericView>* mView; -// id mWindow; -// id mParentWindow; -# ifndef DGL_FILE_BROWSER_DISABLED - NSOpenPanel* fOpenFilePanel; - id fFilePanelDelegate; -# endif -#elif defined(DISTRHO_OS_WINDOWS) -// HWND hwnd; -// HWND hwndParent; -# ifndef DGL_FILE_BROWSER_DISABLED - String fSelectedFile; -# endif -#endif -#endif - -#if 0 -// ----------------------------------------------------------------------- -// Window Private - -struct Window::PrivateData { - // ------------------------------------------------------------------- - - bool handlePluginSpecial(const bool press, const Key key) - { - DBGp("PUGL: handlePluginSpecial : %i %i\n", press, key); - - if (fModal.childFocus != nullptr) - { - fModal.childFocus->focus(); - return true; - } - - int mods = 0x0; - - switch (key) - { - case kKeyShift: - mods |= kModifierShift; - break; - case kKeyControl: - mods |= kModifierControl; - break; - case kKeyAlt: - mods |= kModifierAlt; - break; - default: - break; - } - - if (mods != 0x0) - { - if (press) - fView->mods |= mods; - else - fView->mods &= ~(mods); - } - - Widget::SpecialEvent ev; - ev.press = press; - ev.key = key; - ev.mod = static_cast<Modifier>(fView->mods); - ev.time = 0; - - FOR_EACH_WIDGET_INV(rit) - { - Widget* const widget(*rit); - - if (widget->isVisible() && widget->onSpecial(ev)) - return true; - } - - return false; - } - -#if defined(DISTRHO_OS_MAC) && !defined(DGL_FILE_BROWSER_DISABLED) - static void openPanelDidEnd(NSOpenPanel* panel, int returnCode, void *userData) - { - PrivateData* pData = (PrivateData*)userData; - - if (returnCode == NSOKButton) - { - NSArray* urls = [panel URLs]; - NSURL* fileUrl = nullptr; - - for (NSUInteger i = 0, n = [urls count]; i < n && !fileUrl; ++i) - { - NSURL* url = (NSURL*)[urls objectAtIndex:i]; - if ([url isFileURL]) - fileUrl = url; - } - - if (fileUrl) - { - PuglView* view = pData->fView; - if (view->fileSelectedFunc) - { - const char* fileName = [fileUrl.path UTF8String]; - view->fileSelectedFunc(view, fileName); - } - } - } - - [pData->fOpenFilePanel release]; - pData->fOpenFilePanel = nullptr; - } -#endif - - // ------------------------------------------------------------------- - - DISTRHO_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(PrivateData) -}; -#endif - #endif // DGL_WINDOW_PRIVATE_DATA_HPP_INCLUDED