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:
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