diff --git a/modules/juce_audio_plugin_client/VST/juce_VST_Wrapper.cpp b/modules/juce_audio_plugin_client/VST/juce_VST_Wrapper.cpp index b38206dc5e..d2d42d59d1 100644 --- a/modules/juce_audio_plugin_client/VST/juce_VST_Wrapper.cpp +++ b/modules/juce_audio_plugin_client/VST/juce_VST_Wrapper.cpp @@ -111,11 +111,11 @@ namespace juce { #if JUCE_MAC extern void initialiseMac(); - extern void* attachComponentToWindowRef (Component*, void* windowRef); - extern void detachComponentFromWindowRef (Component*, void* nsWindow); - extern void setNativeHostWindowSize (void* nsWindow, Component*, int newWidth, int newHeight); - extern void checkWindowVisibility (void* nsWindow, Component*); - extern bool forwardCurrentKeyEventToHost (Component*); + extern void* attachComponentToWindowRef (Component*, void* parent, bool isNSView); + extern void detachComponentFromWindowRef (Component*, void* window, bool isNSView); + extern void setNativeHostWindowSize (void* window, Component*, int newWidth, int newHeight, bool isNSView); + extern void checkWindowVisibility (void* window, Component*, bool isNSView); + extern bool forwardCurrentKeyEventToHost (Component*, bool isNSView); #if ! JUCE_64BIT extern void updateEditorCompBounds (Component*); #endif @@ -283,6 +283,11 @@ public: hasShutdown (false), firstProcessCallback (true), shouldDeleteEditor (false), + #if JUCE_64BIT + useNSView (true), + #else + useNSView (false), + #endif processTempBuffer (1, 1), hostWindow (0) { @@ -366,61 +371,70 @@ public: } //============================================================================== - bool getEffectName (char* name) + bool getEffectName (char* name) override { String (JucePlugin_Name).copyToUTF8 (name, 64); return true; } - bool getVendorString (char* text) + bool getVendorString (char* text) override { String (JucePlugin_Manufacturer).copyToUTF8 (text, 64); return true; } - bool getProductString (char* text) { return getEffectName (text); } - VstInt32 getVendorVersion() { return convertHexVersionToDecimal (JucePlugin_VersionCode); } - VstPlugCategory getPlugCategory() { return JucePlugin_VSTCategory; } - bool keysRequired() { return (JucePlugin_EditorRequiresKeyboardFocus) != 0; } + bool getProductString (char* text) override { return getEffectName (text); } + VstInt32 getVendorVersion() override { return convertHexVersionToDecimal (JucePlugin_VersionCode); } + VstPlugCategory getPlugCategory() override { return JucePlugin_VSTCategory; } + bool keysRequired() { return (JucePlugin_EditorRequiresKeyboardFocus) != 0; } - VstInt32 canDo (char* text) + VstInt32 canDo (char* text) override { - VstInt32 result = 0; - if (strcmp (text, "receiveVstEvents") == 0 - || strcmp (text, "receiveVstMidiEvent") == 0 - || strcmp (text, "receiveVstMidiEvents") == 0) + || strcmp (text, "receiveVstMidiEvent") == 0 + || strcmp (text, "receiveVstMidiEvents") == 0) { #if JucePlugin_WantsMidiInput - result = 1; + return 1; #else - result = -1; + return -1; #endif } - else if (strcmp (text, "sendVstEvents") == 0 - || strcmp (text, "sendVstMidiEvent") == 0 - || strcmp (text, "sendVstMidiEvents") == 0) + + if (strcmp (text, "sendVstEvents") == 0 + || strcmp (text, "sendVstMidiEvent") == 0 + || strcmp (text, "sendVstMidiEvents") == 0) { #if JucePlugin_ProducesMidiOutput - result = 1; + return 1; #else - result = -1; + return -1; #endif } - else if (strcmp (text, "receiveVstTimeInfo") == 0 - || strcmp (text, "conformsToWindowRules") == 0 - || strcmp (text, "bypass") == 0) + + if (strcmp (text, "receiveVstTimeInfo") == 0 + || strcmp (text, "conformsToWindowRules") == 0 + || strcmp (text, "bypass") == 0) { - result = 1; + return 1; } - else if (strcmp (text, "openCloseAnyThread") == 0) + + if (strcmp (text, "openCloseAnyThread") == 0) { // This tells Wavelab to use the UI thread to invoke open/close, // like all other hosts do. - result = -1; + return -1; } - return result; + #if JUCE_MAC + if (strcmp (text, "hasCockosViewAsConfig") == 0) + { + useNSView = true; + return 0xbeef0000; + } + #endif + + return 0; } bool getInputProperties (VstInt32 index, VstPinProperties* properties) @@ -1014,7 +1028,7 @@ public: #if JUCE_MAC if (hostWindow != 0) - checkWindowVisibility (hostWindow, editorComp); + checkWindowVisibility (hostWindow, editorComp, useNSView); #endif tryMasterIdle(); @@ -1107,7 +1121,7 @@ public: #if JUCE_MAC if (hostWindow != 0) { - detachComponentFromWindowRef (editorComp, hostWindow); + detachComponentFromWindowRef (editorComp, hostWindow, useNSView); hostWindow = 0; } #endif @@ -1164,7 +1178,7 @@ public: Window editorWnd = (Window) editorComp->getWindowHandle(); XReparentWindow (display, editorWnd, hostWindow, 0, 0); #else - hostWindow = attachComponentToWindowRef (editorComp, ptr); + hostWindow = attachComponentToWindowRef (editorComp, ptr, useNSView); #endif editorComp->setVisible (true); @@ -1210,7 +1224,7 @@ public: { // some hosts don't support the sizeWindow call, so do it manually.. #if JUCE_MAC - setNativeHostWindowSize (hostWindow, editorComp, newWidth, newHeight); + setNativeHostWindowSize (hostWindow, editorComp, newWidth, newHeight, useNSView); #elif JUCE_LINUX // (Currently, all linux hosts support sizeWindow, so this should never need to happen) @@ -1323,7 +1337,7 @@ public: { // If we have an unused keypress, move the key-focus to a host window // and re-inject the event.. - return forwardCurrentKeyEventToHost (this); + return forwardCurrentKeyEventToHost (this, wrapper.useNSView); } #endif @@ -1338,7 +1352,8 @@ public: editor->setBounds (getLocalBounds()); #if JUCE_MAC && ! JUCE_64BIT - updateEditorCompBounds (this); + if (! wrapper.useNSView) + updateEditorCompBounds (this); #endif } @@ -1349,8 +1364,9 @@ public: const int cw = child->getWidth(); const int ch = child->getHeight(); - #if JUCE_MAC && JUCE_64BIT - setTopLeftPosition (0, getHeight() - ch); + #if JUCE_MAC + if (wrapper.useNSView) + setTopLeftPosition (0, getHeight() - ch); #endif wrapper.resizeHostWindow (cw, ch); @@ -1405,7 +1421,8 @@ private: VSTMidiEventList outgoingEvents; VstSpeakerArrangementType speakerIn, speakerOut; int numInChans, numOutChans; - bool isProcessing, isBypassed, hasShutdown, firstProcessCallback, shouldDeleteEditor; + bool isProcessing, isBypassed, hasShutdown, firstProcessCallback; + bool shouldDeleteEditor, useNSView; HeapBlock channels; Array tempChannels; // see note in processReplacing() AudioSampleBuffer processTempBuffer; diff --git a/modules/juce_audio_plugin_client/VST/juce_VST_Wrapper.mm b/modules/juce_audio_plugin_client/VST/juce_VST_Wrapper.mm index 49a633134c..670bbf2f59 100644 --- a/modules/juce_audio_plugin_client/VST/juce_VST_Wrapper.mm +++ b/modules/juce_audio_plugin_client/VST/juce_VST_Wrapper.mm @@ -77,13 +77,82 @@ void initialiseMac() #endif } -void* attachComponentToWindowRef (Component* comp, void* windowRef); -void* attachComponentToWindowRef (Component* comp, void* windowRef) +void* attachComponentToWindowRef (Component* comp, void* parentWindowOrView, bool isNSView); +void* attachComponentToWindowRef (Component* comp, void* parentWindowOrView, bool isNSView) { JUCE_AUTORELEASEPOOL { - #if JUCE_64BIT - NSView* parentView = (NSView*) windowRef; + #if ! JUCE_64BIT + if (! isNSView) + { + NSWindow* hostWindow = [[NSWindow alloc] initWithWindowRef: parentWindowOrView]; + [hostWindow retain]; + [hostWindow setCanHide: YES]; + [hostWindow setReleasedWhenClosed: YES]; + + HIViewRef parentView = 0; + + WindowAttributes attributes; + GetWindowAttributes ((WindowRef) parentWindowOrView, &attributes); + if ((attributes & kWindowCompositingAttribute) != 0) + { + HIViewRef root = HIViewGetRoot ((WindowRef) parentWindowOrView); + HIViewFindByID (root, kHIViewWindowContentID, &parentView); + + if (parentView == 0) + parentView = root; + } + else + { + GetRootControl ((WindowRef) parentWindowOrView, (ControlRef*) &parentView); + + if (parentView == 0) + CreateRootControl ((WindowRef) parentWindowOrView, (ControlRef*) &parentView); + } + + // It seems that the only way to successfully position our overlaid window is by putting a dummy + // HIView into the host's carbon window, and then catching events to see when it gets repositioned + HIViewRef dummyView = 0; + HIImageViewCreate (0, &dummyView); + HIRect r = { {0, 0}, { (float) comp->getWidth(), (float) comp->getHeight()} }; + HIViewSetFrame (dummyView, &r); + HIViewAddSubview (parentView, dummyView); + comp->getProperties().set ("dummyViewRef", String::toHexString ((pointer_sized_int) (void*) dummyView)); + + EventHandlerRef ref; + const EventTypeSpec kControlBoundsChangedEvent = { kEventClassControl, kEventControlBoundsChanged }; + InstallEventHandler (GetControlEventTarget (dummyView), NewEventHandlerUPP (viewBoundsChangedEvent), 1, &kControlBoundsChangedEvent, (void*) comp, &ref); + comp->getProperties().set ("boundsEventRef", String::toHexString ((pointer_sized_int) (void*) ref)); + + updateEditorCompBounds (comp); + + #if ! JucePlugin_EditorRequiresKeyboardFocus + comp->addToDesktop (ComponentPeer::windowIsTemporary | ComponentPeer::windowIgnoresKeyPresses); + #else + comp->addToDesktop (ComponentPeer::windowIsTemporary); + #endif + + comp->setVisible (true); + comp->toFront (false); + + NSView* pluginView = (NSView*) comp->getWindowHandle(); + NSWindow* pluginWindow = [pluginView window]; + [pluginWindow setExcludedFromWindowsMenu: YES]; + [pluginWindow setCanHide: YES]; + + [hostWindow addChildWindow: pluginWindow + ordered: NSWindowAbove]; + [hostWindow orderFront: nil]; + [pluginWindow orderFront: nil]; + + attachWindowHidingHooks (comp, (WindowRef) parentWindowOrView, hostWindow); + + return hostWindow; + } + #endif + + (void) isNSView; + NSView* parentView = (NSView*) parentWindowOrView; #if JucePlugin_EditorRequiresKeyboardFocus comp->addToDesktop (0, parentView); @@ -100,168 +169,120 @@ void* attachComponentToWindowRef (Component* comp, void* windowRef) [[parentView window] setAcceptsMouseMovedEvents: YES]; return parentView; - #else - NSWindow* hostWindow = [[NSWindow alloc] initWithWindowRef: windowRef]; - [hostWindow retain]; - [hostWindow setCanHide: YES]; - [hostWindow setReleasedWhenClosed: YES]; - - HIViewRef parentView = 0; - - WindowAttributes attributes; - GetWindowAttributes ((WindowRef) windowRef, &attributes); - if ((attributes & kWindowCompositingAttribute) != 0) - { - HIViewRef root = HIViewGetRoot ((WindowRef) windowRef); - HIViewFindByID (root, kHIViewWindowContentID, &parentView); - - if (parentView == 0) - parentView = root; - } - else - { - GetRootControl ((WindowRef) windowRef, (ControlRef*) &parentView); - - if (parentView == 0) - CreateRootControl ((WindowRef) windowRef, (ControlRef*) &parentView); - } - - // It seems that the only way to successfully position our overlaid window is by putting a dummy - // HIView into the host's carbon window, and then catching events to see when it gets repositioned - HIViewRef dummyView = 0; - HIImageViewCreate (0, &dummyView); - HIRect r = { {0, 0}, { (float) comp->getWidth(), (float) comp->getHeight()} }; - HIViewSetFrame (dummyView, &r); - HIViewAddSubview (parentView, dummyView); - comp->getProperties().set ("dummyViewRef", String::toHexString ((pointer_sized_int) (void*) dummyView)); - - EventHandlerRef ref; - const EventTypeSpec kControlBoundsChangedEvent = { kEventClassControl, kEventControlBoundsChanged }; - InstallEventHandler (GetControlEventTarget (dummyView), NewEventHandlerUPP (viewBoundsChangedEvent), 1, &kControlBoundsChangedEvent, (void*) comp, &ref); - comp->getProperties().set ("boundsEventRef", String::toHexString ((pointer_sized_int) (void*) ref)); - - updateEditorCompBounds (comp); - - #if ! JucePlugin_EditorRequiresKeyboardFocus - comp->addToDesktop (ComponentPeer::windowIsTemporary | ComponentPeer::windowIgnoresKeyPresses); - #else - comp->addToDesktop (ComponentPeer::windowIsTemporary); - #endif - - comp->setVisible (true); - comp->toFront (false); - - NSView* pluginView = (NSView*) comp->getWindowHandle(); - NSWindow* pluginWindow = [pluginView window]; - [pluginWindow setExcludedFromWindowsMenu: YES]; - [pluginWindow setCanHide: YES]; - - [hostWindow addChildWindow: pluginWindow - ordered: NSWindowAbove]; - [hostWindow orderFront: nil]; - [pluginWindow orderFront: nil]; - - attachWindowHidingHooks (comp, (WindowRef) windowRef, hostWindow); - - return hostWindow; - #endif } } -void detachComponentFromWindowRef (Component* comp, void* nsWindow); -void detachComponentFromWindowRef (Component* comp, void* nsWindow) +void detachComponentFromWindowRef (Component* comp, void* window, bool isNSView); +void detachComponentFromWindowRef (Component* comp, void* window, bool isNSView) { JUCE_AUTORELEASEPOOL { - #if JUCE_64BIT - comp->removeFromDesktop(); - #else - EventHandlerRef ref = (EventHandlerRef) (void*) (pointer_sized_int) - comp->getProperties() ["boundsEventRef"].toString().getHexValue64(); - RemoveEventHandler (ref); + #if ! JUCE_64BIT + if (! isNSView) + { + EventHandlerRef ref = (EventHandlerRef) (void*) (pointer_sized_int) + comp->getProperties() ["boundsEventRef"].toString().getHexValue64(); + RemoveEventHandler (ref); - removeWindowHidingHooks (comp); + removeWindowHidingHooks (comp); - HIViewRef dummyView = (HIViewRef) (void*) (pointer_sized_int) - comp->getProperties() ["dummyViewRef"].toString().getHexValue64(); + HIViewRef dummyView = (HIViewRef) (void*) (pointer_sized_int) + comp->getProperties() ["dummyViewRef"].toString().getHexValue64(); - if (HIViewIsValid (dummyView)) - CFRelease (dummyView); + if (HIViewIsValid (dummyView)) + CFRelease (dummyView); - NSWindow* hostWindow = (NSWindow*) nsWindow; - NSView* pluginView = (NSView*) comp->getWindowHandle(); - NSWindow* pluginWindow = [pluginView window]; + NSWindow* hostWindow = (NSWindow*) window; + NSView* pluginView = (NSView*) comp->getWindowHandle(); + NSWindow* pluginWindow = [pluginView window]; - [pluginView retain]; - [hostWindow removeChildWindow: pluginWindow]; - [pluginWindow close]; - comp->removeFromDesktop(); - [pluginView release]; + [pluginView retain]; + [hostWindow removeChildWindow: pluginWindow]; + [pluginWindow close]; + comp->removeFromDesktop(); + [pluginView release]; - [hostWindow release]; + [hostWindow release]; - static bool needToRunMessageLoop = ! PluginHostType().isReaper(); + static bool needToRunMessageLoop = ! PluginHostType().isReaper(); - // The event loop needs to be run between closing the window and deleting the plugin, - // presumably to let the cocoa objects get tidied up. Leaving out this line causes crashes - // in Live when you delete the plugin with its window open. - // (Doing it this way rather than using a single longer timout means that we can guarantee - // how many messages will be dispatched, which seems to be vital in Reaper) - if (needToRunMessageLoop) - for (int i = 20; --i >= 0;) - MessageManager::getInstance()->runDispatchLoopUntil (1); + // The event loop needs to be run between closing the window and deleting the plugin, + // presumably to let the cocoa objects get tidied up. Leaving out this line causes crashes + // in Live when you delete the plugin with its window open. + // (Doing it this way rather than using a single longer timout means that we can guarantee + // how many messages will be dispatched, which seems to be vital in Reaper) + if (needToRunMessageLoop) + for (int i = 20; --i >= 0;) + MessageManager::getInstance()->runDispatchLoopUntil (1); + + return; + } #endif + + (void) isNSView; + comp->removeFromDesktop(); } } -void setNativeHostWindowSize (void* nsWindow, Component* component, int newWidth, int newHeight); -void setNativeHostWindowSize (void* nsWindow, Component* component, int newWidth, int newHeight) +void setNativeHostWindowSize (void* window, Component* component, int newWidth, int newHeight, bool isNSView); +void setNativeHostWindowSize (void* window, Component* component, int newWidth, int newHeight, bool isNSView) { + (void) isNSView; (void) window; (void) isNSView; + JUCE_AUTORELEASEPOOL { - #if JUCE_64BIT - if (NSView* hostView = (NSView*) nsWindow) + #if ! JUCE_64BIT + if (! isNSView) + { + if (HIViewRef dummyView = (HIViewRef) (void*) (pointer_sized_int) + component->getProperties() ["dummyViewRef"].toString().getHexValue64()) + { + HIRect frameRect; + HIViewGetFrame (dummyView, &frameRect); + frameRect.size.width = newWidth; + frameRect.size.height = newHeight; + HIViewSetFrame (dummyView, &frameRect); + } + + return; + } + #endif + + if (NSView* hostView = (NSView*) window) { // xxx is this necessary, or do the hosts detect a change in the child view and do this automatically? [hostView setFrameSize: NSMakeSize ([hostView frame].size.width + (newWidth - component->getWidth()), [hostView frame].size.height + (newHeight - component->getHeight()))]; } - #else - (void) nsWindow; - - if (HIViewRef dummyView = (HIViewRef) (void*) (pointer_sized_int) - component->getProperties() ["dummyViewRef"].toString().getHexValue64()) - { - HIRect frameRect; - HIViewGetFrame (dummyView, &frameRect); - frameRect.size.width = newWidth; - frameRect.size.height = newHeight; - HIViewSetFrame (dummyView, &frameRect); - } - #endif } } -void checkWindowVisibility (void* nsWindow, Component* comp); -void checkWindowVisibility (void* nsWindow, Component* comp) +void checkWindowVisibility (void* window, Component* comp, bool isNSView); +void checkWindowVisibility (void* window, Component* comp, bool isNSView) { + (void) window; (void) comp; (void) isNSView; + #if ! JUCE_64BIT - comp->setVisible ([((NSWindow*) nsWindow) isVisible]); + if (! isNSView) + comp->setVisible ([((NSWindow*) window) isVisible]); #endif } -bool forwardCurrentKeyEventToHost (Component* comp); -bool forwardCurrentKeyEventToHost (Component* comp) +bool forwardCurrentKeyEventToHost (Component* comp, bool isNSView); +bool forwardCurrentKeyEventToHost (Component* comp, bool isNSView) { - #if JUCE_64BIT - (void) comp; - return false; - #else - NSWindow* win = [(NSView*) comp->getWindowHandle() window]; - [[win parentWindow] makeKeyWindow]; - repostCurrentNSEvent(); - return true; + #if ! JUCE_64BIT + if (! isNSView) + { + NSWindow* win = [(NSView*) comp->getWindowHandle() window]; + [[win parentWindow] makeKeyWindow]; + repostCurrentNSEvent(); + return true; + } #endif + + (void) comp; (void) isNSView; + return false; } } // (juce namespace)