From dce7676eb83ede14ff92d76beddddc30e3df674e Mon Sep 17 00:00:00 2001 From: falkTX Date: Mon, 20 Apr 2020 07:33:52 +0100 Subject: [PATCH] Restructure of code for new pugl, WIP Signed-off-by: falkTX --- Makefile | 6 +- dgl/Widget.hpp | 3 + dgl/Window.hpp | 42 +- dgl/src/Application.cpp | 2 +- dgl/src/ApplicationPrivateData.hpp | 3 + dgl/src/ImageWidgets.cpp | 4 +- dgl/src/Widget.cpp | 2 + dgl/src/Window.cpp | 141 ++-- dgl/src/WindowPrivateData.cpp | 329 +++++++- dgl/src/WindowPrivateData.hpp | 1133 ++++++---------------------- dgl/src/pugl-extra/extras.c | 29 + dgl/src/pugl-extra/extras.h | 50 ++ dgl/src/pugl-extra/haiku.cpp | 81 ++ dgl/src/pugl-extra/haiku.h | 35 + dgl/src/pugl-extra/mac.m | 48 ++ dgl/src/pugl-extra/win.c | 118 +++ dgl/src/pugl-extra/x11.c | 111 +++ distrho/src/DistrhoPluginVST.cpp | 1 + distrho/src/DistrhoUI.cpp | 2 - distrho/src/DistrhoUIDSSI.cpp | 1 + distrho/src/DistrhoUIInternal.hpp | 6 +- distrho/src/DistrhoUILV2.cpp | 3 +- 22 files changed, 1171 insertions(+), 979 deletions(-) create mode 100644 dgl/src/pugl-extra/extras.c create mode 100644 dgl/src/pugl-extra/extras.h create mode 100644 dgl/src/pugl-extra/haiku.cpp create mode 100644 dgl/src/pugl-extra/haiku.h create mode 100644 dgl/src/pugl-extra/mac.m create mode 100644 dgl/src/pugl-extra/win.c create mode 100644 dgl/src/pugl-extra/x11.c diff --git a/Makefile b/Makefile index e573a456..f57cc1e9 100644 --- a/Makefile +++ b/Makefile @@ -27,9 +27,9 @@ examples: dgl $(MAKE) all -C examples/Parameters $(MAKE) all -C examples/States -ifeq ($(HAVE_CAIRO),true) - $(MAKE) all -C examples/CairoUI -endif +# ifeq ($(HAVE_CAIRO),true) +# $(MAKE) all -C examples/CairoUI +# endif ifneq ($(MACOS_OR_WINDOWS),true) # ExternalUI is WIP diff --git a/dgl/Widget.hpp b/dgl/Widget.hpp index f8d7139d..a54c3de0 100644 --- a/dgl/Widget.hpp +++ b/dgl/Widget.hpp @@ -301,11 +301,14 @@ public: */ void setAbsolutePos(const Point& pos) noexcept; +#if 0 + // TODO: should we remove this? /** Get this widget's window application. Same as calling getParentWindow().getApp(). */ Application& getParentApp() const noexcept; +#endif /** Get parent window, as passed in the constructor. diff --git a/dgl/Window.hpp b/dgl/Window.hpp index 7f4e16e8..1fa7f819 100644 --- a/dgl/Window.hpp +++ b/dgl/Window.hpp @@ -1,6 +1,6 @@ /* * DISTRHO Plugin Framework (DPF) - * Copyright (C) 2012-2019 Filipe Coelho + * Copyright (C) 2012-2020 Filipe Coelho * * 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 @@ -77,8 +77,8 @@ public: #endif // DGL_FILE_BROWSER_DISABLED explicit Window(Application& app); - explicit Window(Application& app, Window& parent); - explicit Window(Application& app, intptr_t parentId, double scaling, bool resizable); + explicit Window(Window& transientParentWindow); + explicit Window(Application& app, uintptr_t parentWindowHandle, double scaling, bool resizable); virtual ~Window(); void show(); @@ -88,6 +88,7 @@ public: void focus(); void repaint() noexcept; + void repaint(const Rectangle& rect) noexcept; #ifndef DGL_FILE_BROWSER_DISABLED bool openFileBrowser(const FileBrowserOptions& options); @@ -96,10 +97,13 @@ public: bool isEmbed() const noexcept; bool isVisible() const noexcept; - void setVisible(bool yesNo); + void setVisible(bool visible); bool isResizable() const noexcept; - void setResizable(bool yesNo); + void setResizable(bool resizable); + + bool getIgnoringKeyRepeat() const noexcept; + void setIgnoringKeyRepeat(bool ignore) noexcept; uint getWidth() const noexcept; uint getHeight() const noexcept; @@ -115,11 +119,20 @@ public: double getScaling() const noexcept; - bool getIgnoringKeyRepeat() const noexcept; - void setIgnoringKeyRepeat(bool ignore) noexcept; - +#if 0 + // should this be removed? Application& getApp() const noexcept; - uintptr_t getWindowId() const noexcept; +#endif + + /** + Get the "native" window handle. + Returned value depends on the platform: + - HaikuOS: This is a pointer to a `BView`. + - MacOS: This is a pointer to an `NSView*`. + - Windows: This is a `HWND`. + - Everything else: This is an [X11] `Window`. + */ + uintptr_t getNativeWindowHandle() const noexcept; const GraphicsContext& getGraphicsContext() const noexcept; @@ -157,7 +170,16 @@ private: bool handlePluginKeyboard(const bool press, const uint key); bool handlePluginSpecial(const bool press, const Key key); - DISTRHO_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(Window) + // Prevent copies +#ifdef DISTRHO_PROPER_CPP11_SUPPORT + Window& operator=(Window&) = delete; + Window& operator=(const Window&) = delete; +#else + Window& operator=(Window&); + Window& operator=(const Window&); +#endif + + DISTRHO_LEAK_DETECTOR(Window); }; // ----------------------------------------------------------------------- diff --git a/dgl/src/Application.cpp b/dgl/src/Application.cpp index db99e746..0ab17764 100644 --- a/dgl/src/Application.cpp +++ b/dgl/src/Application.cpp @@ -35,7 +35,7 @@ void Application::idle() void Application::exec(const uint idleTime) { - while (!pData->isQuitting) + while (! pData->isQuitting) pData->idle(idleTime); } diff --git a/dgl/src/ApplicationPrivateData.hpp b/dgl/src/ApplicationPrivateData.hpp index 477f5bb6..ad64e4f9 100644 --- a/dgl/src/ApplicationPrivateData.hpp +++ b/dgl/src/ApplicationPrivateData.hpp @@ -47,6 +47,8 @@ struct Application::PrivateData { { puglSetWorldHandle(world, this); + // puglSetLogLevel(world, PUGL_LOG_LEVEL_DEBUG); + // TODO puglSetClassName } @@ -58,6 +60,7 @@ struct Application::PrivateData { windows.clear(); idleCallbacks.clear(); + d_stdout("calling puglFreeWorld"); puglFreeWorld(world); } diff --git a/dgl/src/ImageWidgets.cpp b/dgl/src/ImageWidgets.cpp index de94ca02..f42f066d 100644 --- a/dgl/src/ImageWidgets.cpp +++ b/dgl/src/ImageWidgets.cpp @@ -27,7 +27,7 @@ START_NAMESPACE_DGL #ifndef DISTRHO_OS_HAIKU ImageAboutWindow::ImageAboutWindow(Window& parent, const Image& image) - : Window(parent.getApp(), parent), + : Window(parent), Widget((Window&)*this), fImgBackground(image) { @@ -37,7 +37,7 @@ ImageAboutWindow::ImageAboutWindow(Window& parent, const Image& image) } ImageAboutWindow::ImageAboutWindow(Widget* widget, const Image& image) - : Window(widget->getParentApp(), widget->getParentWindow()), + : Window(widget->getParentWindow()), Widget((Window&)*this), fImgBackground(image) { diff --git a/dgl/src/Widget.cpp b/dgl/src/Widget.cpp index 4ef69b8e..89083cab 100644 --- a/dgl/src/Widget.cpp +++ b/dgl/src/Widget.cpp @@ -179,10 +179,12 @@ void Widget::setAbsolutePos(const Point& pos) noexcept pData->parent.repaint(); } +#if 0 Application& Widget::getParentApp() const noexcept { return pData->parent.getApp(); } +#endif Window& Widget::getParentWindow() const noexcept { diff --git a/dgl/src/Window.cpp b/dgl/src/Window.cpp index dac1b9f9..f424be99 100644 --- a/dgl/src/Window.cpp +++ b/dgl/src/Window.cpp @@ -14,34 +14,27 @@ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ -// we need this for now -//#define PUGL_GRAB_FOCUS 1 - -// #include "../Base.hpp" #include "WindowPrivateData.hpp" -// #include "../../distrho/extra/String.hpp" - START_NAMESPACE_DGL // ----------------------------------------------------------------------- // Window Window::Window(Application& app) - : pData(new PrivateData(app, this)) {} + : pData(new PrivateData(app.pData, this)) {} -Window::Window(Application& app, Window& parent) - : pData(new PrivateData(app, this, parent)) {} +Window::Window(Window& transientParentWindow) + : pData(new PrivateData(transientParentWindow.pData->fAppData, this, transientParentWindow)) {} -Window::Window(Application& app, intptr_t parentId, double scaling, bool resizable) - : pData(new PrivateData(app, this, parentId, scaling, resizable)) {} +Window::Window(Application& app, const uintptr_t parentWindowHandle, const double scaling, const bool resizable) + : pData(new PrivateData(app.pData, this, parentWindowHandle, scaling, resizable)) {} Window::~Window() { delete pData; } -#if 0 void Window::show() { pData->setVisible(true); @@ -57,14 +50,19 @@ void Window::close() pData->close(); } +#if 0 void Window::exec(bool lockWait) { pData->exec(lockWait); } +#endif void Window::focus() { - pData->focus(); + if (! pData->fUsingEmbed) + puglRaiseWindow(pData->fView); + + puglGrabFocus(pData->fView); } void Window::repaint() noexcept @@ -72,6 +70,17 @@ void Window::repaint() noexcept puglPostRedisplay(pData->fView); } +void Window::repaint(const Rectangle& rect) noexcept +{ + const PuglRect prect = { + static_cast(rect.getX()), + static_cast(rect.getY()), + static_cast(rect.getWidth()), + static_cast(rect.getHeight()), + }; + puglPostRedisplayRect(pData->fView, prect); +} + bool Window::isEmbed() const noexcept { return pData->fUsingEmbed; @@ -82,88 +91,107 @@ bool Window::isVisible() const noexcept return pData->fVisible; } -void Window::setVisible(bool yesNo) +void Window::setVisible(const bool visible) { - pData->setVisible(yesNo); + pData->setVisible(visible); } bool Window::isResizable() const noexcept { - return pData->fResizable; + return puglGetViewHint(pData->fView, PUGL_RESIZABLE) == PUGL_TRUE; } -void Window::setResizable(bool yesNo) +void Window::setResizable(const bool resizable) { - pData->setResizable(yesNo); + DISTRHO_SAFE_ASSERT_RETURN(pData->fUsingEmbed,); + if (pData->fUsingEmbed) + { + DGL_DBG("Window setResizable cannot be called when embedded\n"); + return; + } + + DGL_DBG("Window setResizable called\n"); + + puglSetViewHint(pData->fView, PUGL_RESIZABLE, resizable ? PUGL_TRUE : PUGL_FALSE); +#ifdef DISTRHO_OS_WINDOWS + puglWin32SetWindowResizable(pData->fView, resizable); +#endif } -void Window::setGeometryConstraints(uint width, uint height, bool aspect) +bool Window::getIgnoringKeyRepeat() const noexcept { - pData->setGeometryConstraints(width, height, aspect); + return puglGetViewHint(pData->fView, PUGL_IGNORE_KEY_REPEAT) == PUGL_TRUE; } -uint Window::getWidth() const noexcept +void Window::setIgnoringKeyRepeat(const bool ignore) noexcept { - return pData->fWidth; + puglSetViewHint(pData->fView, PUGL_IGNORE_KEY_REPEAT, ignore); } -uint Window::getHeight() const noexcept +void Window::setGeometryConstraints(const uint width, const uint height, bool aspect) { - return pData->fHeight; + // Did you forget to set DISTRHO_UI_USER_RESIZABLE ? + DISTRHO_SAFE_ASSERT_RETURN(isResizable(),); + + puglUpdateGeometryConstraints(pData->fView, width, height, aspect); } -Size Window::getSize() const noexcept +uint Window::getWidth() const noexcept { - return Size(pData->fWidth, pData->fHeight); + return puglGetFrame(pData->fView).width; } -void Window::setSize(uint width, uint height) +uint Window::getHeight() const noexcept { - pData->setSize(width, height); + return puglGetFrame(pData->fView).height; } -void Window::setSize(Size size) +Size Window::getSize() const noexcept { - pData->setSize(size.getWidth(), size.getHeight()); + const PuglRect rect = puglGetFrame(pData->fView); + return Size(rect.width, rect.height); } -const char* Window::getTitle() const noexcept +void Window::setSize(const uint width, const uint height) { - return pData->getTitle(); + DISTRHO_SAFE_ASSERT_INT2_RETURN(width > 1 && height > 1, width, height,); + + puglSetWindowSize(pData->fView, width, height); } -void Window::setTitle(const char* title) +void Window::setSize(const Size size) { - pData->setTitle(title); + setSize(size.getWidth(), size.getHeight()); } -void Window::setTransientWinId(uintptr_t winId) +const char* Window::getTitle() const noexcept { - pData->setTransientWinId(winId); + return puglGetWindowTitle(pData->fView); } -double Window::getScaling() const noexcept +void Window::setTitle(const char* const title) { - return pData->getScaling(); + puglSetWindowTitle(pData->fView, title); } -bool Window::getIgnoringKeyRepeat() const noexcept +void Window::setTransientWinId(const uintptr_t winId) { - return pData->getIgnoringKeyRepeat(); + puglSetTransientFor(pData->fView, winId); } -void Window::setIgnoringKeyRepeat(bool ignore) noexcept +double Window::getScaling() const noexcept { - pData->setIgnoringKeyRepeat(ignore); + return pData->fScaling; } -#endif +#if 0 Application& Window::getApp() const noexcept { return pData->fApp; } +#endif -uintptr_t Window::getWindowId() const noexcept +uintptr_t Window::getNativeWindowHandle() const noexcept { return puglGetNativeWindow(pData->fView); } @@ -177,10 +205,13 @@ const GraphicsContext& Window::getGraphicsContext() const noexcept #endif return context; } +#endif void Window::_setAutoScaling(double scaling) noexcept { - pData->setAutoScaling(scaling); + DISTRHO_SAFE_ASSERT_RETURN(scaling > 0.0,); + + pData->fAutoScaling = scaling; } void Window::_addWidget(Widget* const widget) @@ -195,9 +226,8 @@ void Window::_removeWidget(Widget* const widget) void Window::_idle() { - pData->idle(); + pData->windowSpecificIdle(); } -#endif // ----------------------------------------------------------------------- @@ -205,14 +235,14 @@ void Window::addIdleCallback(IdleCallback* const callback) { DISTRHO_SAFE_ASSERT_RETURN(callback != nullptr,) - pData->fApp.pData->idleCallbacks.push_back(callback); + pData->fAppData->idleCallbacks.push_back(callback); } void Window::removeIdleCallback(IdleCallback* const callback) { DISTRHO_SAFE_ASSERT_RETURN(callback != nullptr,) - pData->fApp.pData->idleCallbacks.remove(callback); + pData->fAppData->idleCallbacks.remove(callback); } // ----------------------------------------------------------------------- @@ -242,21 +272,20 @@ void Window::fileBrowserSelected(const char*) } #endif -#if 0 bool Window::handlePluginKeyboard(const bool press, const uint key) { - return pData->handlePluginKeyboard(press, key); + // TODO + return false; + // return pData->handlePluginKeyboard(press, key); } bool Window::handlePluginSpecial(const bool press, const Key key) { - return pData->handlePluginSpecial(press, key); + // TODO + return false; + // return pData->handlePluginSpecial(press, key); } -#endif // ----------------------------------------------------------------------- END_NAMESPACE_DGL - -#undef DBG -#undef DBGF diff --git a/dgl/src/WindowPrivateData.cpp b/dgl/src/WindowPrivateData.cpp index 7b2d6d6c..08ef6333 100644 --- a/dgl/src/WindowPrivateData.cpp +++ b/dgl/src/WindowPrivateData.cpp @@ -27,6 +27,7 @@ extern "C" { #include "pugl-upstream/src/implementation.c" +#include "pugl-extra/extras.c" } #if defined(DISTRHO_OS_HAIKU) @@ -41,18 +42,336 @@ extern "C" { # undef max # undef min #else -# include -# include +# define DGL_PUGL_USING_X11 extern "C" { # include "pugl-upstream/src/x11.c" +// # ifdef DGL_CAIRO +// # include "pugl-upstream/src/x11_cairo.c" +// # endif +# ifdef DGL_OPENGL +# include "pugl-upstream/src/x11_gl.c" +# endif +# define PUGL_DETAIL_X11_H_INCLUDED +# include "pugl-extra/x11.c" } #endif +#include +#include +#include +#include +#include +#include + START_NAMESPACE_DGL // ----------------------------------------------------------------------- -void DGL::Window::PrivateData::Fallback::onDisplayBefore() +void Window::PrivateData::init(const bool resizable) +{ + if (fSelf == nullptr || fView == nullptr) + { + DGL_DBG("Failed!\n"); + return; + } + +// #ifdef DGL_CAIRO +// puglSetBackend(fView, puglCairoBackend()); +// #endif +#ifdef DGL_OPENGL + puglSetBackend(fView, puglGlBackend()); +#endif + + puglSetHandle(fView, this); + puglSetViewHint(fView, PUGL_RESIZABLE, resizable ? PUGL_TRUE : PUGL_FALSE); + puglSetViewHint(fView, PUGL_IGNORE_KEY_REPEAT, PUGL_FALSE); + puglSetEventFunc(fView, puglEventCallback); +// #ifndef DGL_FILE_BROWSER_DISABLED +// puglSetFileSelectedFunc(fView, fileBrowserSelectedCallback); +// #endif + + fAppData->windows.push_back(fSelf); + + DGL_DBG("Success!\n"); +} + +void Window::PrivateData::setVisible(const bool visible) +{ + if (fVisible == visible) + { + DGL_DBG("Window setVisible matches current state, ignoring request\n"); + return; + } + if (fUsingEmbed) + { + DGL_DBG("Window setVisible cannot be called when embedded\n"); + return; + } + + DGL_DBG("Window setVisible called\n"); + + fVisible = visible; + + if (visible) + { +#if 0 && defined(DISTRHO_OS_MAC) + if (mWindow != nullptr) + { + if (mParentWindow != nullptr) + [mParentWindow addChildWindow:mWindow + ordered:NSWindowAbove]; + } +#endif + + if (fFirstInit) + { + puglRealize(fView); +#ifdef DISTRHO_OS_WINDOWS + puglShowWindowCentered(fView); +#else + puglShowWindow(fView); +#endif + fAppData->oneWindowShown(); + fFirstInit = false; + } + else + { +#ifdef DISTRHO_OS_WINDOWS + puglWin32RestoreWindow(fView); +#else + puglShowWindow(fView); +#endif + } + } + else + { +#if 0 && defined(DISTRHO_OS_MAC) + if (mWindow != nullptr) + { + if (mParentWindow != nullptr) + [mParentWindow removeChildWindow:mWindow]; + } +#endif + + puglHideWindow(fView); + +// if (fModal.enabled) +// exec_fini(); + } +} + +void Window::PrivateData::windowSpecificIdle() +{ +#if defined(DISTRHO_OS_WINDOWS) && !defined(DGL_FILE_BROWSER_DISABLED) + if (fSelectedFile.isNotEmpty()) + { + char* const buffer = fSelectedFile.getAndReleaseBuffer(); + fView->fileSelectedFunc(fView, buffer); + std::free(buffer); + } +#endif + + if (fModal.enabled && fModal.parent != nullptr) + fModal.parent->windowSpecificIdle(); +} + +// ----------------------------------------------------------------------- + +static inline int +printModifiers(const uint32_t mods) +{ + return fprintf(stderr, "Modifiers:%s%s%s%s\n", + (mods & PUGL_MOD_SHIFT) ? " Shift" : "", + (mods & PUGL_MOD_CTRL) ? " Ctrl" : "", + (mods & PUGL_MOD_ALT) ? " Alt" : "", + (mods & PUGL_MOD_SUPER) ? " Super" : ""); +} + +static inline int +printEvent(const PuglEvent* event, const char* prefix, const bool verbose) +{ +#define FFMT "%6.1f" +#define PFMT FFMT " " FFMT +#define PRINT(fmt, ...) fprintf(stderr, fmt, __VA_ARGS__) + + switch (event->type) { + case PUGL_NOTHING: + return 0; + case PUGL_KEY_PRESS: + return PRINT("%sKey press code %3u key U+%04X\n", + prefix, + event->key.keycode, + event->key.key); + case PUGL_KEY_RELEASE: + return PRINT("%sKey release code %3u key U+%04X\n", + prefix, + event->key.keycode, + event->key.key); + case PUGL_TEXT: + return PRINT("%sText entry code %3u char U+%04X (%s)\n", + prefix, + event->text.keycode, + event->text.character, + event->text.string); + case PUGL_BUTTON_PRESS: + case PUGL_BUTTON_RELEASE: + return (PRINT("%sMouse %u %s at " PFMT " ", + prefix, + event->button.button, + (event->type == PUGL_BUTTON_PRESS) ? "down" : "up ", + event->button.x, + event->button.y) + + printModifiers(event->scroll.state)); + case PUGL_SCROLL: + return (PRINT("%sScroll %5.1f %5.1f at " PFMT " ", + prefix, + event->scroll.dx, + event->scroll.dy, + event->scroll.x, + event->scroll.y) + + printModifiers(event->scroll.state)); + case PUGL_POINTER_IN: + return PRINT("%sMouse enter at " PFMT "\n", + prefix, + event->crossing.x, + event->crossing.y); + case PUGL_POINTER_OUT: + return PRINT("%sMouse leave at " PFMT "\n", + prefix, + event->crossing.x, + event->crossing.y); + case PUGL_FOCUS_IN: + return PRINT("%sFocus in %i\n", + prefix, + event->focus.mode); + case PUGL_FOCUS_OUT: + return PRINT("%sFocus out %i\n", + prefix, + event->focus.mode); + case PUGL_CLIENT: + return PRINT("%sClient %" PRIXPTR " %" PRIXPTR "\n", + prefix, + event->client.data1, + event->client.data2); + case PUGL_TIMER: + return PRINT("%sTimer %" PRIuPTR "\n", prefix, event->timer.id); + default: + break; + } + + if (verbose) { + switch (event->type) { + case PUGL_CREATE: + return fprintf(stderr, "%sCreate\n", prefix); + case PUGL_DESTROY: + return fprintf(stderr, "%sDestroy\n", prefix); + case PUGL_MAP: + return fprintf(stderr, "%sMap\n", prefix); + case PUGL_UNMAP: + return fprintf(stderr, "%sUnmap\n", prefix); + case PUGL_UPDATE: + return fprintf(stderr, "%sUpdate\n", prefix); + case PUGL_CONFIGURE: + return PRINT("%sConfigure " PFMT " " PFMT "\n", + prefix, + event->configure.x, + event->configure.y, + event->configure.width, + event->configure.height); + case PUGL_EXPOSE: + return PRINT("%sExpose " PFMT " " PFMT "\n", + prefix, + event->expose.x, + event->expose.y, + event->expose.width, + event->expose.height); + case PUGL_CLOSE: + return PRINT("%sClose\n", prefix); + case PUGL_MOTION: + return PRINT("%sMouse motion at " PFMT "\n", + prefix, + event->motion.x, + event->motion.y); + default: + return PRINT("%sUnknown event type %d\n", prefix, (int)event->type); + } + } + +#undef PRINT +#undef PFMT +#undef FFMT + + return 0; +} + +PuglStatus Window::PrivateData::puglEventCallback(PuglView* const view, const PuglEvent* const event) +{ + printEvent(event, "", true); + Window::PrivateData* const pData = (Window::PrivateData*)puglGetHandle(view); + + switch (event->type) + { + ///< No event + case PUGL_NOTHING: + break; + + ///< View created, a #PuglEventCreate + case PUGL_CREATE: +#ifdef DGL_PUGL_USING_X11 + if (! pData->fUsingEmbed) + puglExtraSetWindowTypeAndPID(view); +#endif + break; + + ///< View destroyed, a #PuglEventDestroy + case PUGL_DESTROY: + break; + + ///< View moved/resized, a #PuglEventConfigure + case PUGL_CONFIGURE: + pData->onPuglReshape(event->configure.width, event->configure.height); + break; + + case PUGL_MAP: ///< View made visible, a #PuglEventMap + case PUGL_UNMAP: ///< View made invisible, a #PuglEventUnmap + break; + + ///< View ready to draw, a #PuglEventUpdate + case PUGL_UPDATE: + break; + + ///< View must be drawn, a #PuglEventExpose + case PUGL_EXPOSE: + pData->onPuglDisplay(); + break; + + ///< View will be closed, a #PuglEventClose + case PUGL_CLOSE: + pData->onPuglClose(); + break; + + case PUGL_FOCUS_IN: ///< Keyboard focus entered view, a #PuglEventFocus + case PUGL_FOCUS_OUT: ///< Keyboard focus left view, a #PuglEventFocus + case PUGL_KEY_PRESS: ///< Key pressed, a #PuglEventKey + case PUGL_KEY_RELEASE: ///< Key released, a #PuglEventKey + case PUGL_TEXT: ///< Character entered, a #PuglEventText + case PUGL_POINTER_IN: ///< Pointer entered view, a #PuglEventCrossing + case PUGL_POINTER_OUT: ///< Pointer left view, a #PuglEventCrossing + case PUGL_BUTTON_PRESS: ///< Mouse button pressed, a #PuglEventButton + case PUGL_BUTTON_RELEASE: ///< Mouse button released, a #PuglEventButton + case PUGL_MOTION: ///< Pointer moved, a #PuglEventMotion + case PUGL_SCROLL: ///< Scrolled, a #PuglEventScroll + case PUGL_CLIENT: ///< Custom client message, a #PuglEventClient + case PUGL_TIMER: ///< Timer triggered, a #PuglEventTimer + break; + } + + return PUGL_SUCCESS; +} + +// ----------------------------------------------------------------------- + +void Window::PrivateData::Fallback::onDisplayBefore() { #ifdef DGL_OPENGL glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); @@ -60,11 +379,11 @@ void DGL::Window::PrivateData::Fallback::onDisplayBefore() #endif } -void DGL::Window::PrivateData::Fallback::onDisplayAfter() +void Window::PrivateData::Fallback::onDisplayAfter() { } -void DGL::Window::PrivateData::Fallback::onReshape(const uint width, const uint height) +void Window::PrivateData::Fallback::onReshape(const uint width, const uint height) { #ifdef DGL_OPENGL glEnable(GL_BLEND); diff --git a/dgl/src/WindowPrivateData.hpp b/dgl/src/WindowPrivateData.hpp index c917ffe2..004875e7 100644 --- a/dgl/src/WindowPrivateData.hpp +++ b/dgl/src/WindowPrivateData.hpp @@ -18,9 +18,12 @@ #define DGL_WINDOW_PRIVATE_DATA_HPP_INCLUDED #include "../Window.hpp" + #include "ApplicationPrivateData.hpp" +#include "WidgetPrivateData.hpp" #include "pugl-upstream/include/pugl/pugl.h" +#include "pugl-extra/extras.h" #include @@ -30,14 +33,16 @@ #define FOR_EACH_WIDGET_INV(rit) \ for (std::list::reverse_iterator rit = fWidgets.rbegin(); rit != fWidgets.rend(); ++rit) +#define DGL_DEBUG_EVENTS + #if defined(DEBUG) && defined(DGL_DEBUG_EVENTS) -# define DBG(msg) std::fprintf(stderr, "%s", msg); -# define DBGp(...) std::fprintf(stderr, __VA_ARGS__); -# define DBGF std::fflush(stderr); +# define DGL_DBG(msg) std::fprintf(stderr, "%s", msg); +# define DGL_DBGp(...) std::fprintf(stderr, __VA_ARGS__); +# define DGL_DBGF std::fflush(stderr); #else -# define DBG(msg) -# define DBGp(...) -# define DBGF +# define DGL_DBG(msg) +# define DGL_DBGp(...) +# define DGL_DBGF #endif START_NAMESPACE_DGL @@ -45,13 +50,66 @@ START_NAMESPACE_DGL // ----------------------------------------------------------------------- struct Window::PrivateData { - Application& fApp; - Window* fSelf; - PuglView* fView; + typedef Application::PrivateData AppData; + + AppData* const fAppData; + Window* const fSelf; + PuglView* const fView; // this one depends on build type // GraphicsContext fContext; + bool fFirstInit; + bool fVisible; + bool fUsingEmbed; + double fScaling; + double fAutoScaling; + std::list fWidgets; + + struct Modal { + bool enabled; + PrivateData* parent; + PrivateData* childFocus; + + Modal() + : enabled(false), + parent(nullptr), + childFocus(nullptr) {} + + Modal(PrivateData* const p) + : enabled(false), + parent(p), + childFocus(nullptr) {} + + ~Modal() + { + DISTRHO_SAFE_ASSERT(! enabled); + DISTRHO_SAFE_ASSERT(childFocus == nullptr); + } + + DISTRHO_DECLARE_NON_COPY_STRUCT(Modal) + } fModal; + +// #if defined(DISTRHO_OS_HAIKU) +// BApplication* bApplication; +// BView* bView; +// BWindow* bWindow; +#if defined(DISTRHO_OS_MAC) +// NSView* mView; +// id mWindow; +// id mParentWindow; +# ifndef DGL_FILE_BROWSER_DISABLED + NSOpenPanel* fOpenFilePanel; + id fFilePanelDelegate; +# endif +#elif defined(DISTRHO_OS_WINDOWS) +// HWND hwnd; +// HWND hwndParent; +# ifndef DGL_FILE_BROWSER_DISABLED + String fSelectedFile; +# endif +#endif + // Fallback build-specific Window functions struct Fallback { static void onDisplayBefore(); @@ -59,6 +117,7 @@ struct Window::PrivateData { static void onReshape(uint width, uint height); }; + /* PrivateData(Application& app, Window* const self) : fApp(app), fSelf(self) @@ -76,301 +135,99 @@ struct Window::PrivateData { fSelf(self) { } - -#ifdef DISTRHO_DEFINES_H_INCLUDED - friend class DISTRHO_NAMESPACE::UI; -#endif - - DISTRHO_DECLARE_NON_COPY_STRUCT(PrivateData) -}; - -// ----------------------------------------------------------------------- - -END_NAMESPACE_DGL - -#endif // DGL_WINDOW_PRIVATE_DATA_HPP_INCLUDED - - - - -#if 0 -// ----------------------------------------------------------------------- -// Window Private - -struct Window::PrivateData { - PrivateData(Application& app, Window* const self) - : fApp(app), + */ + PrivateData(Application::PrivateData* const appData, Window* const self) + : fAppData(appData), fSelf(self), - fView(puglInit()), + fView(puglNewView(appData->world)), fFirstInit(true), fVisible(false), - fResizable(true), fUsingEmbed(false), - fWidth(1), - fHeight(1), fScaling(1.0), fAutoScaling(1.0), - fTitle(nullptr), fWidgets(), - fModal(), -#if defined(DISTRHO_OS_HAIKU) - bApplication(nullptr), - bView(nullptr), - bWindow(nullptr) -#elif defined(DISTRHO_OS_MAC) - fNeedsIdle(true), - mView(nullptr), - mWindow(nullptr), - mParentWindow(nullptr) -# ifndef DGL_FILE_BROWSER_DISABLED - , fOpenFilePanel(nullptr), - fFilePanelDelegate(nullptr) -# endif -#elif defined(DISTRHO_OS_WINDOWS) - hwnd(nullptr), - hwndParent(nullptr) -#else - xDisplay(nullptr), - xWindow(0) -#endif + fModal() { - DBG("Creating window without parent..."); DBGF; + DGL_DBG("Creating window without parent..."); DGL_DBGF; init(); } - PrivateData(Application& app, Window* const self, Window& parent) - : fApp(app), + PrivateData(Application::PrivateData* const appData, Window* const self, Window& transientWindow) + : fAppData(appData), fSelf(self), - fView(puglInit()), + fView(puglNewView(appData->world)), fFirstInit(true), fVisible(false), - fResizable(true), fUsingEmbed(false), - fWidth(1), - fHeight(1), fScaling(1.0), fAutoScaling(1.0), - fTitle(nullptr), fWidgets(), - fModal(parent.pData), -#if defined(DISTRHO_OS_HAIKU) - bApplication(nullptr), - bView(nullptr), - bWindow(nullptr) -#elif defined(DISTRHO_OS_MAC) - fNeedsIdle(false), - mView(nullptr), - mWindow(nullptr), - mParentWindow(nullptr) -# ifndef DGL_FILE_BROWSER_DISABLED - , fOpenFilePanel(nullptr), - fFilePanelDelegate(nullptr) -# endif -#elif defined(DISTRHO_OS_WINDOWS) - hwnd(nullptr), - hwndParent(nullptr) -#else - xDisplay(nullptr), - xWindow(0) -#endif + fModal(transientWindow.pData) { - DBG("Creating window with parent..."); DBGF; + DGL_DBG("Creating window with parent..."); DGL_DBGF; init(); - const PuglInternals* const parentImpl(parent.pData->fView->impl); - - // NOTE: almost a 1:1 copy of setTransientWinId() -#if defined(DISTRHO_OS_HAIKU) - // TODO -#elif defined(DISTRHO_OS_MAC) - mParentWindow = parentImpl->window; -#elif defined(DISTRHO_OS_WINDOWS) - hwndParent = parentImpl->hwnd; - SetWindowLongPtr(hwnd, GWLP_HWNDPARENT, (LONG_PTR)hwndParent); -#else - XSetTransientForHint(xDisplay, xWindow, parentImpl->win); -#endif + puglSetTransientFor(fView, transientWindow.getNativeWindowHandle()); } - PrivateData(Application& app, Window* const self, const intptr_t parentId, const double scaling, const bool resizable) - : fApp(app), + PrivateData(Application::PrivateData* const appData, Window* const self, + const uintptr_t parentWindowHandle, + const double scaling, + const bool resizable) + : fAppData(appData), fSelf(self), - fView(puglInit()), + fView(puglNewView(appData->world)), fFirstInit(true), - fVisible(parentId != 0), - fResizable(resizable), - fUsingEmbed(parentId != 0), - fWidth(1), - fHeight(1), + fVisible(parentWindowHandle != 0), + fUsingEmbed(parentWindowHandle != 0), fScaling(scaling), fAutoScaling(1.0), - fTitle(nullptr), fWidgets(), - fModal(), -#if defined(DISTRHO_OS_HAIKU) - bApplication(nullptr), - bView(nullptr), - bWindow(nullptr) -#elif defined(DISTRHO_OS_MAC) - fNeedsIdle(parentId == 0), - mView(nullptr), - mWindow(nullptr), - mParentWindow(nullptr) -# ifndef DGL_FILE_BROWSER_DISABLED - , fOpenFilePanel(nullptr), - fFilePanelDelegate(nullptr) -# endif -#elif defined(DISTRHO_OS_WINDOWS) - hwnd(nullptr), - hwndParent(nullptr) -#else - xDisplay(nullptr), - xWindow(0) -#endif + fModal() { if (fUsingEmbed) { - DBG("Creating embedded window..."); DBGF; - puglInitWindowParent(fView, parentId); + DGL_DBG("Creating embedded window..."); DGL_DBGF; + puglSetParentWindow(fView, parentWindowHandle); } else { - DBG("Creating window without parent..."); DBGF; + DGL_DBG("Creating window without parent..."); DGL_DBGF; } - init(); + init(resizable); if (fUsingEmbed) { - DBG("NOTE: Embed window is always visible and non-resizable\n"); - puglShowWindow(fView); - fApp.pData->oneShown(); - fFirstInit = false; + DGL_DBG("NOTE: Embed window is always visible and non-resizable\n"); +// puglShowWindow(fView); +// fAppData->oneWindowShown(); +// fFirstInit = false; } } - void init() - { - if (fSelf == nullptr || fView == nullptr) - { - DBG("Failed!\n"); - return; - } - - puglInitUserResizable(fView, fResizable); - puglInitWindowSize(fView, static_cast(fWidth), static_cast(fHeight)); - - puglSetHandle(fView, this); - puglSetDisplayFunc(fView, onDisplayCallback); - puglSetKeyboardFunc(fView, onKeyboardCallback); - puglSetMotionFunc(fView, onMotionCallback); - puglSetMouseFunc(fView, onMouseCallback); - puglSetScrollFunc(fView, onScrollCallback); - puglSetSpecialFunc(fView, onSpecialCallback); - puglSetReshapeFunc(fView, onReshapeCallback); - puglSetCloseFunc(fView, onCloseCallback); -#ifndef DGL_FILE_BROWSER_DISABLED - puglSetFileSelectedFunc(fView, fileBrowserSelectedCallback); -#endif - - puglCreateWindow(fView, nullptr); - - PuglInternals* impl = fView->impl; - -#if defined(DISTRHO_OS_HAIKU) - bApplication = impl->app; - bView = impl->view; - bWindow = impl->window; -#elif defined(DISTRHO_OS_MAC) - mView = impl->view; - mWindow = impl->window; - DISTRHO_SAFE_ASSERT(mView != nullptr); - if (fUsingEmbed) { - DISTRHO_SAFE_ASSERT(mWindow == nullptr); - } else { - DISTRHO_SAFE_ASSERT(mWindow != nullptr); - } -#elif defined(DISTRHO_OS_WINDOWS) - hwnd = impl->hwnd; - DISTRHO_SAFE_ASSERT(hwnd != 0); -#else - xDisplay = impl->display; - xWindow = impl->win; - DISTRHO_SAFE_ASSERT(xWindow != 0); - - if (! fUsingEmbed) - { - const pid_t pid = getpid(); - const Atom _nwp = XInternAtom(xDisplay, "_NET_WM_PID", False); - XChangeProperty(xDisplay, xWindow, _nwp, XA_CARDINAL, 32, PropModeReplace, (const uchar*)&pid, 1); - - const Atom _wt = XInternAtom(xDisplay, "_NET_WM_WINDOW_TYPE", False); - - // Setting the window to both dialog and normal will produce a decorated floating dialog - // Order is important: DIALOG needs to come before NORMAL - const Atom _wts[2] = { - XInternAtom(xDisplay, "_NET_WM_WINDOW_TYPE_DIALOG", False), - XInternAtom(xDisplay, "_NET_WM_WINDOW_TYPE_NORMAL", False) - }; - XChangeProperty(xDisplay, xWindow, _wt, XA_ATOM, 32, PropModeReplace, (const uchar*)&_wts, 2); - } -#endif - puglEnterContext(fView); - - fApp.pData->windows.push_back(fSelf); - - DBG("Success!\n"); - } - ~PrivateData() { - DBG("Destroying window..."); DBGF; + DGL_DBG("Destroying window..."); DGL_DBGF; +#if 0 if (fModal.enabled) { exec_fini(); close(); } +#endif fWidgets.clear(); if (fUsingEmbed) { - puglHideWindow(fView); - fApp.pData->oneHidden(); +// puglHideWindow(fView); +// fAppData->oneWindowHidden(); } if (fSelf != nullptr) - { - fApp.pData->windows.remove(fSelf); - fSelf = nullptr; - } - - if (fView != nullptr) - { - puglDestroy(fView); - fView = nullptr; - } - - if (fTitle != nullptr) - { - std::free(fTitle); - fTitle = nullptr; - } - -#if defined(DISTRHO_OS_HAIKU) - bApplication = nullptr; - bView = nullptr; - bWindow = nullptr; -#elif defined(DISTRHO_OS_MAC) - mView = nullptr; - mWindow = nullptr; -#elif defined(DISTRHO_OS_WINDOWS) - hwnd = 0; -#else - xDisplay = nullptr; - xWindow = 0; -#endif + fAppData->windows.remove(fSelf); #if defined(DISTRHO_OS_MAC) && !defined(DGL_FILE_BROWSER_DISABLED) if (fOpenFilePanel) @@ -385,561 +242,194 @@ struct Window::PrivateData { } #endif - DBG("Success!\n"); - } - - // ------------------------------------------------------------------- - - void close() - { - DBG("Window close\n"); - - if (fUsingEmbed) - return; - - setVisible(false); - - if (! fFirstInit) - { - fApp.pData->oneHidden(); - fFirstInit = true; - } - } - - void exec(const bool lockWait) - { - DBG("Window exec\n"); - exec_init(); - - if (lockWait) - { - for (; fVisible && fModal.enabled;) - { - idle(); - d_msleep(10); - } - - exec_fini(); - } - else - { - idle(); - } - } - - // ------------------------------------------------------------------- - - void exec_init() - { - DBG("Window modal loop starting..."); DBGF; - DISTRHO_SAFE_ASSERT_RETURN(fModal.parent != nullptr, setVisible(true)); - - fModal.enabled = true; - fModal.parent->fModal.childFocus = this; - - fModal.parent->setVisible(true); - setVisible(true); - - DBG("Ok\n"); - } - - void exec_fini() - { - DBG("Window modal loop stopping..."); DBGF; - fModal.enabled = false; - - if (fModal.parent != nullptr) - { - fModal.parent->fModal.childFocus = nullptr; - - // the mouse position probably changed since the modal appeared, - // so send a mouse motion event to the modal's parent window -#if defined(DISTRHO_OS_HAIKU) - // TODO -#elif defined(DISTRHO_OS_MAC) - // TODO -#elif defined(DISTRHO_OS_WINDOWS) - // TODO -#else - int i, wx, wy; - uint u; - ::Window w; - if (XQueryPointer(fModal.parent->xDisplay, fModal.parent->xWindow, &w, &w, &i, &i, &wx, &wy, &u) == True) - fModal.parent->onPuglMotion(wx, wy); -#endif - } - - DBG("Ok\n"); - } - - // ------------------------------------------------------------------- - - void focus() - { - DBG("Window focus\n"); -#if defined(DISTRHO_OS_HAIKU) - if (bWindow != nullptr) - { - if (bWindow->LockLooper()) - { - bWindow->Activate(true); - bWindow->UnlockLooper(); - } - } - else - { - bView->MakeFocus(true); - } -#elif defined(DISTRHO_OS_MAC) - if (mWindow != nullptr) - [mWindow makeKeyWindow]; -#elif defined(DISTRHO_OS_WINDOWS) - SetForegroundWindow(hwnd); - SetActiveWindow(hwnd); - SetFocus(hwnd); -#else - XRaiseWindow(xDisplay, xWindow); - XSetInputFocus(xDisplay, xWindow, RevertToPointerRoot, CurrentTime); - XFlush(xDisplay); -#endif - } - - // ------------------------------------------------------------------- - - void setVisible(const bool yesNo) - { - if (fVisible == yesNo) - { - DBG("Window setVisible matches current state, ignoring request\n"); - return; - } - if (fUsingEmbed) - { - DBG("Window setVisible cannot be called when embedded\n"); - return; - } - - DBG("Window setVisible called\n"); - - fVisible = yesNo; - - if (yesNo && fFirstInit) - setSize(fWidth, fHeight, true); - -#if defined(DISTRHO_OS_HAIKU) - if (bWindow != nullptr) - { - if (bWindow->LockLooper()) - { - if (yesNo) - bWindow->Show(); - else - bWindow->Hide(); - - // TODO use flush? - bWindow->Sync(); - bWindow->UnlockLooper(); - } - } - else - { - if (yesNo) - bView->Show(); - else - bView->Hide(); - } -#elif defined(DISTRHO_OS_MAC) - if (yesNo) - { - if (mWindow != nullptr) - { - if (mParentWindow != nullptr) - [mParentWindow addChildWindow:mWindow - ordered:NSWindowAbove]; - - [mWindow setIsVisible:YES]; - } - else - { - [mView setHidden:NO]; - } - } - else - { - if (mWindow != nullptr) - { - if (mParentWindow != nullptr) - [mParentWindow removeChildWindow:mWindow]; - - [mWindow setIsVisible:NO]; - } - else - { - [mView setHidden:YES]; - } - } -#elif defined(DISTRHO_OS_WINDOWS) - if (yesNo) - { - if (fFirstInit) - { - RECT rectChild, rectParent; - - if (hwndParent != nullptr && - GetWindowRect(hwnd, &rectChild) && - GetWindowRect(hwndParent, &rectParent)) - { - SetWindowPos(hwnd, hwndParent, - rectParent.left + (rectChild.right-rectChild.left)/2, - rectParent.top + (rectChild.bottom-rectChild.top)/2, - 0, 0, SWP_SHOWWINDOW|SWP_NOSIZE); - } - else - { - ShowWindow(hwnd, SW_SHOWNORMAL); - } - } - else - { - ShowWindow(hwnd, SW_RESTORE); - } - } - else - { - ShowWindow(hwnd, SW_HIDE); - } - - UpdateWindow(hwnd); -#else - if (yesNo) - XMapRaised(xDisplay, xWindow); - else - XUnmapWindow(xDisplay, xWindow); - - XFlush(xDisplay); -#endif - - if (yesNo) - { - if (fFirstInit) - { - fApp.pData->oneShown(); - fFirstInit = false; - } - } - else if (fModal.enabled) - exec_fini(); - } - - // ------------------------------------------------------------------- - - void setResizable(const bool yesNo) - { - if (fResizable == yesNo) - { - DBG("Window setResizable matches current state, ignoring request\n"); - return; - } - if (fUsingEmbed) - { - DBG("Window setResizable cannot be called when embedded\n"); - return; - } - - DBG("Window setResizable called\n"); - - fResizable = yesNo; - fView->user_resizable = yesNo; - -#if defined(DISTRHO_OS_HAIKU) - // TODO - // B_NO_BORDER - // B_TITLED_WINDOW_LOOK - // bWindow->SetFlags(); -#elif defined(DISTRHO_OS_MAC) - const uint flags = yesNo ? (NSViewWidthSizable|NSViewHeightSizable) : 0x0; - [mView setAutoresizingMask:flags]; -#elif defined(DISTRHO_OS_WINDOWS) - const int winFlags = fResizable ? GetWindowLong(hwnd, GWL_STYLE) | WS_SIZEBOX - : GetWindowLong(hwnd, GWL_STYLE) & ~WS_SIZEBOX; - SetWindowLong(hwnd, GWL_STYLE, winFlags); -#endif - - setSize(fWidth, fHeight, true); - } - - // ------------------------------------------------------------------- - - void setGeometryConstraints(uint width, uint height, bool aspect) - { - // Did you forget to set DISTRHO_UI_USER_RESIZABLE ? - 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) - { - if (width <= 1 || height <= 1) - { - DBGp("Window setSize called with invalid value(s) %i %i, ignoring request\n", width, height); - return; - } - - if (fWidth == width && fHeight == height && ! forced) - { - DBGp("Window setSize matches current size, ignoring request (%i %i)\n", width, height); - return; - } - - fWidth = width; - fHeight = height; - - DBGp("Window setSize called %s, size %i %i, resizable %s\n", forced ? "(forced)" : "(not forced)", width, height, fResizable?"true":"false"); - -#if defined(DISTRHO_OS_HAIKU) - bView->ResizeTo(width, height); - - if (bWindow != nullptr && bWindow->LockLooper()) - { - bWindow->MoveTo(50, 50); - bWindow->ResizeTo(width, height); - - if (! forced) - bWindow->Flush(); - - bWindow->UnlockLooper(); - } - // TODO resizable -#elif defined(DISTRHO_OS_MAC) - [mView setFrame:NSMakeRect(0, 0, width, height)]; - - if (mWindow != nullptr) - { - const NSSize size = NSMakeSize(width, height); - [mWindow setContentSize:size]; - - if (fResizable) - { - [mWindow setContentMinSize:NSMakeSize(1, 1)]; - [mWindow setContentMaxSize:NSMakeSize(99999, 99999)]; - [[mWindow standardWindowButton:NSWindowZoomButton] setHidden:NO]; - } - else - { - [mWindow setContentMinSize:size]; - [mWindow setContentMaxSize:size]; - [[mWindow standardWindowButton:NSWindowZoomButton] setHidden:YES]; - } - } -#elif defined(DISTRHO_OS_WINDOWS) - const int winFlags = WS_POPUPWINDOW | WS_CAPTION | (fResizable ? WS_SIZEBOX : 0x0); - RECT wr = { 0, 0, static_cast(width), static_cast(height) }; - AdjustWindowRectEx(&wr, fUsingEmbed ? WS_CHILD : winFlags, FALSE, WS_EX_TOPMOST); - - SetWindowPos(hwnd, 0, 0, 0, wr.right-wr.left, wr.bottom-wr.top, - SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOOWNERZORDER|SWP_NOZORDER); - - if (! forced) - UpdateWindow(hwnd); -#else - - if (! fResizable) - { - XSizeHints sizeHints; - memset(&sizeHints, 0, sizeof(sizeHints)); - - sizeHints.flags = PSize|PMinSize|PMaxSize; - sizeHints.width = static_cast(width); - sizeHints.height = static_cast(height); - sizeHints.min_width = static_cast(width); - sizeHints.min_height = static_cast(height); - sizeHints.max_width = static_cast(width); - sizeHints.max_height = static_cast(height); - - XSetWMNormalHints(xDisplay, xWindow, &sizeHints); - } - - XResizeWindow(xDisplay, xWindow, width, height); - - if (! forced) - XFlush(xDisplay); -#endif + if (fView != nullptr) + puglFreeView(fView); - puglPostRedisplay(fView); + DGL_DBG("Success!\n"); } // ------------------------------------------------------------------- + // stuff that uses pugl internals or build-specific things - const char* getTitle() const noexcept - { - static const char* const kFallback = ""; + void init(const bool resizable = false); + void setVisible(const bool visible); + void windowSpecificIdle(); + static PuglStatus puglEventCallback(PuglView* const view, const PuglEvent* const event); - return fTitle != nullptr ? fTitle : kFallback; - } + // ------------------------------------------------------------------- - void setTitle(const char* const title) + void close() { - DBGp("Window setTitle \"%s\"\n", title); + DGL_DBG("Window close\n"); - if (fTitle != nullptr) - std::free(fTitle); + if (fUsingEmbed) + return; - fTitle = strdup(title); + setVisible(false); -#if defined(DISTRHO_OS_HAIKU) - if (bWindow != nullptr&& bWindow->LockLooper()) - { - bWindow->SetTitle(title); - bWindow->UnlockLooper(); - } -#elif defined(DISTRHO_OS_MAC) - if (mWindow != nullptr) + if (! fFirstInit) { - NSString* titleString = [[NSString alloc] - initWithBytes:title - length:strlen(title) - encoding:NSUTF8StringEncoding]; - - [mWindow setTitle:titleString]; + fAppData->oneWindowHidden(); + fFirstInit = true; } -#elif defined(DISTRHO_OS_WINDOWS) - SetWindowTextA(hwnd, title); -#else - XStoreName(xDisplay, xWindow, title); - Atom netWmName = XInternAtom(xDisplay, "_NET_WM_NAME", False); - Atom utf8String = XInternAtom(xDisplay, "UTF8_STRING", False); - XChangeProperty(xDisplay, xWindow, netWmName, utf8String, 8, PropModeReplace, (unsigned char *)title, strlen(title)); -#endif - } - - void setTransientWinId(const uintptr_t winId) - { - DISTRHO_SAFE_ASSERT_RETURN(winId != 0,); - -#if defined(DISTRHO_OS_HAIKU) - // TODO -#elif defined(DISTRHO_OS_MAC) - NSWindow* const parentWindow = [NSApp windowWithWindowNumber:winId]; - DISTRHO_SAFE_ASSERT_RETURN(parentWindow != nullptr,); - - [parentWindow addChildWindow:mWindow - ordered:NSWindowAbove]; -#elif defined(DISTRHO_OS_WINDOWS) - hwndParent = (HWND)winId; - SetWindowLongPtr(hwnd, GWLP_HWNDPARENT, (LONG_PTR)winId); -#else - XSetTransientForHint(xDisplay, xWindow, static_cast< ::Window>(winId)); -#endif } // ------------------------------------------------------------------- - double getScaling() const noexcept + void addWidget(Widget* const widget) { - return fScaling; + fWidgets.push_back(widget); } - void setAutoScaling(const double scaling) noexcept + void removeWidget(Widget* const widget) { - DISTRHO_SAFE_ASSERT_RETURN(scaling > 0.0,); - - fAutoScaling = scaling; + fWidgets.remove(widget); } // ------------------------------------------------------------------- - bool getIgnoringKeyRepeat() const noexcept + void onPuglClose() { - return fView->ignoreKeyRepeat; - } + DGL_DBG("PUGL: onClose\n"); - void setIgnoringKeyRepeat(bool ignore) noexcept - { - puglIgnoreKeyRepeat(fView, ignore); - } +// if (fModal.enabled) +// exec_fini(); - // ------------------------------------------------------------------- + fSelf->onClose(); - void addWidget(Widget* const widget) - { - fWidgets.push_back(widget); + if (fModal.childFocus != nullptr) + fModal.childFocus->fSelf->onClose(); + + close(); } - void removeWidget(Widget* const widget) + void onPuglDisplay() { - fWidgets.remove(widget); + fSelf->onDisplayBefore(); + + if (fWidgets.size() != 0) + { + const PuglRect rect = puglGetFrame(fView); + const int width = rect.width; + const int height = rect.height; + + FOR_EACH_WIDGET(it) + { + Widget* const widget(*it); + widget->pData->display(width, height, fAutoScaling, false); + } + } + + fSelf->onDisplayAfter(); } - void idle() + void onPuglReshape(const int width, const int height) { - puglProcessEvents(fView); + DISTRHO_SAFE_ASSERT_INT2_RETURN(width > 1 && height > 1, width, height,); + + DGL_DBGp("PUGL: onReshape : %i %i\n", width, height); -#ifdef DISTRHO_OS_HAIKU - if (bApplication != nullptr) + fSelf->onReshape(width, height); + + FOR_EACH_WIDGET(it) { - // bApplication->Lock(); - // bApplication->Loop(); - // bApplication->Unlock(); + Widget* const widget(*it); + + if (widget->pData->needsFullViewport) + widget->setSize(width, height); } + } + + // ------------------------------------------------------------------- + +#ifdef DISTRHO_DEFINES_H_INCLUDED + friend class DISTRHO_NAMESPACE::UI; #endif + DISTRHO_DECLARE_NON_COPY_STRUCT(PrivateData) +}; -#ifdef DISTRHO_OS_MAC - if (fNeedsIdle) - { - NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; - NSEvent* event; +// ----------------------------------------------------------------------- - for (;;) - { - event = [NSApp - nextEventMatchingMask:NSAnyEventMask - untilDate:[NSDate distantPast] - inMode:NSDefaultRunLoopMode - dequeue:YES]; +END_NAMESPACE_DGL + + +#if 0 +// ----------------------------------------------------------------------- +// Window Private + +struct Window::PrivateData { + // ------------------------------------------------------------------- - if (event == nil) - break; + void exec(const bool lockWait) + { + DBG("Window exec\n"); + exec_init(); - [NSApp sendEvent: event]; + if (lockWait) + { + for (; fVisible && fModal.enabled;) + { + idle(); + d_msleep(10); } - [pool release]; + exec_fini(); } -#endif - -#if defined(DISTRHO_OS_WINDOWS) && !defined(DGL_FILE_BROWSER_DISABLED) - if (fSelectedFile.isNotEmpty()) + else { - char* const buffer = fSelectedFile.getAndReleaseBuffer(); - fView->fileSelectedFunc(fView, buffer); - std::free(buffer); + idle(); } -#endif - - if (fModal.enabled && fModal.parent != nullptr) - fModal.parent->idle(); } // ------------------------------------------------------------------- - void onPuglDisplay() + void exec_init() { - fSelf->onDisplayBefore(); + DBG("Window modal loop starting..."); DBGF; + DISTRHO_SAFE_ASSERT_RETURN(fModal.parent != nullptr, setVisible(true)); - FOR_EACH_WIDGET(it) + fModal.enabled = true; + fModal.parent->fModal.childFocus = this; + + fModal.parent->setVisible(true); + setVisible(true); + + DBG("Ok\n"); + } + + void exec_fini() + { + DBG("Window modal loop stopping..."); DBGF; + fModal.enabled = false; + + if (fModal.parent != nullptr) { - Widget* const widget(*it); - widget->pData->display(fWidth, fHeight, fAutoScaling, false); + fModal.parent->fModal.childFocus = nullptr; + + // the mouse position probably changed since the modal appeared, + // so send a mouse motion event to the modal's parent window +#if defined(DISTRHO_OS_HAIKU) + // TODO +#elif defined(DISTRHO_OS_MAC) + // TODO +#elif defined(DISTRHO_OS_WINDOWS) + // TODO +#else + int i, wx, wy; + uint u; + ::Window w; + if (XQueryPointer(fModal.parent->xDisplay, fModal.parent->xWindow, &w, &w, &i, &i, &wx, &wy, &u) == True) + fModal.parent->onPuglMotion(wx, wy); +#endif } - fSelf->onDisplayAfter(); + DBG("Ok\n"); } + // ------------------------------------------------------------------- + + // ------------------------------------------------------------------- + int onPuglKeyboard(const bool press, const uint key) { DBGp("PUGL: onKeyboard : %i %i\n", press, key); @@ -1077,42 +567,6 @@ struct Window::PrivateData { } } - void onPuglReshape(const int width, const int height) - { - DBGp("PUGL: onReshape : %i %i\n", width, height); - - if (width <= 1 && height <= 1) - return; - - fWidth = static_cast(width); - fHeight = static_cast(height); - - fSelf->onReshape(fWidth, fHeight); - - FOR_EACH_WIDGET(it) - { - Widget* const widget(*it); - - if (widget->pData->needsFullViewport) - widget->setSize(fWidth, fHeight); - } - } - - void onPuglClose() - { - DBG("PUGL: onClose\n"); - - if (fModal.enabled) - exec_fini(); - - fSelf->onClose(); - - if (fModal.childFocus != nullptr) - fModal.childFocus->fSelf->onClose(); - - close(); - } - // ------------------------------------------------------------------- bool handlePluginKeyboard(const bool press, const uint key) @@ -1232,124 +686,11 @@ struct Window::PrivateData { // ------------------------------------------------------------------- - Application& fApp; - Window* fSelf; - GraphicsContext fContext; - PuglView* fView; - - bool fFirstInit; - bool fVisible; - bool fResizable; - bool fUsingEmbed; - uint fWidth; - uint fHeight; - double fScaling; - double fAutoScaling; - char* fTitle; - std::list fWidgets; - - struct Modal { - bool enabled; - PrivateData* parent; - PrivateData* childFocus; - - Modal() - : enabled(false), - parent(nullptr), - childFocus(nullptr) {} - - Modal(PrivateData* const p) - : enabled(false), - parent(p), - childFocus(nullptr) {} - - ~Modal() - { - DISTRHO_SAFE_ASSERT(! enabled); - DISTRHO_SAFE_ASSERT(childFocus == nullptr); - } - - DISTRHO_DECLARE_NON_COPY_STRUCT(Modal) - } fModal; - -#if defined(DISTRHO_OS_HAIKU) - BApplication* bApplication; - BView* bView; - BWindow* bWindow; -#elif defined(DISTRHO_OS_MAC) - bool fNeedsIdle; - NSView* mView; - id mWindow; - id mParentWindow; -# ifndef DGL_FILE_BROWSER_DISABLED - NSOpenPanel* fOpenFilePanel; - id fFilePanelDelegate; -# endif -#elif defined(DISTRHO_OS_WINDOWS) - HWND hwnd; - HWND hwndParent; -# ifndef DGL_FILE_BROWSER_DISABLED - String fSelectedFile; -# endif -#else - Display* xDisplay; - ::Window xWindow; -#endif - - // ------------------------------------------------------------------- - // Callbacks - - #define handlePtr ((PrivateData*)puglGetHandle(view)) - - static void onDisplayCallback(PuglView* view) - { - handlePtr->onPuglDisplay(); - } - - static int onKeyboardCallback(PuglView* view, bool press, uint32_t key) - { - return handlePtr->onPuglKeyboard(press, key); - } - - static int onSpecialCallback(PuglView* view, bool press, PuglKey key) - { - return handlePtr->onPuglSpecial(press, static_cast(key)); - } - - static void onMouseCallback(PuglView* view, int button, bool press, int x, int y) - { - handlePtr->onPuglMouse(button, press, x, y); - } - - static void onMotionCallback(PuglView* view, int x, int y) - { - handlePtr->onPuglMotion(x, y); - } - - static void onScrollCallback(PuglView* view, int x, int y, float dx, float dy) - { - handlePtr->onPuglScroll(x, y, dx, dy); - } - - static void onReshapeCallback(PuglView* view, int width, int height) - { - handlePtr->onPuglReshape(width, height); - } - - static void onCloseCallback(PuglView* view) - { - handlePtr->onPuglClose(); - } - -#ifndef DGL_FILE_BROWSER_DISABLED - static void fileBrowserSelectedCallback(PuglView* view, const char* filename) - { - handlePtr->fSelf->fileBrowserSelected(filename); - } -#endif - - #undef handlePtr - DISTRHO_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(PrivateData) }; #endif + +// #undef DGL_DBG +// #undef DGL_DBGF + +#endif // DGL_WINDOW_PRIVATE_DATA_HPP_INCLUDED diff --git a/dgl/src/pugl-extra/extras.c b/dgl/src/pugl-extra/extras.c new file mode 100644 index 00000000..01e90192 --- /dev/null +++ b/dgl/src/pugl-extra/extras.c @@ -0,0 +1,29 @@ +/* + Copyright (C) 2012-2020 Filipe Coelho + + 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 extras.c pugl extra implementations for DPF. +*/ + +#include "extras.h" + +#include "../pugl-upstream/src/implementation.h" + +const char* +puglGetWindowTitle(const PuglView* view) +{ + return view->title; +} diff --git a/dgl/src/pugl-extra/extras.h b/dgl/src/pugl-extra/extras.h new file mode 100644 index 00000000..f9ff4d61 --- /dev/null +++ b/dgl/src/pugl-extra/extras.h @@ -0,0 +1,50 @@ +/* + Copyright (C) 2012-2020 Filipe Coelho + + 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 pugl.h pugl extra API for DPF. +*/ + +#ifndef PUGL_EXTRAS_PUGL_H +#define PUGL_EXTRAS_PUGL_H + +#include "../pugl-upstream/include/pugl/pugl.h" + +PUGL_BEGIN_DECLS + +PUGL_API const char* +puglGetWindowTitle(const PuglView* view); + +PUGL_API int +puglGetViewHint(const PuglView* view, PuglViewHint hint); + +PUGL_API void +puglRaiseWindow(PuglView* view); + +PUGL_API void +puglSetWindowSize(PuglView* view, unsigned int width, unsigned int height); + +PUGL_API void +puglUpdateGeometryConstraints(PuglView* view, unsigned int width, unsigned int height, bool aspect); + +#ifdef DISTRHO_OS_WINDOWS +PUGL_API void +puglWin32SetWindowResizable(PuglView* view, bool resizable); +#endif + +PUGL_END_DECLS + +#endif // PUGL_EXTRAS_PUGL_H diff --git a/dgl/src/pugl-extra/haiku.cpp b/dgl/src/pugl-extra/haiku.cpp new file mode 100644 index 00000000..b01b6629 --- /dev/null +++ b/dgl/src/pugl-extra/haiku.cpp @@ -0,0 +1,81 @@ +/* + Copyright 2012-2019 David Robillard + Copyright 2019-2020 Filipe Coelho + + 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 mac.cpp HaikuOS implementation. +*/ + +#include "haiku.h" + +#include "pugl/detail/implementation.h" + +PuglStatus +puglGrabFocus(PuglView* view) +{ + view->impl->bView->MakeFocus(true); + return PUGL_SUCCESS; +} + +// extras follow + +void +puglRaiseWindow(PuglView* view) +{ +} + +void +puglSetWindowSize(PuglView* view, unsigned int width, unsigned int height) +{ + bView->ResizeTo(width, height); + + if (bWindow != nullptr && bWindow->LockLooper()) + { + bWindow->MoveTo(50, 50); + bWindow->ResizeTo(width, height); + + if (! forced) + bWindow->Flush(); + + bWindow->UnlockLooper(); + } + // TODO resizable +} + +void setVisible(const bool yesNo) +{ + if (bWindow != nullptr) + { + if (bWindow->LockLooper()) + { + if (yesNo) + bWindow->Show(); + else + bWindow->Hide(); + + // TODO use flush? + bWindow->Sync(); + bWindow->UnlockLooper(); + } + } + else + { + if (yesNo) + bView->Show(); + else + bView->Hide(); + } +} diff --git a/dgl/src/pugl-extra/haiku.h b/dgl/src/pugl-extra/haiku.h new file mode 100644 index 00000000..9930a8df --- /dev/null +++ b/dgl/src/pugl-extra/haiku.h @@ -0,0 +1,35 @@ +/* + Copyright 2012-2019 David Robillard + Copyright 2019-2020 Filipe Coelho + + 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 haiku.h Shared definitions for HaikuOS implementation. +*/ + +#include "pugl/pugl.h" + +#include +#include +// using? interface/ + +struct PuglWorldInternalsImpl { + BApplication* app; +}; + +struct PuglInternalsImpl { + BViewType* view; + BWindow* window; +}; diff --git a/dgl/src/pugl-extra/mac.m b/dgl/src/pugl-extra/mac.m new file mode 100644 index 00000000..853ac246 --- /dev/null +++ b/dgl/src/pugl-extra/mac.m @@ -0,0 +1,48 @@ +/* + Copyright (C) 2012-2020 Filipe Coelho + + 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 mac.m MacOS extra implementation for DPF. +*/ + +#include "pugl/detail/mac.h" + +void +puglRaiseWindow(PuglView* view) +{ +} + +void +puglSetWindowSize(PuglView* view, unsigned int width, unsigned int height) +{ + // NOTE: pugl mac code does nothing with x and y + const PuglRect frame = { 0.0, 0.0, (double)width, (double)height }; + puglSetFrame(view, frame); +} + +void +puglUpdateGeometryConstraints(PuglView* view, unsigned int width, unsigned int height, bool aspect) +{ + // NOTE this is a combination of puglSetMinSize and puglSetAspectRatio + view->minWidth = width; + view->minHeight = height; + + [view->impl->window setContentMinSize:sizePoints(view, width, height)]; + + if (aspect) { + [view->impl->window setContentAspectRatio:sizePoints(view, width, height)]; + } +} diff --git a/dgl/src/pugl-extra/win.c b/dgl/src/pugl-extra/win.c new file mode 100644 index 00000000..dca0db02 --- /dev/null +++ b/dgl/src/pugl-extra/win.c @@ -0,0 +1,118 @@ +/* + Copyright (C) 2012-2020 Filipe Coelho + + 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 win.c Windows extra implementation for DPF. +*/ + +#include "pugl/detail/win.h" + +#include "pugl/detail/implementation.h" + +void +puglRaiseWindow(PuglView* view) +{ + SetForegroundWindow(view->impl->hwnd); + SetActiveWindow(view->impl->hwnd); + return PUGL_SUCCESS; +} + +void +puglSetWindowSize(PuglView* view, unsigned int width, unsigned int height) +{ + view->frame.width = width; + view->frame.height = height; + + // NOTE the following code matches upstream pugl, except we add SWP_NOMOVE flag + if (view->impl->hwnd) { + RECT rect = { (long)frame.x, + (long)frame.y, + (long)frame.x + (long)frame.width, + (long)frame.y + (long)frame.height }; + + AdjustWindowRectEx(&rect, puglWinGetWindowFlags(view), + FALSE, + puglWinGetWindowExFlags(view)); + + SetWindowPos(view->impl->hwnd, + HWND_TOP, + rect.left, + rect.top, + rect.right - rect.left, + rect.bottom - rect.top, + SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOOWNERZORDER | SWP_NOZORDER); + } +} + +void +puglUpdateGeometryConstraints(PuglView* view, unsigned int width, unsigned int height, bool aspect) +{ + // NOTE this is a combination of puglSetMinSize and puglSetAspectRatio, but stilL TODO on pugl + Display* display = view->world->impl->display; + + view->minWidth = width; + view->minHeight = height; + + if (aspect) { + view->minAspectX = width; + view->minAspectY = height; + view->maxAspectX = width; + view->maxAspectY = height; + } +} + +void +puglWin32RestoreWindow(PuglView* view) +{ + PuglInternals* impl = view->impl; + + ShowWindow(impl->hwnd, SW_RESTORE); + SetFocus(impl->hwnd); +} + +void +puglWin32ShowWindowCentered(PuglView* view) +{ + PuglInternals* impl = view->impl; + + RECT rectChild, rectParent; + + if (impl->transientParent != 0 && + GetWindowRect(impl->hwnd, &rectChild) && + GetWindowRect(impl->transientParent, &rectParent)) + { + SetWindowPos(impl->hwnd, (HWND)impl->transientParent, + rectParent.left + (rectChild.right-rectChild.left)/2, + rectParent.top + (rectChild.bottom-rectChild.top)/2, + 0, 0, SWP_SHOWWINDOW|SWP_NOSIZE); + } + else + { + ShowWindow(hwnd, SW_SHOWNORMAL); + } + + SetFocus(impl->hwnd); +} + +void +puglWin32SetWindowResizable(PuglView* view, bool resizable) +{ + PuglInternals* impl = view->impl; + + const int winFlags = resizable ? GetWindowLong(hwnd, GWL_STYLE) | WS_SIZEBOX + : GetWindowLong(hwnd, GWL_STYLE) & ~WS_SIZEBOX; + SetWindowLong(impl->hwnd, GWL_STYLE, winFlags); +} diff --git a/dgl/src/pugl-extra/x11.c b/dgl/src/pugl-extra/x11.c new file mode 100644 index 00000000..595473db --- /dev/null +++ b/dgl/src/pugl-extra/x11.c @@ -0,0 +1,111 @@ +/* + Copyright (C) 2012-2020 Filipe Coelho + + 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 x11.c X11 extra implementation for DPF. +*/ + +// NOTE can't import this file twice! +#ifndef PUGL_DETAIL_X11_H_INCLUDED +#include "../pugl-upstream/src/x11.h" +#endif + +#include "../pugl-upstream/src/implementation.h" + +#include +#include + +void +puglRaiseWindow(PuglView* view) +{ + XRaiseWindow(view->impl->display, view->impl->win); +} + +void +puglSetWindowSize(PuglView* view, unsigned int width, unsigned int height) +{ + view->frame.width = width; + view->frame.height = height; + + if (view->impl->win) { +#if 0 + if (! fResizable) + { + XSizeHints sizeHints; + memset(&sizeHints, 0, sizeof(sizeHints)); + + sizeHints.flags = PSize|PMinSize|PMaxSize; + sizeHints.width = static_cast(width); + sizeHints.height = static_cast(height); + sizeHints.min_width = static_cast(width); + sizeHints.min_height = static_cast(height); + sizeHints.max_width = static_cast(width); + sizeHints.max_height = static_cast(height); + + XSetWMNormalHints(xDisplay, xWindow, &sizeHints); + } +#endif + + XResizeWindow(view->world->impl->display, view->impl->win, width, height); + } +} + +void +puglUpdateGeometryConstraints(PuglView* view, unsigned int width, unsigned int height, bool aspect) +{ + // NOTE this is a combination of puglSetMinSize and puglSetAspectRatio + Display* display = view->world->impl->display; + + view->minWidth = width; + view->minHeight = height; + + if (aspect) { + view->minAspectX = width; + view->minAspectY = height; + view->maxAspectX = width; + view->maxAspectY = height; + } + +#if 0 + if (view->impl->win) { + XSizeHints sizeHints = getSizeHints(view); + XSetNormalHints(display, view->impl->win, &sizeHints); + // NOTE old code used this instead + // XSetWMNormalHints(display, view->impl->win, &sizeHints); + } +#endif +} + +void +puglExtraSetWindowTypeAndPID(PuglView* view) +{ + PuglInternals* const impl = view->impl; + + const pid_t pid = getpid(); + const Atom _nwp = XInternAtom(impl->display, "_NET_WM_PID", False); + XChangeProperty(impl->display, impl->win, _nwp, XA_CARDINAL, 32, PropModeReplace, (const uchar*)&pid, 1); + + const Atom _wt = XInternAtom(impl->display, "_NET_WM_WINDOW_TYPE", False); + + // Setting the window to both dialog and normal will produce a decorated floating dialog + // Order is important: DIALOG needs to come before NORMAL + const Atom _wts[2] = { + XInternAtom(impl->display, "_NET_WM_WINDOW_TYPE_DIALOG", False), + XInternAtom(impl->display, "_NET_WM_WINDOW_TYPE_NORMAL", False) + }; + + XChangeProperty(impl->display, impl->win, _wt, XA_ATOM, 32, PropModeReplace, (const uchar*)&_wts, 2); +} diff --git a/distrho/src/DistrhoPluginVST.cpp b/distrho/src/DistrhoPluginVST.cpp index b5501840..04ff34a8 100644 --- a/distrho/src/DistrhoPluginVST.cpp +++ b/distrho/src/DistrhoPluginVST.cpp @@ -22,6 +22,7 @@ #endif #if DISTRHO_PLUGIN_HAS_UI +# define DISTRHO_UI_IS_STANDALONE 0 # include "DistrhoUIInternal.hpp" #endif diff --git a/distrho/src/DistrhoUI.cpp b/distrho/src/DistrhoUI.cpp index 7bb52475..211cad44 100644 --- a/distrho/src/DistrhoUI.cpp +++ b/distrho/src/DistrhoUI.cpp @@ -38,7 +38,6 @@ Window* d_lastUiWindow = nullptr; // ----------------------------------------------------------------------------------------------------------- #if DISTRHO_PLUGIN_HAS_EXTERNAL_UI -static inline UI* createUiWrapper(void* const dspPtr, const uintptr_t winId, const double scaleFactor, const char* const bundlePath) { d_lastUiDspPtr = dspPtr; @@ -53,7 +52,6 @@ UI* createUiWrapper(void* const dspPtr, const uintptr_t winId, const double scal return ret; } #else -static inline UI* createUiWrapper(void* const dspPtr, Window* const window) { d_lastUiDspPtr = dspPtr; diff --git a/distrho/src/DistrhoUIDSSI.cpp b/distrho/src/DistrhoUIDSSI.cpp index ef3fc365..41504af4 100644 --- a/distrho/src/DistrhoUIDSSI.cpp +++ b/distrho/src/DistrhoUIDSSI.cpp @@ -14,6 +14,7 @@ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ +#define DISTRHO_UI_IS_STANDALONE 1 #include "DistrhoUIInternal.hpp" #if DISTRHO_PLUGIN_WANT_DIRECT_ACCESS diff --git a/distrho/src/DistrhoUIInternal.hpp b/distrho/src/DistrhoUIInternal.hpp index 25c066bd..819ddb68 100644 --- a/distrho/src/DistrhoUIInternal.hpp +++ b/distrho/src/DistrhoUIInternal.hpp @@ -203,7 +203,7 @@ public: return fUI->isRunning(); } - intptr_t getWindowId() const noexcept + uintptr_t getNativeWindowHandle() const noexcept { return 0; } @@ -223,9 +223,9 @@ public: return glWindow.isVisible(); } - intptr_t getWindowId() const noexcept + uintptr_t getNativeWindowHandle() const noexcept { - return glWindow.getWindowId(); + return glWindow.getNativeWindowHandle(); } #endif diff --git a/distrho/src/DistrhoUILV2.cpp b/distrho/src/DistrhoUILV2.cpp index 2db10656..f1a11aba 100644 --- a/distrho/src/DistrhoUILV2.cpp +++ b/distrho/src/DistrhoUILV2.cpp @@ -14,6 +14,7 @@ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ +#define DISTRHO_UI_IS_STANDALONE 0 #include "DistrhoUIInternal.hpp" #include "../extra/String.hpp" @@ -100,7 +101,7 @@ public: fUiResize->ui_resize(fUiResize->handle, fUI.getWidth(), fUI.getHeight()); if (widget != nullptr) - *widget = (LV2UI_Widget)fUI.getWindowId(); + *widget = (LV2UI_Widget)fUI.getNativeWindowHandle(); #if DISTRHO_PLUGIN_WANT_STATE // tell the DSP we're ready to receive msgs