| @@ -29,7 +29,13 @@ | |||
| ============================================================================== | |||
| */ | |||
| /** Creates a floating carbon window that can be used to hold a carbon UI. | |||
| #ifndef __JUCE_MAC_CARBONVIEWWRAPPERCOMPONENT_JUCEHEADER__ | |||
| #define __JUCE_MAC_CARBONVIEWWRAPPERCOMPONENT_JUCEHEADER__ | |||
| //============================================================================== | |||
| /** | |||
| Creates a floating carbon window that can be used to hold a carbon UI. | |||
| This is a handy class that's designed to be inlined where needed, e.g. | |||
| in the audio plugin hosting code. | |||
| @@ -106,6 +112,8 @@ public: | |||
| setOurSizeToEmbeddedViewSize(); | |||
| setEmbeddedWindowToOurSize(); | |||
| creationTime = Time::getCurrentTime(); | |||
| } | |||
| } | |||
| @@ -203,6 +211,11 @@ public: | |||
| void timerCallback() | |||
| { | |||
| setOurSizeToEmbeddedViewSize(); | |||
| // To avoid strange overpainting problems when the UI is first opened, we'll | |||
| // repaint it a few times during the first second that it's on-screen.. | |||
| if ((Time::getCurrentTime() - creationTime).inMilliseconds() < 1000) | |||
| HIViewSetNeedsDisplay (embeddedView, true); | |||
| } | |||
| OSStatus carbonEventHandler (EventHandlerCallRef nextHandlerRef, | |||
| @@ -222,6 +235,8 @@ public: | |||
| SetEventParameter (event, kEventParamClickActivation, typeClickActivationResult, | |||
| sizeof (ClickActivationResult), &howToHandleClick); | |||
| HIViewSetNeedsDisplay (embeddedView, true); | |||
| } | |||
| break; | |||
| } | |||
| @@ -239,6 +254,9 @@ protected: | |||
| WindowRef wrapperWindow; | |||
| HIViewRef embeddedView; | |||
| bool recursiveResize; | |||
| Time creationTime; | |||
| EventHandlerRef eventHandlerRef; | |||
| }; | |||
| #endif // __JUCE_MAC_CARBONVIEWWRAPPERCOMPONENT_JUCEHEADER__ | |||
| @@ -181,11 +181,14 @@ public: | |||
| MenuBarModel* currentModel; | |||
| void addMenuItem (PopupMenu::MenuItemIterator& iter, NSMenu* menuToAddTo, | |||
| void addMenuItem (PopupMenu::MenuItemIterator& iter, NSMenu* menuToAddTo, | |||
| const int topLevelMenuId, const int topLevelIndex) | |||
| { | |||
| NSString* text = juceStringToNS (iter.itemName.upToFirstOccurrenceOf (T("<end>"), false, true)); | |||
| if (text == 0) | |||
| text = @""; | |||
| if (iter.isSeparator) | |||
| { | |||
| [menuToAddTo addItem: [NSMenuItem separatorItem]]; | |||
| @@ -320,7 +323,7 @@ END_JUCE_NAMESPACE | |||
| BEGIN_JUCE_NAMESPACE | |||
| //============================================================================== | |||
| static NSMenu* createStandardAppMenu (NSMenu* menu, const String& appName, | |||
| static NSMenu* createStandardAppMenu (NSMenu* menu, const String& appName, | |||
| const PopupMenu* extraItems) | |||
| { | |||
| if (extraItems != 0 && JuceMainMenuHandler::instance != 0 && extraItems->getNumItems() > 0) | |||
| @@ -329,7 +332,7 @@ static NSMenu* createStandardAppMenu (NSMenu* menu, const String& appName, | |||
| while (iter.next()) | |||
| JuceMainMenuHandler::instance->addMenuItem (iter, menu, 0, -1); | |||
| [menu addItem: [NSMenuItem separatorItem]]; | |||
| } | |||
| @@ -415,7 +418,7 @@ void MenuBarModel::setMacMainMenu (MenuBarModel* newMenuBarModel, | |||
| delete JuceMainMenuHandler::instance; | |||
| jassert (JuceMainMenuHandler::instance == 0); // should be zeroed in the destructor | |||
| jassert (extraAppleMenuItems == 0); // you can't specify some extra items without also supplying a model | |||
| extraAppleMenuItems = 0; | |||
| } | |||
| else | |||
| @@ -1347,8 +1347,8 @@ void NSViewComponentPeer::redirectMovedOrResized() | |||
| //============================================================================== | |||
| void juce_setKioskComponent (Component* kioskModeComponent, bool enableOrDisable) | |||
| { | |||
| // Very annoyingly, this function has to use the old SetSystemUIMode function, | |||
| // which is in Carbon.framework. But, because there's no Cocoa equivalent, it | |||
| // Very annoyingly, this function has to use the old SetSystemUIMode function, | |||
| // which is in Carbon.framework. But, because there's no Cocoa equivalent, it | |||
| // is apparently still available in 64-bit apps.. | |||
| if (enableOrDisable) | |||
| { | |||
| @@ -62,10 +62,12 @@ public: | |||
| //============================================================================== | |||
| const String getName() const { return "Internal"; } | |||
| bool fileMightContainThisPluginType (const File&) { return false; } | |||
| bool fileMightContainThisPluginType (const String&) { return false; } | |||
| const FileSearchPath getDefaultLocationsToSearch() { return FileSearchPath(); } | |||
| void findAllTypesForFile (OwnedArray <PluginDescription>&, const File&) {} | |||
| void findAllTypesForFile (OwnedArray <PluginDescription>&, const String&) {} | |||
| bool doesPluginStillExist (const PluginDescription&) { return true; } | |||
| const String getNameOfPluginFromIdentifier (const String& fileOrIdentifier) { return fileOrIdentifier; } | |||
| const StringArray searchPathsForPlugins (const FileSearchPath&, const bool) { return StringArray(); } | |||
| AudioPluginInstance* createInstanceFromDescription (const PluginDescription& desc); | |||
| //============================================================================== | |||
| @@ -779,8 +779,8 @@ protected: | |||
| UInt8 inData1, | |||
| UInt8 inData2, | |||
| #if defined(MAC_OS_X_VERSION_10_5) | |||
| UInt32 inStartFrame | |||
| #else | |||
| UInt32 inStartFrame) | |||
| #else | |||
| long inStartFrame) | |||
| #endif | |||
| { | |||
| @@ -796,6 +796,14 @@ protected: | |||
| return noErr; | |||
| } | |||
| OSStatus HandleSysEx (const UInt8* inData, UInt32 inLength) | |||
| { | |||
| #if JucePlugin_WantsMidiInput | |||
| midiEvents.addEvent (inData, inLength, 0); | |||
| #endif | |||
| return noErr; | |||
| } | |||
| //============================================================================== | |||
| ComponentResult GetPresets (CFArrayRef* outData) const | |||
| { | |||
| @@ -952,7 +960,7 @@ private: | |||
| - (NSString*) description | |||
| { | |||
| return [NSString stringWithString: @JucePlugin_Name]; | |||
| return [NSString stringWithString: @JucePlugin_Name]; | |||
| } | |||
| - (NSView*) uiViewForAudioUnit: (AudioUnit) inAudioUnit | |||
| @@ -27836,8 +27836,8 @@ public: | |||
| /** Either the file containing the plugin module, or some other unique way | |||
| of identifying it. | |||
| E.g. for an AU, this would be the component ID, because not all AUs actually | |||
| live in a file... | |||
| E.g. for an AU, this would be an ID string that the component manager | |||
| could use to retrieve the plugin. For a VST, it's the file path. | |||
| */ | |||
| String fileOrIdentifier; | |||
| @@ -27965,7 +27965,7 @@ public: | |||
| subtypes, so in that case, each subtype is returned as a separate object. | |||
| */ | |||
| virtual void findAllTypesForFile (OwnedArray <PluginDescription>& results, | |||
| const File& file) = 0; | |||
| const String& fileOrIdentifier) = 0; | |||
| /** Tries to recreate a type from a previously generated PluginDescription. | |||
| @@ -27979,7 +27979,11 @@ public: | |||
| This is for searching for potential files, so it shouldn't actually try to | |||
| load the plugin or do anything time-consuming. | |||
| */ | |||
| virtual bool fileMightContainThisPluginType (const File& file) = 0; | |||
| virtual bool fileMightContainThisPluginType (const String& fileOrIdentifier) = 0; | |||
| /** Returns a readable version of the name of the plugin that this identifier refers to. | |||
| */ | |||
| virtual const String getNameOfPluginFromIdentifier (const String& fileOrIdentifier) = 0; | |||
| /** Checks whether this plugin could possibly be loaded. | |||
| @@ -27988,6 +27992,14 @@ public: | |||
| */ | |||
| virtual bool doesPluginStillExist (const PluginDescription& desc) = 0; | |||
| /** Searches a suggested set of directories for any plugins in this format. | |||
| The path might be ignored, e.g. by AUs, which are found by the OS rather | |||
| than manually. | |||
| */ | |||
| virtual const StringArray searchPathsForPlugins (const FileSearchPath& directoriesToSearch, | |||
| const bool recursive) = 0; | |||
| /** Returns the typical places to look for this kind of plugin. | |||
| Note that if this returns no paths, it means that the format can't be scanned-for | |||
| @@ -28541,7 +28553,7 @@ public: | |||
| /** Looks for a type in the list which comes from this file. | |||
| */ | |||
| PluginDescription* getTypeForFile (const File& file) const throw(); | |||
| PluginDescription* getTypeForFile (const String& fileOrIdentifier) const throw(); | |||
| /** Looks for a type in the list which matches a plugin type ID. | |||
| @@ -28568,14 +28580,15 @@ public: | |||
| file (even if it was already known and hasn't been re-scanned) get returned | |||
| in the array. | |||
| */ | |||
| bool scanAndAddFile (const File& possiblePluginFile, | |||
| bool scanAndAddFile (const String& possiblePluginFileOrIdentifier, | |||
| const bool dontRescanIfAlreadyInList, | |||
| OwnedArray <PluginDescription>& typesFound); | |||
| OwnedArray <PluginDescription>& typesFound, | |||
| AudioPluginFormat& formatToUse); | |||
| /** Returns true if the specified file is already known about and if it | |||
| hasn't been modified since our entry was created. | |||
| */ | |||
| bool isListingUpToDate (const File& possiblePluginFile) const throw(); | |||
| bool isListingUpToDate (const String& possiblePluginFileOrIdentifier) const throw(); | |||
| /** Scans and adds a bunch of files that might have been dragged-and-dropped. | |||
| @@ -34678,9 +34691,11 @@ public: | |||
| ~AudioUnitPluginFormat(); | |||
| const String getName() const { return "AudioUnit"; } | |||
| void findAllTypesForFile (OwnedArray <PluginDescription>& results, const File& file); | |||
| void findAllTypesForFile (OwnedArray <PluginDescription>& results, const String& fileOrIdentifier); | |||
| AudioPluginInstance* createInstanceFromDescription (const PluginDescription& desc); | |||
| bool fileMightContainThisPluginType (const File& file); | |||
| bool fileMightContainThisPluginType (const String& fileOrIdentifier); | |||
| const String getNameOfPluginFromIdentifier (const String& fileOrIdentifier); | |||
| const StringArray searchPathsForPlugins (const FileSearchPath& directoriesToSearch, const bool recursive); | |||
| bool doesPluginStillExist (const PluginDescription& desc); | |||
| const FileSearchPath getDefaultLocationsToSearch(); | |||
| @@ -34718,9 +34733,10 @@ public: | |||
| ~DirectXPluginFormat(); | |||
| const String getName() const { return "DirectX"; } | |||
| void findAllTypesForFile (OwnedArray <PluginDescription>& results, const File& file); | |||
| void findAllTypesForFile (OwnedArray <PluginDescription>& results, const String& fileOrIdentifier); | |||
| AudioPluginInstance* createInstanceFromDescription (const PluginDescription& desc); | |||
| bool fileMightContainThisPluginType (const File& file); | |||
| bool fileMightContainThisPluginType (const String& fileOrIdentifier); | |||
| const String getNameOfPluginFromIdentifier (const String& fileOrIdentifier) { return fileOrIdentifier; } | |||
| const FileSearchPath getDefaultLocationsToSearch(); | |||
| juce_UseDebuggingNewOperator | |||
| @@ -34757,9 +34773,10 @@ public: | |||
| ~LADSPAPluginFormat(); | |||
| const String getName() const { return "LADSPA"; } | |||
| void findAllTypesForFile (OwnedArray <PluginDescription>& results, const File& file); | |||
| void findAllTypesForFile (OwnedArray <PluginDescription>& results, const String& fileOrIdentifier); | |||
| AudioPluginInstance* createInstanceFromDescription (const PluginDescription& desc); | |||
| bool fileMightContainThisPluginType (const File& file); | |||
| bool fileMightContainThisPluginType (const String& fileOrIdentifier); | |||
| const String getNameOfPluginFromIdentifier (const String& fileOrIdentifier) { return fileOrIdentifier; } | |||
| const FileSearchPath getDefaultLocationsToSearch(); | |||
| juce_UseDebuggingNewOperator | |||
| @@ -34794,9 +34811,11 @@ public: | |||
| ~VSTPluginFormat(); | |||
| const String getName() const { return "VST"; } | |||
| void findAllTypesForFile (OwnedArray <PluginDescription>& results, const File& file); | |||
| void findAllTypesForFile (OwnedArray <PluginDescription>& results, const String& fileOrIdentifier); | |||
| AudioPluginInstance* createInstanceFromDescription (const PluginDescription& desc); | |||
| bool fileMightContainThisPluginType (const File& file); | |||
| bool fileMightContainThisPluginType (const String& fileOrIdentifier); | |||
| const String getNameOfPluginFromIdentifier (const String& fileOrIdentifier); | |||
| const StringArray searchPathsForPlugins (const FileSearchPath& directoriesToSearch, const bool recursive); | |||
| bool doesPluginStillExist (const PluginDescription& desc); | |||
| const FileSearchPath getDefaultLocationsToSearch(); | |||
| @@ -34805,6 +34824,8 @@ public: | |||
| private: | |||
| VSTPluginFormat (const VSTPluginFormat&); | |||
| const VSTPluginFormat& operator= (const VSTPluginFormat&); | |||
| void recursiveFileSearch (StringArray& results, const File& dir, const bool recursive); | |||
| }; | |||
| #endif | |||
| @@ -34884,12 +34905,13 @@ public: | |||
| */ | |||
| bool scanNextFile (const bool dontRescanIfAlreadyInList); | |||
| /** Returns the file that will be scanned during the next call to scanNextFile(). | |||
| /** Returns the description of the plugin that will be scanned during the next | |||
| call to scanNextFile(). | |||
| This is handy if you want to show the user which file is currently getting | |||
| scanned. | |||
| */ | |||
| const File getNextPluginFileThatWillBeScanned() const throw(); | |||
| const String getNextPluginFileThatWillBeScanned() const throw(); | |||
| /** Returns the estimated progress, between 0 and 1. | |||
| */ | |||
| @@ -34905,13 +34927,12 @@ public: | |||
| private: | |||
| KnownPluginList& list; | |||
| AudioPluginFormat& format; | |||
| OwnedArray <File> filesToScan; | |||
| StringArray filesOrIdentifiersToScan; | |||
| File deadMansPedalFile; | |||
| StringArray failedFiles; | |||
| int nextIndex; | |||
| float progress; | |||
| void recursiveFileSearch (const File& dir, const bool recursive); | |||
| const StringArray getDeadMansPedalFile() throw(); | |||
| void setDeadMansPedalFile (const StringArray& newContents) throw(); | |||
| @@ -510,7 +510,7 @@ void AudioThumbnail::drawChannel (Graphics& g, | |||
| const float vscale = verticalZoomFactor * h / 256.0f; | |||
| const Rectangle clip (g.getClipBounds()); | |||
| const int skipLeft = clip.getX() - x; | |||
| const int skipLeft = jlimit (0, w, clip.getX() - x); | |||
| w -= skipLeft; | |||
| x += skipLeft; | |||
| @@ -49,9 +49,11 @@ public: | |||
| //============================================================================== | |||
| const String getName() const { return "AudioUnit"; } | |||
| void findAllTypesForFile (OwnedArray <PluginDescription>& results, const File& file); | |||
| void findAllTypesForFile (OwnedArray <PluginDescription>& results, const String& fileOrIdentifier); | |||
| AudioPluginInstance* createInstanceFromDescription (const PluginDescription& desc); | |||
| bool fileMightContainThisPluginType (const File& file); | |||
| bool fileMightContainThisPluginType (const String& fileOrIdentifier); | |||
| const String getNameOfPluginFromIdentifier (const String& fileOrIdentifier); | |||
| const StringArray searchPathsForPlugins (const FileSearchPath& directoriesToSearch, const bool recursive); | |||
| bool doesPluginStillExist (const PluginDescription& desc); | |||
| const FileSearchPath getDefaultLocationsToSearch(); | |||
| @@ -81,6 +81,129 @@ BEGIN_JUCE_NAMESPACE | |||
| static int insideCallback = 0; | |||
| //============================================================================== | |||
| static const String osTypeToString (OSType type) throw() | |||
| { | |||
| char s[4]; | |||
| s[0] = (char) (((uint32) type) >> 24); | |||
| s[1] = (char) (((uint32) type) >> 16); | |||
| s[2] = (char) (((uint32) type) >> 8); | |||
| s[3] = (char) ((uint32) type); | |||
| return String (s, 4); | |||
| } | |||
| static OSType stringToOSType (const String& s1) throw() | |||
| { | |||
| const String s (s1 + " "); | |||
| return (((OSType) (unsigned char) s[0]) << 24) | |||
| | (((OSType) (unsigned char) s[1]) << 16) | |||
| | (((OSType) (unsigned char) s[2]) << 8) | |||
| | ((OSType) (unsigned char) s[3]); | |||
| } | |||
| static const tchar* auIdentifierPrefix = T("AudioUnit:"); | |||
| static const String createAUPluginIdentifier (const ComponentDescription& desc) | |||
| { | |||
| jassert (osTypeToString ('abcd') == T("abcd")); // agh, must have got the endianness wrong.. | |||
| jassert (stringToOSType ("abcd") == (OSType) 'abcd'); // ditto | |||
| String s (auIdentifierPrefix); | |||
| if (desc.componentType == kAudioUnitType_MusicDevice) | |||
| s << "Synths/"; | |||
| else if (desc.componentType == kAudioUnitType_MusicEffect | |||
| || desc.componentType == kAudioUnitType_Effect) | |||
| s << "Effects/"; | |||
| else if (desc.componentType == kAudioUnitType_Generator) | |||
| s << "Generators/"; | |||
| else if (desc.componentType == kAudioUnitType_Panner) | |||
| s << "Panners/"; | |||
| s << osTypeToString (desc.componentType) | |||
| << T(",") | |||
| << osTypeToString (desc.componentSubType) | |||
| << T(",") | |||
| << osTypeToString (desc.componentManufacturer); | |||
| return s; | |||
| } | |||
| static void getAUDetails (ComponentRecord* comp, String& name, String& manufacturer) | |||
| { | |||
| Handle componentNameHandle = NewHandle (sizeof (void*)); | |||
| Handle componentInfoHandle = NewHandle (sizeof (void*)); | |||
| if (componentNameHandle != 0 && componentInfoHandle != 0) | |||
| { | |||
| ComponentDescription desc; | |||
| if (GetComponentInfo (comp, &desc, componentNameHandle, componentInfoHandle, 0) == noErr) | |||
| { | |||
| ConstStr255Param nameString = (ConstStr255Param) (*componentNameHandle); | |||
| ConstStr255Param infoString = (ConstStr255Param) (*componentInfoHandle); | |||
| if (nameString != 0 && nameString[0] != 0) | |||
| { | |||
| const String all ((const char*) nameString + 1, nameString[0]); | |||
| DBG ("name: "+ all); | |||
| manufacturer = all.upToFirstOccurrenceOf (T(":"), false, false).trim(); | |||
| name = all.fromFirstOccurrenceOf (T(":"), false, false).trim(); | |||
| } | |||
| if (infoString != 0 && infoString[0] != 0) | |||
| { | |||
| const String all ((const char*) infoString + 1, infoString[0]); | |||
| DBG ("info: " + all); | |||
| } | |||
| if (name.isEmpty()) | |||
| name = "<Unknown>"; | |||
| } | |||
| DisposeHandle (componentNameHandle); | |||
| DisposeHandle (componentInfoHandle); | |||
| } | |||
| } | |||
| static bool getComponentDescFromIdentifier (const String& fileOrIdentifier, ComponentDescription& desc, | |||
| String& name, String& version, String& manufacturer) | |||
| { | |||
| zerostruct (desc); | |||
| if (fileOrIdentifier.startsWithIgnoreCase (auIdentifierPrefix)) | |||
| { | |||
| String s (fileOrIdentifier.substring (jmax (fileOrIdentifier.lastIndexOfChar (T(':')), | |||
| fileOrIdentifier.lastIndexOfChar (T('/'))) + 1)); | |||
| StringArray tokens; | |||
| tokens.addTokens (s, T(","), 0); | |||
| tokens.trim(); | |||
| tokens.removeEmptyStrings(); | |||
| if (tokens.size() == 3) | |||
| { | |||
| desc.componentType = stringToOSType (tokens[0]); | |||
| desc.componentSubType = stringToOSType (tokens[1]); | |||
| desc.componentManufacturer = stringToOSType (tokens[2]); | |||
| ComponentRecord* comp = FindNextComponent (0, &desc); | |||
| if (comp != 0) | |||
| { | |||
| getAUDetails (comp, name, manufacturer); | |||
| return true; | |||
| } | |||
| } | |||
| } | |||
| return false; | |||
| } | |||
| //============================================================================== | |||
| class AudioUnitPluginWindowCarbon; | |||
| class AudioUnitPluginWindowCocoa; | |||
| @@ -98,11 +221,11 @@ public: | |||
| void fillInPluginDescription (PluginDescription& desc) const | |||
| { | |||
| desc.name = pluginName; | |||
| desc.file = file; | |||
| desc.fileOrIdentifier = createAUPluginIdentifier (componentDesc); | |||
| desc.uid = ((int) componentDesc.componentType) | |||
| ^ ((int) componentDesc.componentSubType) | |||
| ^ ((int) componentDesc.componentManufacturer); | |||
| desc.lastFileModTime = file.getLastModificationTime(); | |||
| desc.lastFileModTime = 0; | |||
| desc.pluginFormatName = "AudioUnit"; | |||
| desc.category = getCategory(); | |||
| desc.manufacturerName = manufacturer; | |||
| @@ -163,7 +286,7 @@ private: | |||
| ComponentDescription componentDesc; | |||
| String pluginName, manufacturer, version; | |||
| File file; | |||
| String fileOrIdentifier; | |||
| CriticalSection lock; | |||
| bool initialised, wantsMidiMessages, wasPlaying; | |||
| @@ -175,7 +298,7 @@ private: | |||
| Array <int> parameterIds; | |||
| //============================================================================== | |||
| bool getComponentDescFromFile (const File& file); | |||
| bool getComponentDescFromFile (const String& fileOrIdentifier); | |||
| void initialise(); | |||
| //============================================================================== | |||
| @@ -257,12 +380,12 @@ private: | |||
| const String getCategory() const; | |||
| //============================================================================== | |||
| AudioUnitPluginInstance (const File& file); | |||
| AudioUnitPluginInstance (const String& fileOrIdentifier); | |||
| }; | |||
| //============================================================================== | |||
| AudioUnitPluginInstance::AudioUnitPluginInstance (const File& file_) | |||
| : file (file_), | |||
| AudioUnitPluginInstance::AudioUnitPluginInstance (const String& fileOrIdentifier) | |||
| : fileOrIdentifier (fileOrIdentifier), | |||
| initialised (false), | |||
| wantsMidiMessages (false), | |||
| audioUnit (0), | |||
| @@ -273,9 +396,9 @@ AudioUnitPluginInstance::AudioUnitPluginInstance (const File& file_) | |||
| { | |||
| ++insideCallback; | |||
| log (T("Opening AU: ") + file.getFullPathName()); | |||
| log (T("Opening AU: ") + fileOrIdentifier); | |||
| if (getComponentDescFromFile (file)) | |||
| if (getComponentDescFromFile (fileOrIdentifier)) | |||
| { | |||
| ComponentRecord* const comp = FindNextComponent (0, &componentDesc); | |||
| @@ -314,15 +437,18 @@ AudioUnitPluginInstance::~AudioUnitPluginInstance() | |||
| juce_free (outputBufferList); | |||
| } | |||
| bool AudioUnitPluginInstance::getComponentDescFromFile (const File& file) | |||
| bool AudioUnitPluginInstance::getComponentDescFromFile (const String& fileOrIdentifier) | |||
| { | |||
| zerostruct (componentDesc); | |||
| if (getComponentDescFromIdentifier (fileOrIdentifier, componentDesc, pluginName, version, manufacturer)) | |||
| return true; | |||
| const File file (fileOrIdentifier); | |||
| if (! file.hasFileExtension (T(".component"))) | |||
| return false; | |||
| const String filename (file.getFullPathName()); | |||
| const char* const utf8 = filename.toUTF8(); | |||
| const char* const utf8 = fileOrIdentifier.toUTF8(); | |||
| CFURLRef url = CFURLCreateFromFileSystemRepresentation (0, (const UInt8*) utf8, | |||
| strlen (utf8), file.isDirectory()); | |||
| if (url != 0) | |||
| @@ -730,15 +856,24 @@ public: | |||
| ~AudioUnitPluginWindowCocoa() | |||
| { | |||
| const bool wasValid = isValid(); | |||
| wrapper->setView (0); | |||
| activeWindows.removeValue (this); | |||
| if (isValid()) | |||
| if (wasValid) | |||
| plugin.editorBeingDeleted (this); | |||
| delete wrapper; | |||
| } | |||
| bool isValid() const { return wrapper->getView() != 0; } | |||
| void paint (Graphics& g) | |||
| { | |||
| g.fillAll (Colours::white); | |||
| } | |||
| void resized() | |||
| { | |||
| wrapper->setSize (getWidth(), getHeight()); | |||
| @@ -794,6 +929,11 @@ private: | |||
| juce_free (info); | |||
| wrapper->setView (pluginView); | |||
| if (pluginView != 0) | |||
| setSize ([pluginView frame].size.width, | |||
| [pluginView frame].size.height); | |||
| return pluginView != 0; | |||
| } | |||
| }; | |||
| @@ -1264,13 +1404,13 @@ AudioUnitPluginFormat::~AudioUnitPluginFormat() | |||
| } | |||
| void AudioUnitPluginFormat::findAllTypesForFile (OwnedArray <PluginDescription>& results, | |||
| const File& file) | |||
| const String& fileOrIdentifier) | |||
| { | |||
| if (! fileMightContainThisPluginType (file)) | |||
| if (! fileMightContainThisPluginType (fileOrIdentifier)) | |||
| return; | |||
| PluginDescription desc; | |||
| desc.file = file; | |||
| desc.fileOrIdentifier = fileOrIdentifier; | |||
| desc.uid = 0; | |||
| AudioUnitPluginInstance* instance = dynamic_cast <AudioUnitPluginInstance*> (createInstanceFromDescription (desc)); | |||
| @@ -1295,9 +1435,9 @@ AudioPluginInstance* AudioUnitPluginFormat::createInstanceFromDescription (const | |||
| { | |||
| AudioUnitPluginInstance* result = 0; | |||
| if (fileMightContainThisPluginType (desc.file)) | |||
| if (fileMightContainThisPluginType (desc.fileOrIdentifier)) | |||
| { | |||
| result = new AudioUnitPluginInstance (desc.file); | |||
| result = new AudioUnitPluginInstance (desc.fileOrIdentifier); | |||
| if (result->audioUnit != 0) | |||
| { | |||
| @@ -1312,15 +1452,73 @@ AudioPluginInstance* AudioUnitPluginFormat::createInstanceFromDescription (const | |||
| return result; | |||
| } | |||
| bool AudioUnitPluginFormat::fileMightContainThisPluginType (const File& f) | |||
| const StringArray AudioUnitPluginFormat::searchPathsForPlugins (const FileSearchPath& /*directoriesToSearch*/, | |||
| const bool /*recursive*/) | |||
| { | |||
| StringArray result; | |||
| ComponentRecord* comp = 0; | |||
| ComponentDescription desc; | |||
| zerostruct (desc); | |||
| for (;;) | |||
| { | |||
| zerostruct (desc); | |||
| comp = FindNextComponent (comp, &desc); | |||
| if (comp == 0) | |||
| break; | |||
| GetComponentInfo (comp, &desc, 0, 0, 0); | |||
| if (desc.componentType == kAudioUnitType_MusicDevice | |||
| || desc.componentType == kAudioUnitType_MusicEffect | |||
| || desc.componentType == kAudioUnitType_Effect | |||
| || desc.componentType == kAudioUnitType_Generator | |||
| || desc.componentType == kAudioUnitType_Panner) | |||
| { | |||
| const String s (createAUPluginIdentifier (desc)); | |||
| DBG (s); | |||
| result.add (s); | |||
| } | |||
| } | |||
| return result; | |||
| } | |||
| bool AudioUnitPluginFormat::fileMightContainThisPluginType (const String& fileOrIdentifier) | |||
| { | |||
| ComponentDescription desc; | |||
| String name, version, manufacturer; | |||
| if (getComponentDescFromIdentifier (fileOrIdentifier, desc, name, version, manufacturer)) | |||
| return FindNextComponent (0, &desc) != 0; | |||
| const File f (fileOrIdentifier); | |||
| return f.hasFileExtension (T(".component")) | |||
| && f.isDirectory(); | |||
| } | |||
| const String AudioUnitPluginFormat::getNameOfPluginFromIdentifier (const String& fileOrIdentifier) | |||
| { | |||
| ComponentDescription desc; | |||
| String name, version, manufacturer; | |||
| getComponentDescFromIdentifier (fileOrIdentifier, desc, name, version, manufacturer); | |||
| if (name.isEmpty()) | |||
| name = fileOrIdentifier; | |||
| return name; | |||
| } | |||
| bool AudioUnitPluginFormat::doesPluginStillExist (const PluginDescription& desc) | |||
| { | |||
| return File (desc.fileOrIdentifier).exists(); | |||
| } | |||
| const FileSearchPath AudioUnitPluginFormat::getDefaultLocationsToSearch() | |||
| { | |||
| return FileSearchPath ("~/Library/Audio/Plug-Ins/Components;/Library/Audio/Plug-Ins/Components"); | |||
| return FileSearchPath ("(Default AudioUnit locations)"); | |||
| } | |||
| #endif | |||
| @@ -53,9 +53,10 @@ public: | |||
| //============================================================================== | |||
| const String getName() const { return "DirectX"; } | |||
| void findAllTypesForFile (OwnedArray <PluginDescription>& results, const File& file); | |||
| void findAllTypesForFile (OwnedArray <PluginDescription>& results, const String& fileOrIdentifier); | |||
| AudioPluginInstance* createInstanceFromDescription (const PluginDescription& desc); | |||
| bool fileMightContainThisPluginType (const File& file); | |||
| bool fileMightContainThisPluginType (const String& fileOrIdentifier); | |||
| const String getNameOfPluginFromIdentifier (const String& fileOrIdentifier) { return fileOrIdentifier; } | |||
| const FileSearchPath getDefaultLocationsToSearch(); | |||
| //============================================================================== | |||
| @@ -53,9 +53,10 @@ public: | |||
| //============================================================================== | |||
| const String getName() const { return "LADSPA"; } | |||
| void findAllTypesForFile (OwnedArray <PluginDescription>& results, const File& file); | |||
| void findAllTypesForFile (OwnedArray <PluginDescription>& results, const String& fileOrIdentifier); | |||
| AudioPluginInstance* createInstanceFromDescription (const PluginDescription& desc); | |||
| bool fileMightContainThisPluginType (const File& file); | |||
| bool fileMightContainThisPluginType (const String& fileOrIdentifier); | |||
| const String getNameOfPluginFromIdentifier (const String& fileOrIdentifier) { return fileOrIdentifier; } | |||
| const FileSearchPath getDefaultLocationsToSearch(); | |||
| //============================================================================== | |||
| @@ -2892,13 +2892,13 @@ VSTPluginFormat::~VSTPluginFormat() | |||
| } | |||
| void VSTPluginFormat::findAllTypesForFile (OwnedArray <PluginDescription>& results, | |||
| const File& file) | |||
| const String& fileOrIdentifier) | |||
| { | |||
| if (! fileMightContainThisPluginType (file)) | |||
| if (! fileMightContainThisPluginType (fileOrIdentifier)) | |||
| return; | |||
| PluginDescription desc; | |||
| desc.fileOrIdentifier = file.getFullPathName(); | |||
| desc.fileOrIdentifier = fileOrIdentifier; | |||
| desc.uid = 0; | |||
| VSTPluginInstance* instance = dynamic_cast <VSTPluginInstance*> (createInstanceFromDescription (desc)); | |||
| @@ -2976,10 +2976,10 @@ AudioPluginInstance* VSTPluginFormat::createInstanceFromDescription (const Plugi | |||
| { | |||
| VSTPluginInstance* result = 0; | |||
| File file (desc.fileOrIdentifier); | |||
| if (fileMightContainThisPluginType (file)) | |||
| if (fileMightContainThisPluginType (desc.fileOrIdentifier)) | |||
| { | |||
| File file (desc.fileOrIdentifier); | |||
| const File previousWorkingDirectory (File::getCurrentWorkingDirectory()); | |||
| file.getParentDirectory().setAsCurrentWorkingDirectory(); | |||
| @@ -3008,8 +3008,10 @@ AudioPluginInstance* VSTPluginFormat::createInstanceFromDescription (const Plugi | |||
| return result; | |||
| } | |||
| bool VSTPluginFormat::fileMightContainThisPluginType (const File& f) | |||
| bool VSTPluginFormat::fileMightContainThisPluginType (const String& fileOrIdentifier) | |||
| { | |||
| const File f (fileOrIdentifier); | |||
| #if JUCE_MAC | |||
| if (f.isDirectory() && f.hasFileExtension (T(".vst"))) | |||
| return true; | |||
| @@ -3041,11 +3043,48 @@ bool VSTPluginFormat::fileMightContainThisPluginType (const File& f) | |||
| #endif | |||
| } | |||
| const String VSTPluginFormat::getNameOfPluginFromIdentifier (const String& fileOrIdentifier) | |||
| { | |||
| return fileOrIdentifier; | |||
| } | |||
| bool VSTPluginFormat::doesPluginStillExist (const PluginDescription& desc) | |||
| { | |||
| return File (desc.fileOrIdentifier).exists(); | |||
| } | |||
| const StringArray VSTPluginFormat::searchPathsForPlugins (const FileSearchPath& directoriesToSearch, const bool recursive) | |||
| { | |||
| StringArray results; | |||
| for (int j = 0; j < directoriesToSearch.getNumPaths(); ++j) | |||
| recursiveFileSearch (results, directoriesToSearch [j], recursive); | |||
| return results; | |||
| } | |||
| void VSTPluginFormat::recursiveFileSearch (StringArray& results, const File& dir, const bool recursive) | |||
| { | |||
| // avoid allowing the dir iterator to be recursive, because we want to avoid letting it delve inside | |||
| // .component or .vst directories. | |||
| DirectoryIterator iter (dir, false, "*", File::findFilesAndDirectories); | |||
| while (iter.next()) | |||
| { | |||
| const File f (iter.getFile()); | |||
| bool isPlugin = false; | |||
| if (fileMightContainThisPluginType (f.getFullPathName())) | |||
| { | |||
| isPlugin = true; | |||
| results.add (f.getFullPathName()); | |||
| } | |||
| if (recursive && (! isPlugin) && f.isDirectory()) | |||
| recursiveFileSearch (results, f, true); | |||
| } | |||
| } | |||
| const FileSearchPath VSTPluginFormat::getDefaultLocationsToSearch() | |||
| { | |||
| #if JUCE_MAC | |||
| @@ -3059,6 +3098,7 @@ const FileSearchPath VSTPluginFormat::getDefaultLocationsToSearch() | |||
| #endif | |||
| } | |||
| END_JUCE_NAMESPACE | |||
| #endif | |||
| @@ -50,9 +50,11 @@ public: | |||
| //============================================================================== | |||
| const String getName() const { return "VST"; } | |||
| void findAllTypesForFile (OwnedArray <PluginDescription>& results, const File& file); | |||
| void findAllTypesForFile (OwnedArray <PluginDescription>& results, const String& fileOrIdentifier); | |||
| AudioPluginInstance* createInstanceFromDescription (const PluginDescription& desc); | |||
| bool fileMightContainThisPluginType (const File& file); | |||
| bool fileMightContainThisPluginType (const String& fileOrIdentifier); | |||
| const String getNameOfPluginFromIdentifier (const String& fileOrIdentifier); | |||
| const StringArray searchPathsForPlugins (const FileSearchPath& directoriesToSearch, const bool recursive); | |||
| bool doesPluginStillExist (const PluginDescription& desc); | |||
| const FileSearchPath getDefaultLocationsToSearch(); | |||
| @@ -62,6 +64,8 @@ public: | |||
| private: | |||
| VSTPluginFormat (const VSTPluginFormat&); | |||
| const VSTPluginFormat& operator= (const VSTPluginFormat&); | |||
| void recursiveFileSearch (StringArray& results, const File& dir, const bool recursive); | |||
| }; | |||
| @@ -68,7 +68,7 @@ public: | |||
| subtypes, so in that case, each subtype is returned as a separate object. | |||
| */ | |||
| virtual void findAllTypesForFile (OwnedArray <PluginDescription>& results, | |||
| const File& file) = 0; | |||
| const String& fileOrIdentifier) = 0; | |||
| /** Tries to recreate a type from a previously generated PluginDescription. | |||
| @@ -82,7 +82,11 @@ public: | |||
| This is for searching for potential files, so it shouldn't actually try to | |||
| load the plugin or do anything time-consuming. | |||
| */ | |||
| virtual bool fileMightContainThisPluginType (const File& file) = 0; | |||
| virtual bool fileMightContainThisPluginType (const String& fileOrIdentifier) = 0; | |||
| /** Returns a readable version of the name of the plugin that this identifier refers to. | |||
| */ | |||
| virtual const String getNameOfPluginFromIdentifier (const String& fileOrIdentifier) = 0; | |||
| /** Checks whether this plugin could possibly be loaded. | |||
| @@ -91,6 +95,13 @@ public: | |||
| */ | |||
| virtual bool doesPluginStillExist (const PluginDescription& desc) = 0; | |||
| /** Searches a suggested set of directories for any plugins in this format. | |||
| The path might be ignored, e.g. by AUs, which are found by the OS rather | |||
| than manually. | |||
| */ | |||
| virtual const StringArray searchPathsForPlugins (const FileSearchPath& directoriesToSearch, | |||
| const bool recursive) = 0; | |||
| /** Returns the typical places to look for this kind of plugin. | |||
| @@ -79,14 +79,14 @@ void AudioPluginFormatManager::addDefaultFormats() | |||
| } | |||
| #endif | |||
| #if JUCE_PLUGINHOST_VST | |||
| formats.add (new VSTPluginFormat()); | |||
| #endif | |||
| #if JUCE_PLUGINHOST_AU && JUCE_MAC | |||
| formats.add (new AudioUnitPluginFormat()); | |||
| #endif | |||
| #if JUCE_PLUGINHOST_VST | |||
| formats.add (new VSTPluginFormat()); | |||
| #endif | |||
| #if JUCE_PLUGINHOST_DX && JUCE_WIN32 | |||
| formats.add (new DirectXPluginFormat()); | |||
| #endif | |||
| @@ -55,10 +55,10 @@ void KnownPluginList::clear() | |||
| } | |||
| } | |||
| PluginDescription* KnownPluginList::getTypeForFile (const File& file) const throw() | |||
| PluginDescription* KnownPluginList::getTypeForFile (const String& fileOrIdentifier) const throw() | |||
| { | |||
| for (int i = 0; i < types.size(); ++i) | |||
| if (types.getUnchecked(i)->fileOrIdentifier == file.getFullPathName()) | |||
| if (types.getUnchecked(i)->fileOrIdentifier == fileOrIdentifier) | |||
| return types.getUnchecked(i); | |||
| return 0; | |||
| @@ -99,17 +99,33 @@ void KnownPluginList::removeType (const int index) throw() | |||
| sendChangeMessage (this); | |||
| } | |||
| bool KnownPluginList::isListingUpToDate (const File& possiblePluginFile) const throw() | |||
| static Time getFileModTime (const String& fileOrIdentifier) throw() | |||
| { | |||
| if (getTypeForFile (possiblePluginFile) == 0) | |||
| if (fileOrIdentifier.startsWithChar (T('/')) | |||
| || fileOrIdentifier[1] == T(':')) | |||
| { | |||
| return File (fileOrIdentifier).getLastModificationTime(); | |||
| } | |||
| return Time (0); | |||
| } | |||
| static bool timesAreDifferent (const Time& t1, const Time& t2) throw() | |||
| { | |||
| return t1 != t2 || t1 == Time (0); | |||
| } | |||
| bool KnownPluginList::isListingUpToDate (const String& fileOrIdentifier) const throw() | |||
| { | |||
| if (getTypeForFile (fileOrIdentifier) == 0) | |||
| return false; | |||
| for (int i = types.size(); --i >= 0;) | |||
| { | |||
| const PluginDescription* const d = types.getUnchecked(i); | |||
| if (d->fileOrIdentifier == possiblePluginFile.getFullPathName() | |||
| && d->lastFileModTime != possiblePluginFile.getLastModificationTime()) | |||
| if (d->fileOrIdentifier == fileOrIdentifier | |||
| && timesAreDifferent (d->lastFileModTime, getFileModTime (fileOrIdentifier))) | |||
| { | |||
| return false; | |||
| } | |||
| @@ -118,14 +134,15 @@ bool KnownPluginList::isListingUpToDate (const File& possiblePluginFile) const t | |||
| return true; | |||
| } | |||
| bool KnownPluginList::scanAndAddFile (const File& possiblePluginFile, | |||
| bool KnownPluginList::scanAndAddFile (const String& fileOrIdentifier, | |||
| const bool dontRescanIfAlreadyInList, | |||
| OwnedArray <PluginDescription>& typesFound) | |||
| OwnedArray <PluginDescription>& typesFound, | |||
| AudioPluginFormat& format) | |||
| { | |||
| bool addedOne = false; | |||
| if (dontRescanIfAlreadyInList | |||
| && getTypeForFile (possiblePluginFile) != 0) | |||
| && getTypeForFile (fileOrIdentifier) != 0) | |||
| { | |||
| bool needsRescanning = false; | |||
| @@ -133,9 +150,9 @@ bool KnownPluginList::scanAndAddFile (const File& possiblePluginFile, | |||
| { | |||
| const PluginDescription* const d = types.getUnchecked(i); | |||
| if (d->fileOrIdentifier == possiblePluginFile.getFullPathName()) | |||
| if (d->fileOrIdentifier == fileOrIdentifier) | |||
| { | |||
| if (d->lastFileModTime != possiblePluginFile.getLastModificationTime()) | |||
| if (timesAreDifferent (d->lastFileModTime, getFileModTime (fileOrIdentifier))) | |||
| needsRescanning = true; | |||
| else | |||
| typesFound.add (new PluginDescription (*d)); | |||
| @@ -146,23 +163,18 @@ bool KnownPluginList::scanAndAddFile (const File& possiblePluginFile, | |||
| return false; | |||
| } | |||
| for (int i = 0; i < AudioPluginFormatManager::getInstance()->getNumFormats(); ++i) | |||
| { | |||
| AudioPluginFormat* const format = AudioPluginFormatManager::getInstance()->getFormat (i); | |||
| OwnedArray <PluginDescription> found; | |||
| format->findAllTypesForFile (found, possiblePluginFile); | |||
| OwnedArray <PluginDescription> found; | |||
| format.findAllTypesForFile (found, fileOrIdentifier); | |||
| for (int i = 0; i < found.size(); ++i) | |||
| { | |||
| PluginDescription* const desc = found.getUnchecked(i); | |||
| jassert (desc != 0); | |||
| for (int i = 0; i < found.size(); ++i) | |||
| { | |||
| PluginDescription* const desc = found.getUnchecked(i); | |||
| jassert (desc != 0); | |||
| if (addType (*desc)) | |||
| addedOne = true; | |||
| if (addType (*desc)) | |||
| addedOne = true; | |||
| typesFound.add (new PluginDescription (*desc)); | |||
| } | |||
| typesFound.add (new PluginDescription (*desc)); | |||
| } | |||
| return addedOne; | |||
| @@ -173,10 +185,20 @@ void KnownPluginList::scanAndAddDragAndDroppedFiles (const StringArray& files, | |||
| { | |||
| for (int i = 0; i < files.size(); ++i) | |||
| { | |||
| const File f (files [i]); | |||
| bool loaded = false; | |||
| for (int j = 0; j < AudioPluginFormatManager::getInstance()->getNumFormats(); ++j) | |||
| { | |||
| AudioPluginFormat* const format = AudioPluginFormatManager::getInstance()->getFormat (j); | |||
| if (scanAndAddFile (files[i], true, typesFound, *format)) | |||
| loaded = true; | |||
| } | |||
| if (! scanAndAddFile (f, true, typesFound)) | |||
| if (! loaded) | |||
| { | |||
| const File f (files[i]); | |||
| if (f.isDirectory()) | |||
| { | |||
| StringArray s; | |||
| @@ -350,7 +372,13 @@ public: | |||
| PopupMenu subMenu; | |||
| sub->addToMenu (subMenu, allPlugins); | |||
| #if JUCE_MAC | |||
| // avoid the special AU formatting nonsense on Mac.. | |||
| m.addSubMenu (sub->folder.fromFirstOccurrenceOf (T(":"), false, false), subMenu); | |||
| #else | |||
| m.addSubMenu (sub->folder, subMenu); | |||
| #endif | |||
| } | |||
| for (i = 0; i < plugins.size(); ++i) | |||
| @@ -74,7 +74,7 @@ public: | |||
| /** Looks for a type in the list which comes from this file. | |||
| */ | |||
| PluginDescription* getTypeForFile (const File& file) const throw(); | |||
| PluginDescription* getTypeForFile (const String& fileOrIdentifier) const throw(); | |||
| /** Looks for a type in the list which matches a plugin type ID. | |||
| @@ -101,14 +101,15 @@ public: | |||
| file (even if it was already known and hasn't been re-scanned) get returned | |||
| in the array. | |||
| */ | |||
| bool scanAndAddFile (const File& possiblePluginFile, | |||
| bool scanAndAddFile (const String& possiblePluginFileOrIdentifier, | |||
| const bool dontRescanIfAlreadyInList, | |||
| OwnedArray <PluginDescription>& typesFound); | |||
| OwnedArray <PluginDescription>& typesFound, | |||
| AudioPluginFormat& formatToUse); | |||
| /** Returns true if the specified file is already known about and if it | |||
| hasn't been modified since our entry was created. | |||
| */ | |||
| bool isListingUpToDate (const File& possiblePluginFile) const throw(); | |||
| bool isListingUpToDate (const String& possiblePluginFileOrIdentifier) const throw(); | |||
| /** Scans and adds a bunch of files that might have been dragged-and-dropped. | |||
| @@ -75,10 +75,10 @@ public: | |||
| String version; | |||
| /** Either the file containing the plugin module, or some other unique way | |||
| of identifying it. | |||
| E.g. for an AU, this would be the component ID, because not all AUs actually | |||
| live in a file... | |||
| of identifying it. | |||
| E.g. for an AU, this would be an ID string that the component manager | |||
| could use to retrieve the plugin. For a VST, it's the file path. | |||
| */ | |||
| String fileOrIdentifier; | |||
| @@ -52,8 +52,7 @@ PluginDirectoryScanner::PluginDirectoryScanner (KnownPluginList& listToAddTo, | |||
| { | |||
| directoriesToSearch.removeRedundantPaths(); | |||
| for (int j = 0; j < directoriesToSearch.getNumPaths(); ++j) | |||
| recursiveFileSearch (directoriesToSearch [j], recursive); | |||
| filesOrIdentifiersToScan = format.searchPathsForPlugins (directoriesToSearch, recursive); | |||
| // If any plugins have crashed recently when being loaded, move them to the | |||
| // end of the list to give the others a chance to load correctly.. | |||
| @@ -61,33 +60,11 @@ PluginDirectoryScanner::PluginDirectoryScanner (KnownPluginList& listToAddTo, | |||
| for (int i = 0; i < crashedPlugins.size(); ++i) | |||
| { | |||
| const File f (crashedPlugins[i]); | |||
| const String f = crashedPlugins[i]; | |||
| for (int j = filesToScan.size(); --j >= 0;) | |||
| if (f == *filesToScan.getUnchecked (j)) | |||
| filesToScan.move (j, -1); | |||
| } | |||
| } | |||
| void PluginDirectoryScanner::recursiveFileSearch (const File& dir, const bool recursive) | |||
| { | |||
| // avoid allowing the dir iterator to be recursive, because we want to avoid letting it delve inside | |||
| // .component or .vst directories. | |||
| DirectoryIterator iter (dir, false, "*", File::findFilesAndDirectories); | |||
| while (iter.next()) | |||
| { | |||
| const File f (iter.getFile()); | |||
| bool isPlugin = false; | |||
| if (format.fileMightContainThisPluginType (f)) | |||
| { | |||
| isPlugin = true; | |||
| filesToScan.add (new File (f)); | |||
| } | |||
| if (recursive && (! isPlugin) && f.isDirectory()) | |||
| recursiveFileSearch (f, true); | |||
| for (int j = filesOrIdentifiersToScan.size(); --j >= 0;) | |||
| if (f == filesOrIdentifiersToScan[j]) | |||
| filesOrIdentifiersToScan.move (j, -1); | |||
| } | |||
| } | |||
| @@ -96,49 +73,45 @@ PluginDirectoryScanner::~PluginDirectoryScanner() | |||
| } | |||
| //============================================================================== | |||
| const File PluginDirectoryScanner::getNextPluginFileThatWillBeScanned() const throw() | |||
| const String PluginDirectoryScanner::getNextPluginFileThatWillBeScanned() const throw() | |||
| { | |||
| File* const file = filesToScan [nextIndex]; | |||
| if (file != 0) | |||
| return *file; | |||
| return File::nonexistent; | |||
| return format.getNameOfPluginFromIdentifier (filesOrIdentifiersToScan [nextIndex]); | |||
| } | |||
| bool PluginDirectoryScanner::scanNextFile (const bool dontRescanIfAlreadyInList) | |||
| { | |||
| File* const file = filesToScan [nextIndex]; | |||
| String file (filesOrIdentifiersToScan [nextIndex]); | |||
| if (file != 0) | |||
| if (file.isNotEmpty()) | |||
| { | |||
| if (! list.isListingUpToDate (*file)) | |||
| if (! list.isListingUpToDate (file)) | |||
| { | |||
| OwnedArray <PluginDescription> typesFound; | |||
| // Add this plugin to the end of the dead-man's pedal list in case it crashes... | |||
| StringArray crashedPlugins (getDeadMansPedalFile()); | |||
| crashedPlugins.removeString (file->getFullPathName()); | |||
| crashedPlugins.add (file->getFullPathName()); | |||
| crashedPlugins.removeString (file); | |||
| crashedPlugins.add (file); | |||
| setDeadMansPedalFile (crashedPlugins); | |||
| list.scanAndAddFile (*file, | |||
| list.scanAndAddFile (file, | |||
| dontRescanIfAlreadyInList, | |||
| typesFound); | |||
| typesFound, | |||
| format); | |||
| // Managed to load without crashing, so remove it from the dead-man's-pedal.. | |||
| crashedPlugins.removeString (file->getFullPathName()); | |||
| crashedPlugins.removeString (file); | |||
| setDeadMansPedalFile (crashedPlugins); | |||
| if (typesFound.size() == 0) | |||
| failedFiles.add (file->getFullPathName()); | |||
| failedFiles.add (file); | |||
| } | |||
| ++nextIndex; | |||
| progress = nextIndex / (float) filesToScan.size(); | |||
| progress = nextIndex / (float) filesOrIdentifiersToScan.size(); | |||
| } | |||
| return nextIndex < filesToScan.size(); | |||
| return nextIndex < filesOrIdentifiersToScan.size(); | |||
| } | |||
| const StringArray PluginDirectoryScanner::getDeadMansPedalFile() throw() | |||
| @@ -89,12 +89,13 @@ public: | |||
| */ | |||
| bool scanNextFile (const bool dontRescanIfAlreadyInList); | |||
| /** Returns the file that will be scanned during the next call to scanNextFile(). | |||
| /** Returns the description of the plugin that will be scanned during the next | |||
| call to scanNextFile(). | |||
| This is handy if you want to show the user which file is currently getting | |||
| scanned. | |||
| */ | |||
| const File getNextPluginFileThatWillBeScanned() const throw(); | |||
| const String getNextPluginFileThatWillBeScanned() const throw(); | |||
| /** Returns the estimated progress, between 0 and 1. | |||
| */ | |||
| @@ -111,13 +112,12 @@ public: | |||
| private: | |||
| KnownPluginList& list; | |||
| AudioPluginFormat& format; | |||
| OwnedArray <File> filesToScan; | |||
| StringArray filesOrIdentifiersToScan; | |||
| File deadMansPedalFile; | |||
| StringArray failedFiles; | |||
| int nextIndex; | |||
| float progress; | |||
| void recursiveFileSearch (const File& dir, const bool recursive); | |||
| const StringArray getDeadMansPedalFile() throw(); | |||
| void setDeadMansPedalFile (const StringArray& newContents) throw(); | |||
| @@ -279,7 +279,7 @@ void PluginListComponent::scanFor (AudioPluginFormat* format) | |||
| for (;;) | |||
| { | |||
| aw.setMessage (TRANS("Testing:\n\n") | |||
| + scanner.getNextPluginFileThatWillBeScanned().getFileName()); | |||
| + scanner.getNextPluginFileThatWillBeScanned()); | |||
| MessageManager::getInstance()->runDispatchLoopUntil (20); | |||
| @@ -181,8 +181,8 @@ public: | |||
| The component must already be on the desktop for this method to work. It will | |||
| be resized to completely fill the screen and any extraneous taskbars, menu bars, | |||
| etc will be hidden. | |||
| To exit kiosk mode, just call setKioskModeComponent (0). When this is called, | |||
| To exit kiosk mode, just call setKioskModeComponent (0). When this is called, | |||
| the component that's currently being used will be resized back to the size | |||
| and position it was in before being put into this mode. | |||
| */ | |||
| @@ -149,9 +149,9 @@ public: | |||
| not to delete a model while it is being used. | |||
| An optional extra menu can be specified, containing items to add to the top of | |||
| the apple menu. (Confusingly, the 'apple' menu isn't the one with a picture of | |||
| an apple, it's the one next to it, with your application's name at the top | |||
| and the services menu etc on it). When one of these items is selected, the | |||
| the apple menu. (Confusingly, the 'apple' menu isn't the one with a picture of | |||
| an apple, it's the one next to it, with your application's name at the top | |||
| and the services menu etc on it). When one of these items is selected, the | |||
| menu bar model will be used to invoke it, and in the menuItemSelected() callback | |||
| the topLevelMenuIndex parameter will be -1. If you pass in an extraAppleMenuItems | |||
| object then newMenuBarModel must be non-null. | |||
| @@ -113,7 +113,7 @@ public: | |||
| { | |||
| Component* const over = dynamic_cast <Component*> (currentlyOver); | |||
| // (note: use a local copy of the dragDesc member in case the callback runs | |||
| // (note: use a local copy of the dragDesc member in case the callback runs | |||
| // a modal loop and deletes this object before the method completes) | |||
| const String dragDescLocal (dragDesc); | |||
| @@ -163,7 +163,7 @@ public: | |||
| hit = hit->getComponentAt (rx, ry); | |||
| } | |||
| // (note: use a local copy of the dragDesc member in case the callback runs | |||
| // (note: use a local copy of the dragDesc member in case the callback runs | |||
| // a modal loop and deletes this object before the method completes) | |||
| const String dragDescLocal (dragDesc); | |||
| @@ -234,7 +234,7 @@ public: | |||
| if (dropAccepted && ddt != 0) | |||
| { | |||
| // (note: use a local copy of the dragDesc member in case the callback runs | |||
| // (note: use a local copy of the dragDesc member in case the callback runs | |||
| // a modal loop and deletes this object before the method completes) | |||
| const String dragDescLocal (dragDesc); | |||
| @@ -247,7 +247,7 @@ public: | |||
| void updateLocation (const bool canDoExternalDrag, int x, int y) | |||
| { | |||
| // (note: use a local copy of the dragDesc member in case the callback runs | |||
| // (note: use a local copy of the dragDesc member in case the callback runs | |||
| // a modal loop and deletes this object before it returns) | |||
| const String dragDescLocal (dragDesc); | |||