Signed-off-by: falkTX <falktx@falktx.com>pull/272/head
| @@ -265,7 +265,7 @@ endif | |||
| ifneq ($(HAIKU_OR_MACOS_OR_WINDOWS),true) | |||
| ifeq ($(HAVE_X11),true) | |||
| DGL_FLAGS += $(shell $(PKG_CONFIG) --cflags x11) | |||
| DGL_FLAGS += $(shell $(PKG_CONFIG) --cflags x11) -DHAVE_X11 | |||
| DGL_SYSTEM_LIBS += $(shell $(PKG_CONFIG) --libs x11) | |||
| ifeq ($(HAVE_XCURSOR),true) | |||
| # TODO -DHAVE_XCURSOR | |||
| @@ -50,6 +50,60 @@ class TopLevelWidget; | |||
| class Window | |||
| { | |||
| public: | |||
| #ifndef DGL_FILE_BROWSER_DISABLED | |||
| /** | |||
| File browser options. | |||
| @see Window::openFileBrowser | |||
| */ | |||
| struct FileBrowserOptions { | |||
| /** | |||
| File browser button state. | |||
| This allows to customize the behaviour of the file browse dialog buttons. | |||
| */ | |||
| enum ButtonState { | |||
| kButtonInvisible, | |||
| kButtonVisibleUnchecked, | |||
| kButtonVisibleChecked, | |||
| }; | |||
| /** Start directory, uses current working directory if null */ | |||
| const char* startDir; | |||
| /** File browser dialog window title, uses "FileBrowser" if null */ | |||
| const char* title; | |||
| /** File browser dialog window width */ | |||
| uint width; | |||
| /** File browser dialog window height */ | |||
| uint height; | |||
| // TODO file filter | |||
| /** | |||
| 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; | |||
| /** Constuctor for default values */ | |||
| Buttons() | |||
| : listAllFiles(kButtonVisibleChecked), | |||
| showHidden(kButtonVisibleUnchecked), | |||
| showPlaces(kButtonVisibleUnchecked) {} | |||
| } buttons; | |||
| /** Constuctor for default values */ | |||
| FileBrowserOptions() | |||
| : startDir(nullptr), | |||
| title(nullptr), | |||
| width(0), | |||
| height(0), | |||
| buttons() {} | |||
| }; | |||
| #endif // DGL_FILE_BROWSER_DISABLED | |||
| /** | |||
| Constructor for a regular, standalone window. | |||
| */ | |||
| @@ -130,7 +184,18 @@ public: | |||
| */ | |||
| void close(); | |||
| /** | |||
| Check if this window is resizable. | |||
| @see setResizable | |||
| */ | |||
| bool isResizable() const noexcept; | |||
| /** | |||
| Set window as resizable (by the user or window manager). | |||
| It is always possible to resize a window programmatically, which is not the same as the user being allowed to it. | |||
| @note This function does nothing for plugins, where the resizable state is set via macro. | |||
| @see DISTRHO_UI_USER_RESIZABLE | |||
| */ | |||
| void setResizable(bool resizable); | |||
| /** | |||
| @@ -247,6 +312,17 @@ public: | |||
| */ | |||
| void focus(); | |||
| #ifndef DGL_FILE_BROWSER_DISABLED | |||
| /** | |||
| 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. | |||
| */ | |||
| bool openFileBrowser(const FileBrowserOptions& options); | |||
| #endif | |||
| /** | |||
| Request repaint of this window, for the entire area. | |||
| */ | |||
| @@ -272,16 +348,15 @@ public: | |||
| bool keepAspectRatio = false, | |||
| bool automaticallyScale = false); | |||
| /* | |||
| void setTransientWinId(uintptr_t winId); | |||
| */ | |||
| /** DEPRECATED Use isIgnoringKeyRepeat(). */ | |||
| DISTRHO_DEPRECATED_BY("isIgnoringKeyRepeat()") | |||
| inline bool getIgnoringKeyRepeat() const noexcept { return isIgnoringKeyRepeat(); } | |||
| /** DEPRECATED Use getScaleFactor(). */ | |||
| DISTRHO_DEPRECATED_BY("getScaleFactor()") | |||
| inline double getScaling() const noexcept { return getScaleFactor(); } | |||
| /** DEPRECATED Use runAsModal(bool). */ | |||
| DISTRHO_DEPRECATED_BY("runAsModal(bool)") | |||
| inline void exec(bool blockWait = false) { runAsModal(blockWait); } | |||
| @@ -302,9 +377,23 @@ protected: | |||
| /** | |||
| A function called when the window is resized. | |||
| If there is a top-level widget associated with this window, its size will be set right after this function. | |||
| The default implementation sets up drawing context where necessary. | |||
| */ | |||
| virtual void onReshape(uint width, uint height); | |||
| #ifndef DGL_FILE_BROWSER_DISABLED | |||
| /** | |||
| A function called when a path is selected by the user, as triggered by openFileBrowser(). | |||
| This action happens after the user confirms the action, so the file browser dialog will be closed at this point. | |||
| The default implementation does nothing. | |||
| */ | |||
| virtual void onFileSelected(const char* filename); | |||
| /** DEPRECATED Use onFileSelected(). */ | |||
| DISTRHO_DEPRECATED_BY("onFileSelected(const char*)") | |||
| inline virtual void fileBrowserSelected(const char* filename) { return onFileSelected(filename); } | |||
| #endif | |||
| private: | |||
| struct PrivateData; | |||
| PrivateData* const pData; | |||
| @@ -319,62 +408,10 @@ private: | |||
| END_NAMESPACE_DGL | |||
| /* TODO | |||
| * add focusEvent with CrossingMode arg | |||
| * add eventcrossing/enter-leave event | |||
| */ | |||
| #if 0 | |||
| #ifndef DGL_FILE_BROWSER_DISABLED | |||
| /** | |||
| File browser options. | |||
| */ | |||
| struct FileBrowserOptions { | |||
| const char* startDir; | |||
| const char* title; | |||
| uint width; | |||
| uint height; | |||
| /** | |||
| File browser buttons. | |||
| 0 means hidden. | |||
| 1 means visible and unchecked. | |||
| 2 means visible and checked. | |||
| */ | |||
| struct Buttons { | |||
| uint listAllFiles; | |||
| uint showHidden; | |||
| uint showPlaces; | |||
| /** Constuctor for default values */ | |||
| Buttons() | |||
| : listAllFiles(2), | |||
| showHidden(1), | |||
| showPlaces(1) {} | |||
| } buttons; | |||
| /** Constuctor for default values */ | |||
| FileBrowserOptions() | |||
| : startDir(nullptr), | |||
| title(nullptr), | |||
| width(0), | |||
| height(0), | |||
| buttons() {} | |||
| }; | |||
| #endif // DGL_FILE_BROWSER_DISABLED | |||
| void addIdleCallback(IdleCallback* const callback); | |||
| void removeIdleCallback(IdleCallback* const callback); | |||
| #ifndef DGL_FILE_BROWSER_DISABLED | |||
| bool openFileBrowser(const FileBrowserOptions& options); | |||
| #endif | |||
| protected: | |||
| #ifndef DGL_FILE_BROWSER_DISABLED | |||
| virtual void fileBrowserSelected(const char* filename); | |||
| #endif | |||
| bool handlePluginKeyboard(const bool press, const uint key); | |||
| bool handlePluginSpecial(const bool press, const Key key); | |||
| #endif | |||
| @@ -201,6 +201,13 @@ void Window::focus() | |||
| pData->focus(); | |||
| } | |||
| #ifndef DGL_FILE_BROWSER_DISABLED | |||
| bool Window::openFileBrowser(const FileBrowserOptions& options) | |||
| { | |||
| return pData->openFileBrowser(options); | |||
| } | |||
| #endif | |||
| void Window::repaint() noexcept | |||
| { | |||
| puglPostRedisplay(pData->view); | |||
| @@ -271,51 +278,20 @@ void Window::onReshape(uint, uint) | |||
| puglFallbackOnResize(pData->view); | |||
| } | |||
| #if 0 | |||
| void Window::setTransientWinId(const uintptr_t winId) | |||
| { | |||
| puglSetTransientFor(pData->fView, winId); | |||
| } | |||
| void Window::_addWidget(Widget* const widget) | |||
| { | |||
| pData->addWidget(widget); | |||
| } | |||
| void Window::_removeWidget(Widget* const widget) | |||
| { | |||
| pData->removeWidget(widget); | |||
| } | |||
| void Window::_idle() | |||
| { | |||
| pData->windowSpecificIdle(); | |||
| } | |||
| // ----------------------------------------------------------------------- | |||
| void Window::addIdleCallback(IdleCallback* const callback) | |||
| #ifndef DGL_FILE_BROWSER_DISABLED | |||
| void Window::onFileSelected(const char*) | |||
| { | |||
| DISTRHO_SAFE_ASSERT_RETURN(callback != nullptr,) | |||
| pData->fAppData->idleCallbacks.push_back(callback); | |||
| } | |||
| #endif | |||
| void Window::removeIdleCallback(IdleCallback* const callback) | |||
| #if 0 | |||
| void Window::setTransientWinId(const uintptr_t winId) | |||
| { | |||
| DISTRHO_SAFE_ASSERT_RETURN(callback != nullptr,) | |||
| pData->fAppData->idleCallbacks.remove(callback); | |||
| puglSetTransientFor(pData->view, winId); | |||
| } | |||
| // ----------------------------------------------------------------------- | |||
| #ifndef DGL_FILE_BROWSER_DISABLED | |||
| void Window::fileBrowserSelected(const char*) | |||
| { | |||
| } | |||
| #endif | |||
| bool Window::handlePluginKeyboard(const bool press, const uint key) | |||
| { | |||
| // TODO | |||
| @@ -19,6 +19,14 @@ | |||
| #include "pugl.hpp" | |||
| #include "../../distrho/extra/String.hpp" | |||
| #ifdef DISTRHO_OS_WINDOWS | |||
| # include <direct.h> | |||
| #else | |||
| # include <unistd.h> | |||
| #endif | |||
| #define DGL_DEBUG_EVENTS | |||
| #if defined(DEBUG) && defined(DGL_DEBUG_EVENTS) | |||
| @@ -66,6 +74,9 @@ Window::PrivateData::PrivateData(Application& a, Window* const s) | |||
| autoScaleFactor(1.0), | |||
| minWidth(0), | |||
| minHeight(0), | |||
| #ifdef DISTRHO_OS_WINDOWS | |||
| win32SelectedFile(nullptr), | |||
| #endif | |||
| modal() | |||
| { | |||
| init(DEFAULT_WIDTH, DEFAULT_HEIGHT, false); | |||
| @@ -85,6 +96,9 @@ Window::PrivateData::PrivateData(Application& a, Window* const s, PrivateData* c | |||
| autoScaleFactor(1.0), | |||
| minWidth(0), | |||
| minHeight(0), | |||
| #ifdef DISTRHO_OS_WINDOWS | |||
| win32SelectedFile(nullptr), | |||
| #endif | |||
| modal(ppData) | |||
| { | |||
| init(DEFAULT_WIDTH, DEFAULT_HEIGHT, false); | |||
| @@ -108,6 +122,9 @@ Window::PrivateData::PrivateData(Application& a, Window* const s, | |||
| autoScaleFactor(1.0), | |||
| minWidth(0), | |||
| minHeight(0), | |||
| #ifdef DISTRHO_OS_WINDOWS | |||
| win32SelectedFile(nullptr), | |||
| #endif | |||
| modal() | |||
| { | |||
| if (isEmbed) | |||
| @@ -142,6 +159,9 @@ Window::PrivateData::PrivateData(Application& a, Window* const s, | |||
| autoScaleFactor(1.0), | |||
| minWidth(0), | |||
| minHeight(0), | |||
| #ifdef DISTRHO_OS_WINDOWS | |||
| win32SelectedFile(nullptr), | |||
| #endif | |||
| modal() | |||
| { | |||
| if (isEmbed) | |||
| @@ -163,6 +183,9 @@ Window::PrivateData::~PrivateData() | |||
| { | |||
| if (isEmbed) | |||
| { | |||
| #ifdef HAVE_X11 | |||
| sofdFileDialogClose(view); | |||
| #endif | |||
| puglHide(view); | |||
| appData->oneWindowClosed(); | |||
| isClosed = true; | |||
| @@ -199,9 +222,6 @@ void Window::PrivateData::init(const uint width, const uint height, const bool r | |||
| puglSetViewHint(view, PUGL_STENCIL_BITS, 8); | |||
| // PUGL_SAMPLES ?? | |||
| puglSetEventFunc(view, puglEventCallback); | |||
| // #ifndef DGL_FILE_BROWSER_DISABLED | |||
| // puglSetFileSelectedFunc(fView, fileBrowserSelectedCallback); | |||
| // #endif | |||
| PuglRect rect = puglGetFrame(view); | |||
| rect.width = width; | |||
| @@ -215,6 +235,21 @@ void Window::PrivateData::init(const uint width, const uint height, const bool r | |||
| // ----------------------------------------------------------------------- | |||
| void Window::PrivateData::close() | |||
| { | |||
| DGL_DBG("Window close\n"); | |||
| // DGL_DBGp("Window close DBG %i %i %p\n", isEmbed, isClosed, appData); | |||
| if (isEmbed || isClosed) | |||
| return; | |||
| isClosed = true; | |||
| hide(); | |||
| appData->oneWindowClosed(); | |||
| } | |||
| // ----------------------------------------------------------------------- | |||
| void Window::PrivateData::show() | |||
| { | |||
| if (isVisible) | |||
| @@ -293,6 +328,9 @@ void Window::PrivateData::hide() | |||
| if (modal.enabled) | |||
| stopModal(); | |||
| #ifdef HAVE_X11 | |||
| sofdFileDialogClose(view); | |||
| #endif | |||
| puglHide(view); | |||
| isVisible = false; | |||
| @@ -300,21 +338,6 @@ void Window::PrivateData::hide() | |||
| // ----------------------------------------------------------------------- | |||
| void Window::PrivateData::close() | |||
| { | |||
| DGL_DBG("Window close\n"); | |||
| // DGL_DBGp("Window close DBG %i %i %p\n", isEmbed, isClosed, appData); | |||
| if (isEmbed || isClosed) | |||
| return; | |||
| isClosed = true; | |||
| hide(); | |||
| appData->oneWindowClosed(); | |||
| } | |||
| // ----------------------------------------------------------------------- | |||
| void Window::PrivateData::focus() | |||
| { | |||
| if (! isEmbed) | |||
| @@ -341,20 +364,29 @@ void Window::PrivateData::setResizable(const bool resizable) | |||
| void Window::PrivateData::idleCallback() | |||
| { | |||
| // #if defined(DISTRHO_OS_WINDOWS) && !defined(DGL_FILE_BROWSER_DISABLED) | |||
| // if (fSelectedFile.isNotEmpty()) | |||
| // { | |||
| // char* const buffer = fSelectedFile.getAndReleaseBuffer(); | |||
| // fView->fileSelectedFunc(fView, buffer); | |||
| // std::free(buffer); | |||
| // } | |||
| // #endif | |||
| // if (modal.enabled && modal.parent != nullptr) | |||
| // modal.parent->idleCallback(); | |||
| #ifndef DGL_FILE_BROWSER_DISABLED | |||
| # ifdef DISTRHO_OS_WINDOWS | |||
| if (char* const path = win32SelectedFile) | |||
| { | |||
| win32SelectedFile = nullptr; | |||
| self->onFileSelected(path); | |||
| std::free(path); | |||
| } | |||
| # endif | |||
| # ifdef HAVE_X11 | |||
| char* path; | |||
| if (sofdFileDialogGetPath(&path)) | |||
| { | |||
| // TODO ignore null path?? | |||
| self->onFileSelected(path); | |||
| sofdFileDialogFree(path); | |||
| } | |||
| # endif | |||
| #endif | |||
| } | |||
| // ----------------------------------------------------------------------- | |||
| // idle callback stuff | |||
| bool Window::PrivateData::addIdleCallback(IdleCallback* const callback, const uint timerFrequencyInMs) | |||
| { | |||
| @@ -379,6 +411,69 @@ bool Window::PrivateData::removeIdleCallback(IdleCallback* const callback) | |||
| return puglStopTimer(view, (uintptr_t)callback) == PUGL_SUCCESS; | |||
| } | |||
| // ----------------------------------------------------------------------- | |||
| // file handling | |||
| bool Window::PrivateData::openFileBrowser(const Window::FileBrowserOptions& options) | |||
| { | |||
| using DISTRHO_NAMESPACE::String; | |||
| // -------------------------------------------------------------------------- | |||
| // configure start dir | |||
| // TODO: get abspath if needed | |||
| // TODO: cross-platform | |||
| String startDir(options.startDir); | |||
| if (startDir.isEmpty()) | |||
| { | |||
| // TESTING verify this whole thing... | |||
| #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(), false); | |||
| if (! startDir.endsWith(DISTRHO_OS_SEP)) | |||
| startDir += DISTRHO_OS_SEP_STR; | |||
| // -------------------------------------------------------------------------- | |||
| // configure title | |||
| String title(options.title); | |||
| if (title.isEmpty()) | |||
| { | |||
| title = puglGetWindowTitle(view); | |||
| if (title.isEmpty()) | |||
| title = "FileBrowser"; | |||
| } | |||
| // -------------------------------------------------------------------------- | |||
| // show | |||
| #ifdef HAVE_X11 | |||
| uint flags = 0x0; | |||
| // TODO flags | |||
| return sofdFileDialogShow(view, startDir, title, flags, options.width, options.height); | |||
| #endif | |||
| return false; | |||
| } | |||
| // ----------------------------------------------------------------------- | |||
| // modal handling | |||
| @@ -30,7 +30,7 @@ class TopLevelWidget; | |||
| // ----------------------------------------------------------------------- | |||
| struct Window::PrivateData : IdleCallback { | |||
| /* Reference to the DGL Application class this (private data) window associates with. */ | |||
| /** Reference to the DGL Application class this (private data) window associates with. */ | |||
| Application& app; | |||
| /** Direct access to the DGL Application private data where we registers ourselves in. */ | |||
| @@ -68,6 +68,11 @@ struct Window::PrivateData : IdleCallback { | |||
| /** Pugl minWidth, minHeight access. */ | |||
| uint minWidth, minHeight; | |||
| #ifdef DISTRHO_OS_WINDOWS | |||
| /** Selected file for openFileBrowser on windows, stored for fake async operation. */ | |||
| const char* win32SelectedFile; | |||
| #endif | |||
| /** Modal window setup. */ | |||
| struct Modal { | |||
| PrivateData* parent; // parent of this window (so we can become modal) | |||
| @@ -102,9 +107,6 @@ struct Window::PrivateData : IdleCallback { | |||
| /** Constructor for a modal window. */ | |||
| explicit PrivateData(Application& app, Window* self, PrivateData* ppData); | |||
| /** Constructor for a regular, standalone window with a transient parent. */ | |||
| // explicit PrivateData(Application& app, Window* self, Window& transientWindow); | |||
| /** Constructor for an embed Window, with a few extra hints from the host side. */ | |||
| explicit PrivateData(Application& app, Window* self, uintptr_t parentWindowHandle, double scaling, bool resizable); | |||
| @@ -118,9 +120,6 @@ struct Window::PrivateData : IdleCallback { | |||
| /** Helper initialization function called at the end of all this class constructors. */ | |||
| void init(uint width, uint height, bool resizable); | |||
| void show(); | |||
| void hide(); | |||
| /** Hide window and notify application of a window close event. | |||
| * Does nothing if window is embed (that is, not standalone). | |||
| * The application event-loop will stop when all windows have been closed. | |||
| @@ -130,17 +129,23 @@ struct Window::PrivateData : IdleCallback { | |||
| */ | |||
| void close(); | |||
| void show(); | |||
| void hide(); | |||
| void focus(); | |||
| void setResizable(bool resizable); | |||
| const GraphicsContext& getGraphicsContext() const noexcept; | |||
| // idle callback stuff | |||
| void idleCallback() override; | |||
| bool addIdleCallback(IdleCallback* callback, uint timerFrequencyInMs); | |||
| bool removeIdleCallback(IdleCallback* callback); | |||
| // file handling | |||
| bool openFileBrowser(const Window::FileBrowserOptions& options); | |||
| // modal handling | |||
| void startModal(); | |||
| void stopModal(); | |||
| @@ -1 +1 @@ | |||
| Subproject commit ecfa817136831ca2fe38561a68344f9e9076d3e7 | |||
| Subproject commit 83ccad73546576a5b439c0fe2415e16509f8f28a | |||
| @@ -89,6 +89,12 @@ | |||
| # endif | |||
| #endif | |||
| #ifdef HAVE_X11 | |||
| # define 400 | |||
| # include "sofd/libsofd.h" | |||
| # include "sofd/libsofd.c" | |||
| #endif | |||
| #ifndef DISTRHO_OS_MAC | |||
| START_NAMESPACE_DGL | |||
| #endif | |||
| @@ -355,6 +361,94 @@ void puglWin32SetWindowResizable(PuglView* const view, const bool resizable) | |||
| : GetWindowLong(impl->hwnd, GWL_STYLE) & ~WS_SIZEBOX; | |||
| SetWindowLong(impl->hwnd, GWL_STYLE, winFlags); | |||
| } | |||
| // -------------------------------------------------------------------------------------------------------------------- | |||
| #endif | |||
| #ifdef HAVE_X11 | |||
| // -------------------------------------------------------------------------------------------------------------------- | |||
| // X11 specific, setup event loop filter for sofd file dialog | |||
| static bool sofd_has_action; | |||
| static char* sofd_filename; | |||
| static bool sofd_event_filter(Display* const display, XEvent* const xevent) | |||
| { | |||
| if (x_fib_handle_events(display, xevent) == 0) | |||
| return false; | |||
| if (sofd_filename != nullptr) | |||
| std::free(sofd_filename); | |||
| if (x_fib_status() > 0) | |||
| sofd_filename = x_fib_filename(); | |||
| else | |||
| sofd_filename = nullptr; | |||
| x_fib_close(display); | |||
| sofd_has_action = true; | |||
| return true; | |||
| } | |||
| void sofdFileDialogSetup(PuglWorld* const world) | |||
| { | |||
| puglX11SetEventFilter(world, sofd_event_filter); | |||
| } | |||
| // -------------------------------------------------------------------------------------------------------------------- | |||
| // X11 specific, show file dialog via sofd | |||
| bool sofdFileDialogShow(PuglView* const view, | |||
| const char* const startDir, const char* const title, | |||
| const uint flags, const uint width, const uint height) | |||
| { | |||
| DISTRHO_SAFE_ASSERT_RETURN(x_fib_configure(0, startDir) == 0, false); | |||
| DISTRHO_SAFE_ASSERT_RETURN(x_fib_configure(1, title) == 0, false); | |||
| /* | |||
| x_fib_cfg_buttons(3, options.buttons.listAllFiles-1); | |||
| x_fib_cfg_buttons(1, options.buttons.showHidden-1); | |||
| x_fib_cfg_buttons(2, options.buttons.showPlaces-1); | |||
| */ | |||
| PuglInternals* const impl = view->impl; | |||
| return (x_fib_show(impl->display, impl->win, width, height) == 0); | |||
| } | |||
| // -------------------------------------------------------------------------------------------------------------------- | |||
| // X11 specific, close sofd file dialog | |||
| void sofdFileDialogClose(PuglView* const view) | |||
| { | |||
| PuglInternals* const impl = view->impl; | |||
| x_fib_close(impl->display); | |||
| } | |||
| // -------------------------------------------------------------------------------------------------------------------- | |||
| // X11 specific, get path chosen via sofd file dialog | |||
| bool sofdFileDialogGetPath(char** path) | |||
| { | |||
| if (! sofd_has_action) | |||
| return false; | |||
| sofd_has_action = false; | |||
| *path = sofd_filename; | |||
| return true; | |||
| } | |||
| // -------------------------------------------------------------------------------------------------------------------- | |||
| // X11 specific, free path of sofd file dialog, no longer needed | |||
| void sofdFileDialogFree(char* const path) | |||
| { | |||
| DISTRHO_SAFE_ASSERT_RETURN(path == nullptr || path == sofd_filename,); | |||
| std::free(sofd_filename); | |||
| sofd_filename = nullptr; | |||
| } | |||
| // -------------------------------------------------------------------------------------------------------------------- | |||
| #endif | |||
| // -------------------------------------------------------------------------------------------------------------------- | |||
| @@ -88,6 +88,28 @@ PUGL_API void | |||
| puglWin32SetWindowResizable(PuglView* view, bool resizable); | |||
| #endif | |||
| #ifdef HAVE_X11 | |||
| // X11 specific, setup event loop filter for sofd file dialog | |||
| PUGL_API void | |||
| sofdFileDialogSetup(PuglWorld* world); | |||
| // X11 specific, show file dialog via sofd | |||
| PUGL_API bool | |||
| sofdFileDialogShow(PuglView* view, const char* startDir, const char* title, uint flags, uint width, uint height); | |||
| // X11 specific, close sofd file dialog | |||
| PUGL_API void | |||
| sofdFileDialogClose(PuglView* view); | |||
| // X11 specific, get path chosen via sofd file dialog | |||
| PUGL_API bool | |||
| sofdFileDialogGetPath(char** path); | |||
| // X11 specific, free path of sofd file dialog, no longer needed | |||
| PUGL_API void | |||
| sofdFileDialogFree(char* path); | |||
| #endif | |||
| PUGL_END_DECLS | |||
| // -------------------------------------------------------------------------------------------------------------------- | |||
| @@ -32,7 +32,7 @@ | |||
| */ | |||
| #ifdef SOFD_TEST | |||
| #define SOFD_HAVE_X11 | |||
| #define HAVE_X11 | |||
| #include "libsofd.h" | |||
| #endif | |||
| @@ -337,7 +337,7 @@ const char *x_fib_recent_file(const char *appname) { | |||
| return NULL; | |||
| } | |||
| #ifdef SOFD_HAVE_X11 | |||
| #ifdef HAVE_X11 | |||
| #include <mntent.h> | |||
| #include <dirent.h> | |||
| @@ -475,7 +475,10 @@ static int (*_fib_filter_function)(const char *filename); | |||
| #define FAREATEXTL (FAREAMRGL + TEXTSEP) //px; filename text-left FAREAMRGL + TEXTSEP | |||
| #define SORTBTNOFF -10 //px; | |||
| #define DBLCLKTME 400 //msec; double click time | |||
| #ifndef DBLCLKTME | |||
| #define DBLCLKTME 200 //msec; double click time | |||
| #endif | |||
| #define DRAW_OUTLINE | |||
| #define DOUBLE_BUFFER | |||
| @@ -1208,7 +1211,7 @@ static int fib_dirlistadd (Display *dpy, const int i, const char* path, const ch | |||
| static int fib_openrecent (Display *dpy, const char *sel) { | |||
| int i; | |||
| unsigned int j; | |||
| unsigned int j; | |||
| assert (_recentcnt > 0); | |||
| fib_pre_opendir (dpy); | |||
| query_font_geometry (dpy, _fib_gc, "Last Used", &_fib_font_time_width, NULL, NULL, NULL); | |||
| @@ -1332,8 +1335,8 @@ static int fib_open (Display *dpy, int item) { | |||
| static void cb_cancel (Display *dpy) { | |||
| _status = -1; | |||
| // unused | |||
| return; (void)dpy; | |||
| // unused | |||
| return; (void)dpy; | |||
| } | |||
| static void cb_open (Display *dpy) { | |||
| @@ -1478,8 +1481,8 @@ static int fib_widget_at_pos (Display *dpy, int x, int y, int *it) { | |||
| return 0; | |||
| // unused | |||
| (void)dpy; | |||
| // unused | |||
| (void)dpy; | |||
| } | |||
| static void fib_update_hover (Display *dpy, int need_expose, const int type, const int item) { | |||
| @@ -1592,9 +1595,11 @@ static void fib_mousedown (Display *dpy, int x, int y, int btn, unsigned long ti | |||
| fib_select (dpy, it); | |||
| _dblclk = time; | |||
| } | |||
| /*if (_fsel >= 0) { | |||
| /* | |||
| if (_fsel >= 0) { | |||
| if (!(_dirlist[_fsel].flags & 4)); | |||
| }*/ | |||
| } | |||
| */ | |||
| } | |||
| break; | |||
| case 1: // paths | |||
| @@ -1656,8 +1661,8 @@ static void fib_mousedown (Display *dpy, int x, int y, int btn, unsigned long ti | |||
| static void fib_mouseup (Display *dpy, int x, int y, int btn, unsigned long time) { | |||
| _scrl_my = -1; | |||
| // unused | |||
| return; (void)dpy; (void)x; (void)y; (void)btn; (void)time; | |||
| // unused | |||
| return; (void)dpy; (void)x; (void)y; (void)btn; (void)time; | |||
| } | |||
| static void add_place_raw (Display *dpy, const char *name, const char *path) { | |||
| @@ -1885,8 +1890,8 @@ static int x_error_handler (Display *d, XErrorEvent *e) { | |||
| font_err = 1; | |||
| return 0; | |||
| // unused | |||
| (void)d; (void)e; | |||
| // unused | |||
| (void)d; (void)e; | |||
| } | |||
| int x_fib_show (Display *dpy, Window parent, int x, int y) { | |||
| @@ -2340,7 +2345,7 @@ char *x_fib_filename () { | |||
| else | |||
| return NULL; | |||
| } | |||
| #endif // SOFD_HAVE_X11 | |||
| #endif // HAVE_X11 | |||
| #if defined(__clang__) | |||
| # pragma clang diagnostic pop | |||
| @@ -22,10 +22,15 @@ | |||
| */ | |||
| #ifndef LIBSOFD_H | |||
| #define LIBSOFD_H | |||
| #define LIBSOFD_H 1 | |||
| #ifdef HAVE_X11 | |||
| #include <X11/Xlib.h> | |||
| #ifdef __cplusplus | |||
| extern "C" { | |||
| #endif | |||
| /////////////////////////////////////////////////////////////////////////////// | |||
| /* public API */ | |||
| @@ -110,6 +115,16 @@ int x_fib_cfg_buttons (int k, int v); | |||
| */ | |||
| int x_fib_cfg_filter_callback (int (*cb)(const char*)); | |||
| #ifdef __cplusplus | |||
| } | |||
| #endif | |||
| #endif /* END X11 specific functions */ | |||
| #ifdef __cplusplus | |||
| extern "C" { | |||
| #endif | |||
| /* 'recently used' API. x-platform | |||
| * NOTE: all functions use a static cache and are not reentrant. | |||
| * It is expected that none of these functions are called in | |||
| @@ -172,4 +187,8 @@ unsigned int x_fib_recent_count (); | |||
| */ | |||
| const char *x_fib_recent_at (unsigned int i); | |||
| #endif // LIBSOFD_H | |||
| #ifdef __cplusplus | |||
| } | |||
| #endif | |||
| #endif // header guard | |||
| @@ -246,7 +246,7 @@ protected: | |||
| # ifndef DGL_FILE_BROWSER_DISABLED | |||
| /** | |||
| File browser selected function. | |||
| @see Window::fileBrowserSelected(const char*) | |||
| @see Window::onFileSelected(const char*) | |||
| */ | |||
| virtual void uiFileBrowserSelected(const char* filename); | |||
| # endif | |||
| @@ -185,6 +185,7 @@ void UI::uiFileBrowserSelected(const char*) | |||
| void UI::uiReshape(uint, uint) | |||
| { | |||
| // NOTE this must be the same as Window::onReshape | |||
| pData->fallbackOnResize(); | |||
| } | |||
| @@ -201,7 +202,9 @@ void UI::onResize(const ResizeEvent& ev) | |||
| const uint width = ev.size.getWidth(); | |||
| const uint height = ev.size.getHeight(); | |||
| /* | |||
| pData->window.setSize(width, height); | |||
| */ | |||
| uiData->setSizeCallback(width, height); | |||
| } | |||
| #endif // !DISTRHO_PLUGIN_HAS_EXTERNAL_UI | |||
| @@ -95,25 +95,25 @@ protected: | |||
| UI::PrivateData* const uiData = fUI->uiData; | |||
| DISTRHO_SAFE_ASSERT_RETURN(uiData != nullptr,); | |||
| /* | |||
| uiData->resizeInProgress = true; | |||
| fUI->setSize(width, height); | |||
| uiData->resizeInProgress = false; | |||
| */ | |||
| fUI->uiReshape(width, height); | |||
| fIsReady = true; | |||
| } | |||
| #if 0 /* TODO */ | |||
| # ifndef DGL_FILE_BROWSER_DISABLED | |||
| // custom file-browser selected | |||
| void fileBrowserSelected(const char* filename) override | |||
| void onFileSelected(const char* const filename) override | |||
| { | |||
| DISTRHO_SAFE_ASSERT_RETURN(fUI != nullptr,); | |||
| fUI->uiFileBrowserSelected(filename); | |||
| } | |||
| # endif | |||
| #endif | |||
| private: | |||
| UI* const fUI; | |||