From 829498e39799b8fadbd762108cd71644f15fc083 Mon Sep 17 00:00:00 2001 From: jules Date: Thu, 28 May 2009 14:10:55 +0000 Subject: [PATCH] Added Carbon UI support to the AU wrapper --- .../JuceDemoPlugin.xcodeproj/project.pbxproj | 50 ++- .../wrapper/AU/juce_AU_Resources.r | 35 +- .../wrapper/AU/juce_AU_Wrapper.mm | 338 +++++++++++++++++- 3 files changed, 407 insertions(+), 16 deletions(-) diff --git a/extras/audio plugins/demo/build/mac/JuceDemoPlugin.xcodeproj/project.pbxproj b/extras/audio plugins/demo/build/mac/JuceDemoPlugin.xcodeproj/project.pbxproj index 867e7de30e..f19f63fded 100644 --- a/extras/audio plugins/demo/build/mac/JuceDemoPlugin.xcodeproj/project.pbxproj +++ b/extras/audio plugins/demo/build/mac/JuceDemoPlugin.xcodeproj/project.pbxproj @@ -52,6 +52,14 @@ 843796F60EFC0102002A2725 /* CommonDebugSettings.xcconfig in Resources */ = {isa = PBXBuildFile; fileRef = 843796F40EFC0102002A2725 /* CommonDebugSettings.xcconfig */; }; 843796F70EFC0102002A2725 /* CommonReleaseSettings.xcconfig in Resources */ = {isa = PBXBuildFile; fileRef = 843796F50EFC0102002A2725 /* CommonReleaseSettings.xcconfig */; }; 843797050EFC0269002A2725 /* libPluginLibrary.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 843797030EFC022E002A2725 /* libPluginLibrary.a */; }; + 84D3AB5F0FCC744600EA8080 /* AUCarbonViewBase.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 84D3AB5E0FCC744600EA8080 /* AUCarbonViewBase.cpp */; }; + 84D3AB630FCC749100EA8080 /* AUCarbonViewBase.h in Headers */ = {isa = PBXBuildFile; fileRef = 84D3AB620FCC749100EA8080 /* AUCarbonViewBase.h */; }; + 84D3AB670FCC74B300EA8080 /* CarbonEventHandler.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 84D3AB650FCC74B300EA8080 /* CarbonEventHandler.cpp */; }; + 84D3AB680FCC74B300EA8080 /* CarbonEventHandler.h in Headers */ = {isa = PBXBuildFile; fileRef = 84D3AB660FCC74B300EA8080 /* CarbonEventHandler.h */; }; + 84D3AB6C0FCC74DA00EA8080 /* AUCarbonViewControl.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 84D3AB6A0FCC74DA00EA8080 /* AUCarbonViewControl.cpp */; }; + 84D3AB6D0FCC74DA00EA8080 /* AUCarbonViewControl.h in Headers */ = {isa = PBXBuildFile; fileRef = 84D3AB6B0FCC74DA00EA8080 /* AUCarbonViewControl.h */; }; + 84D3AB700FCC74F400EA8080 /* AUCarbonViewDispatch.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 84D3AB6F0FCC74F400EA8080 /* AUCarbonViewDispatch.cpp */; }; + 84D3AB740FCC759700EA8080 /* AUViewLocalizedStringKeys.h in Headers */ = {isa = PBXBuildFile; fileRef = 84D3AB730FCC759700EA8080 /* AUViewLocalizedStringKeys.h */; }; 8BA05AAE072073D300365D66 /* AUBase.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 8BA05A7F072073D200365D66 /* AUBase.cpp */; }; 8BA05AAF072073D300365D66 /* AUBase.h in Headers */ = {isa = PBXBuildFile; fileRef = 8BA05A80072073D200365D66 /* AUBase.h */; }; 8BA05AB0072073D300365D66 /* AUDispatch.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 8BA05A81072073D200365D66 /* AUDispatch.cpp */; }; @@ -108,7 +116,7 @@ 843792A80EFBF14B002A2725 /* juce_LibrarySource.mm */ = {isa = PBXFileReference; explicitFileType = sourcecode.cpp.objcpp; fileEncoding = 4; name = juce_LibrarySource.mm; path = ../../src/juce_LibrarySource.mm; sourceTree = SOURCE_ROOT; }; 843792A90EFBF14B002A2725 /* JucePluginCharacteristics.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = JucePluginCharacteristics.h; path = ../../src/JucePluginCharacteristics.h; sourceTree = SOURCE_ROOT; }; 843792B30EFBF175002A2725 /* juce_AU_Resources.r */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.rez; name = juce_AU_Resources.r; path = ../../../wrapper/AU/juce_AU_Resources.r; sourceTree = SOURCE_ROOT; }; - 843792B40EFBF175002A2725 /* juce_AU_Wrapper.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; name = juce_AU_Wrapper.mm; path = ../../../wrapper/AU/juce_AU_Wrapper.mm; sourceTree = SOURCE_ROOT; }; + 843792B40EFBF175002A2725 /* juce_AU_Wrapper.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; lineEnding = 2; name = juce_AU_Wrapper.mm; path = ../../../wrapper/AU/juce_AU_Wrapper.mm; sourceTree = SOURCE_ROOT; }; 843795630EFBF323002A2725 /* AudioToolbox.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AudioToolbox.framework; path = /System/Library/Frameworks/AudioToolbox.framework; sourceTree = ""; }; 843795640EFBF323002A2725 /* AudioUnit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AudioUnit.framework; path = /System/Library/Frameworks/AudioUnit.framework; sourceTree = ""; }; 843795650EFBF323002A2725 /* Cocoa.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Cocoa.framework; path = /System/Library/Frameworks/Cocoa.framework; sourceTree = ""; }; @@ -141,6 +149,14 @@ 843796F40EFC0102002A2725 /* CommonDebugSettings.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = CommonDebugSettings.xcconfig; path = /Users/jules/SDKs/PT_80_SDK/AlturaPorts/TDMPlugIns/common/Mac/CommonDebugSettings.xcconfig; sourceTree = ""; }; 843796F50EFC0102002A2725 /* CommonReleaseSettings.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = CommonReleaseSettings.xcconfig; path = /Users/jules/SDKs/PT_80_SDK/AlturaPorts/TDMPlugIns/common/Mac/CommonReleaseSettings.xcconfig; sourceTree = ""; }; 843796FE0EFC022E002A2725 /* PluginLibrary.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = PluginLibrary.xcodeproj; path = /Users/jules/stuff/PT_73_SDK/AlturaPorts/TDMPlugIns/PlugInLibrary/MacBuild/PluginLibrary.xcodeproj; sourceTree = ""; }; + 84D3AB5E0FCC744600EA8080 /* AUCarbonViewBase.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = AUCarbonViewBase.cpp; path = Examples/CoreAudio/AudioUnits/AUPublic/AUCarbonViewBase/AUCarbonViewBase.cpp; sourceTree = DEVELOPER_DIR; }; + 84D3AB620FCC749100EA8080 /* AUCarbonViewBase.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = AUCarbonViewBase.h; path = Examples/CoreAudio/AudioUnits/AUPublic/AUCarbonViewBase/AUCarbonViewBase.h; sourceTree = DEVELOPER_DIR; }; + 84D3AB650FCC74B300EA8080 /* CarbonEventHandler.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = CarbonEventHandler.cpp; path = Examples/CoreAudio/AudioUnits/AUPublic/AUCarbonViewBase/CarbonEventHandler.cpp; sourceTree = DEVELOPER_DIR; }; + 84D3AB660FCC74B300EA8080 /* CarbonEventHandler.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = CarbonEventHandler.h; path = Examples/CoreAudio/AudioUnits/AUPublic/AUCarbonViewBase/CarbonEventHandler.h; sourceTree = DEVELOPER_DIR; }; + 84D3AB6A0FCC74DA00EA8080 /* AUCarbonViewControl.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = AUCarbonViewControl.cpp; path = Examples/CoreAudio/AudioUnits/AUPublic/AUCarbonViewBase/AUCarbonViewControl.cpp; sourceTree = DEVELOPER_DIR; }; + 84D3AB6B0FCC74DA00EA8080 /* AUCarbonViewControl.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = AUCarbonViewControl.h; path = Examples/CoreAudio/AudioUnits/AUPublic/AUCarbonViewBase/AUCarbonViewControl.h; sourceTree = DEVELOPER_DIR; }; + 84D3AB6F0FCC74F400EA8080 /* AUCarbonViewDispatch.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = AUCarbonViewDispatch.cpp; path = Examples/CoreAudio/AudioUnits/AUPublic/AUCarbonViewBase/AUCarbonViewDispatch.cpp; sourceTree = DEVELOPER_DIR; }; + 84D3AB730FCC759700EA8080 /* AUViewLocalizedStringKeys.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = AUViewLocalizedStringKeys.h; path = Examples/CoreAudio/AudioUnits/AUPublic/AUViewBase/AUViewLocalizedStringKeys.h; sourceTree = DEVELOPER_DIR; }; 8BA05A7F072073D200365D66 /* AUBase.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = AUBase.cpp; sourceTree = ""; }; 8BA05A80072073D200365D66 /* AUBase.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = AUBase.h; sourceTree = ""; }; 8BA05A81072073D200365D66 /* AUDispatch.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = AUDispatch.cpp; sourceTree = ""; }; @@ -325,9 +341,33 @@ name = Products; sourceTree = ""; }; + 84D3AB5D0FCC741E00EA8080 /* AUCarbonViewBase */ = { + isa = PBXGroup; + children = ( + 84D3AB6F0FCC74F400EA8080 /* AUCarbonViewDispatch.cpp */, + 84D3AB6A0FCC74DA00EA8080 /* AUCarbonViewControl.cpp */, + 84D3AB6B0FCC74DA00EA8080 /* AUCarbonViewControl.h */, + 84D3AB650FCC74B300EA8080 /* CarbonEventHandler.cpp */, + 84D3AB660FCC74B300EA8080 /* CarbonEventHandler.h */, + 84D3AB5E0FCC744600EA8080 /* AUCarbonViewBase.cpp */, + 84D3AB620FCC749100EA8080 /* AUCarbonViewBase.h */, + ); + name = AUCarbonViewBase; + sourceTree = ""; + }; + 84D3AB720FCC758200EA8080 /* AUViewBase */ = { + isa = PBXGroup; + children = ( + 84D3AB730FCC759700EA8080 /* AUViewLocalizedStringKeys.h */, + ); + name = AUViewBase; + sourceTree = ""; + }; 8BA05A7D072073D200365D66 /* AUPublic */ = { isa = PBXGroup; children = ( + 84D3AB720FCC758200EA8080 /* AUViewBase */, + 84D3AB5D0FCC741E00EA8080 /* AUCarbonViewBase */, 8BA05A7E072073D200365D66 /* AUBase */, 8BA05A99072073D200365D66 /* OtherBases */, 8BA05AA6072073D200365D66 /* Utility */, @@ -441,6 +481,10 @@ 8437966E0EFBF357002A2725 /* AUOutputBase.h in Headers */, 843796720EFBF357002A2725 /* MusicDeviceBase.h in Headers */, 843796DF0EFBFD16002A2725 /* juce_RTAS_DigiCode_Header.h in Headers */, + 84D3AB630FCC749100EA8080 /* AUCarbonViewBase.h in Headers */, + 84D3AB680FCC74B300EA8080 /* CarbonEventHandler.h in Headers */, + 84D3AB6D0FCC74DA00EA8080 /* AUCarbonViewControl.h in Headers */, + 84D3AB740FCC759700EA8080 /* AUViewLocalizedStringKeys.h in Headers */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -559,6 +603,10 @@ 843796DE0EFBFD16002A2725 /* juce_RTAS_DigiCode3.cpp in Sources */, 843796E10EFBFD16002A2725 /* juce_RTAS_MacUtilities.mm in Sources */, 843796E20EFBFD16002A2725 /* juce_RTAS_Wrapper.cpp in Sources */, + 84D3AB5F0FCC744600EA8080 /* AUCarbonViewBase.cpp in Sources */, + 84D3AB670FCC74B300EA8080 /* CarbonEventHandler.cpp in Sources */, + 84D3AB6C0FCC74DA00EA8080 /* AUCarbonViewControl.cpp in Sources */, + 84D3AB700FCC74F400EA8080 /* AUCarbonViewDispatch.cpp in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; diff --git a/extras/audio plugins/wrapper/AU/juce_AU_Resources.r b/extras/audio plugins/wrapper/AU/juce_AU_Resources.r index 3b5b0799a6..07c595ed48 100644 --- a/extras/audio plugins/wrapper/AU/juce_AU_Resources.r +++ b/extras/audio plugins/wrapper/AU/juce_AU_Resources.r @@ -44,14 +44,33 @@ //============================================================================== // component resources for Audio Unit -#define RES_ID 1000 -#define COMP_TYPE JucePlugin_AUMainType -#define COMP_SUBTYPE JucePlugin_AUSubType -#define COMP_MANUF JucePlugin_AUManufacturerCode -#define VERSION JucePlugin_VersionCode -#define NAME JucePlugin_Manufacturer ": " JucePlugin_Name -#define DESCRIPTION JucePlugin_Desc -#define ENTRY_POINT JucePlugin_AUExportPrefixQuoted "Entry" +#define RES_ID 1000 +#define COMP_TYPE JucePlugin_AUMainType +#define COMP_SUBTYPE JucePlugin_AUSubType +#define COMP_MANUF JucePlugin_AUManufacturerCode +#define VERSION JucePlugin_VersionCode +#define NAME JucePlugin_Manufacturer ": " JucePlugin_Name +#define DESCRIPTION JucePlugin_Desc +#define ENTRY_POINT JucePlugin_AUExportPrefixQuoted "Entry" #include "AUResources.r" +//============================================================================== +// component resources for Audio Unit Carbon View + +#ifndef BUILD_AU_CARBON_UI + #define BUILD_AU_CARBON_UI 1 +#endif + +#if BUILD_AU_CARBON_UI + #define RES_ID 2000 + #define COMP_TYPE kAudioUnitCarbonViewComponentType + #define COMP_SUBTYPE JucePlugin_AUSubType + #define COMP_MANUF JucePlugin_AUManufacturerCode + #define VERSION JucePlugin_VersionCode + #define NAME JucePlugin_Manufacturer ": " JucePlugin_Name " View" + #define DESCRIPTION NAME + #define ENTRY_POINT JucePlugin_AUExportPrefixQuoted "ViewEntry" + + #include "AUResources.r" +#endif diff --git a/extras/audio plugins/wrapper/AU/juce_AU_Wrapper.mm b/extras/audio plugins/wrapper/AU/juce_AU_Wrapper.mm index 71d571b447..8d053210b7 100644 --- a/extras/audio plugins/wrapper/AU/juce_AU_Wrapper.mm +++ b/extras/audio plugins/wrapper/AU/juce_AU_Wrapper.mm @@ -39,6 +39,20 @@ #if JucePlugin_Build_AU +/** The BUILD_AU_CARBON_UI flag lets you specify whether old-school carbon hosts are supported as + well as ones that can open a cocoa view. If this is enabled, you'll need to also add the AUCarbonBase + files to your project. +*/ +#ifndef BUILD_AU_CARBON_UI + #define BUILD_AU_CARBON_UI 1 +#endif + +#if BUILD_AU_CARBON_UI + #undef Button + #include "AUCarbonViewBase.h" + class JuceAUView; +#endif + //============================================================================== #define juceFilterObjectPropertyID 0x1a45ffe9 static VoidArray activePlugins; @@ -61,7 +75,6 @@ END_JUCE_NAMESPACE and make it create an instance of the filter subclass that you're building. */ extern AudioProcessor* JUCE_CALLTYPE createPluginFilter(); -class JuceAUView; //============================================================================== #define CONCAT_MACRO(Part1, Part2) Part1 ## Part2 @@ -101,6 +114,10 @@ public: { if (activePlugins.size() == 0) { +#if BUILD_AU_CARBON_UI + NSApplicationLoad(); +#endif + initialiseJuce_GUI(); #ifdef JucePlugin_CFBundleIdentifier @@ -402,6 +419,20 @@ public: return juceFilter->getLatencySamples() / GetSampleRate(); } + //============================================================================== +#if BUILD_AU_CARBON_UI + int GetNumCustomUIComponents() { return 1; } + + void GetUIComponentDescs (ComponentDescription* inDescArray) + { + inDescArray[0].componentType = kAudioUnitCarbonViewComponentType; + inDescArray[0].componentSubType = JucePlugin_AUSubType; + inDescArray[0].componentManufacturer = JucePlugin_AUManufacturerCode; + inDescArray[0].componentFlags = 0; + inDescArray[0].componentFlagsMask = 0; + } +#endif + //============================================================================== bool getCurrentPosition (AudioPlayHead::CurrentPositionInfo& info) { @@ -885,12 +916,59 @@ private: CriticalSection incomingMidiLock; }; +//============================================================================== +class EditorCompHolder : public Component, + public ComponentListener +{ +public: + EditorCompHolder (AudioProcessorEditor* const editorComp) + { + setSize (editorComp->getWidth(), editorComp->getHeight()); + addAndMakeVisible (editorComp); + editorComp->addComponentListener (this); + } + + ~EditorCompHolder() + { + deleteAllChildren(); + } + + void componentParentHierarchyChanged (Component& component) + { + if (component.getParentComponent() != this) + component.removeComponentListener (this); + } + + void componentMovedOrResized (Component& component, bool wasMoved, bool wasResized) + { + Component* comp = getChildComponent(0); + + if (comp != 0 && wasResized) + { + const int w = jmax (32, comp->getWidth()); + const int h = jmax (32, comp->getHeight()); + + if (getWidth() != w || getHeight() != h) + setSize (w, h); + + NSView* view = (NSView*) getWindowHandle(); + NSRect r = [[view superview] frame]; + r.origin.y = r.origin.y + r.size.height - component.getHeight(); + r.size.width = component.getWidth(); + r.size.height = component.getHeight(); + [[view superview] setFrame: r]; + [view setFrame: NSMakeRect (0, 0, component.getWidth(), component.getHeight())]; + [view setNeedsDisplay: YES]; + } + } +}; + //============================================================================== @interface JuceUIViewClass : NSView { AudioProcessor* filter; JuceAU* au; - AudioProcessorEditor* editorComp; + EditorCompHolder* editorComp; } - (JuceUIViewClass*) initWithFilter: (AudioProcessor*) filter @@ -910,7 +988,7 @@ private: { filter = filter_; au = au_; - editorComp = editorComp_; + editorComp = new EditorCompHolder (editorComp_); [super initWithFrame: NSMakeRect (0, 0, editorComp_->getWidth(), editorComp_->getHeight())]; [self setHidden: NO]; @@ -918,7 +996,6 @@ private: editorComp->addToDesktop (0, (void*) self); editorComp->setVisible (true); - editorComp->addComponentListener (au); return self; } @@ -929,8 +1006,8 @@ private: // is trying to delete our plugin.. jassert (Component::getCurrentlyModalComponent() == 0); - if (editorComp != 0) - filter->editorBeingDeleted (editorComp); + if (editorComp != 0 && editorComp->getChildComponent(0) != 0) + filter->editorBeingDeleted ((AudioProcessorEditor*) editorComp->getChildComponent(0)); deleteAndZero (editorComp); @@ -1008,6 +1085,250 @@ private: } @end + +#if BUILD_AU_CARBON_UI + +//============================================================================== +class JuceAUView : public AUCarbonViewBase +{ + AudioProcessor* juceFilter; + Component* windowComp; + +public: + JuceAUView (AudioUnitCarbonView auview) + : AUCarbonViewBase (auview), + juceFilter (0), + windowComp (0) + { + } + + ~JuceAUView() + { + deleteUI(); + } + + ComponentResult CreateUI (Float32 /*inXOffset*/, Float32 /*inYOffset*/) + { + const ScopedAutoReleasePool pool; + + if (juceFilter == 0) + { + void* pointers[2]; + UInt32 propertySize = sizeof (pointers); + + AudioUnitGetProperty (GetEditAudioUnit(), + juceFilterObjectPropertyID, + kAudioUnitScope_Global, + 0, + pointers, + &propertySize); + + juceFilter = (AudioProcessor*) pointers[0]; + } + + if (juceFilter != 0) + { + deleteUI(); + + AudioProcessorEditor* editorComp = juceFilter->createEditorIfNeeded(); + editorComp->setOpaque (true); + windowComp = new ComponentInHIView (editorComp, mCarbonPane); + } + else + { + jassertfalse // can't get a pointer to our effect + } + + return noErr; + } + + AudioUnitCarbonViewEventListener getEventListener() const throw() { return mEventListener; } + void* getEventListenerUserData() const throw() { return mEventListenerUserData; } + +private: + void deleteUI() + { + PopupMenu::dismissAllActiveMenus(); + + // there's some kind of component currently modal, but the host + // is trying to delete our plugin.. + jassert (Component::getCurrentlyModalComponent() == 0); + + if (windowComp != 0 && windowComp->getChildComponent(0) != 0) + juceFilter->editorBeingDeleted ((AudioProcessorEditor*) windowComp->getChildComponent(0)); + + deleteAndZero (windowComp); + } + + //============================================================================== + // Uses a child NSWindow to sit in front of a HIView and display our component + class ComponentInHIView : public Component, + public ComponentListener + { + public: + //============================================================================== + ComponentInHIView (Component* const contentComp, HIViewRef parentHIView) + : parentView (parentHIView), + recursive (false) + { + const ScopedAutoReleasePool pool; + + jassert (contentComp != 0); + addAndMakeVisible (contentComp); + setOpaque (true); + setVisible (true); + setBroughtToFrontOnMouseClick (true); + + setSize (contentComp->getWidth(), contentComp->getHeight()); + SizeControl (parentHIView, contentComp->getWidth(), contentComp->getHeight()); + + WindowRef windowRef = HIViewGetWindow (parentHIView); + hostWindow = [[NSWindow alloc] initWithWindowRef: windowRef]; + + [hostWindow retain]; + [hostWindow setCanHide: YES]; + [hostWindow setReleasedWhenClosed: YES]; + + updateWindowPos(); + +#if ! JucePlugin_EditorRequiresKeyboardFocus + addToDesktop (ComponentPeer::windowIsTemporary | ComponentPeer::windowIgnoresKeyPresses); + setWantsKeyboardFocus (false); +#else + addToDesktop (ComponentPeer::windowIsTemporary); +#endif + + setVisible (true); + toFront (false); + + addSubWindow(); + + // Adds a callback bodge to work around some problems with wrapped + // carbon windows.. + const EventTypeSpec eventsToCatch[] = { + { kEventClassWindow, kEventWindowShown }, + { kEventClassWindow, kEventWindowHidden } + }; + + InstallWindowEventHandler ((WindowRef) windowRef, + NewEventHandlerUPP (windowVisibilityBodge), + GetEventTypeCount (eventsToCatch), eventsToCatch, + (void*) hostWindow, 0); + + contentComp->addComponentListener (this); + } + + ~ComponentInHIView() + { + Component* const comp = getChildComponent(0); + + if (comp != 0) + comp->removeComponentListener (this); + + const ScopedAutoReleasePool pool; + + NSWindow* pluginWindow = [((NSView*) getWindowHandle()) window]; + [hostWindow removeChildWindow: pluginWindow]; + removeFromDesktop(); + + [hostWindow release]; + hostWindow = 0; + + deleteAllChildren(); + } + + void updateWindowPos() + { + HIPoint f; + f.x = f.y = 0; + HIPointConvert (&f, kHICoordSpaceView, parentView, kHICoordSpaceScreenPixel, 0); + setTopLeftPosition ((int) f.x, (int) f.y); + } + + void addSubWindow() + { + NSWindow* pluginWindow = [((NSView*) getWindowHandle()) window]; + [pluginWindow setExcludedFromWindowsMenu: YES]; + [pluginWindow setCanHide: YES]; + + [hostWindow addChildWindow: pluginWindow + ordered: NSWindowAbove]; + [hostWindow orderFront: nil]; + [pluginWindow orderFront: nil]; + } + + void resized() + { + if (getChildComponent(0) != 0) + getChildComponent(0)->setBounds (0, 0, getWidth(), getHeight()); + } + + void paint (Graphics& g) {} + + void componentParentHierarchyChanged (Component& component) + { + if (component.getParentComponent() != this) + component.removeComponentListener (this); + } + + void componentMovedOrResized (Component& component, bool wasMoved, bool wasResized) + { + if (! recursive) + { + recursive = true; + + Component* comp = getChildComponent(0); + + if (comp != 0 && wasResized) + { + const int w = jmax (32, comp->getWidth()); + const int h = jmax (32, comp->getHeight()); + + SizeControl (parentView, w, h); + + if (getWidth() != w || getHeight() != h) + setSize (w, h); + + comp->repaint(); + + updateWindowPos(); + addSubWindow(); // (need this for AULab) + } + + recursive = false; + } + } + + private: + HIViewRef parentView; + NSWindow* hostWindow; + bool recursive; + + /* When you wrap a WindowRef as an NSWindow, it seems to bugger up the HideWindow + function, so when the host tries (and fails) to hide the window, this catches + the event and does the job properly. + */ + static pascal OSStatus windowVisibilityBodge (EventHandlerCallRef, EventRef e, void* user) + { + NSWindow* hostWindow = (NSWindow*) user; + + switch (GetEventKind (e)) + { + case kEventWindowShown: + [hostWindow orderFront: nil]; + break; + case kEventWindowHidden: + [hostWindow orderOut: nil]; + break; + } + + return eventNotHandledErr; + } + }; +}; + +#endif + //============================================================================== #define JUCE_COMPONENT_ENTRYX(Class, Name, Suffix) \ extern "C" __attribute__((visibility("default"))) ComponentResult Name ## Suffix (ComponentParameters* params, Class* obj); \ @@ -1019,6 +1340,9 @@ extern "C" __attribute__((visibility("default"))) ComponentResult Name ## Suffix #define JUCE_COMPONENT_ENTRY(Class, Name, Suffix) JUCE_COMPONENT_ENTRYX(Class, Name, Suffix) JUCE_COMPONENT_ENTRY (JuceAU, JucePlugin_AUExportPrefix, Entry) -//JUCE_COMPONENT_ENTRY (JuceAUView, JucePlugin_AUExportPrefix, ViewEntry) + +#if BUILD_AU_CARBON_UI + JUCE_COMPONENT_ENTRY (JuceAUView, JucePlugin_AUExportPrefix, ViewEntry) +#endif #endif