| @@ -1,5 +1,5 @@ | |||||
| DISTRHO Plugin Framework (DPF) | DISTRHO Plugin Framework (DPF) | ||||
| Copyright (C) 2012-2014 Filipe Coelho <falktx@falktx.com> | |||||
| Copyright (C) 2012-2018 Filipe Coelho <falktx@falktx.com> | |||||
| Permission to use, copy, modify, and/or distribute this software for any purpose with | 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 | or without fee is hereby granted, provided that the above copyright notice and this | ||||
| @@ -77,12 +77,12 @@ all: | |||||
| # Common | # Common | ||||
| $(BUILD_DIR)/%.c.o: %.c | $(BUILD_DIR)/%.c.o: %.c | ||||
| -@mkdir -p $(BUILD_DIR) | |||||
| -@mkdir -p "$(shell dirname $(BUILD_DIR)/$<)" | |||||
| @echo "Compiling $<" | @echo "Compiling $<" | ||||
| @$(CC) $< $(BUILD_C_FLAGS) -c -o $@ | @$(CC) $< $(BUILD_C_FLAGS) -c -o $@ | ||||
| $(BUILD_DIR)/%.cpp.o: %.cpp | $(BUILD_DIR)/%.cpp.o: %.cpp | ||||
| -@mkdir -p $(BUILD_DIR) | |||||
| -@mkdir -p "$(shell dirname $(BUILD_DIR)/$<)" | |||||
| @echo "Compiling $<" | @echo "Compiling $<" | ||||
| @$(CXX) $< $(BUILD_CXX_FLAGS) -c -o $@ | @$(CXX) $< $(BUILD_CXX_FLAGS) -c -o $@ | ||||
| @@ -27,6 +27,9 @@ List of plugins made with DPF:<br/> | |||||
| - [DISTRHO ndc Plugs](https://github.com/DISTRHO/ndc-Plugs) | - [DISTRHO ndc Plugs](https://github.com/DISTRHO/ndc-Plugs) | ||||
| - [Juice Plugins](https://github.com/DISTRHO/JuicePlugins) (work in progress) | - [Juice Plugins](https://github.com/DISTRHO/JuicePlugins) (work in progress) | ||||
| - [ZamAudio Suite](https://github.com/zamaudio/zam-plugins) | - [ZamAudio Suite](https://github.com/zamaudio/zam-plugins) | ||||
| - [DragonFly-Reverb](https://github.com/michaelwillis/dragonfly-reverb) | |||||
| - [Wolf-Shaper](https://github.com/pdesaulniers/wolf-shaper) | |||||
| - [YK Chorus](https://github.com/SpotlightKid/ykchorus) | |||||
| Plugin examples are available in the `example/` folder inside this repo.<br/> | Plugin examples are available in the `example/` folder inside this repo.<br/> | ||||
| @@ -240,7 +240,7 @@ public: | |||||
| { | { | ||||
| public: | public: | ||||
| virtual ~Callback() {} | virtual ~Callback() {} | ||||
| virtual void imageSwitchClicked(ImageSwitch* imageButton, bool down) = 0; | |||||
| virtual void imageSwitchClicked(ImageSwitch* imageSwitch, bool down) = 0; | |||||
| }; | }; | ||||
| explicit ImageSwitch(Window& parent, const Image& imageNormal, const Image& imageDown) noexcept; | explicit ImageSwitch(Window& parent, const Image& imageNormal, const Image& imageDown) noexcept; | ||||
| @@ -92,6 +92,8 @@ public: | |||||
| bool openFileBrowser(const FileBrowserOptions& options); | bool openFileBrowser(const FileBrowserOptions& options); | ||||
| #endif | #endif | ||||
| bool isEmbed() const noexcept; | |||||
| bool isVisible() const noexcept; | bool isVisible() const noexcept; | ||||
| void setVisible(bool yesNo); | void setVisible(bool yesNo); | ||||
| @@ -107,8 +109,15 @@ public: | |||||
| const char* getTitle() const noexcept; | const char* getTitle() const noexcept; | ||||
| void setTitle(const char* title); | void setTitle(const char* title); | ||||
| void setGeometryConstraints(uint width, uint height, bool aspect); | |||||
| void setTransientWinId(uintptr_t winId); | void setTransientWinId(uintptr_t winId); | ||||
| double getScaling() const noexcept; | |||||
| void setScaling(double scaling) noexcept; | |||||
| bool getIgnoringKeyRepeat() const noexcept; | |||||
| void setIgnoringKeyRepeat(bool ignore) noexcept; | |||||
| Application& getApp() const noexcept; | Application& getApp() const noexcept; | ||||
| intptr_t getWindowId() const noexcept; | intptr_t getWindowId() const noexcept; | ||||
| @@ -237,7 +237,7 @@ bool Size<T>::isNotNull() const noexcept | |||||
| template<typename T> | template<typename T> | ||||
| bool Size<T>::isValid() const noexcept | bool Size<T>::isValid() const noexcept | ||||
| { | { | ||||
| return fWidth > 1 && fHeight > 1; | |||||
| return fWidth > 0 && fHeight > 0; | |||||
| } | } | ||||
| template<typename T> | template<typename T> | ||||
| @@ -447,10 +447,8 @@ void NanoVG::translate(float x, float y) | |||||
| void NanoVG::rotate(float angle) | void NanoVG::rotate(float angle) | ||||
| { | { | ||||
| if (fContext == nullptr) return; | |||||
| DISTRHO_SAFE_ASSERT_RETURN(angle > 0.0f,); | |||||
| nvgRotate(fContext, angle); | |||||
| if (fContext != nullptr) | |||||
| nvgRotate(fContext, angle); | |||||
| } | } | ||||
| void NanoVG::skewX(float angle) | void NanoVG::skewX(float angle) | ||||
| @@ -63,7 +63,7 @@ struct Widget::PrivateData { | |||||
| subWidgets.clear(); | subWidgets.clear(); | ||||
| } | } | ||||
| void display(const uint width, const uint height, const bool renderingSubWidget) | |||||
| void display(const uint width, const uint height, const double scaling, const bool renderingSubWidget) | |||||
| { | { | ||||
| if ((skipDisplay && ! renderingSubWidget) || size.isInvalid() || ! visible) | if ((skipDisplay && ! renderingSubWidget) || size.isInvalid() || ! visible) | ||||
| return; | return; | ||||
| @@ -76,29 +76,32 @@ struct Widget::PrivateData { | |||||
| if (needsFullViewport || (absolutePos.isZero() && size == Size<uint>(width, height))) | if (needsFullViewport || (absolutePos.isZero() && size == Size<uint>(width, height))) | ||||
| { | { | ||||
| // full viewport size | // full viewport size | ||||
| glViewport(0, 0, static_cast<GLsizei>(width), static_cast<GLsizei>(height)); | |||||
| glViewport(0, | |||||
| -(height * scaling - height), | |||||
| width * scaling, | |||||
| height * scaling); | |||||
| } | } | ||||
| else if (needsScaling) | else if (needsScaling) | ||||
| { | { | ||||
| // limit viewport to widget bounds | // limit viewport to widget bounds | ||||
| glViewport(absolutePos.getX(), | glViewport(absolutePos.getX(), | ||||
| static_cast<int>(height - self->getHeight()) - absolutePos.getY(), | |||||
| static_cast<GLsizei>(self->getWidth()), | |||||
| static_cast<GLsizei>(self->getHeight())); | |||||
| height - self->getHeight() - absolutePos.getY(), | |||||
| self->getWidth(), | |||||
| self->getHeight()); | |||||
| } | } | ||||
| else | else | ||||
| { | { | ||||
| // only set viewport pos | // only set viewport pos | ||||
| glViewport(absolutePos.getX(), | |||||
| /*static_cast<int>(height - self->getHeight())*/ - absolutePos.getY(), | |||||
| static_cast<GLsizei>(width), | |||||
| static_cast<GLsizei>(height)); | |||||
| glViewport(absolutePos.getX() * scaling, | |||||
| -std::round((height * scaling - height) + (absolutePos.getY() * scaling)), | |||||
| std::round(width * scaling), | |||||
| std::round(height * scaling)); | |||||
| // then cut the outer bounds | // then cut the outer bounds | ||||
| glScissor(absolutePos.getX(), | |||||
| static_cast<int>(height - self->getHeight()) - absolutePos.getY(), | |||||
| static_cast<GLsizei>(self->getWidth()), | |||||
| static_cast<GLsizei>(self->getHeight())); | |||||
| glScissor(absolutePos.getX() * scaling, | |||||
| height - std::round((self->getHeight() + absolutePos.getY()) * scaling), | |||||
| std::round(self->getWidth() * scaling), | |||||
| std::round(self->getHeight() * scaling)); | |||||
| glEnable(GL_SCISSOR_TEST); | glEnable(GL_SCISSOR_TEST); | ||||
| needsDisableScissor = true; | needsDisableScissor = true; | ||||
| @@ -113,17 +116,17 @@ struct Widget::PrivateData { | |||||
| needsDisableScissor = false; | needsDisableScissor = false; | ||||
| } | } | ||||
| displaySubWidgets(width, height); | |||||
| displaySubWidgets(width, height, scaling); | |||||
| } | } | ||||
| void displaySubWidgets(const uint width, const uint height) | |||||
| void displaySubWidgets(const uint width, const uint height, const double scaling) | |||||
| { | { | ||||
| for (std::vector<Widget*>::iterator it = subWidgets.begin(); it != subWidgets.end(); ++it) | for (std::vector<Widget*>::iterator it = subWidgets.begin(); it != subWidgets.end(); ++it) | ||||
| { | { | ||||
| Widget* const widget(*it); | Widget* const widget(*it); | ||||
| DISTRHO_SAFE_ASSERT_CONTINUE(widget->pData != this); | DISTRHO_SAFE_ASSERT_CONTINUE(widget->pData != this); | ||||
| widget->pData->display(width, height, true); | |||||
| widget->pData->display(width, height, scaling, true); | |||||
| } | } | ||||
| } | } | ||||
| @@ -19,10 +19,6 @@ | |||||
| #include "../Base.hpp" | #include "../Base.hpp" | ||||
| #undef PUGL_HAVE_CAIRO | |||||
| #undef PUGL_HAVE_GL | |||||
| #define PUGL_HAVE_GL 1 | |||||
| #include "pugl/pugl.h" | #include "pugl/pugl.h" | ||||
| #if defined(__GNUC__) && (__GNUC__ >= 7) | #if defined(__GNUC__) && (__GNUC__ >= 7) | ||||
| @@ -61,7 +57,7 @@ extern "C" { | |||||
| #define FOR_EACH_WIDGET_INV(rit) \ | #define FOR_EACH_WIDGET_INV(rit) \ | ||||
| for (std::list<Widget*>::reverse_iterator rit = fWidgets.rbegin(); rit != fWidgets.rend(); ++rit) | for (std::list<Widget*>::reverse_iterator rit = fWidgets.rbegin(); rit != fWidgets.rend(); ++rit) | ||||
| #ifdef DEBUG | |||||
| #if defined(DEBUG) && defined(DGL_DEBUG_EVENTS) | |||||
| # define DBG(msg) std::fprintf(stderr, "%s", msg); | # define DBG(msg) std::fprintf(stderr, "%s", msg); | ||||
| # define DBGp(...) std::fprintf(stderr, __VA_ARGS__); | # define DBGp(...) std::fprintf(stderr, __VA_ARGS__); | ||||
| # define DBGF std::fflush(stderr); | # define DBGF std::fflush(stderr); | ||||
| @@ -87,6 +83,7 @@ struct Window::PrivateData { | |||||
| fUsingEmbed(false), | fUsingEmbed(false), | ||||
| fWidth(1), | fWidth(1), | ||||
| fHeight(1), | fHeight(1), | ||||
| fScaling(1.0), | |||||
| fTitle(nullptr), | fTitle(nullptr), | ||||
| fWidgets(), | fWidgets(), | ||||
| fModal(), | fModal(), | ||||
| @@ -117,6 +114,7 @@ struct Window::PrivateData { | |||||
| fUsingEmbed(false), | fUsingEmbed(false), | ||||
| fWidth(1), | fWidth(1), | ||||
| fHeight(1), | fHeight(1), | ||||
| fScaling(1.0), | |||||
| fTitle(nullptr), | fTitle(nullptr), | ||||
| fWidgets(), | fWidgets(), | ||||
| fModal(parent.pData), | fModal(parent.pData), | ||||
| @@ -159,6 +157,7 @@ struct Window::PrivateData { | |||||
| fUsingEmbed(parentId != 0), | fUsingEmbed(parentId != 0), | ||||
| fWidth(1), | fWidth(1), | ||||
| fHeight(1), | fHeight(1), | ||||
| fScaling(1.0), | |||||
| fTitle(nullptr), | fTitle(nullptr), | ||||
| fWidgets(), | fWidgets(), | ||||
| fModal(), | fModal(), | ||||
| @@ -204,7 +203,6 @@ struct Window::PrivateData { | |||||
| return; | return; | ||||
| } | } | ||||
| puglInitContextType(fView, PUGL_GL); | |||||
| puglInitUserResizable(fView, fResizable); | puglInitUserResizable(fView, fResizable); | ||||
| puglInitWindowSize(fView, static_cast<int>(fWidth), static_cast<int>(fHeight)); | puglInitWindowSize(fView, static_cast<int>(fWidth), static_cast<int>(fHeight)); | ||||
| @@ -539,6 +537,7 @@ struct Window::PrivateData { | |||||
| DBG("Window setResizable called\n"); | DBG("Window setResizable called\n"); | ||||
| fResizable = yesNo; | fResizable = yesNo; | ||||
| fView->user_resizable = yesNo; | |||||
| #if defined(DISTRHO_OS_WINDOWS) | #if defined(DISTRHO_OS_WINDOWS) | ||||
| const int winFlags = fResizable ? GetWindowLong(hwnd, GWL_STYLE) | WS_SIZEBOX | const int winFlags = fResizable ? GetWindowLong(hwnd, GWL_STYLE) | WS_SIZEBOX | ||||
| @@ -554,6 +553,17 @@ struct Window::PrivateData { | |||||
| // ------------------------------------------------------------------- | // ------------------------------------------------------------------- | ||||
| void setGeometryConstraints(uint width, uint height, bool aspect) | |||||
| { | |||||
| DISTRHO_SAFE_ASSERT_RETURN(fResizable,); | |||||
| fView->min_width = width; | |||||
| fView->min_height = height; | |||||
| puglUpdateGeometryConstraints(fView, width, height, aspect); | |||||
| } | |||||
| // ------------------------------------------------------------------- | |||||
| void setSize(uint width, uint height, const bool forced = false) | void setSize(uint width, uint height, const bool forced = false) | ||||
| { | { | ||||
| if (width <= 1 || height <= 1) | if (width <= 1 || height <= 1) | ||||
| @@ -605,7 +615,6 @@ struct Window::PrivateData { | |||||
| } | } | ||||
| } | } | ||||
| #else | #else | ||||
| XResizeWindow(xDisplay, xWindow, width, height); | |||||
| if (! fResizable) | if (! fResizable) | ||||
| { | { | ||||
| @@ -620,9 +629,11 @@ struct Window::PrivateData { | |||||
| sizeHints.max_width = static_cast<int>(width); | sizeHints.max_width = static_cast<int>(width); | ||||
| sizeHints.max_height = static_cast<int>(height); | sizeHints.max_height = static_cast<int>(height); | ||||
| XSetNormalHints(xDisplay, xWindow, &sizeHints); | |||||
| XSetWMNormalHints(xDisplay, xWindow, &sizeHints); | |||||
| } | } | ||||
| XResizeWindow(xDisplay, xWindow, width, height); | |||||
| if (! forced) | if (! forced) | ||||
| XFlush(xDisplay); | XFlush(xDisplay); | ||||
| #endif | #endif | ||||
| @@ -685,6 +696,32 @@ struct Window::PrivateData { | |||||
| // ------------------------------------------------------------------- | // ------------------------------------------------------------------- | ||||
| double getScaling() const noexcept | |||||
| { | |||||
| return fScaling; | |||||
| } | |||||
| void setScaling(double scaling) noexcept | |||||
| { | |||||
| DISTRHO_SAFE_ASSERT_RETURN(scaling > 0.0,); | |||||
| fScaling = scaling; | |||||
| } | |||||
| // ------------------------------------------------------------------- | |||||
| bool getIgnoringKeyRepeat() const noexcept | |||||
| { | |||||
| return fView->ignoreKeyRepeat; | |||||
| } | |||||
| void setIgnoringKeyRepeat(bool ignore) noexcept | |||||
| { | |||||
| puglIgnoreKeyRepeat(fView, ignore); | |||||
| } | |||||
| // ------------------------------------------------------------------- | |||||
| void addWidget(Widget* const widget) | void addWidget(Widget* const widget) | ||||
| { | { | ||||
| fWidgets.push_back(widget); | fWidgets.push_back(widget); | ||||
| @@ -736,7 +773,7 @@ struct Window::PrivateData { | |||||
| FOR_EACH_WIDGET(it) | FOR_EACH_WIDGET(it) | ||||
| { | { | ||||
| Widget* const widget(*it); | Widget* const widget(*it); | ||||
| widget->pData->display(fWidth, fHeight, false); | |||||
| widget->pData->display(fWidth, fHeight, fScaling, false); | |||||
| } | } | ||||
| fSelf->onDisplayAfter(); | fSelf->onDisplayAfter(); | ||||
| @@ -796,7 +833,7 @@ struct Window::PrivateData { | |||||
| return 1; | return 1; | ||||
| } | } | ||||
| void onPuglMouse(const int button, const bool press, const int x, const int y) | |||||
| void onPuglMouse(const int button, const bool press, int x, int y) | |||||
| { | { | ||||
| DBGp("PUGL: onMouse : %i %i %i %i\n", button, press, x, y); | DBGp("PUGL: onMouse : %i %i %i %i\n", button, press, x, y); | ||||
| @@ -806,6 +843,9 @@ struct Window::PrivateData { | |||||
| if (fModal.childFocus != nullptr) | if (fModal.childFocus != nullptr) | ||||
| return fModal.childFocus->focus(); | return fModal.childFocus->focus(); | ||||
| x /= fScaling; | |||||
| y /= fScaling; | |||||
| Widget::MouseEvent ev; | Widget::MouseEvent ev; | ||||
| ev.button = button; | ev.button = button; | ||||
| ev.press = press; | ev.press = press; | ||||
| @@ -823,13 +863,16 @@ struct Window::PrivateData { | |||||
| } | } | ||||
| } | } | ||||
| void onPuglMotion(const int x, const int y) | |||||
| void onPuglMotion(int x, int y) | |||||
| { | { | ||||
| DBGp("PUGL: onMotion : %i %i\n", x, y); | |||||
| // DBGp("PUGL: onMotion : %i %i\n", x, y); | |||||
| if (fModal.childFocus != nullptr) | if (fModal.childFocus != nullptr) | ||||
| return; | return; | ||||
| x /= fScaling; | |||||
| y /= fScaling; | |||||
| Widget::MotionEvent ev; | Widget::MotionEvent ev; | ||||
| ev.mod = static_cast<Modifier>(puglGetModifiers(fView)); | ev.mod = static_cast<Modifier>(puglGetModifiers(fView)); | ||||
| ev.time = puglGetEventTimestamp(fView); | ev.time = puglGetEventTimestamp(fView); | ||||
| @@ -845,13 +888,18 @@ struct Window::PrivateData { | |||||
| } | } | ||||
| } | } | ||||
| void onPuglScroll(const int x, const int y, const float dx, const float dy) | |||||
| void onPuglScroll(int x, int y, float dx, float dy) | |||||
| { | { | ||||
| DBGp("PUGL: onScroll : %i %i %f %f\n", x, y, dx, dy); | DBGp("PUGL: onScroll : %i %i %f %f\n", x, y, dx, dy); | ||||
| if (fModal.childFocus != nullptr) | if (fModal.childFocus != nullptr) | ||||
| return; | return; | ||||
| x /= fScaling; | |||||
| y /= fScaling; | |||||
| dx /= fScaling; | |||||
| dy /= fScaling; | |||||
| Widget::ScrollEvent ev; | Widget::ScrollEvent ev; | ||||
| ev.delta = Point<float>(dx, dy); | ev.delta = Point<float>(dx, dy); | ||||
| ev.mod = static_cast<Modifier>(puglGetModifiers(fView)); | ev.mod = static_cast<Modifier>(puglGetModifiers(fView)); | ||||
| @@ -1000,6 +1048,7 @@ struct Window::PrivateData { | |||||
| bool fUsingEmbed; | bool fUsingEmbed; | ||||
| uint fWidth; | uint fWidth; | ||||
| uint fHeight; | uint fHeight; | ||||
| double fScaling; | |||||
| char* fTitle; | char* fTitle; | ||||
| std::list<Widget*> fWidgets; | std::list<Widget*> fWidgets; | ||||
| @@ -1221,6 +1270,11 @@ bool Window::openFileBrowser(const FileBrowserOptions& options) | |||||
| } | } | ||||
| #endif | #endif | ||||
| bool Window::isEmbed() const noexcept | |||||
| { | |||||
| return pData->fUsingEmbed; | |||||
| } | |||||
| bool Window::isVisible() const noexcept | bool Window::isVisible() const noexcept | ||||
| { | { | ||||
| return pData->fVisible; | return pData->fVisible; | ||||
| @@ -1241,6 +1295,11 @@ void Window::setResizable(bool yesNo) | |||||
| pData->setResizable(yesNo); | pData->setResizable(yesNo); | ||||
| } | } | ||||
| void Window::setGeometryConstraints(uint width, uint height, bool aspect) | |||||
| { | |||||
| pData->setGeometryConstraints(width, height, aspect); | |||||
| } | |||||
| uint Window::getWidth() const noexcept | uint Window::getWidth() const noexcept | ||||
| { | { | ||||
| return pData->fWidth; | return pData->fWidth; | ||||
| @@ -1281,6 +1340,26 @@ void Window::setTransientWinId(uintptr_t winId) | |||||
| pData->setTransientWinId(winId); | pData->setTransientWinId(winId); | ||||
| } | } | ||||
| double Window::getScaling() const noexcept | |||||
| { | |||||
| return pData->getScaling(); | |||||
| } | |||||
| void Window::setScaling(double scaling) noexcept | |||||
| { | |||||
| pData->setScaling(scaling); | |||||
| } | |||||
| bool Window::getIgnoringKeyRepeat() const noexcept | |||||
| { | |||||
| return pData->getIgnoringKeyRepeat(); | |||||
| } | |||||
| void Window::setIgnoringKeyRepeat(bool ignore) noexcept | |||||
| { | |||||
| pData->setIgnoringKeyRepeat(ignore); | |||||
| } | |||||
| Application& Window::getApp() const noexcept | Application& Window::getApp() const noexcept | ||||
| { | { | ||||
| return pData->fApp; | return pData->fApp; | ||||
| @@ -1,121 +0,0 @@ | |||||
| /* | |||||
| Copyright 2014 David Robillard <http://drobilla.net> | |||||
| 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. | |||||
| THIS 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 PUGL_COMMON_H_INCLUDED | |||||
| #define PUGL_COMMON_H_INCLUDED | |||||
| #ifdef __cplusplus | |||||
| extern "C" { | |||||
| #endif | |||||
| /** | |||||
| @addtogroup pugl | |||||
| @{ | |||||
| */ | |||||
| /** | |||||
| A Pugl view. | |||||
| */ | |||||
| typedef struct PuglViewImpl PuglView; | |||||
| /** | |||||
| A native window handle. | |||||
| On X11, this is a Window. | |||||
| On OSX, this is an NSView*. | |||||
| On Windows, this is a HWND. | |||||
| */ | |||||
| typedef intptr_t PuglNativeWindow; | |||||
| /** | |||||
| Handle for opaque user data. | |||||
| */ | |||||
| typedef void* PuglHandle; | |||||
| /** | |||||
| Return status code. | |||||
| */ | |||||
| typedef enum { | |||||
| PUGL_SUCCESS = 0 | |||||
| } PuglStatus; | |||||
| /** | |||||
| Drawing context type. | |||||
| */ | |||||
| typedef enum { | |||||
| PUGL_GL, | |||||
| PUGL_CAIRO | |||||
| } PuglContextType; | |||||
| /** | |||||
| Convenience symbols for ASCII control characters. | |||||
| */ | |||||
| typedef enum { | |||||
| PUGL_CHAR_BACKSPACE = 0x08, | |||||
| PUGL_CHAR_ESCAPE = 0x1B, | |||||
| PUGL_CHAR_DELETE = 0x7F | |||||
| } PuglChar; | |||||
| /** | |||||
| Keyboard modifier flags. | |||||
| */ | |||||
| typedef enum { | |||||
| PUGL_MOD_SHIFT = 1 << 0, /**< Shift key */ | |||||
| PUGL_MOD_CTRL = 1 << 1, /**< Control key */ | |||||
| PUGL_MOD_ALT = 1 << 2, /**< Alt/Option key */ | |||||
| PUGL_MOD_SUPER = 1 << 3 /**< Mod4/Command/Windows key */ | |||||
| } PuglMod; | |||||
| /** | |||||
| Special (non-Unicode) keyboard keys. | |||||
| */ | |||||
| typedef enum { | |||||
| PUGL_KEY_F1 = 1, | |||||
| PUGL_KEY_F2, | |||||
| PUGL_KEY_F3, | |||||
| PUGL_KEY_F4, | |||||
| PUGL_KEY_F5, | |||||
| PUGL_KEY_F6, | |||||
| PUGL_KEY_F7, | |||||
| PUGL_KEY_F8, | |||||
| PUGL_KEY_F9, | |||||
| PUGL_KEY_F10, | |||||
| PUGL_KEY_F11, | |||||
| PUGL_KEY_F12, | |||||
| PUGL_KEY_LEFT, | |||||
| PUGL_KEY_UP, | |||||
| PUGL_KEY_RIGHT, | |||||
| PUGL_KEY_DOWN, | |||||
| PUGL_KEY_PAGE_UP, | |||||
| PUGL_KEY_PAGE_DOWN, | |||||
| PUGL_KEY_HOME, | |||||
| PUGL_KEY_END, | |||||
| PUGL_KEY_INSERT, | |||||
| PUGL_KEY_SHIFT, | |||||
| PUGL_KEY_CTRL, | |||||
| PUGL_KEY_ALT, | |||||
| PUGL_KEY_SUPER | |||||
| } PuglKey; | |||||
| /** | |||||
| @} | |||||
| */ | |||||
| #ifdef __cplusplus | |||||
| } /* extern "C" */ | |||||
| #endif | |||||
| #endif /* PUGL_COMMON_H_INCLUDED */ | |||||
| @@ -1,41 +0,0 @@ | |||||
| /* | |||||
| Copyright 2014 David Robillard <http://drobilla.net> | |||||
| 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. | |||||
| THIS 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 PUGL_EVENT_H_INCLUDED | |||||
| #define PUGL_EVENT_H_INCLUDED | |||||
| #ifdef __cplusplus | |||||
| extern "C" { | |||||
| #else | |||||
| # include <stdbool.h> | |||||
| #endif | |||||
| #include "pugl/common.h" | |||||
| /** | |||||
| @addtogroup pugl | |||||
| @{ | |||||
| */ | |||||
| /** | |||||
| @} | |||||
| */ | |||||
| #ifdef __cplusplus | |||||
| } /* extern "C" */ | |||||
| #endif | |||||
| #endif /* PUGL_EVENT_H_INCLUDED */ | |||||
| @@ -1,32 +0,0 @@ | |||||
| /* | |||||
| Copyright 2012-2014 David Robillard <http://drobilla.net> | |||||
| 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. | |||||
| THIS 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. | |||||
| */ | |||||
| /** | |||||
| @file gl.h Portable header wrapper for gl.h. | |||||
| Unfortunately, GL includes vary across platforms so this header allows for | |||||
| pure portable programs. | |||||
| */ | |||||
| #ifdef __APPLE__ | |||||
| # include "OpenGL/gl.h" | |||||
| #else | |||||
| # ifdef _WIN32 | |||||
| # include <windows.h> /* Broken Windows GL headers require this */ | |||||
| # endif | |||||
| # include "GL/gl.h" | |||||
| #endif | |||||
| @@ -1,32 +0,0 @@ | |||||
| /* | |||||
| Copyright 2012-2014 David Robillard <http://drobilla.net> | |||||
| 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. | |||||
| THIS 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. | |||||
| */ | |||||
| /** | |||||
| @file glu.h Portable header wrapper for glu.h. | |||||
| Unfortunately, GL includes vary across platforms so this header allows for | |||||
| pure portable programs. | |||||
| */ | |||||
| #ifdef __APPLE__ | |||||
| # include "OpenGL/glu.h" | |||||
| #else | |||||
| # ifdef _WIN32 | |||||
| # include <windows.h> /* Broken Windows GL headers require this */ | |||||
| # endif | |||||
| # include "GL/glu.h" | |||||
| #endif | |||||
| @@ -23,28 +23,25 @@ | |||||
| #include <stdint.h> | #include <stdint.h> | ||||
| #include "pugl/common.h" | |||||
| #include "pugl/event.h" | |||||
| #ifdef PUGL_SHARED | |||||
| # ifdef _WIN32 | |||||
| # define PUGL_LIB_IMPORT __declspec(dllimport) | |||||
| # define PUGL_LIB_EXPORT __declspec(dllexport) | |||||
| # else | |||||
| # define PUGL_LIB_IMPORT __attribute__((visibility("default"))) | |||||
| # define PUGL_LIB_EXPORT __attribute__((visibility("default"))) | |||||
| # endif | |||||
| # ifdef PUGL_INTERNAL | |||||
| # define PUGL_API PUGL_LIB_EXPORT | |||||
| # else | |||||
| # define PUGL_API PUGL_LIB_IMPORT | |||||
| # endif | |||||
| /* | |||||
| This API is pure portable C and contains no platform specific elements, or | |||||
| even a GL dependency. However, unfortunately GL includes vary across | |||||
| platforms so they are included here to allow for pure portable programs. | |||||
| */ | |||||
| #ifdef __APPLE__ | |||||
| # include "OpenGL/gl.h" | |||||
| #else | #else | ||||
| # ifdef _WIN32 | # ifdef _WIN32 | ||||
| # define PUGL_API | |||||
| # else | |||||
| # define PUGL_API __attribute__((visibility("hidden"))) | |||||
| # include <winsock2.h> | |||||
| # include <windows.h> /* Broken Windows GL headers require this */ | |||||
| # endif | # endif | ||||
| # include "GL/gl.h" | |||||
| #endif | |||||
| #ifdef _WIN32 | |||||
| # define PUGL_API | |||||
| #else | |||||
| # define PUGL_API __attribute__((visibility("hidden"))) | |||||
| #endif | #endif | ||||
| #ifdef __cplusplus | #ifdef __cplusplus | ||||
| @@ -59,6 +56,82 @@ extern "C" { | |||||
| @{ | @{ | ||||
| */ | */ | ||||
| /** | |||||
| A Pugl view. | |||||
| */ | |||||
| typedef struct PuglViewImpl PuglView; | |||||
| /** | |||||
| A native window handle. | |||||
| On X11, this is a Window. | |||||
| On OSX, this is an NSView*. | |||||
| On Windows, this is a HWND. | |||||
| */ | |||||
| typedef intptr_t PuglNativeWindow; | |||||
| /** | |||||
| Return status code. | |||||
| */ | |||||
| typedef enum { | |||||
| PUGL_SUCCESS = 0 | |||||
| } PuglStatus; | |||||
| /** | |||||
| Convenience symbols for ASCII control characters. | |||||
| */ | |||||
| typedef enum { | |||||
| PUGL_CHAR_BACKSPACE = 0x08, | |||||
| PUGL_CHAR_ESCAPE = 0x1B, | |||||
| PUGL_CHAR_DELETE = 0x7F | |||||
| } PuglChar; | |||||
| /** | |||||
| Special (non-Unicode) keyboard keys. | |||||
| */ | |||||
| typedef enum { | |||||
| PUGL_KEY_F1 = 1, | |||||
| PUGL_KEY_F2, | |||||
| PUGL_KEY_F3, | |||||
| PUGL_KEY_F4, | |||||
| PUGL_KEY_F5, | |||||
| PUGL_KEY_F6, | |||||
| PUGL_KEY_F7, | |||||
| PUGL_KEY_F8, | |||||
| PUGL_KEY_F9, | |||||
| PUGL_KEY_F10, | |||||
| PUGL_KEY_F11, | |||||
| PUGL_KEY_F12, | |||||
| PUGL_KEY_LEFT, | |||||
| PUGL_KEY_UP, | |||||
| PUGL_KEY_RIGHT, | |||||
| PUGL_KEY_DOWN, | |||||
| PUGL_KEY_PAGE_UP, | |||||
| PUGL_KEY_PAGE_DOWN, | |||||
| PUGL_KEY_HOME, | |||||
| PUGL_KEY_END, | |||||
| PUGL_KEY_INSERT, | |||||
| PUGL_KEY_SHIFT, | |||||
| PUGL_KEY_CTRL, | |||||
| PUGL_KEY_ALT, | |||||
| PUGL_KEY_SUPER | |||||
| } PuglKey; | |||||
| /** | |||||
| Keyboard modifier flags. | |||||
| */ | |||||
| typedef enum { | |||||
| PUGL_MOD_SHIFT = 1 << 0, /**< Shift key */ | |||||
| PUGL_MOD_CTRL = 1 << 1, /**< Control key */ | |||||
| PUGL_MOD_ALT = 1 << 2, /**< Alt/Option key */ | |||||
| PUGL_MOD_SUPER = 1 << 3 /**< Mod4/Command/Windows key */ | |||||
| } PuglMod; | |||||
| /** | |||||
| Handle for opaque user data. | |||||
| */ | |||||
| typedef void* PuglHandle; | |||||
| /** | /** | ||||
| A function called when the window is closed. | A function called when the window is closed. | ||||
| */ | */ | ||||
| @@ -105,6 +178,16 @@ typedef void (*PuglMouseFunc)( | |||||
| */ | */ | ||||
| typedef void (*PuglReshapeFunc)(PuglView* view, int width, int height); | typedef void (*PuglReshapeFunc)(PuglView* view, int width, int height); | ||||
| /** | |||||
| A function called outside of gl-context when the plugin schedules a resize via puglPostResize. | |||||
| @param view The view being resized. | |||||
| @param width The new width to resize to (variable is initialized to current size) | |||||
| @param height The new height to resize to (variable is initialized to current size) | |||||
| @param set_hints If not null, set window-hints | |||||
| */ | |||||
| typedef void (*PuglResizeFunc)(PuglView* view, int *width, int *height, int *set_hints); | |||||
| /** | /** | ||||
| A function called on scrolling (e.g. mouse wheel or track pad). | A function called on scrolling (e.g. mouse wheel or track pad). | ||||
| @@ -190,12 +273,6 @@ puglInitUserResizable(PuglView* view, bool resizable); | |||||
| PUGL_API void | PUGL_API void | ||||
| puglInitTransientFor(PuglView* view, uintptr_t parent); | puglInitTransientFor(PuglView* view, uintptr_t parent); | ||||
| /** | |||||
| Set the context type before creating a window. | |||||
| */ | |||||
| PUGL_API void | |||||
| puglInitContextType(PuglView* view, PuglContextType type); | |||||
| /** | /** | ||||
| @} | @} | ||||
| */ | */ | ||||
| @@ -215,13 +292,31 @@ PUGL_API int | |||||
| puglCreateWindow(PuglView* view, const char* title); | puglCreateWindow(PuglView* view, const char* title); | ||||
| /** | /** | ||||
| Show the current window. | |||||
| Create a new GL window. | |||||
| @param parent Parent window, or 0 for top level. | |||||
| @param title Window title, or NULL. | |||||
| @param width Window width in pixels. | |||||
| @param height Window height in pixels. | |||||
| @param resizable Whether window should be user resizable. | |||||
| */ | |||||
| PUGL_API PuglView* | |||||
| puglCreate(PuglNativeWindow parent, | |||||
| const char* title, | |||||
| int min_width, | |||||
| int min_height, | |||||
| int width, | |||||
| int height, | |||||
| bool resizable, | |||||
| unsigned long transientId); | |||||
| /** | |||||
| Show Window (external ui) | |||||
| */ | */ | ||||
| PUGL_API void | PUGL_API void | ||||
| puglShowWindow(PuglView* view); | puglShowWindow(PuglView* view); | ||||
| /** | /** | ||||
| Hide the current window. | |||||
| Hide Window (external ui) | |||||
| */ | */ | ||||
| PUGL_API void | PUGL_API void | ||||
| puglHideWindow(PuglView* view); | puglHideWindow(PuglView* view); | ||||
| @@ -254,15 +349,6 @@ puglSetHandle(PuglView* view, PuglHandle handle); | |||||
| PUGL_API PuglHandle | PUGL_API PuglHandle | ||||
| puglGetHandle(PuglView* view); | puglGetHandle(PuglView* view); | ||||
| /** | |||||
| Get the drawing context. | |||||
| For PUGL_GL contexts, this is unused and returns NULL. | |||||
| For PUGL_CAIRO contexts, this returns a pointer to a cairo_t. | |||||
| */ | |||||
| PUGL_API void* | |||||
| puglGetContext(PuglView* view); | |||||
| /** | /** | ||||
| Return the timestamp (if any) of the currently-processing event. | Return the timestamp (if any) of the currently-processing event. | ||||
| */ | */ | ||||
| @@ -337,6 +423,12 @@ puglSetSpecialFunc(PuglView* view, PuglSpecialFunc specialFunc); | |||||
| PUGL_API void | PUGL_API void | ||||
| puglSetReshapeFunc(PuglView* view, PuglReshapeFunc reshapeFunc); | puglSetReshapeFunc(PuglView* view, PuglReshapeFunc reshapeFunc); | ||||
| /** | |||||
| Set callback function to change window size. | |||||
| */ | |||||
| PUGL_API void | |||||
| puglSetResizeFunc(PuglView* view, PuglResizeFunc resizeFunc); | |||||
| /** | /** | ||||
| Set the function to call on file-browser selections. | Set the function to call on file-browser selections. | ||||
| */ | */ | ||||
| @@ -347,6 +439,12 @@ puglSetFileSelectedFunc(PuglView* view, PuglFileSelectedFunc fileSelectedFunc); | |||||
| @} | @} | ||||
| */ | */ | ||||
| /** | |||||
| TODO document this. | |||||
| */ | |||||
| PUGL_API int | |||||
| puglUpdateGeometryConstraints(PuglView* view, int min_width, int min_height, bool aspect); | |||||
| /** | /** | ||||
| Grab the input focus. | Grab the input focus. | ||||
| */ | */ | ||||
| @@ -368,6 +466,12 @@ puglProcessEvents(PuglView* view); | |||||
| PUGL_API void | PUGL_API void | ||||
| puglPostRedisplay(PuglView* view); | puglPostRedisplay(PuglView* view); | ||||
| /** | |||||
| Request a resize on the next call to puglProcessEvents(). | |||||
| */ | |||||
| PUGL_API void | |||||
| puglPostResize(PuglView* view); | |||||
| /** | /** | ||||
| Destroy a GL window. | Destroy a GL window. | ||||
| */ | */ | ||||
| @@ -20,27 +20,9 @@ | |||||
| Note this file contains function definitions, so it must be compiled into | Note this file contains function definitions, so it must be compiled into | ||||
| the final binary exactly once. Each platform specific implementation file | the final binary exactly once. Each platform specific implementation file | ||||
| including it once should achieve this. | including it once should achieve this. | ||||
| If you are copying the pugl code into your source tree, the following | |||||
| symbols can be defined to tweak pugl behaviour: | |||||
| PUGL_HAVE_CAIRO: Include Cairo support code. | |||||
| PUGL_HAVE_GL: Include OpenGL support code. | |||||
| PUGL_GRAB_FOCUS: Work around reparent keyboard issues by grabbing focus. | |||||
| PUGL_VERBOSE: Print GL information to console. | |||||
| */ | */ | ||||
| #include "pugl/pugl.h" | |||||
| #include "pugl/event.h" | |||||
| #ifdef PUGL_VERBOSE | |||||
| # include <stdio.h> | |||||
| # define PUGL_LOG(str) fprintf(stderr, "pugl: " str) | |||||
| # define PUGL_LOGF(fmt, ...) fprintf(stderr, "pugl: " fmt, __VA_ARGS__) | |||||
| #else | |||||
| # define PUGL_LOG(str) | |||||
| # define PUGL_LOGF(fmt, ...) | |||||
| #endif | |||||
| #include "pugl.h" | |||||
| typedef struct PuglInternalsImpl PuglInternals; | typedef struct PuglInternalsImpl PuglInternals; | ||||
| @@ -52,14 +34,13 @@ struct PuglViewImpl { | |||||
| PuglMotionFunc motionFunc; | PuglMotionFunc motionFunc; | ||||
| PuglMouseFunc mouseFunc; | PuglMouseFunc mouseFunc; | ||||
| PuglReshapeFunc reshapeFunc; | PuglReshapeFunc reshapeFunc; | ||||
| PuglResizeFunc resizeFunc; | |||||
| PuglScrollFunc scrollFunc; | PuglScrollFunc scrollFunc; | ||||
| PuglSpecialFunc specialFunc; | PuglSpecialFunc specialFunc; | ||||
| PuglFileSelectedFunc fileSelectedFunc; | PuglFileSelectedFunc fileSelectedFunc; | ||||
| PuglInternals* impl; | |||||
| PuglInternals* impl; | |||||
| PuglNativeWindow parent; | PuglNativeWindow parent; | ||||
| PuglContextType ctx_type; | |||||
| uintptr_t transient_parent; | uintptr_t transient_parent; | ||||
| int width; | int width; | ||||
| @@ -70,7 +51,8 @@ struct PuglViewImpl { | |||||
| bool mouse_in_view; | bool mouse_in_view; | ||||
| bool ignoreKeyRepeat; | bool ignoreKeyRepeat; | ||||
| bool redisplay; | bool redisplay; | ||||
| bool resizable; | |||||
| bool user_resizable; | |||||
| bool pending_resize; | |||||
| uint32_t event_timestamp_ms; | uint32_t event_timestamp_ms; | ||||
| }; | }; | ||||
| @@ -120,7 +102,7 @@ puglInitWindowParent(PuglView* view, PuglNativeWindow parent) | |||||
| void | void | ||||
| puglInitUserResizable(PuglView* view, bool resizable) | puglInitUserResizable(PuglView* view, bool resizable) | ||||
| { | { | ||||
| view->resizable = resizable; | |||||
| view->user_resizable = resizable; | |||||
| } | } | ||||
| void | void | ||||
| @@ -129,10 +111,33 @@ puglInitTransientFor(PuglView* view, uintptr_t parent) | |||||
| view->transient_parent = parent; | view->transient_parent = parent; | ||||
| } | } | ||||
| void | |||||
| puglInitContextType(PuglView* view, PuglContextType type) | |||||
| PuglView* | |||||
| puglCreate(PuglNativeWindow parent, | |||||
| const char* title, | |||||
| int min_width, | |||||
| int min_height, | |||||
| int width, | |||||
| int height, | |||||
| bool resizable, | |||||
| unsigned long transientId) | |||||
| { | { | ||||
| view->ctx_type = type; | |||||
| PuglView* view = puglInit(); | |||||
| if (!view) { | |||||
| return NULL; | |||||
| } | |||||
| puglInitWindowParent(view, parent); | |||||
| puglInitWindowMinSize(view, min_width, min_height); | |||||
| puglInitWindowSize(view, width, height); | |||||
| puglInitUserResizable(view, resizable); | |||||
| puglInitTransientFor(view, transientId); | |||||
| if (!puglCreateWindow(view, title)) { | |||||
| free(view); | |||||
| return NULL; | |||||
| } | |||||
| return view; | |||||
| } | } | ||||
| void | void | ||||
| @@ -201,6 +206,12 @@ puglSetReshapeFunc(PuglView* view, PuglReshapeFunc reshapeFunc) | |||||
| view->reshapeFunc = reshapeFunc; | view->reshapeFunc = reshapeFunc; | ||||
| } | } | ||||
| void | |||||
| puglSetResizeFunc(PuglView* view, PuglResizeFunc resizeFunc) | |||||
| { | |||||
| view->resizeFunc = resizeFunc; | |||||
| } | |||||
| void | void | ||||
| puglSetScrollFunc(PuglView* view, PuglScrollFunc scrollFunc) | puglSetScrollFunc(PuglView* view, PuglScrollFunc scrollFunc) | ||||
| { | { | ||||
| @@ -225,45 +236,19 @@ puglEnterContext(PuglView* view); | |||||
| void | void | ||||
| puglLeaveContext(PuglView* view, bool flush); | puglLeaveContext(PuglView* view, bool flush); | ||||
| #if 0 | |||||
| /** Return the code point for buf, or the replacement character on error. */ | |||||
| static uint32_t | |||||
| puglDecodeUTF8(const uint8_t* buf) | |||||
| { | |||||
| #define FAIL_IF(cond) { if (cond) return 0xFFFD; } | |||||
| /* http://en.wikipedia.org/wiki/UTF-8 */ | |||||
| if (buf[0] < 0x80) { | |||||
| return buf[0]; | |||||
| } else if (buf[0] < 0xC2) { | |||||
| return 0xFFFD; | |||||
| } else if (buf[0] < 0xE0) { | |||||
| FAIL_IF((buf[1] & 0xC0) != 0x80); | |||||
| return (buf[0] << 6) + buf[1] - 0x3080; | |||||
| } else if (buf[0] < 0xF0) { | |||||
| FAIL_IF((buf[1] & 0xC0) != 0x80); | |||||
| FAIL_IF(buf[0] == 0xE0 && buf[1] < 0xA0); | |||||
| FAIL_IF((buf[2] & 0xC0) != 0x80); | |||||
| return (buf[0] << 12) + (buf[1] << 6) + buf[2] - 0xE2080; | |||||
| } else if (buf[0] < 0xF5) { | |||||
| FAIL_IF((buf[1] & 0xC0) != 0x80); | |||||
| FAIL_IF(buf[0] == 0xF0 && buf[1] < 0x90); | |||||
| FAIL_IF(buf[0] == 0xF4 && buf[1] >= 0x90); | |||||
| FAIL_IF((buf[2] & 0xC0) != 0x80); | |||||
| FAIL_IF((buf[3] & 0xC0) != 0x80); | |||||
| return ((buf[0] << 18) + | |||||
| (buf[1] << 12) + | |||||
| (buf[2] << 6) + | |||||
| buf[3] - 0x3C82080); | |||||
| } | |||||
| return 0xFFFD; | |||||
| } | |||||
| #endif | |||||
| static void | static void | ||||
| puglDefaultReshape(PuglView* view, int width, int height) | |||||
| puglDefaultReshape(int width, int height) | |||||
| { | { | ||||
| #ifdef ROBTK_HERE | |||||
| glViewport(0, 0, width, height); | |||||
| glMatrixMode(GL_PROJECTION); | |||||
| glLoadIdentity(); | |||||
| glOrtho(-1.0f, 1.0f, -1.0f, 1.0f, -1.0f, 1.0f); | |||||
| glClear(GL_COLOR_BUFFER_BIT); | |||||
| glMatrixMode(GL_MODELVIEW); | |||||
| glLoadIdentity(); | |||||
| #else | |||||
| glMatrixMode(GL_PROJECTION); | glMatrixMode(GL_PROJECTION); | ||||
| glLoadIdentity(); | glLoadIdentity(); | ||||
| glOrtho(0, width, height, 0, 0, 1); | glOrtho(0, width, height, 0, 0, 1); | ||||
| @@ -271,82 +256,5 @@ puglDefaultReshape(PuglView* view, int width, int height) | |||||
| glMatrixMode(GL_MODELVIEW); | glMatrixMode(GL_MODELVIEW); | ||||
| glLoadIdentity(); | glLoadIdentity(); | ||||
| return; | |||||
| // unused | |||||
| (void)view; | |||||
| } | |||||
| #if 0 | |||||
| static void | |||||
| puglDispatchEvent(PuglView* view, const PuglEvent* event) | |||||
| { | |||||
| if (view->eventFunc) { | |||||
| view->eventFunc(view, event); | |||||
| } | |||||
| switch (event->type) { | |||||
| case PUGL_CONFIGURE: | |||||
| puglEnterContext(view); | |||||
| view->width = event->configure.width; | |||||
| view->height = event->configure.height; | |||||
| if (view->reshapeFunc) { | |||||
| view->reshapeFunc(view, view->width, view->height); | |||||
| } | |||||
| puglLeaveContext(view, false); | |||||
| break; | |||||
| case PUGL_EXPOSE: | |||||
| if (event->expose.count == 0) { | |||||
| puglEnterContext(view); | |||||
| if (view->displayFunc) { | |||||
| view->displayFunc(view); | |||||
| } | |||||
| view->redisplay = false; | |||||
| puglLeaveContext(view, true); | |||||
| } | |||||
| break; | |||||
| case PUGL_MOTION_NOTIFY: | |||||
| view->event_timestamp_ms = event->motion.time; | |||||
| view->mods = event->motion.state; | |||||
| if (view->motionFunc) { | |||||
| view->motionFunc(view, event->motion.x, event->motion.y); | |||||
| } | |||||
| break; | |||||
| case PUGL_SCROLL: | |||||
| if (view->scrollFunc) { | |||||
| view->scrollFunc(view, | |||||
| event->scroll.x, event->scroll.y, | |||||
| event->scroll.dx, event->scroll.dy); | |||||
| } | |||||
| break; | |||||
| case PUGL_BUTTON_PRESS: | |||||
| case PUGL_BUTTON_RELEASE: | |||||
| view->event_timestamp_ms = event->button.time; | |||||
| view->mods = event->button.state; | |||||
| if (view->mouseFunc) { | |||||
| view->mouseFunc(view, | |||||
| event->button.button, | |||||
| event->type == PUGL_BUTTON_PRESS, | |||||
| event->button.x, | |||||
| event->button.y); | |||||
| } | |||||
| break; | |||||
| case PUGL_KEY_PRESS: | |||||
| case PUGL_KEY_RELEASE: | |||||
| view->event_timestamp_ms = event->key.time; | |||||
| view->mods = event->key.state; | |||||
| if (event->key.special && view->specialFunc) { | |||||
| view->specialFunc(view, | |||||
| event->type == PUGL_KEY_PRESS, | |||||
| event->key.special); | |||||
| } else if (event->key.character && view->keyboardFunc) { | |||||
| view->keyboardFunc(view, | |||||
| event->type == PUGL_KEY_PRESS, | |||||
| event->key.character); | |||||
| } | |||||
| break; | |||||
| default: | |||||
| break; | |||||
| } | |||||
| } | |||||
| #endif | #endif | ||||
| } | |||||
| @@ -218,7 +218,7 @@ puglDisplay(PuglView* view) | |||||
| if (puglview->reshapeFunc) { | if (puglview->reshapeFunc) { | ||||
| puglview->reshapeFunc(puglview, width, height); | puglview->reshapeFunc(puglview, width, height); | ||||
| } else { | } else { | ||||
| puglDefaultReshape(puglview, width, height); | |||||
| puglDefaultReshape(width, height); | |||||
| } | } | ||||
| puglLeaveContext(puglview, false); | puglLeaveContext(puglview, false); | ||||
| @@ -427,18 +427,13 @@ puglInitInternals() | |||||
| void | void | ||||
| puglEnterContext(PuglView* view) | puglEnterContext(PuglView* view) | ||||
| { | { | ||||
| #ifdef PUGL_HAVE_GL | |||||
| if (view->ctx_type == PUGL_GL) { | |||||
| [[view->impl->glview openGLContext] makeCurrentContext]; | |||||
| } | |||||
| #endif | |||||
| [[view->impl->glview openGLContext] makeCurrentContext]; | |||||
| } | } | ||||
| void | void | ||||
| puglLeaveContext(PuglView* view, bool flush) | puglLeaveContext(PuglView* view, bool flush) | ||||
| { | { | ||||
| #ifdef PUGL_HAVE_GL | |||||
| if (view->ctx_type == PUGL_GL && flush) { | |||||
| if (flush) { | |||||
| if (view->impl->glview->doubleBuffered) { | if (view->impl->glview->doubleBuffered) { | ||||
| [[view->impl->glview openGLContext] flushBuffer]; | [[view->impl->glview openGLContext] flushBuffer]; | ||||
| } else { | } else { | ||||
| @@ -446,7 +441,6 @@ puglLeaveContext(PuglView* view, bool flush) | |||||
| } | } | ||||
| //[NSOpenGLContext clearCurrentContext]; | //[NSOpenGLContext clearCurrentContext]; | ||||
| } | } | ||||
| #endif | |||||
| } | } | ||||
| int | int | ||||
| @@ -465,7 +459,7 @@ puglCreateWindow(PuglView* view, const char* title) | |||||
| impl->glview->puglview = view; | impl->glview->puglview = view; | ||||
| if (view->resizable) { | |||||
| if (view->user_resizable) { | |||||
| [impl->glview setAutoresizingMask:NSViewWidthSizable|NSViewHeightSizable]; | [impl->glview setAutoresizingMask:NSViewWidthSizable|NSViewHeightSizable]; | ||||
| } | } | ||||
| @@ -566,11 +560,14 @@ puglGetNativeWindow(PuglView* view) | |||||
| return (PuglNativeWindow)view->impl->glview; | return (PuglNativeWindow)view->impl->glview; | ||||
| } | } | ||||
| void* | |||||
| puglGetContext(PuglView* view) | |||||
| int | |||||
| puglUpdateGeometryConstraints(PuglView* view, int min_width, int min_height, bool aspect) | |||||
| { | { | ||||
| return NULL; | |||||
| // TODO | |||||
| return 1; | |||||
| // unused | |||||
| (void)view; | (void)view; | ||||
| (void)min_width; | |||||
| (void)min_height; | |||||
| (void)aspect; | |||||
| } | } | ||||
| @@ -76,25 +76,17 @@ puglInitInternals() | |||||
| void | void | ||||
| puglEnterContext(PuglView* view) | puglEnterContext(PuglView* view) | ||||
| { | { | ||||
| #ifdef PUGL_HAVE_GL | |||||
| if (view->ctx_type == PUGL_GL) { | |||||
| wglMakeCurrent(view->impl->hdc, view->impl->hglrc); | |||||
| } | |||||
| #endif | |||||
| wglMakeCurrent(view->impl->hdc, view->impl->hglrc); | |||||
| } | } | ||||
| void | void | ||||
| puglLeaveContext(PuglView* view, bool flush) | puglLeaveContext(PuglView* view, bool flush) | ||||
| { | { | ||||
| #ifdef PUGL_HAVE_GL | |||||
| if (view->ctx_type == PUGL_GL) { | |||||
| if (flush) { | |||||
| glFlush(); | |||||
| SwapBuffers(view->impl->hdc); | |||||
| } | |||||
| wglMakeCurrent(NULL, NULL); | |||||
| if (flush) { | |||||
| glFlush(); | |||||
| SwapBuffers(view->impl->hdc); | |||||
| } | } | ||||
| #endif | |||||
| wglMakeCurrent(NULL, NULL); | |||||
| } | } | ||||
| int | int | ||||
| @@ -137,7 +129,7 @@ puglCreateWindow(PuglView* view, const char* title) | |||||
| } | } | ||||
| int winFlags = WS_POPUPWINDOW | WS_CAPTION; | int winFlags = WS_POPUPWINDOW | WS_CAPTION; | ||||
| if (view->resizable) { | |||||
| if (view->user_resizable) { | |||||
| winFlags |= WS_SIZEBOX; | winFlags |= WS_SIZEBOX; | ||||
| if (view->min_width > 0 && view->min_height > 0) { | if (view->min_width > 0 && view->min_height > 0) { | ||||
| // Adjust the minimum window size to accomodate requested view size | // Adjust the minimum window size to accomodate requested view size | ||||
| @@ -231,7 +223,7 @@ puglReshape(PuglView* view, int width, int height) | |||||
| if (view->reshapeFunc) { | if (view->reshapeFunc) { | ||||
| view->reshapeFunc(view, width, height); | view->reshapeFunc(view, width, height); | ||||
| } else { | } else { | ||||
| puglDefaultReshape(view, width, height); | |||||
| puglDefaultReshape(width, height); | |||||
| } | } | ||||
| view->width = width; | view->width = width; | ||||
| @@ -477,13 +469,14 @@ puglGetNativeWindow(PuglView* view) | |||||
| return (PuglNativeWindow)view->impl->hwnd; | return (PuglNativeWindow)view->impl->hwnd; | ||||
| } | } | ||||
| void* | |||||
| puglGetContext(PuglView* /*view*/) | |||||
| int | |||||
| puglUpdateGeometryConstraints(PuglView* view, int min_width, int min_height, bool aspect) | |||||
| { | { | ||||
| #ifdef PUGL_HAVE_CAIRO | |||||
| if (view->ctx_type == PUGL_CAIRO) { | |||||
| // TODO | |||||
| } | |||||
| #endif | |||||
| return NULL; | |||||
| // TODO | |||||
| return 1; | |||||
| (void)view; | |||||
| (void)min_width; | |||||
| (void)min_height; | |||||
| (void)aspect; | |||||
| } | } | ||||
| @@ -1,7 +1,7 @@ | |||||
| /* | /* | ||||
| Copyright 2012-2014 David Robillard <http://drobilla.net> | Copyright 2012-2014 David Robillard <http://drobilla.net> | ||||
| Copyright 2013 Robin Gareus <robin@gareus.org> | |||||
| Copyright 2011-2012 Ben Loftis, Harrison Consoles | Copyright 2011-2012 Ben Loftis, Harrison Consoles | ||||
| Copyright 2013,2015 Robin Gareus <robin@gareus.org> | |||||
| Permission to use, copy, modify, and/or distribute this software for any | Permission to use, copy, modify, and/or distribute this software for any | ||||
| purpose with or without fee is hereby granted, provided that the above | purpose with or without fee is hereby granted, provided that the above | ||||
| @@ -24,22 +24,14 @@ | |||||
| #include <stdlib.h> | #include <stdlib.h> | ||||
| #include <string.h> | #include <string.h> | ||||
| #include <GL/gl.h> | |||||
| #include <GL/glx.h> | |||||
| #include <X11/Xatom.h> | #include <X11/Xatom.h> | ||||
| #include <X11/Xlib.h> | #include <X11/Xlib.h> | ||||
| #include <X11/Xutil.h> | #include <X11/Xutil.h> | ||||
| #include <X11/keysym.h> | #include <X11/keysym.h> | ||||
| #ifdef PUGL_HAVE_GL | |||||
| #include <GL/gl.h> | |||||
| #include <GL/glx.h> | |||||
| #endif | |||||
| #ifdef PUGL_HAVE_CAIRO | |||||
| #include <cairo/cairo.h> | |||||
| #include <cairo/cairo-xlib.h> | |||||
| #endif | |||||
| #include "pugl/pugl_internal.h" | |||||
| #include "pugl_internal.h" | |||||
| #ifndef DGL_FILE_BROWSER_DISABLED | #ifndef DGL_FILE_BROWSER_DISABLED | ||||
| #define SOFD_HAVE_X11 | #define SOFD_HAVE_X11 | ||||
| @@ -47,212 +39,145 @@ | |||||
| #include "../sofd/libsofd.c" | #include "../sofd/libsofd.c" | ||||
| #endif | #endif | ||||
| /* work around buggy re-parent & focus issues on some systems | |||||
| * where no keyboard events are passed through even if the | |||||
| * app has mouse-focus and all other events are working. | |||||
| */ | |||||
| //#define PUGL_GRAB_FOCUS | |||||
| /* show messages during initalization | |||||
| */ | |||||
| //#define PUGL_VERBOSE | |||||
| struct PuglInternalsImpl { | struct PuglInternalsImpl { | ||||
| Display* display; | Display* display; | ||||
| int screen; | int screen; | ||||
| Window win; | Window win; | ||||
| XIM xim; | |||||
| XIC xic; | |||||
| #ifdef PUGL_HAVE_CAIRO | |||||
| cairo_t* cr; | |||||
| cairo_surface_t* surface; | |||||
| #endif | |||||
| #ifdef PUGL_HAVE_GL | |||||
| GLXContext ctx; | GLXContext ctx; | ||||
| Bool doubleBuffered; | Bool doubleBuffered; | ||||
| #endif | |||||
| }; | }; | ||||
| PuglInternals* | |||||
| puglInitInternals(void) | |||||
| { | |||||
| return (PuglInternals*)calloc(1, sizeof(PuglInternals)); | |||||
| } | |||||
| static XVisualInfo* | |||||
| getVisual(PuglView* view) | |||||
| { | |||||
| PuglInternals* const impl = view->impl; | |||||
| XVisualInfo* vi = NULL; | |||||
| #ifdef PUGL_HAVE_GL | |||||
| if (view->ctx_type == PUGL_GL) { | |||||
| /** | |||||
| Attributes for single-buffered RGBA with at least | |||||
| 4 bits per color and a 16 bit depth buffer. | |||||
| */ | |||||
| int attrListSgl[] = { | |||||
| GLX_RGBA, | |||||
| GLX_RED_SIZE, 4, | |||||
| GLX_GREEN_SIZE, 4, | |||||
| GLX_BLUE_SIZE, 4, | |||||
| GLX_DEPTH_SIZE, 16, | |||||
| GLX_ARB_multisample, 1, | |||||
| None | |||||
| }; | |||||
| /** | |||||
| Attributes for double-buffered RGBA with at least | |||||
| 4 bits per color and a 16 bit depth buffer. | |||||
| */ | |||||
| int attrListDbl[] = { | |||||
| GLX_RGBA, | |||||
| GLX_DOUBLEBUFFER, | |||||
| GLX_RED_SIZE, 4, | |||||
| GLX_GREEN_SIZE, 4, | |||||
| GLX_BLUE_SIZE, 4, | |||||
| GLX_DEPTH_SIZE, 16, | |||||
| GLX_ARB_multisample, 1, | |||||
| None | |||||
| }; | |||||
| /** | |||||
| Attributes for double-buffered RGBA with multi-sampling | |||||
| (antialiasing) | |||||
| */ | |||||
| int attrListDblMS[] = { | |||||
| GLX_RGBA, | |||||
| GLX_DOUBLEBUFFER, | |||||
| GLX_RED_SIZE, 4, | |||||
| GLX_GREEN_SIZE, 4, | |||||
| GLX_BLUE_SIZE, 4, | |||||
| GLX_ALPHA_SIZE, 4, | |||||
| GLX_DEPTH_SIZE, 16, | |||||
| GLX_SAMPLE_BUFFERS, 1, | |||||
| GLX_SAMPLES, 4, | |||||
| None | |||||
| }; | |||||
| impl->doubleBuffered = True; | |||||
| vi = glXChooseVisual(impl->display, impl->screen, attrListDblMS); | |||||
| if (vi == NULL) { | |||||
| vi = glXChooseVisual(impl->display, impl->screen, attrListDbl); | |||||
| PUGL_LOG("multisampling (antialiasing) is not available\n"); | |||||
| } | |||||
| if (vi == NULL) { | |||||
| vi = glXChooseVisual(impl->display, impl->screen, attrListSgl); | |||||
| impl->doubleBuffered = False; | |||||
| PUGL_LOG("singlebuffered rendering will be used, no doublebuffering available\n"); | |||||
| } | |||||
| } | |||||
| #endif | |||||
| #ifdef PUGL_HAVE_CAIRO | |||||
| if (view->ctx_type == PUGL_CAIRO) { | |||||
| XVisualInfo pat; | |||||
| int n; | |||||
| pat.screen = impl->screen; | |||||
| vi = XGetVisualInfo(impl->display, VisualScreenMask, &pat, &n); | |||||
| } | |||||
| #endif | |||||
| return vi; | |||||
| } | |||||
| static bool | |||||
| createContext(PuglView* view, XVisualInfo* vi) | |||||
| { | |||||
| PuglInternals* const impl = view->impl; | |||||
| /** | |||||
| Attributes for single-buffered RGBA with at least | |||||
| 4 bits per color and a 16 bit depth buffer. | |||||
| */ | |||||
| static int attrListSgl[] = { | |||||
| GLX_RGBA, | |||||
| GLX_RED_SIZE, 4, | |||||
| GLX_GREEN_SIZE, 4, | |||||
| GLX_BLUE_SIZE, 4, | |||||
| GLX_DEPTH_SIZE, 16, | |||||
| GLX_ARB_multisample, 1, | |||||
| None | |||||
| }; | |||||
| #ifdef PUGL_HAVE_GL | |||||
| if (view->ctx_type == PUGL_GL) { | |||||
| impl->ctx = glXCreateContext(impl->display, vi, 0, GL_TRUE); | |||||
| return (impl->ctx != NULL); | |||||
| } | |||||
| #endif | |||||
| #ifdef PUGL_HAVE_CAIRO | |||||
| if (view->ctx_type == PUGL_CAIRO) { | |||||
| impl->surface = cairo_xlib_surface_create( | |||||
| impl->display, impl->win, vi->visual, view->width, view->height); | |||||
| if (impl->surface == NULL) { | |||||
| PUGL_LOG("failed to create cairo surface\n"); | |||||
| return false; | |||||
| } | |||||
| impl->cr = cairo_create(impl->surface); | |||||
| if (impl->cr == NULL) { | |||||
| cairo_surface_destroy(impl->surface); | |||||
| impl->surface = NULL; | |||||
| PUGL_LOG("failed to create cairo context\n"); | |||||
| return false; | |||||
| } | |||||
| return true; | |||||
| } | |||||
| #endif | |||||
| /** | |||||
| Attributes for double-buffered RGBA with at least | |||||
| 4 bits per color and a 16 bit depth buffer. | |||||
| */ | |||||
| static int attrListDbl[] = { | |||||
| GLX_RGBA, | |||||
| GLX_DOUBLEBUFFER, True, | |||||
| GLX_RED_SIZE, 4, | |||||
| GLX_GREEN_SIZE, 4, | |||||
| GLX_BLUE_SIZE, 4, | |||||
| GLX_DEPTH_SIZE, 16, | |||||
| GLX_ARB_multisample, 1, | |||||
| None | |||||
| }; | |||||
| return false; | |||||
| } | |||||
| /** | |||||
| Attributes for double-buffered RGBA with multi-sampling | |||||
| (antialiasing) | |||||
| */ | |||||
| static int attrListDblMS[] = { | |||||
| GLX_RGBA, | |||||
| GLX_DOUBLEBUFFER, True, | |||||
| GLX_RED_SIZE, 4, | |||||
| GLX_GREEN_SIZE, 4, | |||||
| GLX_BLUE_SIZE, 4, | |||||
| GLX_ALPHA_SIZE, 4, | |||||
| GLX_DEPTH_SIZE, 16, | |||||
| GLX_SAMPLE_BUFFERS, 1, | |||||
| GLX_SAMPLES, 4, | |||||
| None | |||||
| }; | |||||
| static void | |||||
| destroyContext(PuglView* view) | |||||
| PuglInternals* | |||||
| puglInitInternals(void) | |||||
| { | { | ||||
| PuglInternals* const impl = view->impl; | |||||
| #ifdef PUGL_HAVE_GL | |||||
| if (view->ctx_type == PUGL_GL) { | |||||
| glXDestroyContext(impl->display, impl->ctx); | |||||
| impl->ctx = NULL; | |||||
| } | |||||
| #endif | |||||
| #ifdef PUGL_HAVE_CAIRO | |||||
| if (view->ctx_type == PUGL_CAIRO) { | |||||
| cairo_destroy(impl->cr); | |||||
| impl->cr = NULL; | |||||
| cairo_surface_destroy(impl->surface); | |||||
| impl->surface = NULL; | |||||
| } | |||||
| #endif | |||||
| return (PuglInternals*)calloc(1, sizeof(PuglInternals)); | |||||
| } | } | ||||
| void | void | ||||
| puglEnterContext(PuglView* view) | puglEnterContext(PuglView* view) | ||||
| { | { | ||||
| #ifdef PUGL_HAVE_GL | |||||
| if (view->ctx_type == PUGL_GL) { | |||||
| glXMakeCurrent(view->impl->display, view->impl->win, view->impl->ctx); | |||||
| } | |||||
| #endif | |||||
| glXMakeCurrent(view->impl->display, view->impl->win, view->impl->ctx); | |||||
| } | } | ||||
| void | void | ||||
| puglLeaveContext(PuglView* view, bool flush) | puglLeaveContext(PuglView* view, bool flush) | ||||
| { | { | ||||
| #ifdef PUGL_HAVE_GL | |||||
| if (view->ctx_type == PUGL_GL) { | |||||
| if (flush) { | |||||
| glFlush(); | |||||
| if (view->impl->doubleBuffered) { | |||||
| glXSwapBuffers(view->impl->display, view->impl->win); | |||||
| } | |||||
| if (flush) { | |||||
| glFlush(); | |||||
| if (view->impl->doubleBuffered) { | |||||
| glXSwapBuffers(view->impl->display, view->impl->win); | |||||
| } | } | ||||
| glXMakeCurrent(view->impl->display, None, NULL); | |||||
| } | } | ||||
| #endif | |||||
| glXMakeCurrent(view->impl->display, None, NULL); | |||||
| } | } | ||||
| int | int | ||||
| puglCreateWindow(PuglView* view, const char* title) | puglCreateWindow(PuglView* view, const char* title) | ||||
| { | { | ||||
| PuglInternals* const impl = view->impl; | |||||
| PuglInternals* impl = (PuglInternals*)calloc(1, sizeof(PuglInternals)); | |||||
| if (!impl) { | |||||
| return 1; | |||||
| } | |||||
| view->impl = impl; | |||||
| impl->display = XOpenDisplay(NULL); | impl->display = XOpenDisplay(NULL); | ||||
| impl->screen = DefaultScreen(impl->display); | |||||
| if (!impl->display) { | |||||
| free(impl); | |||||
| return 1; | |||||
| } | |||||
| impl->screen = DefaultScreen(impl->display); | |||||
| impl->doubleBuffered = True; | |||||
| XVisualInfo* vi = glXChooseVisual(impl->display, impl->screen, attrListDblMS); | |||||
| if (!vi) { | |||||
| vi = glXChooseVisual(impl->display, impl->screen, attrListDbl); | |||||
| #ifdef PUGL_VERBOSE | |||||
| printf("puGL: multisampling (antialiasing) is not available\n"); | |||||
| #endif | |||||
| } | |||||
| if (!vi) { | |||||
| vi = glXChooseVisual(impl->display, impl->screen, attrListSgl); | |||||
| impl->doubleBuffered = False; | |||||
| } | |||||
| XVisualInfo* const vi = getVisual(view); | |||||
| if (!vi) { | if (!vi) { | ||||
| XCloseDisplay(impl->display); | XCloseDisplay(impl->display); | ||||
| impl->display = NULL; | |||||
| free(impl); | |||||
| return 1; | return 1; | ||||
| } | } | ||||
| #ifdef PUGL_HAVE_GL | |||||
| #ifdef PUGL_VERBOSE | |||||
| int glxMajor, glxMinor; | int glxMajor, glxMinor; | ||||
| glXQueryVersion(impl->display, &glxMajor, &glxMinor); | glXQueryVersion(impl->display, &glxMajor, &glxMinor); | ||||
| PUGL_LOGF("GLX Version %d.%d\n", glxMajor, glxMinor); | |||||
| printf("puGL: GLX-Version : %d.%d\n", glxMajor, glxMinor); | |||||
| #endif | #endif | ||||
| impl->ctx = glXCreateContext(impl->display, vi, 0, GL_TRUE); | |||||
| if (!impl->ctx) { | |||||
| XCloseDisplay(impl->display); | |||||
| free(impl); | |||||
| return 1; | |||||
| } | |||||
| Window xParent = view->parent | Window xParent = view->parent | ||||
| ? (Window)view->parent | ? (Window)view->parent | ||||
| : RootWindow(impl->display, impl->screen); | : RootWindow(impl->display, impl->screen); | ||||
| @@ -262,76 +187,55 @@ puglCreateWindow(PuglView* view, const char* title) | |||||
| XSetWindowAttributes attr; | XSetWindowAttributes attr; | ||||
| memset(&attr, 0, sizeof(XSetWindowAttributes)); | memset(&attr, 0, sizeof(XSetWindowAttributes)); | ||||
| attr.background_pixel = BlackPixel(impl->display, impl->screen); | |||||
| attr.border_pixel = BlackPixel(impl->display, impl->screen); | |||||
| attr.colormap = cmap; | |||||
| attr.event_mask = (ExposureMask | StructureNotifyMask | | |||||
| EnterWindowMask | LeaveWindowMask | | |||||
| KeyPressMask | KeyReleaseMask | | |||||
| ButtonPressMask | ButtonReleaseMask | | |||||
| PointerMotionMask | FocusChangeMask); | |||||
| attr.border_pixel = BlackPixel(impl->display, impl->screen); | |||||
| attr.colormap = cmap; | |||||
| attr.event_mask = (ExposureMask | StructureNotifyMask | | |||||
| EnterWindowMask | LeaveWindowMask | | |||||
| KeyPressMask | KeyReleaseMask | | |||||
| ButtonPressMask | ButtonReleaseMask | | |||||
| PointerMotionMask | FocusChangeMask); | |||||
| impl->win = XCreateWindow( | impl->win = XCreateWindow( | ||||
| impl->display, xParent, | impl->display, xParent, | ||||
| 0, 0, view->width, view->height, 0, vi->depth, InputOutput, vi->visual, | 0, 0, view->width, view->height, 0, vi->depth, InputOutput, vi->visual, | ||||
| CWBackPixel | CWBorderPixel | CWColormap | CWEventMask, &attr); | |||||
| if (!createContext(view, vi)) { | |||||
| XDestroyWindow(impl->display, impl->win); | |||||
| impl->win = 0; | |||||
| CWBorderPixel | CWColormap | CWEventMask, &attr); | |||||
| if (!impl->win) { | |||||
| XCloseDisplay(impl->display); | XCloseDisplay(impl->display); | ||||
| impl->display = NULL; | |||||
| free(impl); | |||||
| return 1; | return 1; | ||||
| } | } | ||||
| XSizeHints sizeHints; | |||||
| memset(&sizeHints, 0, sizeof(sizeHints)); | |||||
| if (!view->resizable) { | |||||
| sizeHints.flags = PMinSize|PMaxSize; | |||||
| sizeHints.min_width = view->width; | |||||
| sizeHints.min_height = view->height; | |||||
| sizeHints.max_width = view->width; | |||||
| sizeHints.max_height = view->height; | |||||
| XSetNormalHints(impl->display, impl->win, &sizeHints); | |||||
| } else if (view->min_width > 0 && view->min_height > 0) { | |||||
| sizeHints.flags = PMinSize; | |||||
| sizeHints.min_width = view->min_width; | |||||
| sizeHints.min_height = view->min_height; | |||||
| XSetNormalHints(impl->display, impl->win, &sizeHints); | |||||
| if (view->width > 1 || view->height > 1) { | |||||
| puglUpdateGeometryConstraints(view, view->min_width, view->min_height, view->min_width != view->width); | |||||
| XResizeWindow(view->impl->display, view->impl->win, view->width, view->height); | |||||
| } | } | ||||
| if (title) { | if (title) { | ||||
| XStoreName(impl->display, impl->win, title); | XStoreName(impl->display, impl->win, title); | ||||
| } | } | ||||
| if (!view->parent) { | |||||
| if (view->transient_parent > 0) { | |||||
| XSetTransientForHint(impl->display, impl->win, (Window)view->transient_parent); | |||||
| } | |||||
| if (view->parent) { | |||||
| XMapRaised(impl->display, impl->win); | |||||
| } else { | |||||
| Atom wmDelete = XInternAtom(impl->display, "WM_DELETE_WINDOW", True); | Atom wmDelete = XInternAtom(impl->display, "WM_DELETE_WINDOW", True); | ||||
| XSetWMProtocols(impl->display, impl->win, &wmDelete, 1); | XSetWMProtocols(impl->display, impl->win, &wmDelete, 1); | ||||
| } | } | ||||
| #ifdef PUGL_VERBOSE | |||||
| if (glXIsDirect(impl->display, impl->ctx)) { | if (glXIsDirect(impl->display, impl->ctx)) { | ||||
| PUGL_LOG("DRI enabled (to disable, set LIBGL_ALWAYS_INDIRECT=1\n"); | |||||
| printf("puGL: DRI enabled (to disable, set LIBGL_ALWAYS_INDIRECT=1\n"); | |||||
| } else { | } else { | ||||
| PUGL_LOG("No DRI available\n"); | |||||
| printf("puGL: No DRI available\n"); | |||||
| } | } | ||||
| #endif | |||||
| XFree(vi); | XFree(vi); | ||||
| return PUGL_SUCCESS; | |||||
| } | |||||
| void | |||||
| puglShowWindow(PuglView* view) | |||||
| { | |||||
| XMapRaised(view->impl->display, view->impl->win); | |||||
| } | |||||
| void | |||||
| puglHideWindow(PuglView* view) | |||||
| { | |||||
| XUnmapWindow(view->impl->display, view->impl->win); | |||||
| return 0; | |||||
| } | } | ||||
| void | void | ||||
| @@ -340,18 +244,29 @@ puglDestroy(PuglView* view) | |||||
| if (!view) { | if (!view) { | ||||
| return; | return; | ||||
| } | } | ||||
| #ifndef DGL_FILE_BROWSER_DISABLED | #ifndef DGL_FILE_BROWSER_DISABLED | ||||
| x_fib_close(view->impl->display); | x_fib_close(view->impl->display); | ||||
| #endif | #endif | ||||
| destroyContext(view); | |||||
| glXDestroyContext(view->impl->display, view->impl->ctx); | |||||
| XDestroyWindow(view->impl->display, view->impl->win); | XDestroyWindow(view->impl->display, view->impl->win); | ||||
| XCloseDisplay(view->impl->display); | XCloseDisplay(view->impl->display); | ||||
| free(view->impl); | free(view->impl); | ||||
| free(view); | free(view); | ||||
| } | } | ||||
| void | |||||
| puglShowWindow(PuglView* view) | |||||
| { | |||||
| XMapRaised(view->impl->display, view->impl->win); | |||||
| } | |||||
| void | |||||
| puglHideWindow(PuglView* view) | |||||
| { | |||||
| XUnmapWindow(view->impl->display, view->impl->win); | |||||
| } | |||||
| static void | static void | ||||
| puglReshape(PuglView* view, int width, int height) | puglReshape(PuglView* view, int width, int height) | ||||
| { | { | ||||
| @@ -360,7 +275,7 @@ puglReshape(PuglView* view, int width, int height) | |||||
| if (view->reshapeFunc) { | if (view->reshapeFunc) { | ||||
| view->reshapeFunc(view, width, height); | view->reshapeFunc(view, width, height); | ||||
| } else { | } else { | ||||
| puglDefaultReshape(view, width, height); | |||||
| puglDefaultReshape(width, height); | |||||
| } | } | ||||
| puglLeaveContext(view, false); | puglLeaveContext(view, false); | ||||
| @@ -375,7 +290,6 @@ puglDisplay(PuglView* view) | |||||
| puglEnterContext(view); | puglEnterContext(view); | ||||
| view->redisplay = false; | view->redisplay = false; | ||||
| if (view->displayFunc) { | if (view->displayFunc) { | ||||
| view->displayFunc(view); | view->displayFunc(view); | ||||
| } | } | ||||
| @@ -383,6 +297,36 @@ puglDisplay(PuglView* view) | |||||
| puglLeaveContext(view, true); | puglLeaveContext(view, true); | ||||
| } | } | ||||
| static void | |||||
| puglResize(PuglView* view) | |||||
| { | |||||
| int set_hints = 1; | |||||
| view->pending_resize = false; | |||||
| if (!view->resizeFunc) { return; } | |||||
| /* ask the plugin about the new size */ | |||||
| view->resizeFunc(view, &view->width, &view->height, &set_hints); | |||||
| if (set_hints) { | |||||
| XSizeHints sizeHints; | |||||
| memset(&sizeHints, 0, sizeof(sizeHints)); | |||||
| sizeHints.flags = PMinSize|PMaxSize; | |||||
| sizeHints.min_width = view->width; | |||||
| sizeHints.min_height = view->height; | |||||
| sizeHints.max_width = view->user_resizable ? 4096 : view->width; | |||||
| sizeHints.max_height = view->user_resizable ? 4096 : view->height; | |||||
| XSetWMNormalHints(view->impl->display, view->impl->win, &sizeHints); | |||||
| } | |||||
| XResizeWindow(view->impl->display, view->impl->win, view->width, view->height); | |||||
| XFlush(view->impl->display); | |||||
| #ifdef PUGL_VERBOSE | |||||
| printf("puGL: window resize (%dx%d)\n", view->width, view->height); | |||||
| #endif | |||||
| /* and call Reshape in glX context */ | |||||
| puglReshape(view, view->width, view->height); | |||||
| } | |||||
| static PuglKey | static PuglKey | ||||
| keySymToSpecial(KeySym sym) | keySymToSpecial(KeySym sym) | ||||
| { | { | ||||
| @@ -477,6 +421,9 @@ send_event: | |||||
| PuglStatus | PuglStatus | ||||
| puglProcessEvents(PuglView* view) | puglProcessEvents(PuglView* view) | ||||
| { | { | ||||
| int conf_width = -1; | |||||
| int conf_height = -1; | |||||
| XEvent event; | XEvent event; | ||||
| while (XPending(view->impl->display) > 0) { | while (XPending(view->impl->display) > 0) { | ||||
| XNextEvent(view->impl->display, &event); | XNextEvent(view->impl->display, &event); | ||||
| @@ -511,22 +458,26 @@ puglProcessEvents(PuglView* view) | |||||
| } | } | ||||
| switch (event.type) { | switch (event.type) { | ||||
| case UnmapNotify: | |||||
| if (view->motionFunc) { | |||||
| view->motionFunc(view, -1, -1); | |||||
| } | |||||
| break; | |||||
| case MapNotify: | case MapNotify: | ||||
| puglReshape(view, view->width, view->height); | puglReshape(view, view->width, view->height); | ||||
| break; | break; | ||||
| case ConfigureNotify: | case ConfigureNotify: | ||||
| if ((event.xconfigure.width != view->width) || | if ((event.xconfigure.width != view->width) || | ||||
| (event.xconfigure.height != view->height)) { | (event.xconfigure.height != view->height)) { | ||||
| puglReshape(view, | |||||
| event.xconfigure.width, | |||||
| event.xconfigure.height); | |||||
| conf_width = event.xconfigure.width; | |||||
| conf_height = event.xconfigure.height; | |||||
| } | } | ||||
| break; | break; | ||||
| case Expose: | case Expose: | ||||
| if (event.xexpose.count != 0) { | if (event.xexpose.count != 0) { | ||||
| break; | break; | ||||
| } | } | ||||
| puglDisplay(view); | |||||
| view->redisplay = true; | |||||
| break; | break; | ||||
| case MotionNotify: | case MotionNotify: | ||||
| setModifiers(view, event.xmotion.state, event.xmotion.time); | setModifiers(view, event.xmotion.state, event.xmotion.time); | ||||
| @@ -602,6 +553,14 @@ puglProcessEvents(PuglView* view) | |||||
| } | } | ||||
| } | } | ||||
| if (conf_width != -1) { | |||||
| puglReshape(view, conf_width, conf_height); | |||||
| } | |||||
| if (view->pending_resize) { | |||||
| puglResize(view); | |||||
| } | |||||
| if (view->redisplay) { | if (view->redisplay) { | ||||
| puglDisplay(view); | puglDisplay(view); | ||||
| } | } | ||||
| @@ -615,22 +574,35 @@ puglPostRedisplay(PuglView* view) | |||||
| view->redisplay = true; | view->redisplay = true; | ||||
| } | } | ||||
| void | |||||
| puglPostResize(PuglView* view) | |||||
| { | |||||
| view->pending_resize = true; | |||||
| } | |||||
| PuglNativeWindow | PuglNativeWindow | ||||
| puglGetNativeWindow(PuglView* view) | puglGetNativeWindow(PuglView* view) | ||||
| { | { | ||||
| return view->impl->win; | return view->impl->win; | ||||
| } | } | ||||
| void* | |||||
| puglGetContext(PuglView* view) | |||||
| int | |||||
| puglUpdateGeometryConstraints(PuglView* view, int min_width, int min_height, bool aspect) | |||||
| { | { | ||||
| #ifdef PUGL_HAVE_CAIRO | |||||
| if (view->ctx_type == PUGL_CAIRO) { | |||||
| return view->impl->cr; | |||||
| XSizeHints sizeHints; | |||||
| memset(&sizeHints, 0, sizeof(sizeHints)); | |||||
| sizeHints.flags = PMinSize|PMaxSize; | |||||
| sizeHints.min_width = min_width; | |||||
| sizeHints.min_height = min_height; | |||||
| sizeHints.max_width = view->user_resizable ? 4096 : min_width; | |||||
| sizeHints.max_height = view->user_resizable ? 4096 : min_height; | |||||
| if (aspect) { | |||||
| sizeHints.flags |= PAspect; | |||||
| sizeHints.min_aspect.x = min_width; | |||||
| sizeHints.min_aspect.y = min_height; | |||||
| sizeHints.max_aspect.x = min_width; | |||||
| sizeHints.max_aspect.y = min_height; | |||||
| } | } | ||||
| #endif | |||||
| return NULL; | |||||
| // may be unused | |||||
| (void)view; | |||||
| XSetWMNormalHints(view->impl->display, view->impl->win, &sizeHints); | |||||
| return 0; | |||||
| } | } | ||||
| @@ -546,7 +546,7 @@ struct TimePosition { | |||||
| /** | /** | ||||
| Current tick within beat.@n | Current tick within beat.@n | ||||
| Should always be > 0 and <= @a ticksPerBeat.@n | |||||
| Should always be >= 0 and < @a ticksPerBeat.@n | |||||
| The first tick is tick '0'. | The first tick is tick '0'. | ||||
| */ | */ | ||||
| int32_t tick; | int32_t tick; | ||||
| @@ -567,7 +567,7 @@ struct TimePosition { | |||||
| float beatType; | float beatType; | ||||
| /** | /** | ||||
| Number of ticks within a bar.@n | |||||
| Number of ticks within a beat.@n | |||||
| Usually a moderately large integer with many denominators, such as 1920.0. | Usually a moderately large integer with many denominators, such as 1920.0. | ||||
| */ | */ | ||||
| double ticksPerBeat; | double ticksPerBeat; | ||||
| @@ -590,6 +590,22 @@ struct TimePosition { | |||||
| beatType(0.0f), | beatType(0.0f), | ||||
| ticksPerBeat(0.0), | ticksPerBeat(0.0), | ||||
| beatsPerMinute(0.0) {} | beatsPerMinute(0.0) {} | ||||
| /** | |||||
| Reinitialize this position using the default null initialization. | |||||
| */ | |||||
| void clear() noexcept | |||||
| { | |||||
| valid = false; | |||||
| bar = 0; | |||||
| beat = 0; | |||||
| tick = 0; | |||||
| barStartTick = 0.0; | |||||
| beatsPerBar = 0.0f; | |||||
| beatType = 0.0f; | |||||
| ticksPerBeat = 0.0; | |||||
| beatsPerMinute = 0.0; | |||||
| } | |||||
| } bbt; | } bbt; | ||||
| /** | /** | ||||
| @@ -599,6 +615,16 @@ struct TimePosition { | |||||
| : playing(false), | : playing(false), | ||||
| frame(0), | frame(0), | ||||
| bbt() {} | bbt() {} | ||||
| /** | |||||
| Reinitialize this position using the default null initialization. | |||||
| */ | |||||
| void clear() noexcept | |||||
| { | |||||
| playing = false; | |||||
| frame = 0; | |||||
| bbt.clear(); | |||||
| } | |||||
| }; | }; | ||||
| /** @} */ | /** @} */ | ||||
| @@ -1,6 +1,6 @@ | |||||
| /* | /* | ||||
| * DISTRHO Plugin Framework (DPF) | * DISTRHO Plugin Framework (DPF) | ||||
| * Copyright (C) 2012-2016 Filipe Coelho <falktx@falktx.com> | |||||
| * Copyright (C) 2012-2018 Filipe Coelho <falktx@falktx.com> | |||||
| * | * | ||||
| * Permission to use, copy, modify, and/or distribute this software for any purpose with | * 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 | * or without fee is hereby granted, provided that the above copyright notice and this | ||||
| @@ -20,7 +20,8 @@ | |||||
| #include "extra/LeakDetector.hpp" | #include "extra/LeakDetector.hpp" | ||||
| #include "src/DistrhoPluginChecks.h" | #include "src/DistrhoPluginChecks.h" | ||||
| #ifndef HAVE_DGL | |||||
| #if DISTRHO_PLUGIN_HAS_EXTERNAL_UI | |||||
| # include "../dgl/Base.hpp" | |||||
| # include "extra/ExternalWindow.hpp" | # include "extra/ExternalWindow.hpp" | ||||
| typedef DISTRHO_NAMESPACE::ExternalWindow UIWidget; | typedef DISTRHO_NAMESPACE::ExternalWindow UIWidget; | ||||
| #elif DISTRHO_UI_USE_NANOVG | #elif DISTRHO_UI_USE_NANOVG | ||||
| @@ -54,13 +55,28 @@ public: | |||||
| UI class constructor. | UI class constructor. | ||||
| The UI should be initialized to a default state that matches the plugin side. | The UI should be initialized to a default state that matches the plugin side. | ||||
| */ | */ | ||||
| UI(uint width = 0, uint height = 0); | |||||
| UI(uint width = 0, uint height = 0, bool userResizable = false); | |||||
| /** | /** | ||||
| Destructor. | Destructor. | ||||
| */ | */ | ||||
| virtual ~UI(); | virtual ~UI(); | ||||
| /** | |||||
| Wherever this UI is resizable by the user. | |||||
| This simply returns the value passed in the constructor. | |||||
| */ | |||||
| bool isUserResizable() const noexcept; | |||||
| #if !DISTRHO_PLUGIN_HAS_EXTERNAL_UI | |||||
| /** | |||||
| Set geometry constraints for the UI when resized by the user, and optionally scale UI automatically. | |||||
| @see Window::setGeometryConstraints(uint,uint,bool) | |||||
| @see Window::setScaling(double) | |||||
| */ | |||||
| void setGeometryConstraints(uint minWidth, uint minHeight, bool keepAspectRatio, bool automaticallyScale = false); | |||||
| #endif | |||||
| /* -------------------------------------------------------------------------------------------------------- | /* -------------------------------------------------------------------------------------------------------- | ||||
| * Host state */ | * Host state */ | ||||
| @@ -166,7 +182,7 @@ protected: | |||||
| */ | */ | ||||
| virtual void sampleRateChanged(double newSampleRate); | virtual void sampleRateChanged(double newSampleRate); | ||||
| #ifdef HAVE_DGL | |||||
| #if !DISTRHO_PLUGIN_HAS_EXTERNAL_UI | |||||
| /* -------------------------------------------------------------------------------------------------------- | /* -------------------------------------------------------------------------------------------------------- | ||||
| * UI Callbacks (optional) */ | * UI Callbacks (optional) */ | ||||
| @@ -176,13 +192,13 @@ protected: | |||||
| */ | */ | ||||
| virtual void uiIdle() {} | virtual void uiIdle() {} | ||||
| #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::fileBrowserSelected(const char*) | ||||
| */ | */ | ||||
| virtual void uiFileBrowserSelected(const char* filename); | virtual void uiFileBrowserSelected(const char* filename); | ||||
| #endif | |||||
| # endif | |||||
| /** | /** | ||||
| OpenGL window reshape function, called when parent window is resized. | OpenGL window reshape function, called when parent window is resized. | ||||
| @@ -210,7 +226,7 @@ private: | |||||
| friend class UIExporter; | friend class UIExporter; | ||||
| friend class UIExporterWindow; | friend class UIExporterWindow; | ||||
| #ifdef HAVE_DGL | |||||
| #if !DISTRHO_PLUGIN_HAS_EXTERNAL_UI | |||||
| // these should not be used | // these should not be used | ||||
| void setAbsoluteX(int) const noexcept {} | void setAbsoluteX(int) const noexcept {} | ||||
| void setAbsoluteY(int) const noexcept {} | void setAbsoluteY(int) const noexcept {} | ||||
| @@ -40,6 +40,8 @@ public: | |||||
| : width(w), | : width(w), | ||||
| height(h), | height(h), | ||||
| title(t), | title(t), | ||||
| transientWinId(0), | |||||
| visible(false), | |||||
| pid(0) {} | pid(0) {} | ||||
| virtual ~ExternalWindow() | virtual ~ExternalWindow() | ||||
| @@ -62,9 +64,14 @@ public: | |||||
| return title; | return title; | ||||
| } | } | ||||
| void setTitle(const char* const t) noexcept | |||||
| uintptr_t getTransientWinId() const noexcept | |||||
| { | { | ||||
| title = t; | |||||
| return transientWinId; | |||||
| } | |||||
| bool isVisible() const noexcept | |||||
| { | |||||
| return visible; | |||||
| } | } | ||||
| bool isRunning() noexcept | bool isRunning() noexcept | ||||
| @@ -84,6 +91,27 @@ public: | |||||
| return true; | return true; | ||||
| } | } | ||||
| virtual void setSize(uint w, uint h) | |||||
| { | |||||
| width = w; | |||||
| height = h; | |||||
| } | |||||
| virtual void setTitle(const char* const t) | |||||
| { | |||||
| title = t; | |||||
| } | |||||
| virtual void setTransientWinId(const uintptr_t winId) | |||||
| { | |||||
| transientWinId = winId; | |||||
| } | |||||
| virtual void setVisible(const bool yesNo) | |||||
| { | |||||
| visible = yesNo; | |||||
| } | |||||
| protected: | protected: | ||||
| bool startExternalProcess(const char* args[]) | bool startExternalProcess(const char* args[]) | ||||
| { | { | ||||
| @@ -107,14 +135,6 @@ protected: | |||||
| } | } | ||||
| } | } | ||||
| private: | |||||
| uint width; | |||||
| uint height; | |||||
| String title; | |||||
| pid_t pid; | |||||
| friend class UIExporter; | |||||
| void terminateAndWaitForProcess() | void terminateAndWaitForProcess() | ||||
| { | { | ||||
| if (pid <= 0) | if (pid <= 0) | ||||
| @@ -162,6 +182,16 @@ private: | |||||
| } | } | ||||
| } | } | ||||
| private: | |||||
| uint width; | |||||
| uint height; | |||||
| String title; | |||||
| uintptr_t transientWinId; | |||||
| bool visible; | |||||
| pid_t pid; | |||||
| friend class UIExporter; | |||||
| DISTRHO_DECLARE_NON_COPY_CLASS(ExternalWindow) | DISTRHO_DECLARE_NON_COPY_CLASS(ExternalWindow) | ||||
| }; | }; | ||||
| @@ -66,6 +66,15 @@ | |||||
| # define nullptr NULL | # define nullptr NULL | ||||
| #endif | #endif | ||||
| /* Define DISTRHO_DEPRECATED */ | |||||
| #if defined(__GNUC__) | |||||
| # define DISTRHO_DEPRECATED __attribute__((deprecated)) | |||||
| #elif defined(_MSC_VER) | |||||
| # define DISTRHO_DEPRECATED __declspec(deprecated) | |||||
| #else | |||||
| # define DISTRHO_DEPRECATED | |||||
| #endif | |||||
| /* Define DISTRHO_SAFE_ASSERT* */ | /* Define DISTRHO_SAFE_ASSERT* */ | ||||
| #define DISTRHO_SAFE_ASSERT(cond) if (! (cond)) d_safe_assert(#cond, __FILE__, __LINE__); | #define DISTRHO_SAFE_ASSERT(cond) if (! (cond)) d_safe_assert(#cond, __FILE__, __LINE__); | ||||
| #define DISTRHO_SAFE_ASSERT_BREAK(cond) if (! (cond)) { d_safe_assert(#cond, __FILE__, __LINE__); break; } | #define DISTRHO_SAFE_ASSERT_BREAK(cond) if (! (cond)) { d_safe_assert(#cond, __FILE__, __LINE__); break; } | ||||
| @@ -126,7 +126,8 @@ | |||||
| // ----------------------------------------------------------------------- | // ----------------------------------------------------------------------- | ||||
| // Enable full state if plugin exports presets | // Enable full state if plugin exports presets | ||||
| #if DISTRHO_PLUGIN_WANT_PROGRAMS && DISTRHO_PLUGIN_WANT_STATE | |||||
| #if DISTRHO_PLUGIN_WANT_PROGRAMS && DISTRHO_PLUGIN_WANT_STATE && ! DISTRHO_PLUGIN_WANT_FULL_STATE | |||||
| # warning Plugins with programs and state need to implement full state API | |||||
| # undef DISTRHO_PLUGIN_WANT_FULL_STATE | # undef DISTRHO_PLUGIN_WANT_FULL_STATE | ||||
| # define DISTRHO_PLUGIN_WANT_FULL_STATE 1 | # define DISTRHO_PLUGIN_WANT_FULL_STATE 1 | ||||
| #endif | #endif | ||||
| @@ -16,11 +16,6 @@ | |||||
| #include "DistrhoPluginInternal.hpp" | #include "DistrhoPluginInternal.hpp" | ||||
| #if DISTRHO_PLUGIN_HAS_UI && ! DISTRHO_PLUGIN_HAS_EMBED_UI | |||||
| # undef DISTRHO_PLUGIN_HAS_UI | |||||
| # define DISTRHO_PLUGIN_HAS_UI 0 | |||||
| #endif | |||||
| #if DISTRHO_PLUGIN_HAS_UI | #if DISTRHO_PLUGIN_HAS_UI | ||||
| # include "DistrhoUIInternal.hpp" | # include "DistrhoUIInternal.hpp" | ||||
| #else | #else | ||||
| @@ -286,9 +286,9 @@ public: | |||||
| # if DISTRHO_PLUGIN_WANT_STATE | # if DISTRHO_PLUGIN_WANT_STATE | ||||
| char* dssi_configure(const char* const key, const char* const value) | char* dssi_configure(const char* const key, const char* const value) | ||||
| { | { | ||||
| if (std::strncmp(key, DSSI_RESERVED_CONFIGURE_PREFIX, std::strlen(DSSI_RESERVED_CONFIGURE_PREFIX) == 0)) | |||||
| if (std::strncmp(key, DSSI_RESERVED_CONFIGURE_PREFIX, std::strlen(DSSI_RESERVED_CONFIGURE_PREFIX)) == 0) | |||||
| return nullptr; | return nullptr; | ||||
| if (std::strncmp(key, DSSI_GLOBAL_CONFIGURE_PREFIX, std::strlen(DSSI_GLOBAL_CONFIGURE_PREFIX) == 0)) | |||||
| if (std::strncmp(key, DSSI_GLOBAL_CONFIGURE_PREFIX, std::strlen(DSSI_GLOBAL_CONFIGURE_PREFIX)) == 0) | |||||
| return nullptr; | return nullptr; | ||||
| fPlugin.setState(key, value); | fPlugin.setState(key, value); | ||||
| @@ -169,7 +169,7 @@ public: | |||||
| void lv2_activate() | void lv2_activate() | ||||
| { | { | ||||
| #if DISTRHO_PLUGIN_WANT_TIMEPOS | #if DISTRHO_PLUGIN_WANT_TIMEPOS | ||||
| std::memset(&fTimePosition, 0, sizeof(TimePosition)); | |||||
| fTimePosition.clear(); | |||||
| // hosts may not send all values, resulting on some invalid data | // hosts may not send all values, resulting on some invalid data | ||||
| fTimePosition.bbt.bar = 1; | fTimePosition.bbt.bar = 1; | ||||
| @@ -613,7 +613,6 @@ public: | |||||
| fEventsOutData.initIfNeeded(fURIDs.atomSequence); | fEventsOutData.initIfNeeded(fURIDs.atomSequence); | ||||
| LV2_Atom_Event* aev; | LV2_Atom_Event* aev; | ||||
| uint32_t offset = fEventsOutData.offset; | |||||
| const uint32_t capacity = fEventsOutData.capacity; | const uint32_t capacity = fEventsOutData.capacity; | ||||
| for (uint32_t i=0, count=fPlugin.getStateCount(); i < count; ++i) | for (uint32_t i=0, count=fPlugin.getStateCount(); i < count; ++i) | ||||
| @@ -635,8 +634,11 @@ public: | |||||
| // set msg size (key + value + separator + 2x null terminator) | // set msg size (key + value + separator + 2x null terminator) | ||||
| const size_t msgSize(key.length()+value.length()+3); | const size_t msgSize(key.length()+value.length()+3); | ||||
| if (sizeof(LV2_Atom_Event) + msgSize > capacity - offset) | |||||
| if (sizeof(LV2_Atom_Event) + msgSize > capacity - fEventsOutData.offset) | |||||
| { | |||||
| d_stdout("Sending key '%s' to UI failed, out of space", key.buffer()); | |||||
| break; | break; | ||||
| } | |||||
| // reserve msg space | // reserve msg space | ||||
| // FIXME create a large enough buffer beforehand | // FIXME create a large enough buffer beforehand | ||||
| @@ -644,15 +646,15 @@ public: | |||||
| std::memset(msgBuf, 0, msgSize); | std::memset(msgBuf, 0, msgSize); | ||||
| // write key and value in atom bufer | // write key and value in atom bufer | ||||
| std::memcpy(msgBuf, key.buffer(), key.length()); | |||||
| std::memcpy(msgBuf+(key.length()+1), value.buffer(), value.length()); | |||||
| std::memcpy(msgBuf, key.buffer(), key.length()+1); | |||||
| std::memcpy(msgBuf+(key.length()+1), value.buffer(), value.length()+1); | |||||
| // put data | // put data | ||||
| aev = (LV2_Atom_Event*)(LV2_ATOM_CONTENTS(LV2_Atom_Sequence, fEventsOutData.port) + offset); | |||||
| aev = (LV2_Atom_Event*)(LV2_ATOM_CONTENTS(LV2_Atom_Sequence, fEventsOutData.port) + fEventsOutData.offset); | |||||
| aev->time.frames = 0; | aev->time.frames = 0; | ||||
| aev->body.type = fURIDs.distrhoState; | aev->body.type = fURIDs.distrhoState; | ||||
| aev->body.size = msgSize; | aev->body.size = msgSize; | ||||
| std::memcpy(LV2_ATOM_BODY(&aev->body), msgBuf, msgSize-1); | |||||
| std::memcpy(LV2_ATOM_BODY(&aev->body), msgBuf, msgSize); | |||||
| fEventsOutData.growBy(lv2_atom_pad_size(sizeof(LV2_Atom_Event) + msgSize)); | fEventsOutData.growBy(lv2_atom_pad_size(sizeof(LV2_Atom_Event) + msgSize)); | ||||
| @@ -139,6 +139,7 @@ void lv2_generate_ttl(const char* const basename) | |||||
| # endif | # endif | ||||
| manifestString += "\n"; | manifestString += "\n"; | ||||
| # if DISTRHO_PLUGIN_HAS_EMBED_UI | # if DISTRHO_PLUGIN_HAS_EMBED_UI | ||||
| // TODO: pluginUI.isUserResizable() | |||||
| manifestString += " lv2:optionalFeature ui:noUserResize ,\n"; | manifestString += " lv2:optionalFeature ui:noUserResize ,\n"; | ||||
| manifestString += " ui:resize ,\n"; | manifestString += " ui:resize ,\n"; | ||||
| manifestString += " ui:touch ;\n"; | manifestString += " ui:touch ;\n"; | ||||
| @@ -148,9 +149,10 @@ void lv2_generate_ttl(const char* const basename) | |||||
| manifestString += " <" LV2_INSTANCE_ACCESS_URI "> ,\n"; | manifestString += " <" LV2_INSTANCE_ACCESS_URI "> ,\n"; | ||||
| manifestString += " <" LV2_OPTIONS__options "> ,\n"; | manifestString += " <" LV2_OPTIONS__options "> ,\n"; | ||||
| manifestString += " <" LV2_URID__map "> .\n"; | manifestString += " <" LV2_URID__map "> .\n"; | ||||
| # else | |||||
| manifestString += " opts:supportedOption <" LV2_PARAMETERS__sampleRate "> .\n"; | |||||
| # else // DISTRHO_PLUGIN_WANT_DIRECT_ACCESS | |||||
| manifestString += " rdfs:seeAlso <" + uiTTL + "> .\n"; | manifestString += " rdfs:seeAlso <" + uiTTL + "> .\n"; | ||||
| # endif | |||||
| # endif // DISTRHO_PLUGIN_WANT_DIRECT_ACCESS | |||||
| manifestString += "\n"; | manifestString += "\n"; | ||||
| #endif | #endif | ||||
| @@ -192,7 +194,7 @@ void lv2_generate_ttl(const char* const basename) | |||||
| String pluginString; | String pluginString; | ||||
| // header | // header | ||||
| #if DISTRHO_LV2_USE_EVENTS_IN | |||||
| #if DISTRHO_LV2_USE_EVENTS_IN || DISTRHO_LV2_USE_EVENTS_OUT | |||||
| pluginString += "@prefix atom: <" LV2_ATOM_PREFIX "> .\n"; | pluginString += "@prefix atom: <" LV2_ATOM_PREFIX "> .\n"; | ||||
| #endif | #endif | ||||
| pluginString += "@prefix doap: <http://usefulinc.com/ns/doap#> .\n"; | pluginString += "@prefix doap: <http://usefulinc.com/ns/doap#> .\n"; | ||||
| @@ -628,6 +630,7 @@ void lv2_generate_ttl(const char* const basename) | |||||
| # endif | # endif | ||||
| uiString += "\n"; | uiString += "\n"; | ||||
| # if DISTRHO_PLUGIN_HAS_EMBED_UI | # if DISTRHO_PLUGIN_HAS_EMBED_UI | ||||
| // TODO: pluginUI.isUserResizable() | |||||
| uiString += " lv2:optionalFeature ui:noUserResize ,\n"; | uiString += " lv2:optionalFeature ui:noUserResize ,\n"; | ||||
| uiString += " ui:resize ,\n"; | uiString += " ui:resize ,\n"; | ||||
| uiString += " ui:touch ;\n"; | uiString += " ui:touch ;\n"; | ||||
| @@ -72,8 +72,16 @@ static const writeMidiFunc writeMidiCallback = nullptr; | |||||
| void strncpy(char* const dst, const char* const src, const size_t size) | void strncpy(char* const dst, const char* const src, const size_t size) | ||||
| { | { | ||||
| DISTRHO_SAFE_ASSERT_RETURN(size > 0,); | DISTRHO_SAFE_ASSERT_RETURN(size > 0,); | ||||
| std::memcpy(dst, src, std::min(std::strlen(src), size-1)); | |||||
| dst[size-1] = '\0'; | |||||
| if (const size_t len = std::min(std::strlen(src), size-1U)) | |||||
| { | |||||
| std::memcpy(dst, src, len); | |||||
| dst[len] = '\0'; | |||||
| } | |||||
| else | |||||
| { | |||||
| dst[0] = '\0'; | |||||
| } | |||||
| } | } | ||||
| void snprintf_param(char* const dst, const float value, const size_t size) | void snprintf_param(char* const dst, const float value, const size_t size) | ||||
| @@ -965,7 +973,7 @@ public: | |||||
| if (vstTimeInfo->flags & (kVstPpqPosValid|kVstTimeSigValid)) | if (vstTimeInfo->flags & (kVstPpqPosValid|kVstTimeSigValid)) | ||||
| { | { | ||||
| const int ppqPerBar = vstTimeInfo->timeSigNumerator * 4 / vstTimeInfo->timeSigDenominator; | const int ppqPerBar = vstTimeInfo->timeSigNumerator * 4 / vstTimeInfo->timeSigDenominator; | ||||
| const double barBeats = (std::fmod(vstTimeInfo->ppqPos, ppqPerBar) / ppqPerBar) * vstTimeInfo->timeSigDenominator; | |||||
| const double barBeats = (std::fmod(vstTimeInfo->ppqPos, ppqPerBar) / ppqPerBar) * vstTimeInfo->timeSigNumerator; | |||||
| const double rest = std::fmod(barBeats, 1.0); | const double rest = std::fmod(barBeats, 1.0); | ||||
| fTimePosition.bbt.bar = int(vstTimeInfo->ppqPos)/ppqPerBar + 1; | fTimePosition.bbt.bar = int(vstTimeInfo->ppqPos)/ppqPerBar + 1; | ||||
| @@ -1,6 +1,6 @@ | |||||
| /* | /* | ||||
| * DISTRHO Plugin Framework (DPF) | * DISTRHO Plugin Framework (DPF) | ||||
| * Copyright (C) 2012-2016 Filipe Coelho <falktx@falktx.com> | |||||
| * Copyright (C) 2012-2018 Filipe Coelho <falktx@falktx.com> | |||||
| * | * | ||||
| * Permission to use, copy, modify, and/or distribute this software for any purpose with | * 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 | * or without fee is hereby granted, provided that the above copyright notice and this | ||||
| @@ -15,8 +15,7 @@ | |||||
| */ | */ | ||||
| #include "DistrhoUIInternal.hpp" | #include "DistrhoUIInternal.hpp" | ||||
| #ifdef HAVE_DGL | |||||
| #if !DISTRHO_PLUGIN_HAS_EXTERNAL_UI | |||||
| # include "src/WidgetPrivateData.hpp" | # include "src/WidgetPrivateData.hpp" | ||||
| #endif | #endif | ||||
| @@ -27,29 +26,30 @@ START_NAMESPACE_DISTRHO | |||||
| double d_lastUiSampleRate = 0.0; | double d_lastUiSampleRate = 0.0; | ||||
| void* d_lastUiDspPtr = nullptr; | void* d_lastUiDspPtr = nullptr; | ||||
| #ifdef HAVE_DGL | |||||
| Window* d_lastUiWindow = nullptr; | |||||
| #endif | |||||
| #if DISTRHO_PLUGIN_HAS_EXTERNAL_UI | |||||
| uintptr_t g_nextWindowId = 0; | uintptr_t g_nextWindowId = 0; | ||||
| const char* g_nextBundlePath = nullptr; | const char* g_nextBundlePath = nullptr; | ||||
| #else | |||||
| Window* d_lastUiWindow = nullptr; | |||||
| #endif | |||||
| /* ------------------------------------------------------------------------------------------------------------ | /* ------------------------------------------------------------------------------------------------------------ | ||||
| * UI */ | * UI */ | ||||
| #ifdef HAVE_DGL | |||||
| UI::UI(uint width, uint height) | |||||
| #if DISTRHO_PLUGIN_HAS_EXTERNAL_UI | |||||
| UI::UI(uint width, uint height, bool userResizable) | |||||
| : UIWidget(width, height), | |||||
| pData(new PrivateData(userResizable)) {} | |||||
| #else | |||||
| UI::UI(uint width, uint height, bool userResizable) | |||||
| : UIWidget(*d_lastUiWindow), | : UIWidget(*d_lastUiWindow), | ||||
| pData(new PrivateData()) | |||||
| pData(new PrivateData(userResizable)) | |||||
| { | { | ||||
| ((UIWidget*)this)->pData->needsFullViewport = false; | ((UIWidget*)this)->pData->needsFullViewport = false; | ||||
| if (width > 0 && height > 0) | if (width > 0 && height > 0) | ||||
| setSize(width, height); | setSize(width, height); | ||||
| } | } | ||||
| #else | |||||
| UI::UI(uint width, uint height) | |||||
| : UIWidget(width, height), | |||||
| pData(new PrivateData()) {} | |||||
| #endif | #endif | ||||
| UI::~UI() | UI::~UI() | ||||
| @@ -57,6 +57,25 @@ UI::~UI() | |||||
| delete pData; | delete pData; | ||||
| } | } | ||||
| bool UI::isUserResizable() const noexcept | |||||
| { | |||||
| return pData->userResizable; | |||||
| } | |||||
| #if !DISTRHO_PLUGIN_HAS_EXTERNAL_UI | |||||
| void UI::setGeometryConstraints(uint minWidth, uint minHeight, bool keepAspectRatio, bool automaticallyScale) | |||||
| { | |||||
| DISTRHO_SAFE_ASSERT_RETURN(minWidth > 0,); | |||||
| DISTRHO_SAFE_ASSERT_RETURN(minHeight > 0,); | |||||
| pData->automaticallyScale = automaticallyScale; | |||||
| pData->minWidth = minWidth; | |||||
| pData->minHeight = minHeight; | |||||
| getParentWindow().setGeometryConstraints(minWidth, minHeight, keepAspectRatio); | |||||
| } | |||||
| #endif | |||||
| /* ------------------------------------------------------------------------------------------------------------ | /* ------------------------------------------------------------------------------------------------------------ | ||||
| * Host state */ | * Host state */ | ||||
| @@ -121,15 +140,15 @@ uintptr_t UI::getNextWindowId() noexcept | |||||
| void UI::sampleRateChanged(double) {} | void UI::sampleRateChanged(double) {} | ||||
| #ifdef HAVE_DGL | |||||
| #if !DISTRHO_PLUGIN_HAS_EXTERNAL_UI | |||||
| /* ------------------------------------------------------------------------------------------------------------ | /* ------------------------------------------------------------------------------------------------------------ | ||||
| * UI Callbacks (optional) */ | * UI Callbacks (optional) */ | ||||
| #ifndef DGL_FILE_BROWSER_DISABLED | |||||
| # ifndef DGL_FILE_BROWSER_DISABLED | |||||
| void UI::uiFileBrowserSelected(const char*) | void UI::uiFileBrowserSelected(const char*) | ||||
| { | { | ||||
| } | } | ||||
| #endif | |||||
| # endif | |||||
| void UI::uiReshape(uint width, uint height) | void UI::uiReshape(uint width, uint height) | ||||
| { | { | ||||
| @@ -148,9 +167,12 @@ void UI::uiReshape(uint width, uint height) | |||||
| void UI::onResize(const ResizeEvent& ev) | void UI::onResize(const ResizeEvent& ev) | ||||
| { | { | ||||
| if (pData->resizeInProgress) | |||||
| return; | |||||
| pData->setSizeCallback(ev.size.getWidth(), ev.size.getHeight()); | pData->setSizeCallback(ev.size.getWidth(), ev.size.getHeight()); | ||||
| } | } | ||||
| #endif | |||||
| #endif // !DISTRHO_PLUGIN_HAS_EXTERNAL_UI | |||||
| // ----------------------------------------------------------------------------------------------------------- | // ----------------------------------------------------------------------------------------------------------- | ||||
| @@ -194,7 +194,7 @@ protected: | |||||
| uint8_t mdata[4] = { | uint8_t mdata[4] = { | ||||
| 0, | 0, | ||||
| channel + (velocity != 0 ? 0x90 : 0x80), | |||||
| static_cast<uint8_t>(channel + (velocity != 0 ? 0x90 : 0x80)), | |||||
| note, | note, | ||||
| velocity | velocity | ||||
| }; | }; | ||||
| @@ -19,7 +19,10 @@ | |||||
| #include "../DistrhoUI.hpp" | #include "../DistrhoUI.hpp" | ||||
| #ifdef HAVE_DGL | |||||
| #if DISTRHO_PLUGIN_HAS_EXTERNAL_UI | |||||
| # include "../extra/Sleep.hpp" | |||||
| using DGL_NAMESPACE::IdleCallback; | |||||
| #else | |||||
| # include "../../dgl/Application.hpp" | # include "../../dgl/Application.hpp" | ||||
| # include "../../dgl/Window.hpp" | # include "../../dgl/Window.hpp" | ||||
| using DGL_NAMESPACE::Application; | using DGL_NAMESPACE::Application; | ||||
| @@ -34,7 +37,7 @@ START_NAMESPACE_DISTRHO | |||||
| extern double d_lastUiSampleRate; | extern double d_lastUiSampleRate; | ||||
| extern void* d_lastUiDspPtr; | extern void* d_lastUiDspPtr; | ||||
| #ifdef HAVE_DGL | |||||
| #if !DISTRHO_PLUGIN_HAS_EXTERNAL_UI | |||||
| extern Window* d_lastUiWindow; | extern Window* d_lastUiWindow; | ||||
| #endif | #endif | ||||
| extern uintptr_t g_nextWindowId; | extern uintptr_t g_nextWindowId; | ||||
| @@ -60,6 +63,13 @@ struct UI::PrivateData { | |||||
| void* dspPtr; | void* dspPtr; | ||||
| #endif | #endif | ||||
| // UI | |||||
| const bool userResizable; | |||||
| bool automaticallyScale; | |||||
| bool resizeInProgress; | |||||
| uint minWidth; | |||||
| uint minHeight; | |||||
| // Callbacks | // Callbacks | ||||
| void* callbacksPtr; | void* callbacksPtr; | ||||
| editParamFunc editParamCallbackFunc; | editParamFunc editParamCallbackFunc; | ||||
| @@ -68,12 +78,17 @@ struct UI::PrivateData { | |||||
| sendNoteFunc sendNoteCallbackFunc; | sendNoteFunc sendNoteCallbackFunc; | ||||
| setSizeFunc setSizeCallbackFunc; | setSizeFunc setSizeCallbackFunc; | ||||
| PrivateData() noexcept | |||||
| PrivateData(const bool resizable) noexcept | |||||
| : sampleRate(d_lastUiSampleRate), | : sampleRate(d_lastUiSampleRate), | ||||
| parameterOffset(0), | parameterOffset(0), | ||||
| #if DISTRHO_PLUGIN_WANT_DIRECT_ACCESS | #if DISTRHO_PLUGIN_WANT_DIRECT_ACCESS | ||||
| dspPtr(d_lastUiDspPtr), | dspPtr(d_lastUiDspPtr), | ||||
| #endif | #endif | ||||
| userResizable(resizable), | |||||
| automaticallyScale(false), | |||||
| resizeInProgress(false), | |||||
| minWidth(0), | |||||
| minHeight(0), | |||||
| callbacksPtr(nullptr), | callbacksPtr(nullptr), | ||||
| editParamCallbackFunc(nullptr), | editParamCallbackFunc(nullptr), | ||||
| setParamCallbackFunc(nullptr), | setParamCallbackFunc(nullptr), | ||||
| @@ -134,7 +149,20 @@ struct UI::PrivateData { | |||||
| // ----------------------------------------------------------------------- | // ----------------------------------------------------------------------- | ||||
| // Plugin Window, needed to take care of resize properly | // Plugin Window, needed to take care of resize properly | ||||
| #ifdef HAVE_DGL | |||||
| #if DISTRHO_PLUGIN_HAS_EXTERNAL_UI | |||||
| static inline | |||||
| UI* createUiWrapper(void* const dspPtr, const uintptr_t winId, const char* const bundlePath) | |||||
| { | |||||
| d_lastUiDspPtr = dspPtr; | |||||
| g_nextWindowId = winId; | |||||
| g_nextBundlePath = bundlePath; | |||||
| UI* const ret = createUI(); | |||||
| d_lastUiDspPtr = nullptr; | |||||
| g_nextWindowId = 0; | |||||
| g_nextBundlePath = nullptr; | |||||
| return ret; | |||||
| } | |||||
| #else // DISTRHO_PLUGIN_HAS_EXTERNAL_UI | |||||
| static inline | static inline | ||||
| UI* createUiWrapper(void* const dspPtr, Window* const window) | UI* createUiWrapper(void* const dspPtr, Window* const window) | ||||
| { | { | ||||
| @@ -155,9 +183,9 @@ public: | |||||
| fIsReady(false) | fIsReady(false) | ||||
| { | { | ||||
| DISTRHO_SAFE_ASSERT_RETURN(fUI != nullptr,); | DISTRHO_SAFE_ASSERT_RETURN(fUI != nullptr,); | ||||
| DISTRHO_SAFE_ASSERT_RETURN(fUI->pData != nullptr,); | |||||
| // set window size | |||||
| setResizable(false); | |||||
| setResizable(fUI->pData->userResizable); | |||||
| setSize(fUI->getWidth(), fUI->getHeight()); | setSize(fUI->getWidth(), fUI->getHeight()); | ||||
| } | } | ||||
| @@ -182,11 +210,25 @@ protected: | |||||
| { | { | ||||
| DISTRHO_SAFE_ASSERT_RETURN(fUI != nullptr,); | DISTRHO_SAFE_ASSERT_RETURN(fUI != nullptr,); | ||||
| UI::PrivateData* const pData = fUI->pData; | |||||
| DISTRHO_SAFE_ASSERT_RETURN(pData != nullptr,); | |||||
| if (pData->automaticallyScale) | |||||
| { | |||||
| const double scaleHorizontal = static_cast<double>(width) / static_cast<double>(pData->minWidth); | |||||
| const double scaleVertical = static_cast<double>(height) / static_cast<double>(pData->minHeight); | |||||
| setScaling(scaleHorizontal < scaleVertical ? scaleHorizontal : scaleVertical); | |||||
| } | |||||
| pData->resizeInProgress = true; | |||||
| fUI->setSize(width, height); | |||||
| pData->resizeInProgress = false; | |||||
| fUI->uiReshape(width, height); | fUI->uiReshape(width, height); | ||||
| fIsReady = true; | fIsReady = true; | ||||
| } | } | ||||
| #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 fileBrowserSelected(const char* filename) override | ||||
| { | { | ||||
| @@ -194,26 +236,13 @@ protected: | |||||
| fUI->uiFileBrowserSelected(filename); | fUI->uiFileBrowserSelected(filename); | ||||
| } | } | ||||
| #endif | |||||
| # endif | |||||
| private: | private: | ||||
| UI* const fUI; | UI* const fUI; | ||||
| bool fIsReady; | bool fIsReady; | ||||
| }; | }; | ||||
| #else | |||||
| static inline | |||||
| UI* createUiWrapper(void* const dspPtr, const uintptr_t winId, const char* const bundlePath) | |||||
| { | |||||
| d_lastUiDspPtr = dspPtr; | |||||
| g_nextWindowId = winId; | |||||
| g_nextBundlePath = bundlePath; | |||||
| UI* const ret = createUI(); | |||||
| d_lastUiDspPtr = nullptr; | |||||
| g_nextWindowId = 0; | |||||
| g_nextBundlePath = nullptr; | |||||
| return ret; | |||||
| } | |||||
| #endif | |||||
| #endif // DISTRHO_PLUGIN_HAS_EXTERNAL_UI | |||||
| // ----------------------------------------------------------------------- | // ----------------------------------------------------------------------- | ||||
| // UI exporter class | // UI exporter class | ||||
| @@ -230,13 +259,13 @@ public: | |||||
| const setSizeFunc setSizeCall, | const setSizeFunc setSizeCall, | ||||
| void* const dspPtr = nullptr, | void* const dspPtr = nullptr, | ||||
| const char* const bundlePath = nullptr) | const char* const bundlePath = nullptr) | ||||
| #ifdef HAVE_DGL | |||||
| #if DISTRHO_PLUGIN_HAS_EXTERNAL_UI | |||||
| : fUI(createUiWrapper(dspPtr, winId, bundlePath)), | |||||
| #else | |||||
| : glApp(), | : glApp(), | ||||
| glWindow(glApp, winId, dspPtr), | glWindow(glApp, winId, dspPtr), | ||||
| fChangingSize(false), | fChangingSize(false), | ||||
| fUI(glWindow.getUI()), | fUI(glWindow.getUI()), | ||||
| #else | |||||
| : fUI(createUiWrapper(dspPtr, winId, bundlePath)), | |||||
| #endif | #endif | ||||
| fData((fUI != nullptr) ? fUI->pData : nullptr) | fData((fUI != nullptr) ? fUI->pData : nullptr) | ||||
| { | { | ||||
| @@ -250,54 +279,65 @@ public: | |||||
| fData->sendNoteCallbackFunc = sendNoteCall; | fData->sendNoteCallbackFunc = sendNoteCall; | ||||
| fData->setSizeCallbackFunc = setSizeCall; | fData->setSizeCallbackFunc = setSizeCall; | ||||
| #ifdef HAVE_DGL | |||||
| #if !DISTRHO_PLUGIN_HAS_EXTERNAL_UI | |||||
| // unused | // unused | ||||
| return; (void)bundlePath; | return; (void)bundlePath; | ||||
| #endif | #endif | ||||
| } | } | ||||
| #if DISTRHO_PLUGIN_HAS_EXTERNAL_UI | |||||
| ~UIExporter() | |||||
| { | |||||
| delete fUI; | |||||
| } | |||||
| #endif | |||||
| // ------------------------------------------------------------------- | // ------------------------------------------------------------------- | ||||
| #if DISTRHO_PLUGIN_HAS_EXTERNAL_UI | |||||
| uint getWidth() const noexcept | uint getWidth() const noexcept | ||||
| { | { | ||||
| #ifdef HAVE_DGL | |||||
| return glWindow.getWidth(); | |||||
| #else | |||||
| DISTRHO_SAFE_ASSERT_RETURN(fUI != nullptr, 1); | DISTRHO_SAFE_ASSERT_RETURN(fUI != nullptr, 1); | ||||
| return fUI->getWidth(); | return fUI->getWidth(); | ||||
| #endif | |||||
| } | } | ||||
| uint getHeight() const noexcept | uint getHeight() const noexcept | ||||
| { | { | ||||
| #ifdef HAVE_DGL | |||||
| return glWindow.getHeight(); | |||||
| #else | |||||
| DISTRHO_SAFE_ASSERT_RETURN(fUI != nullptr, 1); | DISTRHO_SAFE_ASSERT_RETURN(fUI != nullptr, 1); | ||||
| return fUI->getHeight(); | return fUI->getHeight(); | ||||
| #endif | |||||
| } | } | ||||
| bool isVisible() const noexcept | bool isVisible() const noexcept | ||||
| { | { | ||||
| #ifdef HAVE_DGL | |||||
| return glWindow.isVisible(); | |||||
| #else | |||||
| DISTRHO_SAFE_ASSERT_RETURN(fUI != nullptr, false); | DISTRHO_SAFE_ASSERT_RETURN(fUI != nullptr, false); | ||||
| return fUI->isRunning(); | return fUI->isRunning(); | ||||
| #endif | |||||
| } | } | ||||
| // ------------------------------------------------------------------- | |||||
| intptr_t getWindowId() const noexcept | |||||
| { | |||||
| return 0; | |||||
| } | |||||
| #else | |||||
| uint getWidth() const noexcept | |||||
| { | |||||
| return glWindow.getWidth(); | |||||
| } | |||||
| uint getHeight() const noexcept | |||||
| { | |||||
| return glWindow.getHeight(); | |||||
| } | |||||
| bool isVisible() const noexcept | |||||
| { | |||||
| return glWindow.isVisible(); | |||||
| } | |||||
| intptr_t getWindowId() const noexcept | intptr_t getWindowId() const noexcept | ||||
| { | { | ||||
| #ifdef HAVE_DGL | |||||
| return glWindow.getWindowId(); | return glWindow.getWindowId(); | ||||
| #else | |||||
| return 0; | |||||
| #endif | |||||
| } | } | ||||
| #endif | |||||
| // ------------------------------------------------------------------- | // ------------------------------------------------------------------- | ||||
| @@ -339,7 +379,39 @@ public: | |||||
| // ------------------------------------------------------------------- | // ------------------------------------------------------------------- | ||||
| #ifdef HAVE_DGL | |||||
| #if DISTRHO_PLUGIN_HAS_EXTERNAL_UI | |||||
| void exec(IdleCallback* const cb) | |||||
| { | |||||
| DISTRHO_SAFE_ASSERT_RETURN(cb != nullptr,); | |||||
| DISTRHO_SAFE_ASSERT_RETURN(fUI != nullptr,); | |||||
| fUI->setVisible(true); | |||||
| cb->idleCallback(); | |||||
| while (fUI->isRunning()) | |||||
| { | |||||
| d_msleep(10); | |||||
| cb->idleCallback(); | |||||
| } | |||||
| } | |||||
| void exec_idle() | |||||
| { | |||||
| } | |||||
| bool idle() | |||||
| { | |||||
| return true; | |||||
| } | |||||
| void quit() | |||||
| { | |||||
| DISTRHO_SAFE_ASSERT_RETURN(fUI != nullptr,); | |||||
| fUI->setVisible(false); | |||||
| fUI->terminateAndWaitForProcess(); | |||||
| } | |||||
| #else | |||||
| void exec(IdleCallback* const cb) | void exec(IdleCallback* const cb) | ||||
| { | { | ||||
| DISTRHO_SAFE_ASSERT_RETURN(cb != nullptr,); | DISTRHO_SAFE_ASSERT_RETURN(cb != nullptr,); | ||||
| @@ -355,48 +427,64 @@ public: | |||||
| if (glWindow.isReady()) | if (glWindow.isReady()) | ||||
| fUI->uiIdle(); | fUI->uiIdle(); | ||||
| } | } | ||||
| #endif | |||||
| bool idle() | bool idle() | ||||
| { | { | ||||
| DISTRHO_SAFE_ASSERT_RETURN(fUI != nullptr, false); | DISTRHO_SAFE_ASSERT_RETURN(fUI != nullptr, false); | ||||
| #ifdef HAVE_DGL | |||||
| glApp.idle(); | glApp.idle(); | ||||
| if (glWindow.isReady()) | if (glWindow.isReady()) | ||||
| fUI->uiIdle(); | fUI->uiIdle(); | ||||
| return ! glApp.isQuiting(); | return ! glApp.isQuiting(); | ||||
| #else | |||||
| return fUI->isRunning(); | |||||
| #endif | |||||
| } | } | ||||
| void quit() | void quit() | ||||
| { | { | ||||
| #ifdef HAVE_DGL | |||||
| glWindow.close(); | glWindow.close(); | ||||
| glApp.quit(); | glApp.quit(); | ||||
| #else | |||||
| DISTRHO_SAFE_ASSERT_RETURN(fUI != nullptr,); | |||||
| fUI->terminateAndWaitForProcess(); | |||||
| #endif | |||||
| } | } | ||||
| #endif | |||||
| // ------------------------------------------------------------------- | // ------------------------------------------------------------------- | ||||
| #if DISTRHO_PLUGIN_HAS_EXTERNAL_UI | |||||
| void setWindowTitle(const char* const uiTitle) | void setWindowTitle(const char* const uiTitle) | ||||
| { | { | ||||
| #ifdef HAVE_DGL | |||||
| glWindow.setTitle(uiTitle); | |||||
| #else | |||||
| DISTRHO_SAFE_ASSERT_RETURN(fUI != nullptr,); | DISTRHO_SAFE_ASSERT_RETURN(fUI != nullptr,); | ||||
| fUI->setTitle(uiTitle); | fUI->setTitle(uiTitle); | ||||
| #endif | |||||
| } | } | ||||
| #ifdef HAVE_DGL | |||||
| void setWindowSize(const uint width, const uint height, const bool = false) | |||||
| { | |||||
| DISTRHO_SAFE_ASSERT_RETURN(fUI != nullptr,); | |||||
| fUI->setSize(width, height); | |||||
| } | |||||
| void setWindowTransientWinId(const uintptr_t winId) | |||||
| { | |||||
| DISTRHO_SAFE_ASSERT_RETURN(fUI != nullptr,); | |||||
| fUI->setTransientWinId(winId); | |||||
| } | |||||
| bool setWindowVisible(const bool yesNo) | |||||
| { | |||||
| DISTRHO_SAFE_ASSERT_RETURN(fUI != nullptr, false); | |||||
| fUI->setVisible(yesNo); | |||||
| return fUI->isRunning(); | |||||
| } | |||||
| #else | |||||
| void setWindowTitle(const char* const uiTitle) | |||||
| { | |||||
| glWindow.setTitle(uiTitle); | |||||
| } | |||||
| void setWindowSize(const uint width, const uint height, const bool updateUI = false) | void setWindowSize(const uint width, const uint height, const bool updateUI = false) | ||||
| { | { | ||||
| DISTRHO_SAFE_ASSERT_RETURN(fUI != nullptr,); | DISTRHO_SAFE_ASSERT_RETURN(fUI != nullptr,); | ||||
| @@ -431,12 +519,8 @@ public: | |||||
| bool handlePluginSpecial(const bool press, const Key key) | bool handlePluginSpecial(const bool press, const Key key) | ||||
| { | { | ||||
| return glWindow.handlePluginKeyboard(press, key); | |||||
| return glWindow.handlePluginSpecial(press, key); | |||||
| } | } | ||||
| #else | |||||
| void setWindowSize(const uint, const uint, const bool) {} | |||||
| void setWindowTransientWinId(const uintptr_t) {} | |||||
| bool setWindowVisible(const bool) { return true; } | |||||
| #endif | #endif | ||||
| // ------------------------------------------------------------------- | // ------------------------------------------------------------------- | ||||
| @@ -457,7 +541,7 @@ public: | |||||
| } | } | ||||
| private: | private: | ||||
| #ifdef HAVE_DGL | |||||
| #if !DISTRHO_PLUGIN_HAS_EXTERNAL_UI | |||||
| // ------------------------------------------------------------------- | // ------------------------------------------------------------------- | ||||
| // DGL Application and Window for this widget | // DGL Application and Window for this widget | ||||
| @@ -117,13 +117,13 @@ lv2_atom_sequence_next(const LV2_Atom_Event* i) | |||||
| @endcode | @endcode | ||||
| */ | */ | ||||
| #define LV2_ATOM_SEQUENCE_FOREACH(seq, iter) \ | #define LV2_ATOM_SEQUENCE_FOREACH(seq, iter) \ | ||||
| for (const LV2_Atom_Event* (iter) = lv2_atom_sequence_begin(&(seq)->body); \ | |||||
| for (const LV2_Atom_Event* iter = lv2_atom_sequence_begin(&(seq)->body); \ | |||||
| !lv2_atom_sequence_is_end(&(seq)->body, (seq)->atom.size, (iter)); \ | !lv2_atom_sequence_is_end(&(seq)->body, (seq)->atom.size, (iter)); \ | ||||
| (iter) = lv2_atom_sequence_next(iter)) | (iter) = lv2_atom_sequence_next(iter)) | ||||
| /** Like LV2_ATOM_SEQUENCE_FOREACH but for a headerless sequence body. */ | /** Like LV2_ATOM_SEQUENCE_FOREACH but for a headerless sequence body. */ | ||||
| #define LV2_ATOM_SEQUENCE_BODY_FOREACH(body, size, iter) \ | #define LV2_ATOM_SEQUENCE_BODY_FOREACH(body, size, iter) \ | ||||
| for (const LV2_Atom_Event* (iter) = lv2_atom_sequence_begin(body); \ | |||||
| for (const LV2_Atom_Event* iter = lv2_atom_sequence_begin(body); \ | |||||
| !lv2_atom_sequence_is_end(body, size, (iter)); \ | !lv2_atom_sequence_is_end(body, size, (iter)); \ | ||||
| (iter) = lv2_atom_sequence_next(iter)) | (iter) = lv2_atom_sequence_next(iter)) | ||||
| @@ -214,13 +214,13 @@ lv2_atom_tuple_next(const LV2_Atom* i) | |||||
| @endcode | @endcode | ||||
| */ | */ | ||||
| #define LV2_ATOM_TUPLE_FOREACH(tuple, iter) \ | #define LV2_ATOM_TUPLE_FOREACH(tuple, iter) \ | ||||
| for (const LV2_Atom* (iter) = lv2_atom_tuple_begin(tuple); \ | |||||
| for (const LV2_Atom* iter = lv2_atom_tuple_begin(tuple); \ | |||||
| !lv2_atom_tuple_is_end(LV2_ATOM_BODY_CONST(tuple), (tuple)->size, (iter)); \ | !lv2_atom_tuple_is_end(LV2_ATOM_BODY_CONST(tuple), (tuple)->size, (iter)); \ | ||||
| (iter) = lv2_atom_tuple_next(iter)) | (iter) = lv2_atom_tuple_next(iter)) | ||||
| /** Like LV2_ATOM_TUPLE_FOREACH but for a headerless tuple body. */ | /** Like LV2_ATOM_TUPLE_FOREACH but for a headerless tuple body. */ | ||||
| #define LV2_ATOM_TUPLE_BODY_FOREACH(body, size, iter) \ | #define LV2_ATOM_TUPLE_BODY_FOREACH(body, size, iter) \ | ||||
| for (const LV2_Atom* (iter) = (const LV2_Atom*)body; \ | |||||
| for (const LV2_Atom* iter = (const LV2_Atom*)body; \ | |||||
| !lv2_atom_tuple_is_end(body, size, (iter)); \ | !lv2_atom_tuple_is_end(body, size, (iter)); \ | ||||
| (iter) = lv2_atom_tuple_next(iter)) | (iter) = lv2_atom_tuple_next(iter)) | ||||
| @@ -270,13 +270,13 @@ lv2_atom_object_next(const LV2_Atom_Property_Body* i) | |||||
| @endcode | @endcode | ||||
| */ | */ | ||||
| #define LV2_ATOM_OBJECT_FOREACH(obj, iter) \ | #define LV2_ATOM_OBJECT_FOREACH(obj, iter) \ | ||||
| for (const LV2_Atom_Property_Body* (iter) = lv2_atom_object_begin(&(obj)->body); \ | |||||
| for (const LV2_Atom_Property_Body* iter = lv2_atom_object_begin(&(obj)->body); \ | |||||
| !lv2_atom_object_is_end(&(obj)->body, (obj)->atom.size, (iter)); \ | !lv2_atom_object_is_end(&(obj)->body, (obj)->atom.size, (iter)); \ | ||||
| (iter) = lv2_atom_object_next(iter)) | (iter) = lv2_atom_object_next(iter)) | ||||
| /** Like LV2_ATOM_OBJECT_FOREACH but for a headerless object body. */ | /** Like LV2_ATOM_OBJECT_FOREACH but for a headerless object body. */ | ||||
| #define LV2_ATOM_OBJECT_BODY_FOREACH(body, size, iter) \ | #define LV2_ATOM_OBJECT_BODY_FOREACH(body, size, iter) \ | ||||
| for (const LV2_Atom_Property_Body* (iter) = lv2_atom_object_begin(body); \ | |||||
| for (const LV2_Atom_Property_Body* iter = lv2_atom_object_begin(body); \ | |||||
| !lv2_atom_object_is_end(body, size, (iter)); \ | !lv2_atom_object_is_end(body, size, (iter)); \ | ||||
| (iter) = lv2_atom_object_next(iter)) | (iter) = lv2_atom_object_next(iter)) | ||||
| @@ -0,0 +1,113 @@ | |||||
| #!/usr/bin/env python3 | |||||
| # -*- coding: utf-8 -*- | |||||
| # DISTRHO Plugin Framework (DPF) | |||||
| # Copyright (C) 2012-2019 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. | |||||
| import os, sys | |||||
| # ----------------------------------------------------- | |||||
| def png2c(namespace, filenames): | |||||
| fdH = open("%s.hpp" % namespace, "w") | |||||
| fdH.write("/* (Auto-generated binary data file). */\n") | |||||
| fdH.write("\n") | |||||
| fdH.write("#ifndef BINARY_%s_HPP\n" % namespace.upper()) | |||||
| fdH.write("#define BINARY_%s_HPP\n" % namespace.upper()) | |||||
| fdH.write("\n") | |||||
| fdH.write("namespace %s\n" % namespace) | |||||
| fdH.write("{\n") | |||||
| fdC = open("%s.cpp" % namespace, "w") | |||||
| fdC.write("/* (Auto-generated binary data file). */\n") | |||||
| fdC.write("\n") | |||||
| fdC.write("#include \"%s.hpp\"\n" % namespace) | |||||
| fdC.write("\n") | |||||
| tempIndex = 1 | |||||
| for filename in filenames: | |||||
| shortFilename = filename.rsplit(os.sep, 1)[-1].split(".", 1)[0] | |||||
| shortFilename = shortFilename.replace("-", "_") | |||||
| pngData = open(filename, 'rb').read() | |||||
| print("Generating data for \"%s\"" % (filename)) | |||||
| fdH.write(" extern const char* %sData;\n" % shortFilename) | |||||
| fdH.write(" const unsigned int %sDataSize = %i;\n" % (shortFilename, len(pngData))) | |||||
| if tempIndex != len(filenames): | |||||
| fdH.write("\n") | |||||
| fdC.write("static const unsigned char temp_%s_%i[] = {\n" % (shortFilename, tempIndex)) | |||||
| curColumn = 1 | |||||
| fdC.write(" ") | |||||
| for data in pngData: | |||||
| if curColumn == 0: | |||||
| fdC.write(" ") | |||||
| fdC.write(" %3u," % data) | |||||
| if curColumn > 20: | |||||
| fdC.write("\n ") | |||||
| curColumn = 1 | |||||
| else: | |||||
| curColumn += 1 | |||||
| fdC.write("};\n") | |||||
| fdC.write("const char* %s::%sData = (const char*)temp_%s_%i;\n" % (namespace, shortFilename, shortFilename, tempIndex)) | |||||
| if tempIndex != len(filenames): | |||||
| fdC.write("\n") | |||||
| tempIndex += 1 | |||||
| fdH.write("}\n") | |||||
| fdH.write("\n") | |||||
| fdH.write("#endif // BINARY_%s_HPP\n" % namespace.upper()) | |||||
| fdH.write("\n") | |||||
| fdH.close() | |||||
| fdC.write("\n") | |||||
| fdC.close() | |||||
| # ----------------------------------------------------- | |||||
| if __name__ == '__main__': | |||||
| if len(sys.argv) != 3: | |||||
| print("Usage: %s <namespace> <artwork-folder>" % sys.argv[0]) | |||||
| quit() | |||||
| namespace = sys.argv[1].replace("-","_") | |||||
| artFolder = sys.argv[2] | |||||
| if not os.path.exists(artFolder): | |||||
| print("Folder '%s' does not exist" % artFolder) | |||||
| quit() | |||||
| # find png files | |||||
| pngFiles = [] | |||||
| for root, dirs, files in os.walk(artFolder): | |||||
| for name in [name for name in files if name.lower().endswith(".png")]: | |||||
| pngFiles.append(os.path.join(root, name)) | |||||
| pngFiles.sort() | |||||
| # create code now | |||||
| png2c(namespace, pngFiles) | |||||
| @@ -1,8 +1,8 @@ | |||||
| #!/usr/bin/env python | |||||
| #!/usr/bin/env python3 | |||||
| # -*- coding: utf-8 -*- | # -*- coding: utf-8 -*- | ||||
| # DISTRHO Plugin Framework (DPF) | # DISTRHO Plugin Framework (DPF) | ||||
| # Copyright (C) 2012-2016 Filipe Coelho <falktx@falktx.com> | |||||
| # Copyright (C) 2012-2019 Filipe Coelho <falktx@falktx.com> | |||||
| # | # | ||||
| # Permission to use, copy, modify, and/or distribute this software for any purpose with | # 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 | # or without fee is hereby granted, provided that the above copyright notice and this | ||||
| @@ -52,7 +52,10 @@ def png2rgba(namespace, filenames): | |||||
| shortFilename = filename.rsplit(os.sep, 1)[-1].split(".", 1)[0] | shortFilename = filename.rsplit(os.sep, 1)[-1].split(".", 1)[0] | ||||
| shortFilename = shortFilename.replace("-", "_") | shortFilename = shortFilename.replace("-", "_") | ||||
| png = Image.open(filename) | |||||
| png = Image.open(filename) | |||||
| if png.getpalette(): | |||||
| png = png.convert() | |||||
| pngNumpy = numpy.array(png) | pngNumpy = numpy.array(png) | ||||
| pngData = pngNumpy.tolist() | pngData = pngNumpy.tolist() | ||||
| #pngData.reverse() | #pngData.reverse() | ||||
| @@ -60,8 +60,8 @@ public: | |||||
| }; | }; | ||||
| MVerb(){ | MVerb(){ | ||||
| DampingFreq = 18000.; | |||||
| BandwidthFreq = 18000.; | |||||
| DampingFreq = 0.9; | |||||
| BandwidthFreq = 0.9; | |||||
| SampleRate = 44100.; | SampleRate = 44100.; | ||||
| Decay = 0.5; | Decay = 0.5; | ||||
| Gain = 1.; | Gain = 1.; | ||||