Signed-off-by: falkTX <falktx@falktx.com>pull/452/head
| @@ -545,6 +545,7 @@ private: | |||
| uint height, | |||
| double scaleFactor, | |||
| bool resizable, | |||
| bool usesScheduledRepaints, | |||
| bool usesSizeRequest, | |||
| bool doPostInit); | |||
| @@ -23,6 +23,7 @@ | |||
| START_NAMESPACE_DGL | |||
| typedef std::list<DGL_NAMESPACE::Window*>::iterator WindowListIterator; | |||
| typedef std::list<DGL_NAMESPACE::Window*>::reverse_iterator WindowListReverseIterator; | |||
| static d_ThreadHandle getCurrentThreadHandle() noexcept | |||
| @@ -59,6 +60,7 @@ Application::PrivateData::PrivateData(const bool standalone) | |||
| isQuitting(false), | |||
| isQuittingInNextCycle(false), | |||
| isStarting(true), | |||
| needsRepaint(false), | |||
| visibleWindows(0), | |||
| mainThreadHandle(getCurrentThreadHandle()), | |||
| windows(), | |||
| @@ -144,6 +146,20 @@ void Application::PrivateData::triggerIdleCallbacks() | |||
| } | |||
| } | |||
| void Application::PrivateData::repaintIfNeeeded() | |||
| { | |||
| if (needsRepaint) | |||
| { | |||
| needsRepaint = false; | |||
| for (WindowListIterator it = windows.begin(), ite = windows.end(); it != ite; ++it) | |||
| { | |||
| DGL_NAMESPACE::Window* const window(*it); | |||
| window->repaint(); | |||
| } | |||
| } | |||
| } | |||
| void Application::PrivateData::quit() | |||
| { | |||
| if (! isThisTheMainThread(mainThreadHandle)) | |||
| @@ -63,6 +63,9 @@ struct Application::PrivateData { | |||
| /** Whether the applicating is starting up, that is, no windows have been made visible yet. Defaults to true. */ | |||
| bool isStarting; | |||
| /** When true force all windows to be repainted on next idle. */ | |||
| bool needsRepaint; | |||
| /** Counter of visible windows, only used in standalone mode. | |||
| If 0->1, application is starting. If 1->0, application is quitting/stopping. */ | |||
| uint visibleWindows; | |||
| @@ -96,6 +99,9 @@ struct Application::PrivateData { | |||
| /** Run each idle callback without updating pugl world. */ | |||
| void triggerIdleCallbacks(); | |||
| /** Trigger a repaint of all windows if @a needsRepaint is true. */ | |||
| void repaintIfNeeeded(); | |||
| /** Set flag indicating application is quitting, and close all windows in reverse order of registration. | |||
| For standalone mode only. */ | |||
| void quit(); | |||
| @@ -106,7 +106,7 @@ Window::Window(Application& app, | |||
| const uint height, | |||
| const double scaleFactor, | |||
| const bool resizable) | |||
| : pData(new PrivateData(app, this, parentWindowHandle, width, height, scaleFactor, resizable, false)) | |||
| : pData(new PrivateData(app, this, parentWindowHandle, width, height, scaleFactor, resizable, false, false)) | |||
| { | |||
| pData->initPost(); | |||
| } | |||
| @@ -117,9 +117,11 @@ Window::Window(Application& app, | |||
| const uint height, | |||
| const double scaleFactor, | |||
| const bool resizable, | |||
| const bool isVST3, | |||
| const bool usesScheduledRepaints, | |||
| const bool usesSizeRequest, | |||
| const bool doPostInit) | |||
| : pData(new PrivateData(app, this, parentWindowHandle, width, height, scaleFactor, resizable, isVST3)) | |||
| : pData(new PrivateData(app, this, parentWindowHandle, width, height, scaleFactor, resizable, | |||
| usesScheduledRepaints, usesSizeRequest)) | |||
| { | |||
| if (doPostInit) | |||
| pData->initPost(); | |||
| @@ -411,8 +413,13 @@ bool Window::openFileBrowser(const FileBrowserOptions& options) | |||
| void Window::repaint() noexcept | |||
| { | |||
| if (pData->view != nullptr) | |||
| puglPostRedisplay(pData->view); | |||
| if (pData->view == nullptr) | |||
| return; | |||
| if (pData->usesScheduledRepaints) | |||
| pData->appData->needsRepaint = true; | |||
| puglPostRedisplay(pData->view); | |||
| } | |||
| void Window::repaint(const Rectangle<uint>& rect) noexcept | |||
| @@ -420,6 +427,9 @@ void Window::repaint(const Rectangle<uint>& rect) noexcept | |||
| if (pData->view == nullptr) | |||
| return; | |||
| if (pData->usesScheduledRepaints) | |||
| pData->appData->needsRepaint = true; | |||
| PuglRect prect = { | |||
| static_cast<PuglCoord>(rect.getX()), | |||
| static_cast<PuglCoord>(rect.getY()), | |||
| @@ -115,6 +115,7 @@ Window::PrivateData::PrivateData(Application& a, Window* const s) | |||
| isClosed(true), | |||
| isVisible(false), | |||
| isEmbed(false), | |||
| usesScheduledRepaints(false), | |||
| usesSizeRequest(false), | |||
| scaleFactor(DGL_NAMESPACE::getScaleFactor(view)), | |||
| autoScaling(false), | |||
| @@ -144,6 +145,7 @@ Window::PrivateData::PrivateData(Application& a, Window* const s, PrivateData* c | |||
| isClosed(true), | |||
| isVisible(false), | |||
| isEmbed(false), | |||
| usesScheduledRepaints(false), | |||
| usesSizeRequest(false), | |||
| scaleFactor(ppData->scaleFactor), | |||
| autoScaling(false), | |||
| @@ -175,6 +177,7 @@ Window::PrivateData::PrivateData(Application& a, Window* const s, | |||
| isClosed(parentWindowHandle == 0), | |||
| isVisible(parentWindowHandle != 0), | |||
| isEmbed(parentWindowHandle != 0), | |||
| usesScheduledRepaints(false), | |||
| usesSizeRequest(false), | |||
| scaleFactor(scale != 0.0 ? scale : DGL_NAMESPACE::getScaleFactor(view)), | |||
| autoScaling(false), | |||
| @@ -198,7 +201,9 @@ Window::PrivateData::PrivateData(Application& a, Window* const s, | |||
| Window::PrivateData::PrivateData(Application& a, Window* const s, | |||
| const uintptr_t parentWindowHandle, | |||
| const uint width, const uint height, | |||
| const double scale, const bool resizable, const bool usesSizeRequest_) | |||
| const double scale, const bool resizable, | |||
| const bool _usesScheduledRepaints, | |||
| const bool _usesSizeRequest) | |||
| : app(a), | |||
| appData(a.pData), | |||
| self(s), | |||
| @@ -207,7 +212,8 @@ Window::PrivateData::PrivateData(Application& a, Window* const s, | |||
| isClosed(parentWindowHandle == 0), | |||
| isVisible(parentWindowHandle != 0 && view != nullptr), | |||
| isEmbed(parentWindowHandle != 0), | |||
| usesSizeRequest(usesSizeRequest_), | |||
| usesScheduledRepaints(_usesScheduledRepaints), | |||
| usesSizeRequest(_usesSizeRequest), | |||
| scaleFactor(scale != 0.0 ? scale : DGL_NAMESPACE::getScaleFactor(view)), | |||
| autoScaling(false), | |||
| autoScaleFactor(1.0), | |||
| @@ -60,7 +60,10 @@ struct Window::PrivateData : IdleCallback { | |||
| /** Whether this Window is embed into another (usually not DGL-controlled) Window. */ | |||
| const bool isEmbed; | |||
| /** Whether to ignore resize requests and feed them into the host instead. used for VST3 */ | |||
| /** Whether to schedule repaints on the next idle call, used for AU */ | |||
| const bool usesScheduledRepaints; | |||
| /** Whether to ignore resize requests and feed them into the host instead, used for CLAP and VST3 */ | |||
| const bool usesSizeRequest; | |||
| /** Scale factor to report to widgets on request, purely informational. */ | |||
| @@ -131,7 +134,8 @@ struct Window::PrivateData : IdleCallback { | |||
| /** Constructor for an embed Window, with a few extra hints from the host side. */ | |||
| explicit PrivateData(Application& app, Window* self, uintptr_t parentWindowHandle, | |||
| uint width, uint height, double scaling, bool resizable, bool isVST3); | |||
| uint width, uint height, double scaling, bool resizable, | |||
| bool usesScheduledRepaints, bool usesSizeRequest); | |||
| /** Destructor. */ | |||
| ~PrivateData() override; | |||
| @@ -155,12 +155,17 @@ public: | |||
| void postSetup() | |||
| { | |||
| const NSSize size = NSMakeSize(fUI.getWidth(), fUI.getHeight()); | |||
| const double scaleFactor = fUI.getScaleFactor(); | |||
| const NSSize size = NSMakeSize(fUI.getWidth() / scaleFactor, fUI.getHeight() / scaleFactor); | |||
| NSView* const uiView = reinterpret_cast<NSView*>(fUI.getNativeWindowHandle()); | |||
| [fParentView setAutoresizesSubviews:fUI.isResizable()]; | |||
| [fParentView setFrameSize:size]; | |||
| for (NSView* subview in [uiView subviews]) | |||
| { | |||
| [subview setFrameSize:size]; | |||
| break; | |||
| } | |||
| [uiView setFrameSize:size]; | |||
| [fParentView setFrameSize:size]; | |||
| } | |||
| private: | |||
| @@ -362,7 +367,8 @@ private: | |||
| void setSize(const uint width, const uint height) | |||
| { | |||
| [fParentView setFrameSize:NSMakeSize(width, height)]; | |||
| const double scaleFactor = fUI.getScaleFactor(); | |||
| [fParentView setFrameSize:NSMakeSize(width / scaleFactor, height / scaleFactor)]; | |||
| } | |||
| static void setSizeCallback(void* const ptr, const uint width, const uint height) | |||
| @@ -396,7 +402,7 @@ END_NAMESPACE_DISTRHO | |||
| - (id) initWithPreferredSize:(NSSize)size | |||
| { | |||
| self = [super initWithFrame: NSMakeRect (0, 0, size.width, size.height)]; | |||
| self = [super initWithFrame: NSMakeRect(0, 0, size.width, size.height)]; | |||
| [self setHidden:NO]; | |||
| return self; | |||
| } | |||
| @@ -467,8 +473,7 @@ END_NAMESPACE_DISTRHO | |||
| #endif | |||
| #if defined(DISTRHO_UI_DEFAULT_WIDTH) && defined(DISTRHO_UI_DEFAULT_HEIGHT) | |||
| const double scaleFactor = [NSScreen mainScreen].backingScaleFactor; | |||
| inPreferredSize = NSMakeSize(DISTRHO_UI_DEFAULT_WIDTH * scaleFactor, DISTRHO_UI_DEFAULT_HEIGHT * scaleFactor); | |||
| inPreferredSize = NSMakeSize(DISTRHO_UI_DEFAULT_WIDTH, DISTRHO_UI_DEFAULT_HEIGHT); | |||
| #endif | |||
| // create view | |||
| @@ -1,6 +1,6 @@ | |||
| /* | |||
| * DISTRHO Plugin Framework (DPF) | |||
| * Copyright (C) 2012-2022 Filipe Coelho <falktx@falktx.com> | |||
| * Copyright (C) 2012-2024 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 | |||
| @@ -232,6 +232,7 @@ public: | |||
| DISTRHO_SAFE_ASSERT_RETURN(ui != nullptr, ); | |||
| ui->uiIdle(); | |||
| uiData->app.repaintIfNeeeded(); | |||
| } | |||
| void showAndFocus() | |||
| @@ -247,6 +248,7 @@ public: | |||
| uiData->app.idle(); | |||
| ui->uiIdle(); | |||
| uiData->app.repaintIfNeeeded(); | |||
| return ! uiData->app.isQuitting(); | |||
| } | |||
| @@ -277,6 +279,7 @@ public: | |||
| uiData->app.triggerIdleCallbacks(); | |||
| ui->uiIdle(); | |||
| uiData->app.repaintIfNeeeded(); | |||
| } | |||
| #if !DISTRHO_PLUGIN_HAS_EXTERNAL_UI | |||
| @@ -1,6 +1,6 @@ | |||
| /* | |||
| * DISTRHO Plugin Framework (DPF) | |||
| * Copyright (C) 2012-2022 Filipe Coelho <falktx@falktx.com> | |||
| * Copyright (C) 2012-2024 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 | |||
| @@ -43,13 +43,19 @@ | |||
| # define DISTRHO_UI_IS_STANDALONE 0 | |||
| #endif | |||
| #if defined(DISTRHO_PLUGIN_TARGET_AU) | |||
| # define DISTRHO_UI_USES_SCHEDULED_REPAINTS true | |||
| #else | |||
| # define DISTRHO_UI_USES_SCHEDULED_REPAINTS false | |||
| #endif | |||
| #if defined(DISTRHO_PLUGIN_TARGET_VST3) || defined(DISTRHO_PLUGIN_TARGET_CLAP) | |||
| # define DISTRHO_UI_USES_SIZE_REQUEST true | |||
| #else | |||
| # define DISTRHO_UI_USES_SIZE_REQUEST false | |||
| #endif | |||
| #ifdef DISTRHO_PLUGIN_TARGET_VST2 | |||
| #if defined(DISTRHO_PLUGIN_TARGET_AU) || defined(DISTRHO_PLUGIN_TARGET_VST2) | |||
| # undef DISTRHO_UI_USER_RESIZABLE | |||
| # define DISTRHO_UI_USER_RESIZABLE 0 | |||
| #endif | |||
| @@ -103,6 +109,7 @@ struct PluginApplication | |||
| void idle() {} | |||
| void quit() {} | |||
| void triggerIdleCallbacks() {} | |||
| void repaintIfNeeeded() {} | |||
| DISTRHO_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(PluginApplication) | |||
| }; | |||
| @@ -137,6 +144,11 @@ public: | |||
| pData->triggerIdleCallbacks(); | |||
| } | |||
| void repaintIfNeeeded() | |||
| { | |||
| pData->repaintIfNeeeded(); | |||
| } | |||
| DISTRHO_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(PluginApplication) | |||
| }; | |||
| #endif | |||
| @@ -194,7 +206,10 @@ public: | |||
| const uint height, | |||
| const double scaleFactor) | |||
| : Window(app, parentWindowHandle, width, height, scaleFactor, | |||
| DISTRHO_UI_USER_RESIZABLE, DISTRHO_UI_USES_SIZE_REQUEST, false), | |||
| DISTRHO_UI_USER_RESIZABLE, | |||
| DISTRHO_UI_USES_SCHEDULED_REPAINTS, | |||
| DISTRHO_UI_USES_SIZE_REQUEST, | |||
| false), | |||
| ui(uiPtr), | |||
| initializing(true), | |||
| receivedReshapeDuringInit(false) | |||
| @@ -1,6 +1,6 @@ | |||
| /* | |||
| * DISTRHO Plugin Framework (DPF) | |||
| * Copyright (C) 2012-2021 Filipe Coelho <falktx@falktx.com> | |||
| * Copyright (C) 2012-2024 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 | |||
| @@ -38,13 +38,23 @@ public: | |||
| std::memset(fParameters, 0, sizeof(float)*kParameterCount); | |||
| std::memset(fStrBuf, 0, sizeof(char)*(0xff+1)); | |||
| #ifdef DGL_NO_SHARED_RESOURCES | |||
| #ifdef DGL_NO_SHARED_RESOURCES | |||
| createFontFromFile("sans", "/usr/share/fonts/truetype/ttf-dejavu/DejaVuSans.ttf"); | |||
| #else | |||
| #else | |||
| loadSharedResources(); | |||
| #endif | |||
| setGeometryConstraints(DISTRHO_UI_DEFAULT_WIDTH, DISTRHO_UI_DEFAULT_HEIGHT, true); | |||
| #endif | |||
| if (d_isNotEqual(fScaleFactor, 1.0)) | |||
| { | |||
| const uint width = DISTRHO_UI_DEFAULT_WIDTH * fScaleFactor; | |||
| const uint height = DISTRHO_UI_DEFAULT_HEIGHT * fScaleFactor; | |||
| setGeometryConstraints(width, height, true); | |||
| setSize(width, height); | |||
| } | |||
| else | |||
| { | |||
| setGeometryConstraints(DISTRHO_UI_DEFAULT_WIDTH, DISTRHO_UI_DEFAULT_HEIGHT, true); | |||
| } | |||
| // no need to show resize handle if window is user-resizable | |||
| if (fResizable) | |||