commit 6c832980f6090a8bf1d2a4abf522b3ad3c709908
parent 4f3d99304f8d9cc583aa737e40a1716dff37e021
Author: falkTX <falktx@falktx.com>
Date: Sat, 28 May 2022 14:48:35 +0100
Cleanup file dialog namespaces, add DISTRHO_UI_FILE_BROWSER
Signed-off-by: falkTX <falktx@falktx.com>
Diffstat:
16 files changed, 879 insertions(+), 839 deletions(-)
diff --git a/dgl/Application.hpp b/dgl/Application.hpp
@@ -1,6 +1,6 @@
/*
* DISTRHO Plugin Framework (DPF)
- * Copyright (C) 2012-2021 Filipe Coelho <falktx@falktx.com>
+ * Copyright (C) 2012-2022 Filipe Coelho <falktx@falktx.com>
*
* Permission to use, copy, modify, and/or distribute this software for any purpose with
* or without fee is hereby granted, provided that the above copyright notice and this
@@ -19,6 +19,12 @@
#include "Base.hpp"
+#ifdef DISTRHO_NAMESPACE
+START_NAMESPACE_DISTRHO
+class PluginApplication;
+END_NAMESPACE_DISTRHO
+#endif
+
START_NAMESPACE_DGL
// --------------------------------------------------------------------------------------------------------------------
@@ -116,8 +122,10 @@ public:
private:
struct PrivateData;
PrivateData* const pData;
- friend class PluginApplication;
friend class Window;
+ #ifdef DISTRHO_NAMESPACE
+ friend class DISTRHO_NAMESPACE::PluginApplication;
+ #endif
DISTRHO_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(Application)
};
diff --git a/dgl/FileBrowserDialog.hpp b/dgl/FileBrowserDialog.hpp
@@ -0,0 +1,28 @@
+/*
+ * DISTRHO Plugin Framework (DPF)
+ * Copyright (C) 2012-2022 Filipe Coelho <falktx@falktx.com>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any purpose with
+ * or without fee is hereby granted, provided that the above copyright notice and this
+ * permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD
+ * TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN
+ * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
+ * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
+ * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef DGL_FILE_BROWSER_DIALOG_HPP_INCLUDED
+#define DGL_FILE_BROWSER_DIALOG_HPP_INCLUDED
+
+#include "Base.hpp"
+
+START_NAMESPACE_DGL
+
+#include "../distrho/extra/FileBrowserDialogImpl.hpp"
+
+END_NAMESPACE_DGL
+
+#endif // DGL_FILE_BROWSER_DIALOG_HPP_INCLUDED
diff --git a/dgl/Window.hpp b/dgl/Window.hpp
@@ -20,15 +20,20 @@
#include "Geometry.hpp"
#ifndef DGL_FILE_BROWSER_DISABLED
-# include "../distrho/extra/FileBrowserDialog.hpp"
+# include "FileBrowserDialog.hpp"
#endif
#include <vector>
+#ifdef DISTRHO_NAMESPACE
+START_NAMESPACE_DISTRHO
+class PluginWindow;
+END_NAMESPACE_DISTRHO
+#endif
+
START_NAMESPACE_DGL
class Application;
-class PluginWindow;
class TopLevelWidget;
// -----------------------------------------------------------------------
@@ -59,11 +64,6 @@ class DISTRHO_API Window
struct PrivateData;
public:
-#ifndef DGL_FILE_BROWSER_DISABLED
- typedef DISTRHO_NAMESPACE::FileBrowserHandle FileBrowserHandle;
- typedef DISTRHO_NAMESPACE::FileBrowserOptions FileBrowserOptions;
-#endif
-
/**
Window graphics context as a scoped struct.
This class gives graphics context drawing time to a window's widgets.
@@ -400,7 +400,7 @@ public:
This function does not block the event loop.
*/
- bool openFileBrowser(const FileBrowserOptions& options = FileBrowserOptions());
+ bool openFileBrowser(const DGL_NAMESPACE::FileBrowserOptions& options = FileBrowserOptions());
#endif
/**
@@ -521,8 +521,10 @@ protected:
private:
PrivateData* const pData;
friend class Application;
- friend class PluginWindow;
friend class TopLevelWidget;
+ #ifdef DISTRHO_NAMESPACE
+ friend class DISTRHO_NAMESPACE::PluginWindow;
+ #endif
/** @internal */
explicit Window(Application& app,
diff --git a/dgl/src/WindowPrivateData.hpp b/dgl/src/WindowPrivateData.hpp
@@ -44,9 +44,6 @@ struct Window::PrivateData : IdleCallback {
/** Pugl view instance. */
PuglView* view;
- /** Pugl view instance of the transient parent window. */
-// PuglView* const transientParentView;
-
/** Reserved space for graphics context. */
mutable uint8_t graphicsContext[sizeof(void*)];
@@ -91,7 +88,7 @@ struct Window::PrivateData : IdleCallback {
#ifndef DGL_FILE_BROWSER_DISABLED
/** Handle for file browser dialog operations. */
- FileBrowserHandle fileBrowserHandle;
+ DGL_NAMESPACE::FileBrowserHandle fileBrowserHandle;
#endif
/** Modal window setup. */
@@ -168,7 +165,7 @@ struct Window::PrivateData : IdleCallback {
#ifndef DGL_FILE_BROWSER_DISABLED
// file handling
- bool openFileBrowser(const FileBrowserOptions& options);
+ bool openFileBrowser(const DGL_NAMESPACE::FileBrowserOptions& options);
#endif
static void renderToPicture(const char* filename, const GraphicsContext& context, uint width, uint height);
diff --git a/dgl/src/pugl.cpp b/dgl/src/pugl.cpp
@@ -101,10 +101,12 @@
#endif
#ifndef DGL_FILE_BROWSER_DISABLED
+# define FILE_BROWSER_DIALOG_DGL_NAMESPACE
+# include "../FileBrowserDialog.hpp"
# ifdef DISTRHO_OS_MAC
-# import "../../distrho/extra/FileBrowserDialog.cpp"
+# import "../../distrho/extra/FileBrowserDialogImpl.cpp"
# else
-# include "../../distrho/extra/FileBrowserDialog.cpp"
+# include "../../distrho/extra/FileBrowserDialogImpl.cpp"
# endif
#endif
diff --git a/distrho/DistrhoUI.hpp b/distrho/DistrhoUI.hpp
@@ -48,16 +48,14 @@ typedef DGL_NAMESPACE::NanoTopLevelWidget UIWidget;
typedef DGL_NAMESPACE::TopLevelWidget UIWidget;
#endif
-#ifndef DGL_FILE_BROWSER_DISABLED
+#if DISTRHO_UI_FILE_BROWSER
# include "extra/FileBrowserDialog.hpp"
#endif
-START_NAMESPACE_DGL
-class PluginWindow;
-END_NAMESPACE_DGL
-
START_NAMESPACE_DISTRHO
+class PluginWindow;
+
/* ------------------------------------------------------------------------------------------------------------
* DPF UI */
@@ -185,7 +183,7 @@ public:
void sendNote(uint8_t channel, uint8_t note, uint8_t velocity);
#endif
-#ifndef DGL_FILE_BROWSER_DISABLED
+#if DISTRHO_UI_FILE_BROWSER
/**
Open a file browser dialog with this window as transient parent.@n
A few options can be specified to setup the dialog.
@@ -198,7 +196,7 @@ public:
@note This is exactly the same API as provided by the Window class,
but redeclared here so that non-embed/DGL based UIs can still use file browser related functions.
*/
- bool openFileBrowser(const FileBrowserOptions& options = FileBrowserOptions());
+ bool openFileBrowser(const DISTRHO_NAMESPACE::FileBrowserOptions& options = FileBrowserOptions());
#endif
#if DISTRHO_PLUGIN_WANT_DIRECT_ACCESS
@@ -334,7 +332,7 @@ protected:
virtual void uiReshape(uint width, uint height);
#endif // !DISTRHO_PLUGIN_HAS_EXTERNAL_UI
-#ifndef DGL_FILE_BROWSER_DISABLED
+#if DISTRHO_UI_FILE_BROWSER
/**
Window file selected function, called when a path is selected by the user, as triggered by openFileBrowser().
This function is for plugin UIs to be able to override Window::onFileSelected(const char*).
@@ -371,7 +369,7 @@ protected:
private:
struct PrivateData;
PrivateData* const uiData;
- friend class DGL_NAMESPACE::PluginWindow;
+ friend class PluginWindow;
friend class UIExporter;
#if !DISTRHO_PLUGIN_HAS_EXTERNAL_UI
/** @internal */
diff --git a/distrho/DistrhoUI_macOS.mm b/distrho/DistrhoUI_macOS.mm
@@ -26,7 +26,7 @@
# import <Cocoa/Cocoa.h>
# include <algorithm>
# include <cmath>
-# ifndef DGL_FILE_BROWSER_DISABLED
+# if DISTRHO_UI_FILE_BROWSER
# import "extra/FileBrowserDialog.cpp"
# endif
diff --git a/distrho/extra/FileBrowserDialog.cpp b/distrho/extra/FileBrowserDialog.cpp
@@ -1,636 +0,0 @@
-/*
- * DISTRHO Plugin Framework (DPF)
- * Copyright (C) 2012-2021 Filipe Coelho <falktx@falktx.com>
- *
- * Permission to use, copy, modify, and/or distribute this software for any purpose with
- * or without fee is hereby granted, provided that the above copyright notice and this
- * permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD
- * TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN
- * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
- * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
- * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
- * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- */
-
-#include "FileBrowserDialog.hpp"
-#include "ScopedPointer.hpp"
-#include "String.hpp"
-
-#ifdef DISTRHO_OS_MAC
-# import <Cocoa/Cocoa.h>
-#endif
-#ifdef DISTRHO_OS_WINDOWS
-# include <direct.h>
-# include <process.h>
-# include <winsock2.h>
-# include <windows.h>
-# include <commdlg.h>
-# include <vector>
-#else
-# include <unistd.h>
-#endif
-#ifdef HAVE_DBUS
-# include <dbus/dbus.h>
-#endif
-#ifdef HAVE_X11
-# define DBLCLKTME 400
-# include "sofd/libsofd.h"
-# include "sofd/libsofd.c"
-#endif
-
-START_NAMESPACE_DISTRHO
-
-// --------------------------------------------------------------------------------------------------------------------
-
-// static pointer used for signal null/none action taken
-static const char* const kSelectedFileCancelled = "__dpf_cancelled__";
-
-struct FileBrowserData {
- const char* selectedFile;
-
-#ifdef DISTRHO_OS_MAC
- NSSavePanel* nsBasePanel;
- NSOpenPanel* nsOpenPanel;
-#endif
-#ifdef HAVE_DBUS
- DBusConnection* dbuscon;
-#endif
-#ifdef HAVE_X11
- Display* x11display;
-#endif
-
-#ifdef DISTRHO_OS_WINDOWS
- OPENFILENAMEW ofn;
- volatile bool threadCancelled;
- uintptr_t threadHandle;
- std::vector<WCHAR> fileNameW;
- std::vector<WCHAR> startDirW;
- std::vector<WCHAR> titleW;
- const bool saving;
- bool isEmbed;
-
- FileBrowserData(const bool save)
- : selectedFile(nullptr),
- threadCancelled(false),
- threadHandle(0),
- fileNameW(32768),
- saving(save),
- isEmbed(false)
- {
- std::memset(&ofn, 0, sizeof(ofn));
- ofn.lStructSize = sizeof(ofn);
- ofn.lpstrFile = fileNameW.data();
- ofn.nMaxFile = (DWORD)fileNameW.size();
- }
-
- ~FileBrowserData()
- {
- if (cancelAndStop())
- free();
- }
-
- void setupAndStart(const bool embed,
- const char* const startDir,
- const char* const windowTitle,
- const uintptr_t winId,
- const FileBrowserOptions options)
- {
- isEmbed = embed;
-
- ofn.hwndOwner = (HWND)winId;
-
- ofn.Flags = OFN_EXPLORER | OFN_PATHMUSTEXIST | OFN_FILEMUSTEXIST | OFN_NOCHANGEDIR;
- if (options.buttons.showHidden == FileBrowserOptions::kButtonVisibleChecked)
- ofn.Flags |= OFN_FORCESHOWHIDDEN;
-
- ofn.FlagsEx = 0x0;
- if (options.buttons.showPlaces == FileBrowserOptions::kButtonInvisible)
- ofn.FlagsEx |= OFN_EX_NOPLACESBAR;
-
- startDirW.resize(std::strlen(startDir) + 1);
- if (MultiByteToWideChar(CP_UTF8, 0, startDir, -1, startDirW.data(), static_cast<int>(startDirW.size())))
- ofn.lpstrInitialDir = startDirW.data();
-
- titleW.resize(std::strlen(windowTitle) + 1);
- if (MultiByteToWideChar(CP_UTF8, 0, windowTitle, -1, titleW.data(), static_cast<int>(titleW.size())))
- ofn.lpstrTitle = titleW.data();
-
- uint threadId;
- threadCancelled = false;
- threadHandle = _beginthreadex(nullptr, 0, _run, this, 0, &threadId);
- }
-
- bool cancelAndStop()
- {
- threadCancelled = true;
-
- if (threadHandle == 0)
- return true;
-
- // if previous dialog running, carefully close its window
- const HWND owner = isEmbed ? GetParent(ofn.hwndOwner) : ofn.hwndOwner;
-
- 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)threadHandle, 5000);
- }
- }
-
- if (threadHandle == 0)
- return true;
-
- // not good if thread still running, but let's close the handle anyway
- CloseHandle((HANDLE)threadHandle);
- threadHandle = 0;
- return false;
- }
-
- void run()
- {
- const char* nextFile = nullptr;
-
- if (saving ? GetSaveFileNameW(&ofn) : 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))
- {
- nextFile = strdup(fileNameA.data());
- }
- }
-
- if (threadCancelled)
- {
- threadHandle = 0;
- return;
- }
-
- if (nextFile == nullptr)
- nextFile = kSelectedFileCancelled;
-
- selectedFile = nextFile;
- threadHandle = 0;
- }
-
- static unsigned __stdcall _run(void* const arg)
- {
- // CoInitializeEx(nullptr, COINIT_MULTITHREADED);
- static_cast<FileBrowserData*>(arg)->run();
- // CoUninitialize();
- _endthreadex(0);
- return 0;
- }
-#else // DISTRHO_OS_WINDOWS
- FileBrowserData(const bool saving)
- : selectedFile(nullptr)
- {
-#ifdef DISTRHO_OS_MAC
- if (saving)
- {
- nsOpenPanel = nullptr;
- nsBasePanel = [[NSSavePanel savePanel]retain];
- }
- else
- {
- nsOpenPanel = [[NSOpenPanel openPanel]retain];
- nsBasePanel = nsOpenPanel;
- }
-#endif
-#ifdef HAVE_DBUS
- if ((dbuscon = dbus_bus_get(DBUS_BUS_SESSION, nullptr)) != nullptr)
- dbus_connection_set_exit_on_disconnect(dbuscon, false);
-#endif
-#ifdef HAVE_X11
- x11display = XOpenDisplay(nullptr);
-#endif
-
- // maybe unused
- return; (void)saving;
- }
-
- ~FileBrowserData()
- {
-#ifdef DISTRHO_OS_MAC
- [nsBasePanel release];
-#endif
-#ifdef HAVE_DBUS
- if (dbuscon != nullptr)
- dbus_connection_unref(dbuscon);
-#endif
-#ifdef HAVE_X11
- if (x11display != nullptr)
- XCloseDisplay(x11display);
-#endif
-
- free();
- }
-#endif
-
- void free()
- {
- if (selectedFile == nullptr)
- return;
-
- if (selectedFile == kSelectedFileCancelled || std::strcmp(selectedFile, kSelectedFileCancelled) == 0)
- {
- selectedFile = nullptr;
- return;
- }
-
- std::free(const_cast<char*>(selectedFile));
- selectedFile = nullptr;
- }
-};
-
-// --------------------------------------------------------------------------------------------------------------------
-
-#ifdef DISTRHO_FILE_BROWSER_DIALOG_EXTRA_NAMESPACE
-namespace DISTRHO_FILE_BROWSER_DIALOG_EXTRA_NAMESPACE {
-#endif
-
-// --------------------------------------------------------------------------------------------------------------------
-
-FileBrowserHandle fileBrowserCreate(const bool isEmbed,
- const uintptr_t windowId,
- const double scaleFactor,
- const FileBrowserOptions& options)
-{
- String startDir(options.startDir);
-
- if (startDir.isEmpty())
- {
-#ifdef DISTRHO_OS_WINDOWS
- if (char* const cwd = _getcwd(nullptr, 0))
- {
- startDir = cwd;
- std::free(cwd);
- }
-#else
- if (char* const cwd = getcwd(nullptr, 0))
- {
- startDir = cwd;
- std::free(cwd);
- }
-#endif
- }
-
- DISTRHO_SAFE_ASSERT_RETURN(startDir.isNotEmpty(), nullptr);
-
- if (! startDir.endsWith(DISTRHO_OS_SEP))
- startDir += DISTRHO_OS_SEP_STR;
-
- String windowTitle(options.title);
-
- if (windowTitle.isEmpty())
- windowTitle = "FileBrowser";
-
- ScopedPointer<FileBrowserData> handle(new FileBrowserData(options.saving));
-
-#ifdef DISTRHO_OS_MAC
-# if MAC_OS_X_VERSION_MIN_REQUIRED <= MAC_OS_X_VERSION_10_8
- // unsupported
- return nullptr;
-# else
- NSSavePanel* const nsBasePanel = handle->nsBasePanel;
- DISTRHO_SAFE_ASSERT_RETURN(nsBasePanel != nullptr, nullptr);
-
- if (! options.saving)
- {
- NSOpenPanel* const nsOpenPanel = handle->nsOpenPanel;
- DISTRHO_SAFE_ASSERT_RETURN(nsOpenPanel != nullptr, nullptr);
-
- [nsOpenPanel setAllowsMultipleSelection:NO];
- [nsOpenPanel setCanChooseDirectories:NO];
- [nsOpenPanel setCanChooseFiles:YES];
- }
-
- [nsBasePanel setDirectoryURL:[NSURL fileURLWithPath:[NSString stringWithUTF8String:startDir]]];
-
- // TODO file filter using allowedContentTypes: [UTType]
-
- if (options.buttons.listAllFiles == FileBrowserOptions::kButtonVisibleChecked)
- [nsBasePanel setAllowsOtherFileTypes:YES];
- if (options.buttons.showHidden == FileBrowserOptions::kButtonVisibleChecked)
- [nsBasePanel setShowsHiddenFiles:YES];
-
- NSString* const titleString = [[NSString alloc]
- initWithBytes:windowTitle
- length:strlen(windowTitle)
- encoding:NSUTF8StringEncoding];
- [nsBasePanel setTitle:titleString];
-
- FileBrowserData* const handleptr = handle.get();
-
- dispatch_async(dispatch_get_main_queue(), ^
- {
- [nsBasePanel beginSheetModalForWindow:[(NSView*)windowId window]
- completionHandler:^(NSModalResponse result)
- {
- if (result == NSModalResponseOK && [[nsBasePanel URL] isFileURL])
- {
- NSString* const path = [[nsBasePanel URL] path];
- handleptr->selectedFile = strdup([path UTF8String]);
- }
- else
- {
- handleptr->selectedFile = kSelectedFileCancelled;
- }
- }];
- });
-# endif
-#endif
-
-#ifdef DISTRHO_OS_WINDOWS
- handle->setupAndStart(isEmbed, startDir, windowTitle, windowId, options);
-#endif
-
-#ifdef HAVE_DBUS
- // optional, can be null
- DBusConnection* const dbuscon = handle->dbuscon;
-
- // https://flatpak.github.io/xdg-desktop-portal/portal-docs.html#gdbus-org.freedesktop.portal.FileChooser
- if (dbuscon != nullptr)
- {
- // if this is the first time we are calling into DBus, check if things are working
- static bool checkAvailable = !dbus_bus_name_has_owner(dbuscon, "org.freedesktop.portal.Desktop", nullptr);
-
- if (checkAvailable)
- {
- checkAvailable = false;
-
- if (DBusMessage* const msg = dbus_message_new_method_call("org.freedesktop.portal.Desktop",
- "/org/freedesktop/portal/desktop",
- "org.freedesktop.portal.FileChooser",
- "version"))
- {
- if (DBusMessage* const reply = dbus_connection_send_with_reply_and_block(dbuscon, msg, 250, nullptr))
- dbus_message_unref(reply);
-
- dbus_message_unref(msg);
- }
- }
-
- // Any subsquent calls should have this DBus service active
- if (dbus_bus_name_has_owner(dbuscon, "org.freedesktop.portal.Desktop", nullptr))
- {
- if (DBusMessage* const msg = dbus_message_new_method_call("org.freedesktop.portal.Desktop",
- "/org/freedesktop/portal/desktop",
- "org.freedesktop.portal.FileChooser",
- options.saving ? "SaveFile" : "OpenFile"))
- {
- #ifdef HAVE_X11
- char windowIdStr[32];
- memset(windowIdStr, 0, sizeof(windowIdStr));
- snprintf(windowIdStr, sizeof(windowIdStr)-1, "x11:%llx", (ulonglong)windowId);
- const char* windowIdStrPtr = windowIdStr;
- #endif
-
- dbus_message_append_args(msg,
- #ifdef HAVE_X11
- DBUS_TYPE_STRING, &windowIdStrPtr,
- #endif
- DBUS_TYPE_STRING, &windowTitle,
- DBUS_TYPE_INVALID);
-
- DBusMessageIter iter, array;
- dbus_message_iter_init_append(msg, &iter);
- dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "{sv}", &array);
-
- {
- DBusMessageIter dict, variant, variantArray;
- const char* const current_folder_key = "current_folder";
- const char* const current_folder_val = startDir.buffer();
-
- dbus_message_iter_open_container(&array, DBUS_TYPE_DICT_ENTRY, nullptr, &dict);
- dbus_message_iter_append_basic(&dict, DBUS_TYPE_STRING, ¤t_folder_key);
- dbus_message_iter_open_container(&dict, DBUS_TYPE_VARIANT, "ay", &variant);
- dbus_message_iter_open_container(&variant, DBUS_TYPE_ARRAY, "y", &variantArray);
- dbus_message_iter_append_fixed_array(&variantArray, DBUS_TYPE_BYTE,
- ¤t_folder_val, startDir.length()+1);
- dbus_message_iter_close_container(&variant, &variantArray);
- dbus_message_iter_close_container(&dict, &variant);
- dbus_message_iter_close_container(&array, &dict);
- }
-
- dbus_message_iter_close_container(&iter, &array);
-
- dbus_connection_send(dbuscon, msg, nullptr);
-
- dbus_message_unref(msg);
- return handle.release();
- }
- }
- }
-#endif
-
-#ifdef HAVE_X11
- Display* const x11display = handle->x11display;
- DISTRHO_SAFE_ASSERT_RETURN(x11display != nullptr, nullptr);
-
- // unsupported at the moment
- if (options.saving)
- return nullptr;
-
- DISTRHO_SAFE_ASSERT_RETURN(x_fib_configure(0, startDir) == 0, nullptr);
- DISTRHO_SAFE_ASSERT_RETURN(x_fib_configure(1, windowTitle) == 0, nullptr);
-
- const int button1 = options.buttons.showHidden == FileBrowserOptions::kButtonVisibleChecked ? 1
- : options.buttons.showHidden == FileBrowserOptions::kButtonVisibleUnchecked ? 0 : -1;
- const int button2 = options.buttons.showPlaces == FileBrowserOptions::kButtonVisibleChecked ? 1
- : options.buttons.showPlaces == FileBrowserOptions::kButtonVisibleUnchecked ? 0 : -1;
- const int button3 = options.buttons.listAllFiles == FileBrowserOptions::kButtonVisibleChecked ? 1
- : options.buttons.listAllFiles == FileBrowserOptions::kButtonVisibleUnchecked ? 0 : -1;
-
- x_fib_cfg_buttons(1, button1);
- x_fib_cfg_buttons(2, button2);
- x_fib_cfg_buttons(3, button3);
-
- if (x_fib_show(x11display, windowId, 0, 0, scaleFactor + 0.5) != 0)
- return nullptr;
-#endif
-
- return handle.release();
-
- // might be unused
- (void)isEmbed;
- (void)windowId;
- (void)scaleFactor;
-}
-
-// --------------------------------------------------------------------------------------------------------------------
-// returns true if dialog was closed (with or without a file selection)
-
-bool fileBrowserIdle(const FileBrowserHandle handle)
-{
-#ifdef HAVE_DBUS
- if (DBusConnection* dbuscon = handle->dbuscon)
- {
- while (dbus_connection_dispatch(dbuscon) == DBUS_DISPATCH_DATA_REMAINS) {}
- dbus_connection_read_write_dispatch(dbuscon, 0);
-
- if (DBusMessage* const message = dbus_connection_pop_message(dbuscon))
- {
- const char* const interface = dbus_message_get_interface(message);
- const char* const member = dbus_message_get_member(message);
-
- if (interface != nullptr && std::strcmp(interface, "org.freedesktop.portal.Request") == 0
- && member != nullptr && std::strcmp(member, "Response") == 0)
- {
- do {
- DBusMessageIter iter;
- dbus_message_iter_init(message, &iter);
-
- // starts with uint32 for return/exit code
- DISTRHO_SAFE_ASSERT_BREAK(dbus_message_iter_get_arg_type(&iter) == DBUS_TYPE_UINT32);
-
- uint32_t ret = 1;
- dbus_message_iter_get_basic(&iter, &ret);
-
- if (ret != 0)
- break;
-
- // next must be array
- dbus_message_iter_next(&iter);
- DISTRHO_SAFE_ASSERT_BREAK(dbus_message_iter_get_arg_type(&iter) == DBUS_TYPE_ARRAY);
-
- // open dict array
- DBusMessageIter dictArray;
- dbus_message_iter_recurse(&iter, &dictArray);
- DISTRHO_SAFE_ASSERT_BREAK(dbus_message_iter_get_arg_type(&dictArray) == DBUS_TYPE_DICT_ENTRY);
-
- // open containing dict
- DBusMessageIter dict;
- dbus_message_iter_recurse(&dictArray, &dict);
-
- // look for dict with string "uris"
- DISTRHO_SAFE_ASSERT_BREAK(dbus_message_iter_get_arg_type(&dict) == DBUS_TYPE_STRING);
-
- const char* key = nullptr;
- dbus_message_iter_get_basic(&dict, &key);
- DISTRHO_SAFE_ASSERT_BREAK(key != nullptr);
-
- // keep going until we find it
- while (std::strcmp(key, "uris") != 0)
- {
- key = nullptr;
- dbus_message_iter_next(&dictArray);
- DISTRHO_SAFE_ASSERT_BREAK(dbus_message_iter_get_arg_type(&dictArray) == DBUS_TYPE_DICT_ENTRY);
-
- dbus_message_iter_recurse(&dictArray, &dict);
- DISTRHO_SAFE_ASSERT_BREAK(dbus_message_iter_get_arg_type(&dict) == DBUS_TYPE_STRING);
-
- dbus_message_iter_get_basic(&dict, &key);
- DISTRHO_SAFE_ASSERT_BREAK(key != nullptr);
- }
-
- if (key == nullptr)
- break;
-
- // then comes variant
- dbus_message_iter_next(&dict);
- DISTRHO_SAFE_ASSERT_BREAK(dbus_message_iter_get_arg_type(&dict) == DBUS_TYPE_VARIANT);
-
- DBusMessageIter variant;
- dbus_message_iter_recurse(&dict, &variant);
- DISTRHO_SAFE_ASSERT_BREAK(dbus_message_iter_get_arg_type(&variant) == DBUS_TYPE_ARRAY);
-
- // open variant array (variant type is string)
- DBusMessageIter variantArray;
- dbus_message_iter_recurse(&variant, &variantArray);
- DISTRHO_SAFE_ASSERT_BREAK(dbus_message_iter_get_arg_type(&variantArray) == DBUS_TYPE_STRING);
-
- const char* value = nullptr;
- dbus_message_iter_get_basic(&variantArray, &value);
-
- // and finally we have our dear value, just make sure it is local
- DISTRHO_SAFE_ASSERT_BREAK(value != nullptr);
-
- if (const char* const localvalue = std::strstr(value, "file:///"))
- handle->selectedFile = strdup(localvalue + 7);
-
- } while(false);
-
- if (handle->selectedFile == nullptr)
- handle->selectedFile = kSelectedFileCancelled;
- }
- }
- }
-#endif
-
-#ifdef HAVE_X11
- Display* const x11display = handle->x11display;
-
- if (x11display == nullptr)
- return false;
-
- XEvent event;
- while (XPending(x11display) > 0)
- {
- XNextEvent(x11display, &event);
-
- if (x_fib_handle_events(x11display, &event) == 0)
- continue;
-
- if (x_fib_status() > 0)
- handle->selectedFile = x_fib_filename();
- else
- handle->selectedFile = kSelectedFileCancelled;
-
- x_fib_close(x11display);
- XCloseDisplay(x11display);
- handle->x11display = nullptr;
- break;
- }
-#endif
-
- return handle->selectedFile != nullptr;
-}
-
-// --------------------------------------------------------------------------------------------------------------------
-// close sofd file dialog
-
-void fileBrowserClose(const FileBrowserHandle handle)
-{
-#ifdef HAVE_X11
- if (Display* const x11display = handle->x11display)
- x_fib_close(x11display);
-#endif
-
- delete handle;
-}
-
-// --------------------------------------------------------------------------------------------------------------------
-// get path chosen via sofd file dialog
-
-const char* fileBrowserGetPath(const FileBrowserHandle handle)
-{
- if (const char* const selectedFile = handle->selectedFile)
- if (selectedFile != kSelectedFileCancelled && std::strcmp(selectedFile, kSelectedFileCancelled) != 0)
- return selectedFile;
-
- return nullptr;
-}
-
-// --------------------------------------------------------------------------------------------------------------------
-
-#ifdef DISTRHO_FILE_BROWSER_DIALOG_EXTRA_NAMESPACE
-}
-#endif
-
-END_NAMESPACE_DISTRHO
diff --git a/distrho/extra/FileBrowserDialog.hpp b/distrho/extra/FileBrowserDialog.hpp
@@ -1,6 +1,6 @@
/*
* DISTRHO Plugin Framework (DPF)
- * Copyright (C) 2012-2021 Filipe Coelho <falktx@falktx.com>
+ * Copyright (C) 2012-2022 Filipe Coelho <falktx@falktx.com>
*
* Permission to use, copy, modify, and/or distribute this software for any purpose with
* or without fee is hereby granted, provided that the above copyright notice and this
@@ -21,113 +21,7 @@
START_NAMESPACE_DISTRHO
-// --------------------------------------------------------------------------------------------------------------------
-// File Browser Dialog stuff
-
-struct FileBrowserData;
-typedef FileBrowserData* FileBrowserHandle;
-
-// --------------------------------------------------------------------------------------------------------------------
-
-/**
- File browser options, for customizing the file browser dialog.@n
- By default the file browser dialog will be work as "open file" in the current working directory.
-*/
-struct FileBrowserOptions {
- /** Whether we are saving, opening files otherwise (default) */
- bool saving;
-
- /** Start directory, uses current working directory if null */
- const char* startDir;
-
- /** File browser dialog window title, uses "FileBrowser" if null */
- const char* title;
-
- // TODO file filter
-
- /**
- File browser button state.
- This allows to customize the behaviour of the file browse dialog buttons.
- Note these are merely hints, not all systems support them.
- */
- enum ButtonState {
- kButtonInvisible,
- kButtonVisibleUnchecked,
- kButtonVisibleChecked,
- };
-
- /**
- File browser buttons.
- */
- struct Buttons {
- /** Whether to list all files vs only those with matching file extension */
- ButtonState listAllFiles;
- /** Whether to show hidden files */
- ButtonState showHidden;
- /** Whether to show list of places (bookmarks) */
- ButtonState showPlaces;
-
- /** Constructor for default values */
- Buttons()
- : listAllFiles(kButtonVisibleChecked),
- showHidden(kButtonVisibleUnchecked),
- showPlaces(kButtonVisibleChecked) {}
- } buttons;
-
- /** Constructor for default values */
- FileBrowserOptions()
- : saving(false),
- startDir(nullptr),
- title(nullptr),
- buttons() {}
-};
-
-// --------------------------------------------------------------------------------------------------------------------
-
-#ifdef DISTRHO_FILE_BROWSER_DIALOG_EXTRA_NAMESPACE
-namespace DISTRHO_FILE_BROWSER_DIALOG_EXTRA_NAMESPACE {
-#endif
-
-/**
- Create a new file browser dialog.
-
- @p isEmbed: Whether the window this dialog belongs to is an embed/child window (needed to close dialog on Windows)
- @p windowId: The native window id to attach this dialog to as transient parent (X11 Window, HWND or NSView*)
- @p scaleFactor: Scale factor to use (only used on X11)
- @p options: Extra options, optional
- By default the file browser dialog will be work as "open file" in the current working directory.
-*/
-FileBrowserHandle fileBrowserCreate(bool isEmbed,
- uintptr_t windowId,
- double scaleFactor,
- const FileBrowserOptions& options = FileBrowserOptions());
-
-/**
- Idle the file browser dialog handle.@n
- Returns true if dialog was closed (with or without a file selection),
- in which case the handle must not be used afterwards.
- You can then call fileBrowserGetPath to know the selected file (or null if cancelled).
-*/
-bool fileBrowserIdle(const FileBrowserHandle handle);
-
-/**
- Close the file browser dialog, handle must not be used afterwards.
-*/
-void fileBrowserClose(const FileBrowserHandle handle);
-
-/**
- Get the path chosen by the user or null.@n
- Should only be called after fileBrowserIdle returns true.
-*/
-const char* fileBrowserGetPath(const FileBrowserHandle handle);
-
-// --------------------------------------------------------------------------------------------------------------------
-
-#ifdef DISTRHO_FILE_BROWSER_DIALOG_EXTRA_NAMESPACE
-}
-#endif
-
-// --------------------------------------------------------------------------------------------------------------------
+#include "FileBrowserDialogImpl.hpp"
END_NAMESPACE_DISTRHO
diff --git a/distrho/extra/FileBrowserDialogImpl.cpp b/distrho/extra/FileBrowserDialogImpl.cpp
@@ -0,0 +1,643 @@
+/*
+ * DISTRHO Plugin Framework (DPF)
+ * Copyright (C) 2012-2022 Filipe Coelho <falktx@falktx.com>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any purpose with
+ * or without fee is hereby granted, provided that the above copyright notice and this
+ * permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD
+ * TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN
+ * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
+ * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
+ * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#if !defined(DISTRHO_FILE_BROWSER_DIALOG_HPP_INCLUDED) && !defined(DGL_FILE_BROWSER_DIALOG_HPP_INCLUDED)
+# error bad include
+#endif
+#if !defined(FILE_BROWSER_DIALOG_DISTRHO_NAMESPACE) && !defined(FILE_BROWSER_DIALOG_DGL_NAMESPACE)
+# error bad usage
+#endif
+
+#include "ScopedPointer.hpp"
+#include "String.hpp"
+
+#ifdef DISTRHO_OS_MAC
+# import <Cocoa/Cocoa.h>
+#endif
+#ifdef DISTRHO_OS_WINDOWS
+# include <direct.h>
+# include <process.h>
+# include <winsock2.h>
+# include <windows.h>
+# include <commdlg.h>
+# include <vector>
+#else
+# include <unistd.h>
+#endif
+#ifdef HAVE_DBUS
+# include <dbus/dbus.h>
+#endif
+#ifdef HAVE_X11
+# define DBLCLKTME 400
+# include "sofd/libsofd.h"
+# include "sofd/libsofd.c"
+#endif
+
+#ifdef FILE_BROWSER_DIALOG_DGL_NAMESPACE
+START_NAMESPACE_DGL
+#else
+START_NAMESPACE_DISTRHO
+#endif
+
+// --------------------------------------------------------------------------------------------------------------------
+
+// static pointer used for signal null/none action taken
+static const char* const kSelectedFileCancelled = "__dpf_cancelled__";
+
+struct FileBrowserData {
+ const char* selectedFile;
+
+#ifdef DISTRHO_OS_MAC
+ NSSavePanel* nsBasePanel;
+ NSOpenPanel* nsOpenPanel;
+#endif
+#ifdef HAVE_DBUS
+ DBusConnection* dbuscon;
+#endif
+#ifdef HAVE_X11
+ Display* x11display;
+#endif
+
+#ifdef DISTRHO_OS_WINDOWS
+ OPENFILENAMEW ofn;
+ volatile bool threadCancelled;
+ uintptr_t threadHandle;
+ std::vector<WCHAR> fileNameW;
+ std::vector<WCHAR> startDirW;
+ std::vector<WCHAR> titleW;
+ const bool saving;
+ bool isEmbed;
+
+ FileBrowserData(const bool save)
+ : selectedFile(nullptr),
+ threadCancelled(false),
+ threadHandle(0),
+ fileNameW(32768),
+ saving(save),
+ isEmbed(false)
+ {
+ std::memset(&ofn, 0, sizeof(ofn));
+ ofn.lStructSize = sizeof(ofn);
+ ofn.lpstrFile = fileNameW.data();
+ ofn.nMaxFile = (DWORD)fileNameW.size();
+ }
+
+ ~FileBrowserData()
+ {
+ if (cancelAndStop())
+ free();
+ }
+
+ void setupAndStart(const bool embed,
+ const char* const startDir,
+ const char* const windowTitle,
+ const uintptr_t winId,
+ const FileBrowserOptions options)
+ {
+ isEmbed = embed;
+
+ ofn.hwndOwner = (HWND)winId;
+
+ ofn.Flags = OFN_EXPLORER | OFN_PATHMUSTEXIST | OFN_FILEMUSTEXIST | OFN_NOCHANGEDIR;
+ if (options.buttons.showHidden == FileBrowserOptions::kButtonVisibleChecked)
+ ofn.Flags |= OFN_FORCESHOWHIDDEN;
+
+ ofn.FlagsEx = 0x0;
+ if (options.buttons.showPlaces == FileBrowserOptions::kButtonInvisible)
+ ofn.FlagsEx |= OFN_EX_NOPLACESBAR;
+
+ startDirW.resize(std::strlen(startDir) + 1);
+ if (MultiByteToWideChar(CP_UTF8, 0, startDir, -1, startDirW.data(), static_cast<int>(startDirW.size())))
+ ofn.lpstrInitialDir = startDirW.data();
+
+ titleW.resize(std::strlen(windowTitle) + 1);
+ if (MultiByteToWideChar(CP_UTF8, 0, windowTitle, -1, titleW.data(), static_cast<int>(titleW.size())))
+ ofn.lpstrTitle = titleW.data();
+
+ uint threadId;
+ threadCancelled = false;
+ threadHandle = _beginthreadex(nullptr, 0, _run, this, 0, &threadId);
+ }
+
+ bool cancelAndStop()
+ {
+ threadCancelled = true;
+
+ if (threadHandle == 0)
+ return true;
+
+ // if previous dialog running, carefully close its window
+ const HWND owner = isEmbed ? GetParent(ofn.hwndOwner) : ofn.hwndOwner;
+
+ 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)threadHandle, 5000);
+ }
+ }
+
+ if (threadHandle == 0)
+ return true;
+
+ // not good if thread still running, but let's close the handle anyway
+ CloseHandle((HANDLE)threadHandle);
+ threadHandle = 0;
+ return false;
+ }
+
+ void run()
+ {
+ const char* nextFile = nullptr;
+
+ if (saving ? GetSaveFileNameW(&ofn) : 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))
+ {
+ nextFile = strdup(fileNameA.data());
+ }
+ }
+
+ if (threadCancelled)
+ {
+ threadHandle = 0;
+ return;
+ }
+
+ if (nextFile == nullptr)
+ nextFile = kSelectedFileCancelled;
+
+ selectedFile = nextFile;
+ threadHandle = 0;
+ }
+
+ static unsigned __stdcall _run(void* const arg)
+ {
+ // CoInitializeEx(nullptr, COINIT_MULTITHREADED);
+ static_cast<FileBrowserData*>(arg)->run();
+ // CoUninitialize();
+ _endthreadex(0);
+ return 0;
+ }
+#else // DISTRHO_OS_WINDOWS
+ FileBrowserData(const bool saving)
+ : selectedFile(nullptr)
+ {
+#ifdef DISTRHO_OS_MAC
+ if (saving)
+ {
+ nsOpenPanel = nullptr;
+ nsBasePanel = [[NSSavePanel savePanel]retain];
+ }
+ else
+ {
+ nsOpenPanel = [[NSOpenPanel openPanel]retain];
+ nsBasePanel = nsOpenPanel;
+ }
+#endif
+#ifdef HAVE_DBUS
+ if ((dbuscon = dbus_bus_get(DBUS_BUS_SESSION, nullptr)) != nullptr)
+ dbus_connection_set_exit_on_disconnect(dbuscon, false);
+#endif
+#ifdef HAVE_X11
+ x11display = XOpenDisplay(nullptr);
+#endif
+
+ // maybe unused
+ return; (void)saving;
+ }
+
+ ~FileBrowserData()
+ {
+#ifdef DISTRHO_OS_MAC
+ [nsBasePanel release];
+#endif
+#ifdef HAVE_DBUS
+ if (dbuscon != nullptr)
+ dbus_connection_unref(dbuscon);
+#endif
+#ifdef HAVE_X11
+ if (x11display != nullptr)
+ XCloseDisplay(x11display);
+#endif
+
+ free();
+ }
+#endif
+
+ void free()
+ {
+ if (selectedFile == nullptr)
+ return;
+
+ if (selectedFile == kSelectedFileCancelled || std::strcmp(selectedFile, kSelectedFileCancelled) == 0)
+ {
+ selectedFile = nullptr;
+ return;
+ }
+
+ std::free(const_cast<char*>(selectedFile));
+ selectedFile = nullptr;
+ }
+};
+
+// --------------------------------------------------------------------------------------------------------------------
+
+FileBrowserHandle fileBrowserCreate(const bool isEmbed,
+ const uintptr_t windowId,
+ const double scaleFactor,
+ const FileBrowserOptions& options)
+{
+ String startDir(options.startDir);
+
+ if (startDir.isEmpty())
+ {
+#ifdef DISTRHO_OS_WINDOWS
+ if (char* const cwd = _getcwd(nullptr, 0))
+ {
+ startDir = cwd;
+ std::free(cwd);
+ }
+#else
+ if (char* const cwd = getcwd(nullptr, 0))
+ {
+ startDir = cwd;
+ std::free(cwd);
+ }
+#endif
+ }
+
+ DISTRHO_SAFE_ASSERT_RETURN(startDir.isNotEmpty(), nullptr);
+
+ if (! startDir.endsWith(DISTRHO_OS_SEP))
+ startDir += DISTRHO_OS_SEP_STR;
+
+ String windowTitle(options.title);
+
+ if (windowTitle.isEmpty())
+ windowTitle = "FileBrowser";
+
+ ScopedPointer<FileBrowserData> handle(new FileBrowserData(options.saving));
+
+#ifdef DISTRHO_OS_MAC
+# if MAC_OS_X_VERSION_MIN_REQUIRED <= MAC_OS_X_VERSION_10_8
+ // unsupported
+ return nullptr;
+# else
+ NSSavePanel* const nsBasePanel = handle->nsBasePanel;
+ DISTRHO_SAFE_ASSERT_RETURN(nsBasePanel != nullptr, nullptr);
+
+ if (! options.saving)
+ {
+ NSOpenPanel* const nsOpenPanel = handle->nsOpenPanel;
+ DISTRHO_SAFE_ASSERT_RETURN(nsOpenPanel != nullptr, nullptr);
+
+ [nsOpenPanel setAllowsMultipleSelection:NO];
+ [nsOpenPanel setCanChooseDirectories:NO];
+ [nsOpenPanel setCanChooseFiles:YES];
+ }
+
+ [nsBasePanel setDirectoryURL:[NSURL fileURLWithPath:[NSString stringWithUTF8String:startDir]]];
+
+ // TODO file filter using allowedContentTypes: [UTType]
+
+ if (options.buttons.listAllFiles == FileBrowserOptions::kButtonVisibleChecked)
+ [nsBasePanel setAllowsOtherFileTypes:YES];
+ if (options.buttons.showHidden == FileBrowserOptions::kButtonVisibleChecked)
+ [nsBasePanel setShowsHiddenFiles:YES];
+
+ NSString* const titleString = [[NSString alloc]
+ initWithBytes:windowTitle
+ length:strlen(windowTitle)
+ encoding:NSUTF8StringEncoding];
+ [nsBasePanel setTitle:titleString];
+
+ FileBrowserData* const handleptr = handle.get();
+
+ dispatch_async(dispatch_get_main_queue(), ^
+ {
+ [nsBasePanel beginSheetModalForWindow:[(NSView*)windowId window]
+ completionHandler:^(NSModalResponse result)
+ {
+ if (result == NSModalResponseOK && [[nsBasePanel URL] isFileURL])
+ {
+ NSString* const path = [[nsBasePanel URL] path];
+ handleptr->selectedFile = strdup([path UTF8String]);
+ }
+ else
+ {
+ handleptr->selectedFile = kSelectedFileCancelled;
+ }
+ }];
+ });
+# endif
+#endif
+
+#ifdef DISTRHO_OS_WINDOWS
+ handle->setupAndStart(isEmbed, startDir, windowTitle, windowId, options);
+#endif
+
+#ifdef HAVE_DBUS
+ // optional, can be null
+ DBusConnection* const dbuscon = handle->dbuscon;
+
+ // https://flatpak.github.io/xdg-desktop-portal/portal-docs.html#gdbus-org.freedesktop.portal.FileChooser
+ if (dbuscon != nullptr)
+ {
+ // if this is the first time we are calling into DBus, check if things are working
+ static bool checkAvailable = !dbus_bus_name_has_owner(dbuscon, "org.freedesktop.portal.Desktop", nullptr);
+
+ if (checkAvailable)
+ {
+ checkAvailable = false;
+
+ if (DBusMessage* const msg = dbus_message_new_method_call("org.freedesktop.portal.Desktop",
+ "/org/freedesktop/portal/desktop",
+ "org.freedesktop.portal.FileChooser",
+ "version"))
+ {
+ if (DBusMessage* const reply = dbus_connection_send_with_reply_and_block(dbuscon, msg, 250, nullptr))
+ dbus_message_unref(reply);
+
+ dbus_message_unref(msg);
+ }
+ }
+
+ // Any subsquent calls should have this DBus service active
+ if (dbus_bus_name_has_owner(dbuscon, "org.freedesktop.portal.Desktop", nullptr))
+ {
+ if (DBusMessage* const msg = dbus_message_new_method_call("org.freedesktop.portal.Desktop",
+ "/org/freedesktop/portal/desktop",
+ "org.freedesktop.portal.FileChooser",
+ options.saving ? "SaveFile" : "OpenFile"))
+ {
+ #ifdef HAVE_X11
+ char windowIdStr[32];
+ memset(windowIdStr, 0, sizeof(windowIdStr));
+ snprintf(windowIdStr, sizeof(windowIdStr)-1, "x11:%llx", (ulonglong)windowId);
+ const char* windowIdStrPtr = windowIdStr;
+ #endif
+
+ dbus_message_append_args(msg,
+ #ifdef HAVE_X11
+ DBUS_TYPE_STRING, &windowIdStrPtr,
+ #endif
+ DBUS_TYPE_STRING, &windowTitle,
+ DBUS_TYPE_INVALID);
+
+ DBusMessageIter iter, array;
+ dbus_message_iter_init_append(msg, &iter);
+ dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "{sv}", &array);
+
+ {
+ DBusMessageIter dict, variant, variantArray;
+ const char* const current_folder_key = "current_folder";
+ const char* const current_folder_val = startDir.buffer();
+
+ dbus_message_iter_open_container(&array, DBUS_TYPE_DICT_ENTRY, nullptr, &dict);
+ dbus_message_iter_append_basic(&dict, DBUS_TYPE_STRING, ¤t_folder_key);
+ dbus_message_iter_open_container(&dict, DBUS_TYPE_VARIANT, "ay", &variant);
+ dbus_message_iter_open_container(&variant, DBUS_TYPE_ARRAY, "y", &variantArray);
+ dbus_message_iter_append_fixed_array(&variantArray, DBUS_TYPE_BYTE,
+ ¤t_folder_val, startDir.length()+1);
+ dbus_message_iter_close_container(&variant, &variantArray);
+ dbus_message_iter_close_container(&dict, &variant);
+ dbus_message_iter_close_container(&array, &dict);
+ }
+
+ dbus_message_iter_close_container(&iter, &array);
+
+ dbus_connection_send(dbuscon, msg, nullptr);
+
+ dbus_message_unref(msg);
+ return handle.release();
+ }
+ }
+ }
+#endif
+
+#ifdef HAVE_X11
+ Display* const x11display = handle->x11display;
+ DISTRHO_SAFE_ASSERT_RETURN(x11display != nullptr, nullptr);
+
+ // unsupported at the moment
+ if (options.saving)
+ return nullptr;
+
+ DISTRHO_SAFE_ASSERT_RETURN(x_fib_configure(0, startDir) == 0, nullptr);
+ DISTRHO_SAFE_ASSERT_RETURN(x_fib_configure(1, windowTitle) == 0, nullptr);
+
+ const int button1 = options.buttons.showHidden == FileBrowserOptions::kButtonVisibleChecked ? 1
+ : options.buttons.showHidden == FileBrowserOptions::kButtonVisibleUnchecked ? 0 : -1;
+ const int button2 = options.buttons.showPlaces == FileBrowserOptions::kButtonVisibleChecked ? 1
+ : options.buttons.showPlaces == FileBrowserOptions::kButtonVisibleUnchecked ? 0 : -1;
+ const int button3 = options.buttons.listAllFiles == FileBrowserOptions::kButtonVisibleChecked ? 1
+ : options.buttons.listAllFiles == FileBrowserOptions::kButtonVisibleUnchecked ? 0 : -1;
+
+ x_fib_cfg_buttons(1, button1);
+ x_fib_cfg_buttons(2, button2);
+ x_fib_cfg_buttons(3, button3);
+
+ if (x_fib_show(x11display, windowId, 0, 0, scaleFactor + 0.5) != 0)
+ return nullptr;
+#endif
+
+ return handle.release();
+
+ // might be unused
+ (void)isEmbed;
+ (void)windowId;
+ (void)scaleFactor;
+}
+
+// --------------------------------------------------------------------------------------------------------------------
+// returns true if dialog was closed (with or without a file selection)
+
+bool fileBrowserIdle(const FileBrowserHandle handle)
+{
+#ifdef HAVE_DBUS
+ if (DBusConnection* dbuscon = handle->dbuscon)
+ {
+ while (dbus_connection_dispatch(dbuscon) == DBUS_DISPATCH_DATA_REMAINS) {}
+ dbus_connection_read_write_dispatch(dbuscon, 0);
+
+ if (DBusMessage* const message = dbus_connection_pop_message(dbuscon))
+ {
+ const char* const interface = dbus_message_get_interface(message);
+ const char* const member = dbus_message_get_member(message);
+
+ if (interface != nullptr && std::strcmp(interface, "org.freedesktop.portal.Request") == 0
+ && member != nullptr && std::strcmp(member, "Response") == 0)
+ {
+ do {
+ DBusMessageIter iter;
+ dbus_message_iter_init(message, &iter);
+
+ // starts with uint32 for return/exit code
+ DISTRHO_SAFE_ASSERT_BREAK(dbus_message_iter_get_arg_type(&iter) == DBUS_TYPE_UINT32);
+
+ uint32_t ret = 1;
+ dbus_message_iter_get_basic(&iter, &ret);
+
+ if (ret != 0)
+ break;
+
+ // next must be array
+ dbus_message_iter_next(&iter);
+ DISTRHO_SAFE_ASSERT_BREAK(dbus_message_iter_get_arg_type(&iter) == DBUS_TYPE_ARRAY);
+
+ // open dict array
+ DBusMessageIter dictArray;
+ dbus_message_iter_recurse(&iter, &dictArray);
+ DISTRHO_SAFE_ASSERT_BREAK(dbus_message_iter_get_arg_type(&dictArray) == DBUS_TYPE_DICT_ENTRY);
+
+ // open containing dict
+ DBusMessageIter dict;
+ dbus_message_iter_recurse(&dictArray, &dict);
+
+ // look for dict with string "uris"
+ DISTRHO_SAFE_ASSERT_BREAK(dbus_message_iter_get_arg_type(&dict) == DBUS_TYPE_STRING);
+
+ const char* key = nullptr;
+ dbus_message_iter_get_basic(&dict, &key);
+ DISTRHO_SAFE_ASSERT_BREAK(key != nullptr);
+
+ // keep going until we find it
+ while (std::strcmp(key, "uris") != 0)
+ {
+ key = nullptr;
+ dbus_message_iter_next(&dictArray);
+ DISTRHO_SAFE_ASSERT_BREAK(dbus_message_iter_get_arg_type(&dictArray) == DBUS_TYPE_DICT_ENTRY);
+
+ dbus_message_iter_recurse(&dictArray, &dict);
+ DISTRHO_SAFE_ASSERT_BREAK(dbus_message_iter_get_arg_type(&dict) == DBUS_TYPE_STRING);
+
+ dbus_message_iter_get_basic(&dict, &key);
+ DISTRHO_SAFE_ASSERT_BREAK(key != nullptr);
+ }
+
+ if (key == nullptr)
+ break;
+
+ // then comes variant
+ dbus_message_iter_next(&dict);
+ DISTRHO_SAFE_ASSERT_BREAK(dbus_message_iter_get_arg_type(&dict) == DBUS_TYPE_VARIANT);
+
+ DBusMessageIter variant;
+ dbus_message_iter_recurse(&dict, &variant);
+ DISTRHO_SAFE_ASSERT_BREAK(dbus_message_iter_get_arg_type(&variant) == DBUS_TYPE_ARRAY);
+
+ // open variant array (variant type is string)
+ DBusMessageIter variantArray;
+ dbus_message_iter_recurse(&variant, &variantArray);
+ DISTRHO_SAFE_ASSERT_BREAK(dbus_message_iter_get_arg_type(&variantArray) == DBUS_TYPE_STRING);
+
+ const char* value = nullptr;
+ dbus_message_iter_get_basic(&variantArray, &value);
+
+ // and finally we have our dear value, just make sure it is local
+ DISTRHO_SAFE_ASSERT_BREAK(value != nullptr);
+
+ if (const char* const localvalue = std::strstr(value, "file:///"))
+ handle->selectedFile = strdup(localvalue + 7);
+
+ } while(false);
+
+ if (handle->selectedFile == nullptr)
+ handle->selectedFile = kSelectedFileCancelled;
+ }
+ }
+ }
+#endif
+
+#ifdef HAVE_X11
+ Display* const x11display = handle->x11display;
+
+ if (x11display == nullptr)
+ return false;
+
+ XEvent event;
+ while (XPending(x11display) > 0)
+ {
+ XNextEvent(x11display, &event);
+
+ if (x_fib_handle_events(x11display, &event) == 0)
+ continue;
+
+ if (x_fib_status() > 0)
+ handle->selectedFile = x_fib_filename();
+ else
+ handle->selectedFile = kSelectedFileCancelled;
+
+ x_fib_close(x11display);
+ XCloseDisplay(x11display);
+ handle->x11display = nullptr;
+ break;
+ }
+#endif
+
+ return handle->selectedFile != nullptr;
+}
+
+// --------------------------------------------------------------------------------------------------------------------
+// close sofd file dialog
+
+void fileBrowserClose(const FileBrowserHandle handle)
+{
+#ifdef HAVE_X11
+ if (Display* const x11display = handle->x11display)
+ x_fib_close(x11display);
+#endif
+
+ delete handle;
+}
+
+// --------------------------------------------------------------------------------------------------------------------
+// get path chosen via sofd file dialog
+
+const char* fileBrowserGetPath(const FileBrowserHandle handle)
+{
+ if (const char* const selectedFile = handle->selectedFile)
+ if (selectedFile != kSelectedFileCancelled && std::strcmp(selectedFile, kSelectedFileCancelled) != 0)
+ return selectedFile;
+
+ return nullptr;
+}
+
+// --------------------------------------------------------------------------------------------------------------------
+
+#ifdef FILE_BROWSER_DIALOG_DGL_NAMESPACE
+END_NAMESPACE_DGL
+#else
+END_NAMESPACE_DISTRHO
+#endif
+
+#undef FILE_BROWSER_DIALOG_DISTRHO_NAMESPACE
+#undef FILE_BROWSER_DIALOG_DGL_NAMESPACE
diff --git a/distrho/extra/FileBrowserDialogImpl.hpp b/distrho/extra/FileBrowserDialogImpl.hpp
@@ -0,0 +1,117 @@
+/*
+ * DISTRHO Plugin Framework (DPF)
+ * Copyright (C) 2012-2022 Filipe Coelho <falktx@falktx.com>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any purpose with
+ * or without fee is hereby granted, provided that the above copyright notice and this
+ * permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD
+ * TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN
+ * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
+ * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
+ * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#if !defined(DISTRHO_FILE_BROWSER_DIALOG_HPP_INCLUDED) && !defined(DGL_FILE_BROWSER_DIALOG_HPP_INCLUDED)
+# error bad include
+#endif
+
+// --------------------------------------------------------------------------------------------------------------------
+// File Browser Dialog stuff
+
+struct FileBrowserData;
+typedef FileBrowserData* FileBrowserHandle;
+
+// --------------------------------------------------------------------------------------------------------------------
+
+/**
+ File browser options, for customizing the file browser dialog.@n
+ By default the file browser dialog will be work as "open file" in the current working directory.
+*/
+struct FileBrowserOptions {
+ /** Whether we are saving, opening files otherwise (default) */
+ bool saving;
+
+ /** Start directory, uses current working directory if null */
+ const char* startDir;
+
+ /** File browser dialog window title, uses "FileBrowser" if null */
+ const char* title;
+
+ // TODO file filter
+
+ /**
+ File browser button state.
+ This allows to customize the behaviour of the file browse dialog buttons.
+ Note these are merely hints, not all systems support them.
+ */
+ enum ButtonState {
+ kButtonInvisible,
+ kButtonVisibleUnchecked,
+ kButtonVisibleChecked,
+ };
+
+ /**
+ File browser buttons.
+ */
+ struct Buttons {
+ /** Whether to list all files vs only those with matching file extension */
+ ButtonState listAllFiles;
+ /** Whether to show hidden files */
+ ButtonState showHidden;
+ /** Whether to show list of places (bookmarks) */
+ ButtonState showPlaces;
+
+ /** Constructor for default values */
+ Buttons()
+ : listAllFiles(kButtonVisibleChecked),
+ showHidden(kButtonVisibleUnchecked),
+ showPlaces(kButtonVisibleChecked) {}
+ } buttons;
+
+ /** Constructor for default values */
+ FileBrowserOptions()
+ : saving(false),
+ startDir(nullptr),
+ title(nullptr),
+ buttons() {}
+};
+
+// --------------------------------------------------------------------------------------------------------------------
+
+/**
+ Create a new file browser dialog.
+
+ @p isEmbed: Whether the window this dialog belongs to is an embed/child window (needed to close dialog on Windows)
+ @p windowId: The native window id to attach this dialog to as transient parent (X11 Window, HWND or NSView*)
+ @p scaleFactor: Scale factor to use (only used on X11)
+ @p options: Extra options, optional
+ By default the file browser dialog will be work as "open file" in the current working directory.
+*/
+FileBrowserHandle fileBrowserCreate(bool isEmbed,
+ uintptr_t windowId,
+ double scaleFactor,
+ const FileBrowserOptions& options = FileBrowserOptions());
+
+/**
+ Idle the file browser dialog handle.@n
+ Returns true if dialog was closed (with or without a file selection),
+ in which case the handle must not be used afterwards.
+ You can then call fileBrowserGetPath to know the selected file (or null if cancelled).
+*/
+bool fileBrowserIdle(const FileBrowserHandle handle);
+
+/**
+ Close the file browser dialog, handle must not be used afterwards.
+*/
+void fileBrowserClose(const FileBrowserHandle handle);
+
+/**
+ Get the path chosen by the user or null.@n
+ Should only be called after fileBrowserIdle returns true.
+*/
+const char* fileBrowserGetPath(const FileBrowserHandle handle);
+
+// --------------------------------------------------------------------------------------------------------------------
diff --git a/distrho/src/DistrhoPluginChecks.h b/distrho/src/DistrhoPluginChecks.h
@@ -90,6 +90,14 @@
# define DISTRHO_PLUGIN_WANT_TIMEPOS 0
#endif
+#ifndef DISTRHO_UI_FILE_BROWSER
+# if defined(DGL_FILE_BROWSER_DISABLED) || DISTRHO_PLUGIN_HAS_EXTERNAL_UI
+# define DISTRHO_UI_FILE_BROWSER 0
+# else
+# define DISTRHO_UI_FILE_BROWSER 1
+# endif
+#endif
+
#ifndef DISTRHO_UI_USER_RESIZABLE
# define DISTRHO_UI_USER_RESIZABLE 0
#endif
@@ -154,7 +162,16 @@
#endif
// -----------------------------------------------------------------------
-// Disable UI if DGL or External UI is not available
+// Disable file browser if using external UI
+
+#if DISTRHO_UI_FILE_BROWSER && DISTRHO_PLUGIN_HAS_EXTERNAL_UI
+# warning file browser APIs do not work for external UIs
+# undef DISTRHO_UI_FILE_BROWSER 0
+# define DISTRHO_UI_FILE_BROWSER 0
+#endif
+
+// -----------------------------------------------------------------------
+// Disable UI if DGL or external UI is not available
#if (defined(DGL_CAIRO) && ! defined(HAVE_CAIRO)) || (defined(DGL_OPENGL) && ! defined(HAVE_OPENGL))
# undef DISTRHO_PLUGIN_HAS_EMBED_UI
diff --git a/distrho/src/DistrhoUI.cpp b/distrho/src/DistrhoUI.cpp
@@ -17,26 +17,27 @@
#include "src/DistrhoPluginChecks.h"
#include "src/DistrhoDefines.h"
-#if !defined(DGL_FILE_BROWSER_DISABLED) && !defined(DISTRHO_UI_FILE_BROWSER) && !defined(DISTRHO_OS_MAC)
+#if DISTRHO_UI_FILE_BROWSER && !defined(DISTRHO_OS_MAC)
# define DISTRHO_PUGL_NAMESPACE_MACRO_HELPER(NS, SEP, FUNCTION) NS ## SEP ## FUNCTION
# define DISTRHO_PUGL_NAMESPACE_MACRO(NS, FUNCTION) DISTRHO_PUGL_NAMESPACE_MACRO_HELPER(NS, _, FUNCTION)
-# define DISTRHO_FILE_BROWSER_DIALOG_EXTRA_NAMESPACE Plugin
-# define x_fib_add_recent DISTRHO_PUGL_NAMESPACE_MACRO(Plugin, x_fib_add_recent)
-# define x_fib_cfg_buttons DISTRHO_PUGL_NAMESPACE_MACRO(Plugin, x_fib_cfg_buttons)
-# define x_fib_cfg_filter_callback DISTRHO_PUGL_NAMESPACE_MACRO(Plugin, x_fib_cfg_filter_callback)
-# define x_fib_close DISTRHO_PUGL_NAMESPACE_MACRO(Plugin, x_fib_close)
-# define x_fib_configure DISTRHO_PUGL_NAMESPACE_MACRO(Plugin, x_fib_configure)
-# define x_fib_filename DISTRHO_PUGL_NAMESPACE_MACRO(Plugin, x_fib_filename)
-# define x_fib_free_recent DISTRHO_PUGL_NAMESPACE_MACRO(Plugin, x_fib_free_recent)
-# define x_fib_handle_events DISTRHO_PUGL_NAMESPACE_MACRO(Plugin, x_fib_handle_events)
-# define x_fib_load_recent DISTRHO_PUGL_NAMESPACE_MACRO(Plugin, x_fib_load_recent)
-# define x_fib_recent_at DISTRHO_PUGL_NAMESPACE_MACRO(Plugin, x_fib_recent_at)
-# define x_fib_recent_count DISTRHO_PUGL_NAMESPACE_MACRO(Plugin, x_fib_recent_count)
-# define x_fib_recent_file DISTRHO_PUGL_NAMESPACE_MACRO(Plugin, x_fib_recent_file)
-# define x_fib_save_recent DISTRHO_PUGL_NAMESPACE_MACRO(Plugin, x_fib_save_recent)
-# define x_fib_show DISTRHO_PUGL_NAMESPACE_MACRO(Plugin, x_fib_show)
-# define x_fib_status DISTRHO_PUGL_NAMESPACE_MACRO(Plugin, x_fib_status)
-# include "../extra/FileBrowserDialog.cpp"
+# define x_fib_add_recent DISTRHO_PUGL_NAMESPACE_MACRO(plugin, x_fib_add_recent)
+# define x_fib_cfg_buttons DISTRHO_PUGL_NAMESPACE_MACRO(plugin, x_fib_cfg_buttons)
+# define x_fib_cfg_filter_callback DISTRHO_PUGL_NAMESPACE_MACRO(plugin, x_fib_cfg_filter_callback)
+# define x_fib_close DISTRHO_PUGL_NAMESPACE_MACRO(plugin, x_fib_close)
+# define x_fib_configure DISTRHO_PUGL_NAMESPACE_MACRO(plugin, x_fib_configure)
+# define x_fib_filename DISTRHO_PUGL_NAMESPACE_MACRO(plugin, x_fib_filename)
+# define x_fib_free_recent DISTRHO_PUGL_NAMESPACE_MACRO(plugin, x_fib_free_recent)
+# define x_fib_handle_events DISTRHO_PUGL_NAMESPACE_MACRO(plugin, x_fib_handle_events)
+# define x_fib_load_recent DISTRHO_PUGL_NAMESPACE_MACRO(plugin, x_fib_load_recent)
+# define x_fib_recent_at DISTRHO_PUGL_NAMESPACE_MACRO(plugin, x_fib_recent_at)
+# define x_fib_recent_count DISTRHO_PUGL_NAMESPACE_MACRO(plugin, x_fib_recent_count)
+# define x_fib_recent_file DISTRHO_PUGL_NAMESPACE_MACRO(plugin, x_fib_recent_file)
+# define x_fib_save_recent DISTRHO_PUGL_NAMESPACE_MACRO(plugin, x_fib_save_recent)
+# define x_fib_show DISTRHO_PUGL_NAMESPACE_MACRO(plugin, x_fib_show)
+# define x_fib_status DISTRHO_PUGL_NAMESPACE_MACRO(plugin, x_fib_status)
+# define FILE_BROWSER_DIALOG_DISTRHO_NAMESPACE
+# include "../extra/FileBrowserDialog.hpp"
+# include "../extra/FileBrowserDialogImpl.cpp"
#endif
#if DISTRHO_PLUGIN_HAS_EXTERNAL_UI
@@ -278,16 +279,10 @@ void UI::sendNote(uint8_t channel, uint8_t note, uint8_t velocity)
}
#endif
-#ifndef DGL_FILE_BROWSER_DISABLED
+#if DISTRHO_UI_FILE_BROWSER
bool UI::openFileBrowser(const FileBrowserOptions& options)
{
-# if DISTRHO_PLUGIN_HAS_EXTERNAL_UI
- // TODO
- return false;
- (void)options;
-# else
- return getWindow().openFileBrowser(options);
-# endif
+ return getWindow().openFileBrowser((DGL_NAMESPACE::FileBrowserOptions&)options);
}
#endif
@@ -368,7 +363,7 @@ void UI::uiReshape(uint, uint)
}
#endif // !DISTRHO_PLUGIN_HAS_EXTERNAL_UI
-#ifndef DGL_FILE_BROWSER_DISABLED
+#if DISTRHO_UI_FILE_BROWSER
void UI::uiFileBrowserSelected(const char*)
{
}
diff --git a/distrho/src/DistrhoUIPrivateData.hpp b/distrho/src/DistrhoUIPrivateData.hpp
@@ -48,13 +48,7 @@
# define DISTRHO_UI_USER_RESIZABLE 0
#endif
-// -----------------------------------------------------------------------
-
-#if DISTRHO_PLUGIN_HAS_EXTERNAL_UI
START_NAMESPACE_DISTRHO
-#else
-START_NAMESPACE_DGL
-#endif
// -----------------------------------------------------------------------
// Plugin Application, will set class name based on plugin details
@@ -107,11 +101,11 @@ struct PluginApplication
DISTRHO_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(PluginApplication)
};
#else
-class PluginApplication : public Application
+class PluginApplication : public DGL_NAMESPACE::Application
{
public:
explicit PluginApplication()
- : Application(DISTRHO_UI_IS_STANDALONE)
+ : DGL_NAMESPACE::Application(DISTRHO_UI_IS_STANDALONE)
{
const char* const className = (
#ifdef DISTRHO_PLUGIN_BRAND
@@ -172,14 +166,14 @@ public:
DISTRHO_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(PluginWindow)
};
#else // DISTRHO_PLUGIN_HAS_EXTERNAL_UI
-class PluginWindow : public Window
+class PluginWindow : public DGL_NAMESPACE::Window
{
- DISTRHO_NAMESPACE::UI* const ui;
+ UI* const ui;
bool initializing;
bool receivedReshapeDuringInit;
public:
- explicit PluginWindow(DISTRHO_NAMESPACE::UI* const uiPtr,
+ explicit PluginWindow(UI* const uiPtr,
PluginApplication& app,
const uintptr_t parentWindowHandle,
const uint width,
@@ -238,7 +232,7 @@ public:
}
#endif
- std::vector<ClipboardDataOffer> getClipboardDataOfferTypes()
+ std::vector<DGL_NAMESPACE::ClipboardDataOffer> getClipboardDataOfferTypes()
{
return Window::getClipboardDataOfferTypes();
}
@@ -287,7 +281,7 @@ protected:
ui->uiScaleFactorChanged(scaleFactor);
}
-# ifndef DGL_FILE_BROWSER_DISABLED
+# if DISTRHO_UI_FILE_BROWSER
void onFileSelected(const char* filename) override;
# endif
@@ -295,21 +289,6 @@ protected:
};
#endif // DISTRHO_PLUGIN_HAS_EXTERNAL_UI
-#if DISTRHO_PLUGIN_HAS_EXTERNAL_UI
-END_NAMESPACE_DISTRHO
-#else
-END_NAMESPACE_DGL
-#endif
-
-// -----------------------------------------------------------------------
-
-START_NAMESPACE_DISTRHO
-
-#if !DISTRHO_PLUGIN_HAS_EXTERNAL_UI
-using DGL_NAMESPACE::PluginApplication;
-using DGL_NAMESPACE::PluginWindow;
-#endif
-
// -----------------------------------------------------------------------
// UI callbacks
@@ -465,7 +444,7 @@ inline bool UI::PrivateData::fileRequestCallback(const char* const key)
snprintf(title, sizeof(title)-1u, DISTRHO_PLUGIN_NAME ": %s", key);
title[sizeof(title)-1u] = '\0';
- FileBrowserOptions opts;
+ DGL_NAMESPACE::FileBrowserOptions opts;
opts.title = title;
return window->openFileBrowser(opts);
#endif
@@ -473,14 +452,10 @@ inline bool UI::PrivateData::fileRequestCallback(const char* const key)
return false;
}
-END_NAMESPACE_DISTRHO
-
// -----------------------------------------------------------------------
// PluginWindow onFileSelected that require UI::PrivateData definitions
-#if !DISTRHO_PLUGIN_HAS_EXTERNAL_UI && !defined(DGL_FILE_BROWSER_DISABLED)
-START_NAMESPACE_DGL
-
+#if DISTRHO_UI_FILE_BROWSER
inline void PluginWindow::onFileSelected(const char* const filename)
{
DISTRHO_SAFE_ASSERT_RETURN(ui != nullptr,);
@@ -488,7 +463,7 @@ inline void PluginWindow::onFileSelected(const char* const filename)
if (initializing)
return;
-# if DISTRHO_PLUGIN_WANT_STATE
+ #if DISTRHO_PLUGIN_WANT_STATE
if (char* const key = ui->uiData->uiStateFileKeyRequest)
{
ui->uiData->uiStateFileKeyRequest = nullptr;
@@ -502,14 +477,14 @@ inline void PluginWindow::onFileSelected(const char* const filename)
std::free(key);
return;
}
-# endif
+ #endif
ui->uiFileBrowserSelected(filename);
}
-
-END_NAMESPACE_DGL
#endif
// -----------------------------------------------------------------------
+END_NAMESPACE_DISTRHO
+
#endif // DISTRHO_UI_PRIVATE_DATA_HPP_INCLUDED
diff --git a/examples/Info/DistrhoPluginInfo.h b/examples/Info/DistrhoPluginInfo.h
@@ -26,6 +26,7 @@
#define DISTRHO_PLUGIN_NUM_INPUTS 2
#define DISTRHO_PLUGIN_NUM_OUTPUTS 2
#define DISTRHO_PLUGIN_WANT_TIMEPOS 1
+#define DISTRHO_UI_FILE_BROWSER 0
#define DISTRHO_UI_USER_RESIZABLE 1
#define DISTRHO_UI_USE_NANOVG 1
diff --git a/pugl-updates-notes.txt b/pugl-updates-notes.txt
@@ -1,6 +1,5 @@
puglClearMinSize needed?
puglSetWindowSize was used on first show, still needed?
-transientParentView needed? remove from WindowPrivateData
update distrhoui.cpp get scale factor to match new parent request setup and pugl