Signed-off-by: falkTX <falktx@falktx.com>pull/272/head
| @@ -265,7 +265,7 @@ endif | |||||
| ifneq ($(HAIKU_OR_MACOS_OR_WINDOWS),true) | ifneq ($(HAIKU_OR_MACOS_OR_WINDOWS),true) | ||||
| ifeq ($(HAVE_X11),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) | DGL_SYSTEM_LIBS += $(shell $(PKG_CONFIG) --libs x11) | ||||
| ifeq ($(HAVE_XCURSOR),true) | ifeq ($(HAVE_XCURSOR),true) | ||||
| # TODO -DHAVE_XCURSOR | # TODO -DHAVE_XCURSOR | ||||
| @@ -50,6 +50,60 @@ class TopLevelWidget; | |||||
| class Window | class Window | ||||
| { | { | ||||
| public: | 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. | Constructor for a regular, standalone window. | ||||
| */ | */ | ||||
| @@ -130,7 +184,18 @@ public: | |||||
| */ | */ | ||||
| void close(); | void close(); | ||||
| /** | |||||
| Check if this window is resizable. | |||||
| @see setResizable | |||||
| */ | |||||
| bool isResizable() const noexcept; | 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); | void setResizable(bool resizable); | ||||
| /** | /** | ||||
| @@ -247,6 +312,17 @@ public: | |||||
| */ | */ | ||||
| void focus(); | 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. | Request repaint of this window, for the entire area. | ||||
| */ | */ | ||||
| @@ -272,16 +348,15 @@ public: | |||||
| bool keepAspectRatio = false, | bool keepAspectRatio = false, | ||||
| bool automaticallyScale = false); | bool automaticallyScale = false); | ||||
| /* | |||||
| void setTransientWinId(uintptr_t winId); | |||||
| */ | |||||
| /** DEPRECATED Use isIgnoringKeyRepeat(). */ | |||||
| DISTRHO_DEPRECATED_BY("isIgnoringKeyRepeat()") | DISTRHO_DEPRECATED_BY("isIgnoringKeyRepeat()") | ||||
| inline bool getIgnoringKeyRepeat() const noexcept { return isIgnoringKeyRepeat(); } | inline bool getIgnoringKeyRepeat() const noexcept { return isIgnoringKeyRepeat(); } | ||||
| /** DEPRECATED Use getScaleFactor(). */ | |||||
| DISTRHO_DEPRECATED_BY("getScaleFactor()") | DISTRHO_DEPRECATED_BY("getScaleFactor()") | ||||
| inline double getScaling() const noexcept { return getScaleFactor(); } | inline double getScaling() const noexcept { return getScaleFactor(); } | ||||
| /** DEPRECATED Use runAsModal(bool). */ | |||||
| DISTRHO_DEPRECATED_BY("runAsModal(bool)") | DISTRHO_DEPRECATED_BY("runAsModal(bool)") | ||||
| inline void exec(bool blockWait = false) { runAsModal(blockWait); } | inline void exec(bool blockWait = false) { runAsModal(blockWait); } | ||||
| @@ -302,9 +377,23 @@ protected: | |||||
| /** | /** | ||||
| A function called when the window is resized. | 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. | 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); | 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: | private: | ||||
| struct PrivateData; | struct PrivateData; | ||||
| PrivateData* const pData; | PrivateData* const pData; | ||||
| @@ -319,62 +408,10 @@ private: | |||||
| END_NAMESPACE_DGL | END_NAMESPACE_DGL | ||||
| /* TODO | /* TODO | ||||
| * add focusEvent with CrossingMode arg | |||||
| * add eventcrossing/enter-leave event | * add eventcrossing/enter-leave event | ||||
| */ | */ | ||||
| #if 0 | #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: | protected: | ||||
| #ifndef DGL_FILE_BROWSER_DISABLED | |||||
| virtual void fileBrowserSelected(const char* filename); | |||||
| #endif | |||||
| bool handlePluginKeyboard(const bool press, const uint key); | bool handlePluginKeyboard(const bool press, const uint key); | ||||
| bool handlePluginSpecial(const bool press, const Key key); | bool handlePluginSpecial(const bool press, const Key key); | ||||
| #endif | #endif | ||||
| @@ -201,6 +201,13 @@ void Window::focus() | |||||
| pData->focus(); | pData->focus(); | ||||
| } | } | ||||
| #ifndef DGL_FILE_BROWSER_DISABLED | |||||
| bool Window::openFileBrowser(const FileBrowserOptions& options) | |||||
| { | |||||
| return pData->openFileBrowser(options); | |||||
| } | |||||
| #endif | |||||
| void Window::repaint() noexcept | void Window::repaint() noexcept | ||||
| { | { | ||||
| puglPostRedisplay(pData->view); | puglPostRedisplay(pData->view); | ||||
| @@ -271,51 +278,20 @@ void Window::onReshape(uint, uint) | |||||
| puglFallbackOnResize(pData->view); | 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) | bool Window::handlePluginKeyboard(const bool press, const uint key) | ||||
| { | { | ||||
| // TODO | // TODO | ||||
| @@ -19,6 +19,14 @@ | |||||
| #include "pugl.hpp" | #include "pugl.hpp" | ||||
| #include "../../distrho/extra/String.hpp" | |||||
| #ifdef DISTRHO_OS_WINDOWS | |||||
| # include <direct.h> | |||||
| #else | |||||
| # include <unistd.h> | |||||
| #endif | |||||
| #define DGL_DEBUG_EVENTS | #define DGL_DEBUG_EVENTS | ||||
| #if defined(DEBUG) && defined(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), | autoScaleFactor(1.0), | ||||
| minWidth(0), | minWidth(0), | ||||
| minHeight(0), | minHeight(0), | ||||
| #ifdef DISTRHO_OS_WINDOWS | |||||
| win32SelectedFile(nullptr), | |||||
| #endif | |||||
| modal() | modal() | ||||
| { | { | ||||
| init(DEFAULT_WIDTH, DEFAULT_HEIGHT, false); | init(DEFAULT_WIDTH, DEFAULT_HEIGHT, false); | ||||
| @@ -85,6 +96,9 @@ Window::PrivateData::PrivateData(Application& a, Window* const s, PrivateData* c | |||||
| autoScaleFactor(1.0), | autoScaleFactor(1.0), | ||||
| minWidth(0), | minWidth(0), | ||||
| minHeight(0), | minHeight(0), | ||||
| #ifdef DISTRHO_OS_WINDOWS | |||||
| win32SelectedFile(nullptr), | |||||
| #endif | |||||
| modal(ppData) | modal(ppData) | ||||
| { | { | ||||
| init(DEFAULT_WIDTH, DEFAULT_HEIGHT, false); | init(DEFAULT_WIDTH, DEFAULT_HEIGHT, false); | ||||
| @@ -108,6 +122,9 @@ Window::PrivateData::PrivateData(Application& a, Window* const s, | |||||
| autoScaleFactor(1.0), | autoScaleFactor(1.0), | ||||
| minWidth(0), | minWidth(0), | ||||
| minHeight(0), | minHeight(0), | ||||
| #ifdef DISTRHO_OS_WINDOWS | |||||
| win32SelectedFile(nullptr), | |||||
| #endif | |||||
| modal() | modal() | ||||
| { | { | ||||
| if (isEmbed) | if (isEmbed) | ||||
| @@ -142,6 +159,9 @@ Window::PrivateData::PrivateData(Application& a, Window* const s, | |||||
| autoScaleFactor(1.0), | autoScaleFactor(1.0), | ||||
| minWidth(0), | minWidth(0), | ||||
| minHeight(0), | minHeight(0), | ||||
| #ifdef DISTRHO_OS_WINDOWS | |||||
| win32SelectedFile(nullptr), | |||||
| #endif | |||||
| modal() | modal() | ||||
| { | { | ||||
| if (isEmbed) | if (isEmbed) | ||||
| @@ -163,6 +183,9 @@ Window::PrivateData::~PrivateData() | |||||
| { | { | ||||
| if (isEmbed) | if (isEmbed) | ||||
| { | { | ||||
| #ifdef HAVE_X11 | |||||
| sofdFileDialogClose(view); | |||||
| #endif | |||||
| puglHide(view); | puglHide(view); | ||||
| appData->oneWindowClosed(); | appData->oneWindowClosed(); | ||||
| isClosed = true; | 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); | puglSetViewHint(view, PUGL_STENCIL_BITS, 8); | ||||
| // PUGL_SAMPLES ?? | // PUGL_SAMPLES ?? | ||||
| puglSetEventFunc(view, puglEventCallback); | puglSetEventFunc(view, puglEventCallback); | ||||
| // #ifndef DGL_FILE_BROWSER_DISABLED | |||||
| // puglSetFileSelectedFunc(fView, fileBrowserSelectedCallback); | |||||
| // #endif | |||||
| PuglRect rect = puglGetFrame(view); | PuglRect rect = puglGetFrame(view); | ||||
| rect.width = width; | 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() | void Window::PrivateData::show() | ||||
| { | { | ||||
| if (isVisible) | if (isVisible) | ||||
| @@ -293,6 +328,9 @@ void Window::PrivateData::hide() | |||||
| if (modal.enabled) | if (modal.enabled) | ||||
| stopModal(); | stopModal(); | ||||
| #ifdef HAVE_X11 | |||||
| sofdFileDialogClose(view); | |||||
| #endif | |||||
| puglHide(view); | puglHide(view); | ||||
| isVisible = false; | 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() | void Window::PrivateData::focus() | ||||
| { | { | ||||
| if (! isEmbed) | if (! isEmbed) | ||||
| @@ -341,20 +364,29 @@ void Window::PrivateData::setResizable(const bool resizable) | |||||
| void Window::PrivateData::idleCallback() | 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) | 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; | 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 | // modal handling | ||||
| @@ -30,7 +30,7 @@ class TopLevelWidget; | |||||
| // ----------------------------------------------------------------------- | // ----------------------------------------------------------------------- | ||||
| struct Window::PrivateData : IdleCallback { | 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; | Application& app; | ||||
| /** Direct access to the DGL Application private data where we registers ourselves in. */ | /** 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. */ | /** Pugl minWidth, minHeight access. */ | ||||
| uint minWidth, minHeight; | 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. */ | /** Modal window setup. */ | ||||
| struct Modal { | struct Modal { | ||||
| PrivateData* parent; // parent of this window (so we can become 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. */ | /** Constructor for a modal window. */ | ||||
| explicit PrivateData(Application& app, Window* self, PrivateData* ppData); | 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. */ | /** 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); | 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. */ | /** Helper initialization function called at the end of all this class constructors. */ | ||||
| void init(uint width, uint height, bool resizable); | void init(uint width, uint height, bool resizable); | ||||
| void show(); | |||||
| void hide(); | |||||
| /** Hide window and notify application of a window close event. | /** Hide window and notify application of a window close event. | ||||
| * Does nothing if window is embed (that is, not standalone). | * Does nothing if window is embed (that is, not standalone). | ||||
| * The application event-loop will stop when all windows have been closed. | * The application event-loop will stop when all windows have been closed. | ||||
| @@ -130,17 +129,23 @@ struct Window::PrivateData : IdleCallback { | |||||
| */ | */ | ||||
| void close(); | void close(); | ||||
| void show(); | |||||
| void hide(); | |||||
| void focus(); | void focus(); | ||||
| void setResizable(bool resizable); | void setResizable(bool resizable); | ||||
| const GraphicsContext& getGraphicsContext() const noexcept; | const GraphicsContext& getGraphicsContext() const noexcept; | ||||
| // idle callback stuff | |||||
| void idleCallback() override; | void idleCallback() override; | ||||
| bool addIdleCallback(IdleCallback* callback, uint timerFrequencyInMs); | bool addIdleCallback(IdleCallback* callback, uint timerFrequencyInMs); | ||||
| bool removeIdleCallback(IdleCallback* callback); | bool removeIdleCallback(IdleCallback* callback); | ||||
| // file handling | |||||
| bool openFileBrowser(const Window::FileBrowserOptions& options); | |||||
| // modal handling | // modal handling | ||||
| void startModal(); | void startModal(); | ||||
| void stopModal(); | void stopModal(); | ||||
| @@ -1 +1 @@ | |||||
| Subproject commit ecfa817136831ca2fe38561a68344f9e9076d3e7 | |||||
| Subproject commit 83ccad73546576a5b439c0fe2415e16509f8f28a | |||||
| @@ -89,6 +89,12 @@ | |||||
| # endif | # endif | ||||
| #endif | #endif | ||||
| #ifdef HAVE_X11 | |||||
| # define 400 | |||||
| # include "sofd/libsofd.h" | |||||
| # include "sofd/libsofd.c" | |||||
| #endif | |||||
| #ifndef DISTRHO_OS_MAC | #ifndef DISTRHO_OS_MAC | ||||
| START_NAMESPACE_DGL | START_NAMESPACE_DGL | ||||
| #endif | #endif | ||||
| @@ -355,6 +361,94 @@ void puglWin32SetWindowResizable(PuglView* const view, const bool resizable) | |||||
| : GetWindowLong(impl->hwnd, GWL_STYLE) & ~WS_SIZEBOX; | : GetWindowLong(impl->hwnd, GWL_STYLE) & ~WS_SIZEBOX; | ||||
| SetWindowLong(impl->hwnd, GWL_STYLE, winFlags); | 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 | #endif | ||||
| // -------------------------------------------------------------------------------------------------------------------- | // -------------------------------------------------------------------------------------------------------------------- | ||||
| @@ -88,6 +88,28 @@ PUGL_API void | |||||
| puglWin32SetWindowResizable(PuglView* view, bool resizable); | puglWin32SetWindowResizable(PuglView* view, bool resizable); | ||||
| #endif | #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 | PUGL_END_DECLS | ||||
| // -------------------------------------------------------------------------------------------------------------------- | // -------------------------------------------------------------------------------------------------------------------- | ||||
| @@ -32,7 +32,7 @@ | |||||
| */ | */ | ||||
| #ifdef SOFD_TEST | #ifdef SOFD_TEST | ||||
| #define SOFD_HAVE_X11 | |||||
| #define HAVE_X11 | |||||
| #include "libsofd.h" | #include "libsofd.h" | ||||
| #endif | #endif | ||||
| @@ -337,7 +337,7 @@ const char *x_fib_recent_file(const char *appname) { | |||||
| return NULL; | return NULL; | ||||
| } | } | ||||
| #ifdef SOFD_HAVE_X11 | |||||
| #ifdef HAVE_X11 | |||||
| #include <mntent.h> | #include <mntent.h> | ||||
| #include <dirent.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 FAREATEXTL (FAREAMRGL + TEXTSEP) //px; filename text-left FAREAMRGL + TEXTSEP | ||||
| #define SORTBTNOFF -10 //px; | #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 DRAW_OUTLINE | ||||
| #define DOUBLE_BUFFER | #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) { | static int fib_openrecent (Display *dpy, const char *sel) { | ||||
| int i; | int i; | ||||
| unsigned int j; | |||||
| unsigned int j; | |||||
| assert (_recentcnt > 0); | assert (_recentcnt > 0); | ||||
| fib_pre_opendir (dpy); | fib_pre_opendir (dpy); | ||||
| query_font_geometry (dpy, _fib_gc, "Last Used", &_fib_font_time_width, NULL, NULL, NULL); | 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) { | static void cb_cancel (Display *dpy) { | ||||
| _status = -1; | _status = -1; | ||||
| // unused | |||||
| return; (void)dpy; | |||||
| // unused | |||||
| return; (void)dpy; | |||||
| } | } | ||||
| static void cb_open (Display *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; | return 0; | ||||
| // unused | |||||
| (void)dpy; | |||||
| // unused | |||||
| (void)dpy; | |||||
| } | } | ||||
| static void fib_update_hover (Display *dpy, int need_expose, const int type, const int item) { | 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); | fib_select (dpy, it); | ||||
| _dblclk = time; | _dblclk = time; | ||||
| } | } | ||||
| /*if (_fsel >= 0) { | |||||
| /* | |||||
| if (_fsel >= 0) { | |||||
| if (!(_dirlist[_fsel].flags & 4)); | if (!(_dirlist[_fsel].flags & 4)); | ||||
| }*/ | |||||
| } | |||||
| */ | |||||
| } | } | ||||
| break; | break; | ||||
| case 1: // paths | 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) { | static void fib_mouseup (Display *dpy, int x, int y, int btn, unsigned long time) { | ||||
| _scrl_my = -1; | _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) { | 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; | font_err = 1; | ||||
| return 0; | return 0; | ||||
| // unused | |||||
| (void)d; (void)e; | |||||
| // unused | |||||
| (void)d; (void)e; | |||||
| } | } | ||||
| int x_fib_show (Display *dpy, Window parent, int x, int y) { | int x_fib_show (Display *dpy, Window parent, int x, int y) { | ||||
| @@ -2340,7 +2345,7 @@ char *x_fib_filename () { | |||||
| else | else | ||||
| return NULL; | return NULL; | ||||
| } | } | ||||
| #endif // SOFD_HAVE_X11 | |||||
| #endif // HAVE_X11 | |||||
| #if defined(__clang__) | #if defined(__clang__) | ||||
| # pragma clang diagnostic pop | # pragma clang diagnostic pop | ||||
| @@ -22,10 +22,15 @@ | |||||
| */ | */ | ||||
| #ifndef LIBSOFD_H | #ifndef LIBSOFD_H | ||||
| #define LIBSOFD_H | |||||
| #define LIBSOFD_H 1 | |||||
| #ifdef HAVE_X11 | |||||
| #include <X11/Xlib.h> | #include <X11/Xlib.h> | ||||
| #ifdef __cplusplus | |||||
| extern "C" { | |||||
| #endif | |||||
| /////////////////////////////////////////////////////////////////////////////// | /////////////////////////////////////////////////////////////////////////////// | ||||
| /* public API */ | /* 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*)); | 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 | /* 'recently used' API. x-platform | ||||
| * NOTE: all functions use a static cache and are not reentrant. | * NOTE: all functions use a static cache and are not reentrant. | ||||
| * It is expected that none of these functions are called in | * 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); | 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 | # ifndef DGL_FILE_BROWSER_DISABLED | ||||
| /** | /** | ||||
| File browser selected function. | File browser selected function. | ||||
| @see Window::fileBrowserSelected(const char*) | |||||
| @see Window::onFileSelected(const char*) | |||||
| */ | */ | ||||
| virtual void uiFileBrowserSelected(const char* filename); | virtual void uiFileBrowserSelected(const char* filename); | ||||
| # endif | # endif | ||||
| @@ -185,6 +185,7 @@ void UI::uiFileBrowserSelected(const char*) | |||||
| void UI::uiReshape(uint, uint) | void UI::uiReshape(uint, uint) | ||||
| { | { | ||||
| // NOTE this must be the same as Window::onReshape | |||||
| pData->fallbackOnResize(); | pData->fallbackOnResize(); | ||||
| } | } | ||||
| @@ -201,7 +202,9 @@ void UI::onResize(const ResizeEvent& ev) | |||||
| const uint width = ev.size.getWidth(); | const uint width = ev.size.getWidth(); | ||||
| const uint height = ev.size.getHeight(); | const uint height = ev.size.getHeight(); | ||||
| /* | |||||
| pData->window.setSize(width, height); | pData->window.setSize(width, height); | ||||
| */ | |||||
| uiData->setSizeCallback(width, height); | uiData->setSizeCallback(width, height); | ||||
| } | } | ||||
| #endif // !DISTRHO_PLUGIN_HAS_EXTERNAL_UI | #endif // !DISTRHO_PLUGIN_HAS_EXTERNAL_UI | ||||
| @@ -95,25 +95,25 @@ protected: | |||||
| UI::PrivateData* const uiData = fUI->uiData; | UI::PrivateData* const uiData = fUI->uiData; | ||||
| DISTRHO_SAFE_ASSERT_RETURN(uiData != nullptr,); | DISTRHO_SAFE_ASSERT_RETURN(uiData != nullptr,); | ||||
| /* | |||||
| uiData->resizeInProgress = true; | uiData->resizeInProgress = true; | ||||
| fUI->setSize(width, height); | fUI->setSize(width, height); | ||||
| uiData->resizeInProgress = false; | uiData->resizeInProgress = false; | ||||
| */ | |||||
| fUI->uiReshape(width, height); | fUI->uiReshape(width, height); | ||||
| fIsReady = true; | fIsReady = true; | ||||
| } | } | ||||
| #if 0 /* TODO */ | |||||
| # ifndef DGL_FILE_BROWSER_DISABLED | # ifndef DGL_FILE_BROWSER_DISABLED | ||||
| // custom file-browser selected | // custom file-browser selected | ||||
| void fileBrowserSelected(const char* filename) override | |||||
| void onFileSelected(const char* const filename) override | |||||
| { | { | ||||
| DISTRHO_SAFE_ASSERT_RETURN(fUI != nullptr,); | DISTRHO_SAFE_ASSERT_RETURN(fUI != nullptr,); | ||||
| fUI->uiFileBrowserSelected(filename); | fUI->uiFileBrowserSelected(filename); | ||||
| } | } | ||||
| # endif | # endif | ||||
| #endif | |||||
| private: | private: | ||||
| UI* const fUI; | UI* const fUI; | ||||