From bf3fd98e0e8a30a5295d393c0d4ac10d1ef6ba69 Mon Sep 17 00:00:00 2001
From: reuk <reuk@users.noreply.github.com>
Date: Mon, 18 Mar 2024 18:38:00 +0000
Subject: [PATCH] AUv3 Client: Avoid blank editor in Live after closing and
 reopening editor window

With macOS 14.4 and Live 11.3, loading a JUCE AUv3 plugin then hiding it
using the editor toggle button (in the rack view at the bottom of the
screen) would trigger an error related to NSViewServiceMarshal in the
console of an attached debugger. Afterwards, the editor window would
always be blank when it was opened again, unless the plugin was deleted
and a new instance created.
---
 .../juce_audio_plugin_client_AUv3.mm          | 84 +++++++++++++------
 1 file changed, 57 insertions(+), 27 deletions(-)

diff --git a/modules/juce_audio_plugin_client/juce_audio_plugin_client_AUv3.mm b/modules/juce_audio_plugin_client/juce_audio_plugin_client_AUv3.mm
index 0ec50977f5..973fad0f0e 100644
--- a/modules/juce_audio_plugin_client/juce_audio_plugin_client_AUv3.mm
+++ b/modules/juce_audio_plugin_client/juce_audio_plugin_client_AUv3.mm
@@ -128,7 +128,6 @@ explicit AudioProcessorHolder (std::unique_ptr<AudioProcessor> p) : processor (s
           processorHolder (new AudioProcessorHolder (createPluginFilterOfType (AudioProcessor::wrapperType_AudioUnitv3)))
     {
         jassert (MessageManager::getInstance()->isThisTheMessageThread());
-        initialiseJuce_GUI();
 
         init();
     }
@@ -1728,6 +1727,7 @@ void operator() (AUParameterObserverToken ptr) const
 
     using ObserverPtr = std::unique_ptr<std::remove_pointer_t<AUParameterObserverToken>, ObserverDestructor>;
 
+    ScopedJuceInitialiser_GUI guiScope;
     AUAudioUnit* au;
     AudioProcessorHolder::Ptr processorHolder;
 
@@ -1799,7 +1799,6 @@ void operator() (AUParameterObserverToken ptr) const
     JuceAUViewController (AUViewController<AUAudioUnitFactory>* p)
         : myself (p)
     {
-        initialiseJuce_GUI();
     }
 
     ~JuceAUViewController()
@@ -1829,16 +1828,10 @@ void loadView()
                     JUCE_IOS_MAC_VIEW* view = [[[JUCE_IOS_MAC_VIEW alloc] initWithFrame: convertToCGRect (editor->getBounds())] autorelease];
                     [myself setView: view];
 
-                   #if JUCE_IOS
                     editor->setVisible (false);
-                   #else
-                    editor->setVisible (true);
-                   #endif
-
-                    detail::PluginUtilities::addToDesktop (*editor, view);
 
                    #if JUCE_IOS
-                    if (JUCE_IOS_MAC_VIEW* peerView = [[[myself view] subviews] objectAtIndex: 0])
+                    if (auto* peerView = getPeerView())
                         [peerView setContentMode: UIViewContentModeTop];
 
                     if (auto* peer = dynamic_cast<UIViewPeerControllerReceiver*> (editor->getPeer()))
@@ -1862,19 +1855,24 @@ void viewDidLayoutSubviews()
 
                     editor->setBounds (convertToRectInt ([[myself view] bounds]));
 
-                    if (JUCE_IOS_MAC_VIEW* peerView = [[[myself view] subviews] objectAtIndex: 0])
-                    {
-                       #if JUCE_IOS
-                        [peerView setNeedsDisplay];
-                       #else
-                        [peerView setNeedsDisplay: YES];
-                       #endif
-                    }
+                    repaintView();
                 }
             }
         }
     }
 
+    void repaintView()
+    {
+        if (auto* peerView = getPeerView())
+        {
+           #if JUCE_IOS
+            [peerView setNeedsDisplay];
+           #else
+            [peerView setNeedsDisplay: YES];
+           #endif
+        }
+    }
+
     void didReceiveMemoryWarning()
     {
         if (auto ptr = processorHolder.get())
@@ -1882,18 +1880,35 @@ void didReceiveMemoryWarning()
                 processor->memoryWarningReceived();
     }
 
-    void viewDidAppear (bool)
+    void viewWillDisappear()
     {
-        if (processorHolder.get() != nullptr)
-            if (AudioProcessorEditor* editor = getAudioProcessor().getActiveEditor())
-                editor->setVisible (true);
+        if (processorHolder.get() == nullptr)
+            return;
+
+        if (auto* editor = getAudioProcessor().getActiveEditor())
+            editor->removeFromDesktop();
     }
 
-    void viewDidDisappear (bool)
+    void viewDidAppear()
     {
-        if (processorHolder.get() != nullptr)
-            if (AudioProcessorEditor* editor = getAudioProcessor().getActiveEditor())
-                editor->setVisible (false);
+        if (processorHolder.get() == nullptr)
+            return;
+
+        if (auto* editor = getAudioProcessor().getActiveEditor())
+        {
+            editor->setVisible (true);
+            detail::PluginUtilities::addToDesktop (*editor, [myself view]);
+            editor->setBounds (convertToRectInt ([[myself view] bounds]));
+        }
+    }
+
+    void viewDidDisappear()
+    {
+        if (processorHolder.get() == nullptr)
+            return;
+
+        if (auto* editor = getAudioProcessor().getActiveEditor())
+            editor->setVisible (false);
     }
 
     CGSize getPreferredContentSize() const
@@ -1921,6 +1936,15 @@ CGSize getPreferredContentSize() const
     }
 
 private:
+    JUCE_IOS_MAC_VIEW* getPeerView() const
+    {
+        if (auto* editor = getAudioProcessor().getActiveEditor())
+            if (auto* peer = editor->getPeer())
+                return static_cast<JUCE_IOS_MAC_VIEW*> (peer->getNativeHandle());
+
+        return nullptr;
+    }
+
     template <typename Callback>
     static void waitForExecutionOnMainThread (Callback&& callback)
     {
@@ -1965,6 +1989,7 @@ static void waitForExecutionOnMainThread (Callback&& callback)
     };
 
     //==============================================================================
+    ScopedJuceInitialiser_GUI guiScope;
     AUViewController<AUAudioUnitFactory>* myself;
     LockedProcessorHolder processorHolder;
     Rectangle<int> preferredSize { 1, 1 };
@@ -1994,8 +2019,13 @@ - (void) viewDidLayout           { cpp->viewDidLayoutSubviews(); }
 
 - (void) didReceiveMemoryWarning { cpp->didReceiveMemoryWarning(); }
 #if JUCE_IOS
-- (void) viewDidAppear: (BOOL) animated { cpp->viewDidAppear (animated); [super viewDidAppear:animated]; }
-- (void) viewDidDisappear: (BOOL) animated { cpp->viewDidDisappear (animated); [super viewDidDisappear:animated]; }
+- (void) viewDidAppear:     (BOOL) animated { cpp->viewDidAppear();     [super viewDidAppear:animated]; }
+- (void) viewDidDisappear:  (BOOL) animated { cpp->viewDidDisappear();  [super viewDidDisappear:animated]; }
+- (void) viewWillDisappear: (BOOL) animated { cpp->viewWillDisappear(); [super viewWillDisappear:animated]; }
+#else
+- (void) viewDidAppear     { cpp->viewDidAppear();     [super viewDidAppear]; }
+- (void) viewDidDisappear  { cpp->viewDidDisappear();  [super viewDidDisappear]; }
+- (void) viewWillDisappear { cpp->viewWillDisappear(); [super viewWillDisappear]; }
 #endif
 @end
 
-- 
2.39.3 (Apple Git-146)

