From 3a84bbb3ebbba9a02a36e65a0048f767f8b5cbd0 Mon Sep 17 00:00:00 2001 From: falkTX Date: Tue, 27 Feb 2024 12:47:47 +0100 Subject: [PATCH] Special case for repainting on AU hosts Signed-off-by: falkTX --- dgl/Window.hpp | 1 + dgl/src/ApplicationPrivateData.cpp | 16 ++++++++++++++++ dgl/src/ApplicationPrivateData.hpp | 6 ++++++ dgl/src/Window.cpp | 20 +++++++++++++++----- dgl/src/WindowPrivateData.cpp | 10 ++++++++-- dgl/src/WindowPrivateData.hpp | 8 ++++++-- distrho/src/DistrhoUIAU.mm | 19 ++++++++++++------- distrho/src/DistrhoUIInternal.hpp | 5 ++++- distrho/src/DistrhoUIPrivateData.hpp | 21 ++++++++++++++++++--- examples/Info/InfoExampleUI.cpp | 22 ++++++++++++++++------ 10 files changed, 102 insertions(+), 26 deletions(-) diff --git a/dgl/Window.hpp b/dgl/Window.hpp index b18fe071..2b5271fa 100644 --- a/dgl/Window.hpp +++ b/dgl/Window.hpp @@ -545,6 +545,7 @@ private: uint height, double scaleFactor, bool resizable, + bool usesScheduledRepaints, bool usesSizeRequest, bool doPostInit); diff --git a/dgl/src/ApplicationPrivateData.cpp b/dgl/src/ApplicationPrivateData.cpp index ccdcbfb1..0e353a7e 100644 --- a/dgl/src/ApplicationPrivateData.cpp +++ b/dgl/src/ApplicationPrivateData.cpp @@ -23,6 +23,7 @@ START_NAMESPACE_DGL +typedef std::list::iterator WindowListIterator; typedef std::list::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)) diff --git a/dgl/src/ApplicationPrivateData.hpp b/dgl/src/ApplicationPrivateData.hpp index 0e33c985..59afaae3 100644 --- a/dgl/src/ApplicationPrivateData.hpp +++ b/dgl/src/ApplicationPrivateData.hpp @@ -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(); diff --git a/dgl/src/Window.cpp b/dgl/src/Window.cpp index a382c937..0fa9dbf0 100644 --- a/dgl/src/Window.cpp +++ b/dgl/src/Window.cpp @@ -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& rect) noexcept @@ -420,6 +427,9 @@ void Window::repaint(const Rectangle& rect) noexcept if (pData->view == nullptr) return; + if (pData->usesScheduledRepaints) + pData->appData->needsRepaint = true; + PuglRect prect = { static_cast(rect.getX()), static_cast(rect.getY()), diff --git a/dgl/src/WindowPrivateData.cpp b/dgl/src/WindowPrivateData.cpp index 524c581d..e4b8d2c7 100644 --- a/dgl/src/WindowPrivateData.cpp +++ b/dgl/src/WindowPrivateData.cpp @@ -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), diff --git a/dgl/src/WindowPrivateData.hpp b/dgl/src/WindowPrivateData.hpp index ea7feb2a..70544f66 100644 --- a/dgl/src/WindowPrivateData.hpp +++ b/dgl/src/WindowPrivateData.hpp @@ -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; diff --git a/distrho/src/DistrhoUIAU.mm b/distrho/src/DistrhoUIAU.mm index 8f1de8c3..af01d224 100644 --- a/distrho/src/DistrhoUIAU.mm +++ b/distrho/src/DistrhoUIAU.mm @@ -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(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 diff --git a/distrho/src/DistrhoUIInternal.hpp b/distrho/src/DistrhoUIInternal.hpp index 00239a80..1865fdaa 100644 --- a/distrho/src/DistrhoUIInternal.hpp +++ b/distrho/src/DistrhoUIInternal.hpp @@ -1,6 +1,6 @@ /* * DISTRHO Plugin Framework (DPF) - * Copyright (C) 2012-2022 Filipe Coelho + * Copyright (C) 2012-2024 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 @@ -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 diff --git a/distrho/src/DistrhoUIPrivateData.hpp b/distrho/src/DistrhoUIPrivateData.hpp index 2dffd15e..dc0296a0 100644 --- a/distrho/src/DistrhoUIPrivateData.hpp +++ b/distrho/src/DistrhoUIPrivateData.hpp @@ -1,6 +1,6 @@ /* * DISTRHO Plugin Framework (DPF) - * Copyright (C) 2012-2022 Filipe Coelho + * Copyright (C) 2012-2024 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 @@ -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) diff --git a/examples/Info/InfoExampleUI.cpp b/examples/Info/InfoExampleUI.cpp index 24f37320..0d66edd6 100644 --- a/examples/Info/InfoExampleUI.cpp +++ b/examples/Info/InfoExampleUI.cpp @@ -1,6 +1,6 @@ /* * DISTRHO Plugin Framework (DPF) - * Copyright (C) 2012-2021 Filipe Coelho + * Copyright (C) 2012-2024 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 @@ -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)