diff --git a/build/linux/platform_specific_code/juce_linux_Files.cpp b/build/linux/platform_specific_code/juce_linux_Files.cpp index a0753bb781..e56399426b 100644 --- a/build/linux/platform_specific_code/juce_linux_Files.cpp +++ b/build/linux/platform_specific_code/juce_linux_Files.cpp @@ -42,6 +42,7 @@ #include #include #include +#include #define U_ISOFS_SUPER_MAGIC (short) 0x9660 // linux/iso_fs.h #define U_MSDOS_SUPER_MAGIC (short) 0x4d44 // linux/msdos_fs.h @@ -261,6 +262,15 @@ const File File::getSpecialLocation (const SpecialLocationType type) case currentExecutableFile: case currentApplicationFile: + if (! executableFile.exists()) + { + Dl_info executableInfo; + dladdr ((const void*) juce_getFileTimes, &executableInfo); + + if (executableInfo.dli_fname != 0) + executableFile = File (String (executableInfo.dli_fname)); + } + // if this fails, it's probably because juce_setCurrentExecutableFileName() // was never called to set the filename - this should be done by the juce // main() function, so maybe you've hacked it to use your own custom main()? diff --git a/build/linux/platform_specific_code/juce_linux_Windowing.cpp b/build/linux/platform_specific_code/juce_linux_Windowing.cpp index 5e5385b243..09ca26f3fd 100644 --- a/build/linux/platform_specific_code/juce_linux_Windowing.cpp +++ b/build/linux/platform_specific_code/juce_linux_Windowing.cpp @@ -660,8 +660,6 @@ public: int ls, ps; const uint8* const pixels = lockPixelDataReadOnly (0, 0, getWidth(), getHeight(), ls, ps); - jassert (! isARGB()) - for (int y = sy; y < sy + dh; ++y) { const uint8* p = pixels + y * ls + sx * ps; @@ -1961,16 +1959,16 @@ private: { int netHints [2]; int numHints = 0; - netHints[numHints] = XInternAtom (display, "_KDE_NET_WM_WINDOW_TYPE_OVERRIDE", True); - - if (netHints [numHints] != 0) - ++numHints; - if ((styleFlags & windowIsTemporary) != 0) netHints [numHints] = XInternAtom (display, "_NET_WM_WINDOW_TYPE_MENU", True); else netHints [numHints] = XInternAtom (display, "_NET_WM_WINDOW_TYPE_NORMAL", True); + if (netHints [numHints] != 0) + ++numHints; + + netHints[numHints] = XInternAtom (display, "_KDE_NET_WM_WINDOW_TYPE_OVERRIDE", True); + if (netHints [numHints] != 0) ++numHints; diff --git a/build/macosx/platform_specific_code/juce_mac_MessageManager.mm b/build/macosx/platform_specific_code/juce_mac_MessageManager.mm index f3c9d90f59..b8721da152 100644 --- a/build/macosx/platform_specific_code/juce_mac_MessageManager.mm +++ b/build/macosx/platform_specific_code/juce_mac_MessageManager.mm @@ -1,462 +1,463 @@ -/* - ============================================================================== - - This file is part of the JUCE library - "Jules' Utility Class Extensions" - Copyright 2004-7 by Raw Material Software ltd. - - ------------------------------------------------------------------------------ - - JUCE can be redistributed and/or modified under the terms of the - GNU General Public License, as published by the Free Software Foundation; - either version 2 of the License, or (at your option) any later version. - - JUCE is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with JUCE; if not, visit www.gnu.org/licenses or write to the - Free Software Foundation, Inc., 59 Temple Place, Suite 330, - Boston, MA 02111-1307 USA - - ------------------------------------------------------------------------------ - - If you'd like to release a closed-source product which uses JUCE, commercial - licenses are also available: visit www.rawmaterialsoftware.com/juce for - more information. - - ============================================================================== -*/ - -// (This file gets included by juce_mac_NativeCode.mm, rather than being -// compiled on its own). -#ifdef JUCE_INCLUDED_FILE - -struct CallbackMessagePayload -{ - MessageCallbackFunction* function; - void* parameter; - void* volatile result; - bool volatile hasBeenExecuted; -}; - -/* When you use multiple DLLs which share similarly-named obj-c classes - like - for example having more than one juce plugin loaded into a host, then when a - method is called, the actual code that runs might actually be in a different module - than the one you expect... So any calls to library functions or statics that are - made inside obj-c methods will probably end up getting executed in a different DLL's - memory space. Not a great thing to happen - this obviously leads to bizarre crashes. - - To work around this insanity, I'm only allowing obj-c methods to make calls to - virtual methods of an object that's known to live inside the right module's space. -*/ -class AppDelegateRedirector -{ -public: - AppDelegateRedirector() {} - virtual ~AppDelegateRedirector() {} - - virtual NSApplicationTerminateReply shouldTerminate() - { - if (JUCEApplication::getInstance() != 0) - { - JUCEApplication::getInstance()->systemRequestedQuit(); - return NSTerminateCancel; - } - - return NSTerminateNow; - } - - virtual BOOL openFile (const NSString* filename) - { - if (JUCEApplication::getInstance() != 0) - { - JUCEApplication::getInstance()->anotherInstanceStarted (nsStringToJuce (filename)); - return YES; - } - - return NO; - } - - virtual void openFiles (NSArray* filenames) - { - StringArray files; - for (unsigned int i = 0; i < [filenames count]; ++i) - files.add (nsStringToJuce ((NSString*) [filenames objectAtIndex: i])); - - if (files.size() > 0 && JUCEApplication::getInstance() != 0) - { - JUCEApplication::getInstance()->anotherInstanceStarted (files.joinIntoString (T(" "))); - } - } - - virtual void focusChanged() - { - juce_HandleProcessFocusChange(); - } - - virtual void deliverMessage (void* message) - { - // no need for an mm lock here - deliverMessage locks it - MessageManager::getInstance()->deliverMessage (message); - } - - virtual void performCallback (CallbackMessagePayload* pl) - { - pl->result = (*pl->function) (pl->parameter); - pl->hasBeenExecuted = true; - } - - virtual void deleteSelf() - { - delete this; - } -}; - -END_JUCE_NAMESPACE -using namespace JUCE_NAMESPACE; - -#define JuceAppDelegate MakeObjCClassName(JuceAppDelegate) - -static int numPendingMessages = 0; -static bool flushingMessages = false; - -@interface JuceAppDelegate : NSObject -{ -@private - id oldDelegate; - AppDelegateRedirector* redirector; -} - -- (JuceAppDelegate*) init; -- (void) dealloc; -- (BOOL) application: (NSApplication*) theApplication openFile: (NSString*) filename; -- (void) application: (NSApplication*) sender openFiles: (NSArray*) filenames; -- (NSApplicationTerminateReply) applicationShouldTerminate: (NSApplication*) app; -- (void) applicationDidBecomeActive: (NSNotification*) aNotification; -- (void) applicationDidResignActive: (NSNotification*) aNotification; -- (void) applicationWillUnhide: (NSNotification*) aNotification; -- (void) customEvent: (id) data; -- (void) performCallback: (id) info; -- (void) dummyMethod; -@end - -@implementation JuceAppDelegate - -- (JuceAppDelegate*) init -{ - [super init]; - - redirector = new AppDelegateRedirector(); - numPendingMessages = 0; - flushingMessages = false; - - NSNotificationCenter* center = [NSNotificationCenter defaultCenter]; - - if (JUCEApplication::getInstance() != 0) - { - oldDelegate = [NSApp delegate]; - [NSApp setDelegate: self]; - } - else - { - oldDelegate = 0; - [center addObserver: self selector: @selector (applicationDidResignActive:) - name: NSApplicationDidResignActiveNotification object: NSApp]; - - [center addObserver: self selector: @selector (applicationDidBecomeActive:) - name: NSApplicationDidBecomeActiveNotification object: NSApp]; - - [center addObserver: self selector: @selector (applicationWillUnhide:) - name: NSApplicationWillUnhideNotification object: NSApp]; - - } - - return self; -} - -- (void) dealloc -{ - if (oldDelegate != 0) - [NSApp setDelegate: oldDelegate]; - - redirector->deleteSelf(); - [super dealloc]; -} - -- (NSApplicationTerminateReply) applicationShouldTerminate: (NSApplication*) app -{ - return redirector->shouldTerminate(); -} - -- (BOOL) application: (NSApplication*) app openFile: (NSString*) filename -{ - return redirector->openFile (filename); -} - -- (void) application: (NSApplication*) sender openFiles: (NSArray*) filenames -{ - return redirector->openFiles (filenames); -} - -- (void) applicationDidBecomeActive: (NSNotification*) aNotification -{ - redirector->focusChanged(); -} - -- (void) applicationDidResignActive: (NSNotification*) aNotification -{ - redirector->focusChanged(); -} - -- (void) applicationWillUnhide: (NSNotification*) aNotification -{ - redirector->focusChanged(); -} - -- (void) customEvent: (id) n -{ - atomicDecrement (numPendingMessages); - - NSData* data = (NSData*) n; - void* message = 0; - [data getBytes: &message length: sizeof (message)]; - - if (message != 0 && ! flushingMessages) - redirector->deliverMessage (message); - - [data release]; -} - -- (void) performCallback: (id) info -{ - if ([info isKindOfClass: [NSData class]]) - { - CallbackMessagePayload* pl = (CallbackMessagePayload*) [((NSData*) info) bytes]; - - if (pl != 0) - redirector->performCallback (pl); - } - else - { - jassertfalse // should never get here! - } -} - -- (void) dummyMethod {} // (used as a way of running a dummy thread) - -@end - -BEGIN_JUCE_NAMESPACE - -static JuceAppDelegate* juceAppDelegate = 0; - -void MessageManager::runDispatchLoop() -{ - if (! quitMessagePosted) // check that the quit message wasn't already posted.. - { - const ScopedAutoReleasePool pool; - - // must only be called by the message thread! - jassert (isThisTheMessageThread()); - - [NSApp run]; - } -} - -void MessageManager::stopDispatchLoop() -{ - quitMessagePosted = true; - [NSApp stop: nil]; -} - -static bool isEventBlockedByModalComps (NSEvent* e) -{ - if (Component::getNumCurrentlyModalComponents() == 0) - return false; - - NSWindow* const w = [e window]; - if (w == 0 || [w worksWhenModal]) - return false; - - bool isKey = false, isInputAttempt = false; - - switch ([e type]) - { - case NSKeyDown: - case NSKeyUp: - isKey = isInputAttempt = true; - break; - - case NSLeftMouseDown: - case NSRightMouseDown: - case NSOtherMouseDown: - isInputAttempt = true; - break; - - case NSLeftMouseDragged: - case NSRightMouseDragged: - case NSLeftMouseUp: - case NSRightMouseUp: - case NSOtherMouseUp: - case NSOtherMouseDragged: - if (Component::getComponentUnderMouse() != 0) - return false; - break; - - case NSMouseMoved: - case NSMouseEntered: - case NSMouseExited: - case NSCursorUpdate: - case NSScrollWheel: - case NSTabletPoint: - case NSTabletProximity: - break; - - default: - return false; - } - - for (int i = ComponentPeer::getNumPeers(); --i >= 0;) - { - ComponentPeer* const peer = ComponentPeer::getPeer (i); - NSView* const compView = (NSView*) peer->getNativeHandle(); - - if ([compView window] == w) - { - if (isKey) - { - if (compView == [w firstResponder]) - return false; - } - else - { - if (NSPointInRect ([compView convertPoint: [e locationInWindow] fromView: nil], - [compView bounds])) - return false; - } - } - } - - if (isInputAttempt) - { - if (! [NSApp isActive]) - [NSApp activateIgnoringOtherApps: YES]; - - Component* const modal = Component::getCurrentlyModalComponent (0); - if (modal != 0) - modal->inputAttemptWhenModal(); - } - - return true; -} - -bool MessageManager::runDispatchLoopUntil (int millisecondsToRunFor) -{ - const ScopedAutoReleasePool pool; - jassert (isThisTheMessageThread()); // must only be called by the message thread - - uint32 endTime = Time::getMillisecondCounter() + millisecondsToRunFor; - NSDate* endDate = [NSDate dateWithTimeIntervalSinceNow: millisecondsToRunFor * 0.001]; - - while (Time::getMillisecondCounter() < endTime && ! quitMessagePosted) - { - const ScopedAutoReleasePool pool; - - [[NSRunLoop currentRunLoop] runMode: NSDefaultRunLoopMode - beforeDate: endDate]; - - NSEvent* e = [NSApp nextEventMatchingMask: NSAnyEventMask - untilDate: endDate - inMode: NSDefaultRunLoopMode - dequeue: YES]; - - if (e != 0 && ! isEventBlockedByModalComps (e)) - [NSApp sendEvent: e]; - } - - return ! quitMessagePosted; -} - -//============================================================================== -void MessageManager::doPlatformSpecificInitialisation() -{ - if (juceAppDelegate == 0) - juceAppDelegate = [[JuceAppDelegate alloc] init]; - - // This launches a dummy thread, which forces Cocoa to initialise NSThreads - // correctly (needed prior to 10.5) - if (! [NSThread isMultiThreaded]) - [NSThread detachNewThreadSelector: @selector (dummyMethod) - toTarget: juceAppDelegate - withObject: nil]; - - initialiseMainMenu(); -} - -void MessageManager::doPlatformSpecificShutdown() -{ - [[NSRunLoop currentRunLoop] cancelPerformSelectorsWithTarget: juceAppDelegate]; - [[NSNotificationCenter defaultCenter] removeObserver: juceAppDelegate]; - - // Annoyingly, cancelPerformSelectorsWithTarget can't actually cancel the messages - // sent by performSelectorOnMainThread, so need to manually flush these before quitting.. - for (int i = 100; --i >= 0 && numPendingMessages > 0;) - { - flushingMessages = true; - getInstance()->runDispatchLoopUntil (10); - } - - [juceAppDelegate release]; - juceAppDelegate = 0; -} - -bool juce_postMessageToSystemQueue (void* message) -{ - atomicIncrement (numPendingMessages); - - [juceAppDelegate performSelectorOnMainThread: @selector (customEvent:) - withObject: (id) [[NSData alloc] initWithBytes: &message - length: (int) sizeof (message)] - waitUntilDone: NO]; - return true; -} - -void MessageManager::broadcastMessage (const String& value) throw() -{ -} - -void* MessageManager::callFunctionOnMessageThread (MessageCallbackFunction* callback, - void* data) -{ - if (isThisTheMessageThread()) - { - return (*callback) (data); - } - else - { - // If a thread has a MessageManagerLock and then tries to call this method, it'll - // deadlock because the message manager is blocked from running, so can never - // call your function.. - jassert (! MessageManager::getInstance()->currentThreadHasLockedMessageManager()); - - const ScopedAutoReleasePool pool; - - CallbackMessagePayload cmp; - cmp.function = callback; - cmp.parameter = data; - cmp.result = 0; - cmp.hasBeenExecuted = false; - - [juceAppDelegate performSelectorOnMainThread: @selector (performCallback:) - withObject: [NSData dataWithBytesNoCopy: &cmp - length: sizeof (cmp) - freeWhenDone: NO] - waitUntilDone: YES]; - - return cmp.result; - } -} - -#endif +/* + ============================================================================== + + This file is part of the JUCE library - "Jules' Utility Class Extensions" + Copyright 2004-7 by Raw Material Software ltd. + + ------------------------------------------------------------------------------ + + JUCE can be redistributed and/or modified under the terms of the + GNU General Public License, as published by the Free Software Foundation; + either version 2 of the License, or (at your option) any later version. + + JUCE is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with JUCE; if not, visit www.gnu.org/licenses or write to the + Free Software Foundation, Inc., 59 Temple Place, Suite 330, + Boston, MA 02111-1307 USA + + ------------------------------------------------------------------------------ + + If you'd like to release a closed-source product which uses JUCE, commercial + licenses are also available: visit www.rawmaterialsoftware.com/juce for + more information. + + ============================================================================== +*/ + +// (This file gets included by juce_mac_NativeCode.mm, rather than being +// compiled on its own). +#ifdef JUCE_INCLUDED_FILE + +struct CallbackMessagePayload +{ + MessageCallbackFunction* function; + void* parameter; + void* volatile result; + bool volatile hasBeenExecuted; +}; + +/* When you use multiple DLLs which share similarly-named obj-c classes - like + for example having more than one juce plugin loaded into a host, then when a + method is called, the actual code that runs might actually be in a different module + than the one you expect... So any calls to library functions or statics that are + made inside obj-c methods will probably end up getting executed in a different DLL's + memory space. Not a great thing to happen - this obviously leads to bizarre crashes. + + To work around this insanity, I'm only allowing obj-c methods to make calls to + virtual methods of an object that's known to live inside the right module's space. +*/ +class AppDelegateRedirector +{ +public: + AppDelegateRedirector() {} + virtual ~AppDelegateRedirector() {} + + virtual NSApplicationTerminateReply shouldTerminate() + { + if (JUCEApplication::getInstance() != 0) + { + JUCEApplication::getInstance()->systemRequestedQuit(); + return NSTerminateCancel; + } + + return NSTerminateNow; + } + + virtual BOOL openFile (const NSString* filename) + { + if (JUCEApplication::getInstance() != 0) + { + JUCEApplication::getInstance()->anotherInstanceStarted (nsStringToJuce (filename)); + return YES; + } + + return NO; + } + + virtual void openFiles (NSArray* filenames) + { + StringArray files; + for (unsigned int i = 0; i < [filenames count]; ++i) + files.add (nsStringToJuce ((NSString*) [filenames objectAtIndex: i])); + + if (files.size() > 0 && JUCEApplication::getInstance() != 0) + { + JUCEApplication::getInstance()->anotherInstanceStarted (files.joinIntoString (T(" "))); + } + } + + virtual void focusChanged() + { + juce_HandleProcessFocusChange(); + } + + virtual void deliverMessage (void* message) + { + // no need for an mm lock here - deliverMessage locks it + MessageManager::getInstance()->deliverMessage (message); + } + + virtual void performCallback (CallbackMessagePayload* pl) + { + pl->result = (*pl->function) (pl->parameter); + pl->hasBeenExecuted = true; + } + + virtual void deleteSelf() + { + delete this; + } +}; + +END_JUCE_NAMESPACE +using namespace JUCE_NAMESPACE; + +#define JuceAppDelegate MakeObjCClassName(JuceAppDelegate) + +static int numPendingMessages = 0; +static bool flushingMessages = false; + +@interface JuceAppDelegate : NSObject +{ +@private + id oldDelegate; + AppDelegateRedirector* redirector; +} + +- (JuceAppDelegate*) init; +- (void) dealloc; +- (BOOL) application: (NSApplication*) theApplication openFile: (NSString*) filename; +- (void) application: (NSApplication*) sender openFiles: (NSArray*) filenames; +- (NSApplicationTerminateReply) applicationShouldTerminate: (NSApplication*) app; +- (void) applicationDidBecomeActive: (NSNotification*) aNotification; +- (void) applicationDidResignActive: (NSNotification*) aNotification; +- (void) applicationWillUnhide: (NSNotification*) aNotification; +- (void) customEvent: (id) data; +- (void) performCallback: (id) info; +- (void) dummyMethod; +@end + +@implementation JuceAppDelegate + +- (JuceAppDelegate*) init +{ + [super init]; + + redirector = new AppDelegateRedirector(); + numPendingMessages = 0; + flushingMessages = false; + + NSNotificationCenter* center = [NSNotificationCenter defaultCenter]; + + if (JUCEApplication::getInstance() != 0) + { + oldDelegate = [NSApp delegate]; + [NSApp setDelegate: self]; + } + else + { + oldDelegate = 0; + [center addObserver: self selector: @selector (applicationDidResignActive:) + name: NSApplicationDidResignActiveNotification object: NSApp]; + + [center addObserver: self selector: @selector (applicationDidBecomeActive:) + name: NSApplicationDidBecomeActiveNotification object: NSApp]; + + [center addObserver: self selector: @selector (applicationWillUnhide:) + name: NSApplicationWillUnhideNotification object: NSApp]; + + } + + return self; +} + +- (void) dealloc +{ + if (oldDelegate != 0) + [NSApp setDelegate: oldDelegate]; + + redirector->deleteSelf(); + [super dealloc]; +} + +- (NSApplicationTerminateReply) applicationShouldTerminate: (NSApplication*) app +{ + return redirector->shouldTerminate(); +} + +- (BOOL) application: (NSApplication*) app openFile: (NSString*) filename +{ + return redirector->openFile (filename); +} + +- (void) application: (NSApplication*) sender openFiles: (NSArray*) filenames +{ + return redirector->openFiles (filenames); +} + +- (void) applicationDidBecomeActive: (NSNotification*) aNotification +{ + redirector->focusChanged(); +} + +- (void) applicationDidResignActive: (NSNotification*) aNotification +{ + redirector->focusChanged(); +} + +- (void) applicationWillUnhide: (NSNotification*) aNotification +{ + redirector->focusChanged(); +} + +- (void) customEvent: (id) n +{ + atomicDecrement (numPendingMessages); + + NSData* data = (NSData*) n; + void* message = 0; + [data getBytes: &message length: sizeof (message)]; + + if (message != 0 && ! flushingMessages) + redirector->deliverMessage (message); + + [data release]; +} + +- (void) performCallback: (id) info +{ + if ([info isKindOfClass: [NSData class]]) + { + CallbackMessagePayload* pl = (CallbackMessagePayload*) [((NSData*) info) bytes]; + + if (pl != 0) + redirector->performCallback (pl); + } + else + { + jassertfalse // should never get here! + } +} + +- (void) dummyMethod {} // (used as a way of running a dummy thread) + +@end + +BEGIN_JUCE_NAMESPACE + +static JuceAppDelegate* juceAppDelegate = 0; + +void MessageManager::runDispatchLoop() +{ + if (! quitMessagePosted) // check that the quit message wasn't already posted.. + { + const ScopedAutoReleasePool pool; + + // must only be called by the message thread! + jassert (isThisTheMessageThread()); + + [NSApp run]; + } +} + +void MessageManager::stopDispatchLoop() +{ + quitMessagePosted = true; + [NSApp stop: nil]; + [NSApp activateIgnoringOtherApps: YES]; // (if the app is inactive, it sits there and ignores the quit request until the next time it gets activated) +} + +static bool isEventBlockedByModalComps (NSEvent* e) +{ + if (Component::getNumCurrentlyModalComponents() == 0) + return false; + + NSWindow* const w = [e window]; + if (w == 0 || [w worksWhenModal]) + return false; + + bool isKey = false, isInputAttempt = false; + + switch ([e type]) + { + case NSKeyDown: + case NSKeyUp: + isKey = isInputAttempt = true; + break; + + case NSLeftMouseDown: + case NSRightMouseDown: + case NSOtherMouseDown: + isInputAttempt = true; + break; + + case NSLeftMouseDragged: + case NSRightMouseDragged: + case NSLeftMouseUp: + case NSRightMouseUp: + case NSOtherMouseUp: + case NSOtherMouseDragged: + if (Component::getComponentUnderMouse() != 0) + return false; + break; + + case NSMouseMoved: + case NSMouseEntered: + case NSMouseExited: + case NSCursorUpdate: + case NSScrollWheel: + case NSTabletPoint: + case NSTabletProximity: + break; + + default: + return false; + } + + for (int i = ComponentPeer::getNumPeers(); --i >= 0;) + { + ComponentPeer* const peer = ComponentPeer::getPeer (i); + NSView* const compView = (NSView*) peer->getNativeHandle(); + + if ([compView window] == w) + { + if (isKey) + { + if (compView == [w firstResponder]) + return false; + } + else + { + if (NSPointInRect ([compView convertPoint: [e locationInWindow] fromView: nil], + [compView bounds])) + return false; + } + } + } + + if (isInputAttempt) + { + if (! [NSApp isActive]) + [NSApp activateIgnoringOtherApps: YES]; + + Component* const modal = Component::getCurrentlyModalComponent (0); + if (modal != 0) + modal->inputAttemptWhenModal(); + } + + return true; +} + +bool MessageManager::runDispatchLoopUntil (int millisecondsToRunFor) +{ + const ScopedAutoReleasePool pool; + jassert (isThisTheMessageThread()); // must only be called by the message thread + + uint32 endTime = Time::getMillisecondCounter() + millisecondsToRunFor; + NSDate* endDate = [NSDate dateWithTimeIntervalSinceNow: millisecondsToRunFor * 0.001]; + + while (Time::getMillisecondCounter() < endTime && ! quitMessagePosted) + { + const ScopedAutoReleasePool pool; + + [[NSRunLoop currentRunLoop] runMode: NSDefaultRunLoopMode + beforeDate: endDate]; + + NSEvent* e = [NSApp nextEventMatchingMask: NSAnyEventMask + untilDate: endDate + inMode: NSDefaultRunLoopMode + dequeue: YES]; + + if (e != 0 && ! isEventBlockedByModalComps (e)) + [NSApp sendEvent: e]; + } + + return ! quitMessagePosted; +} + +//============================================================================== +void MessageManager::doPlatformSpecificInitialisation() +{ + if (juceAppDelegate == 0) + juceAppDelegate = [[JuceAppDelegate alloc] init]; + + // This launches a dummy thread, which forces Cocoa to initialise NSThreads + // correctly (needed prior to 10.5) + if (! [NSThread isMultiThreaded]) + [NSThread detachNewThreadSelector: @selector (dummyMethod) + toTarget: juceAppDelegate + withObject: nil]; + + initialiseMainMenu(); +} + +void MessageManager::doPlatformSpecificShutdown() +{ + [[NSRunLoop currentRunLoop] cancelPerformSelectorsWithTarget: juceAppDelegate]; + [[NSNotificationCenter defaultCenter] removeObserver: juceAppDelegate]; + + // Annoyingly, cancelPerformSelectorsWithTarget can't actually cancel the messages + // sent by performSelectorOnMainThread, so need to manually flush these before quitting.. + for (int i = 100; --i >= 0 && numPendingMessages > 0;) + { + flushingMessages = true; + getInstance()->runDispatchLoopUntil (10); + } + + [juceAppDelegate release]; + juceAppDelegate = 0; +} + +bool juce_postMessageToSystemQueue (void* message) +{ + atomicIncrement (numPendingMessages); + + [juceAppDelegate performSelectorOnMainThread: @selector (customEvent:) + withObject: (id) [[NSData alloc] initWithBytes: &message + length: (int) sizeof (message)] + waitUntilDone: NO]; + return true; +} + +void MessageManager::broadcastMessage (const String& value) throw() +{ +} + +void* MessageManager::callFunctionOnMessageThread (MessageCallbackFunction* callback, + void* data) +{ + if (isThisTheMessageThread()) + { + return (*callback) (data); + } + else + { + // If a thread has a MessageManagerLock and then tries to call this method, it'll + // deadlock because the message manager is blocked from running, so can never + // call your function.. + jassert (! MessageManager::getInstance()->currentThreadHasLockedMessageManager()); + + const ScopedAutoReleasePool pool; + + CallbackMessagePayload cmp; + cmp.function = callback; + cmp.parameter = data; + cmp.result = 0; + cmp.hasBeenExecuted = false; + + [juceAppDelegate performSelectorOnMainThread: @selector (performCallback:) + withObject: [NSData dataWithBytesNoCopy: &cmp + length: sizeof (cmp) + freeWhenDone: NO] + waitUntilDone: YES]; + + return cmp.result; + } +} + +#endif diff --git a/build/macosx/platform_specific_code/juce_mac_NSViewComponentPeer.mm b/build/macosx/platform_specific_code/juce_mac_NSViewComponentPeer.mm index e61e5c5b84..b6102a1a55 100644 --- a/build/macosx/platform_specific_code/juce_mac_NSViewComponentPeer.mm +++ b/build/macosx/platform_specific_code/juce_mac_NSViewComponentPeer.mm @@ -64,6 +64,9 @@ END_JUCE_NAMESPACE - (void) rightMouseDown: (NSEvent*) ev; - (void) rightMouseDragged: (NSEvent*) ev; - (void) rightMouseUp: (NSEvent*) ev; +- (void) otherMouseDown: (NSEvent*) ev; +- (void) otherMouseDragged: (NSEvent*) ev; +- (void) otherMouseUp: (NSEvent*) ev; - (void) scrollWheel: (NSEvent*) ev; - (BOOL) acceptsFirstMouse: (NSEvent*) ev; - (void) frameChanged: (NSNotification*) n; @@ -331,6 +334,21 @@ END_JUCE_NAMESPACE [self mouseUp: ev]; } +- (void) otherMouseDown: (NSEvent*) ev +{ + [self mouseDown: ev]; +} + +- (void) otherMouseDragged: (NSEvent*) ev +{ + [self mouseDragged: ev]; +} + +- (void) otherMouseUp: (NSEvent*) ev +{ + [self mouseUp: ev]; +} + - (void) scrollWheel: (NSEvent*) ev { if (owner != 0) diff --git a/build/win32/platform_specific_code/juce_win32_FileChooser.cpp b/build/win32/platform_specific_code/juce_win32_FileChooser.cpp index b558a0af93..e125c8b42c 100644 --- a/build/win32/platform_specific_code/juce_win32_FileChooser.cpp +++ b/build/win32/platform_specific_code/juce_win32_FileChooser.cpp @@ -70,7 +70,7 @@ static int CALLBACK browseCallbackProc (HWND hWnd, UINT msg, LPARAM lParam, LPAR return 0; } -void juce_setWindowStyleBit (HWND h, int styleType, int feature, bool bitIsSet) throw(); +void juce_setWindowStyleBit (HWND h, const int styleType, const int feature, const bool bitIsSet) throw(); static UINT_PTR CALLBACK openCallback (HWND hdlg, UINT uiMsg, WPARAM /*wParam*/, LPARAM lParam) { diff --git a/build/win32/platform_specific_code/juce_win32_Files.cpp b/build/win32/platform_specific_code/juce_win32_Files.cpp index 94c990e295..c406b09d5d 100644 --- a/build/win32/platform_specific_code/juce_win32_Files.cpp +++ b/build/win32/platform_specific_code/juce_win32_Files.cpp @@ -564,11 +564,10 @@ const File File::getLinkedTarget() const throw() else if (getFileExtension() != T(".lnk")) return result; - IShellLink* shellLink = 0; - if (SUCCEEDED (CoCreateInstance (CLSID_ShellLink, 0, CLSCTX_INPROC_SERVER, - IID_IShellLink, (LPVOID*) &shellLink))) + ComSmartPtr shellLink; + if (SUCCEEDED (shellLink.CoCreateInstance (CLSID_ShellLink, CLSCTX_INPROC_SERVER))) { - IPersistFile* persistFile; + ComSmartPtr persistFile; if (SUCCEEDED (shellLink->QueryInterface (IID_IPersistFile, (LPVOID*) &persistFile))) { if (SUCCEEDED (persistFile->Load ((const WCHAR*) p, STGM_READ)) @@ -580,11 +579,7 @@ const File File::getLinkedTarget() const throw() if (SUCCEEDED (shellLink->GetPath (resolvedPath, MAX_PATH, &winFindData, SLGP_UNCPRIORITY))) result = File (resolvedPath); } - - persistFile->Release(); } - - shellLink->Release(); } return result; diff --git a/build/win32/platform_specific_code/juce_win32_NativeIncludes.h b/build/win32/platform_specific_code/juce_win32_NativeIncludes.h index bb3a7c5895..10023dd811 100644 --- a/build/win32/platform_specific_code/juce_win32_NativeIncludes.h +++ b/build/win32/platform_specific_code/juce_win32_NativeIncludes.h @@ -153,4 +153,46 @@ #pragma warning (pop) #endif +//============================================================================== +/** A simple COM smart pointer. + Avoids having to include ATL just to get one of these. +*/ +template +class ComSmartPtr +{ +public: + ComSmartPtr() throw() : p (0) {} + ComSmartPtr (T* const p_) : p (p_) { if (p_ != 0) p_->AddRef(); } + ComSmartPtr (const ComSmartPtr& p_) : p (p_.p) { if (p != 0) p->AddRef(); } + ~ComSmartPtr() { if (p != 0) p->Release(); } + + operator T*() const throw() { return p; } + T& operator*() const throw() { return *p; } + T** operator&() throw() { return &p; } + T* operator->() const throw() { return p; } + + T* operator= (T* const newP) + { + if (newP != 0) + newP->AddRef(); + + if (p != 0) + p->Release(); + + p = newP; + return newP; + } + + T* operator= (const ComSmartPtr& newP) { return operator= (newP.p); } + + HRESULT CoCreateInstance (REFCLSID rclsid, DWORD dwClsContext) + { + operator= (0); + return ::CoCreateInstance (rclsid, 0, dwClsContext, __uuidof(T), (void**) &p); + } + + T* p; +}; + + #endif // __JUCE_WIN32_NATIVEINCLUDES_JUCEHEADER__ diff --git a/build/win32/platform_specific_code/win32_headers.h b/build/win32/platform_specific_code/win32_headers.h deleted file mode 100644 index 9df7c7c53c..0000000000 --- a/build/win32/platform_specific_code/win32_headers.h +++ /dev/null @@ -1,69 +0,0 @@ -/* - ============================================================================== - - This file is part of the JUCE library - "Jules' Utility Class Extensions" - Copyright 2004-7 by Raw Material Software ltd. - - ------------------------------------------------------------------------------ - - JUCE can be redistributed and/or modified under the terms of the - GNU General Public License, as published by the Free Software Foundation; - either version 2 of the License, or (at your option) any later version. - - JUCE is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with JUCE; if not, visit www.gnu.org/licenses or write to the - Free Software Foundation, Inc., 59 Temple Place, Suite 330, - Boston, MA 02111-1307 USA - - ------------------------------------------------------------------------------ - - If you'd like to release a closed-source product which uses JUCE, commercial - licenses are also available: visit www.rawmaterialsoftware.com/juce for - more information. - - ============================================================================== -*/ - -#ifndef __WIN32_HEADERS_JUCEHEADER__ -#define __WIN32_HEADERS_JUCEHEADER__ - -#include "../../../juce_Config.h" - -#ifndef STRICT - #define STRICT 1 -#endif -#define WIN32_LEAN_AND_MEAN - -// don't want to get told about microsoft's mistakes.. -#ifdef _MSC_VER - #pragma warning (push) - #pragma warning (disable : 4100 4201) -#endif - -// use Platform SDK as win2000 unless this is disabled -#ifndef DISABLE_TRANSPARENT_WINDOWS - #define _WIN32_WINNT 0x0500 -#endif - -#define _UNICODE 1 -#define UNICODE 1 - -#include -#include -#include -#include -#include -#include - -#undef PACKED - -#ifdef _MSC_VER - #pragma warning (pop) -#endif - -#endif // __WIN32_HEADERS_JUCEHEADER__ diff --git a/build/win32/vc8/JUCE.vcproj b/build/win32/vc8/JUCE.vcproj index 7287a64f44..a61f700682 100644 --- a/build/win32/vc8/JUCE.vcproj +++ b/build/win32/vc8/JUCE.vcproj @@ -5762,10 +5762,6 @@ RelativePath="..\platform_specific_code\juce_win32_Windowing.cpp" > - - diff --git a/extras/audio plugins/wrapper/VST/juce_VST_Wrapper.cpp b/extras/audio plugins/wrapper/VST/juce_VST_Wrapper.cpp index 9e0c0ae103..5f0dee8a2b 100644 --- a/extras/audio plugins/wrapper/VST/juce_VST_Wrapper.cpp +++ b/extras/audio plugins/wrapper/VST/juce_VST_Wrapper.cpp @@ -1,1531 +1,1547 @@ -/* - ============================================================================== - - This file is part of the JUCE library - "Jules' Utility Class Extensions" - Copyright 2004-7 by Raw Material Software ltd. - - ------------------------------------------------------------------------------ - - JUCE can be redistributed and/or modified under the terms of the - GNU General Public License, as published by the Free Software Foundation; - either version 2 of the License, or (at your option) any later version. - - JUCE is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with JUCE; if not, visit www.gnu.org/licenses or write to the - Free Software Foundation, Inc., 59 Temple Place, Suite 330, - Boston, MA 02111-1307 USA - - ------------------------------------------------------------------------------ - - If you'd like to release a closed-source product which uses JUCE, commercial - licenses are also available: visit www.rawmaterialsoftware.com/juce for - more information. - - ============================================================================== -*/ - -#ifdef _MSC_VER - #pragma warning (disable : 4996) -#endif - -#ifdef _WIN32 - #include -#elif defined (LINUX) - #include - #include - #include - #undef KeyPress -#else - #include -#endif - -#ifdef PRAGMA_ALIGN_SUPPORTED - #undef PRAGMA_ALIGN_SUPPORTED - #define PRAGMA_ALIGN_SUPPORTED 1 -#endif - -#include "../juce_IncludeCharacteristics.h" - -#if JucePlugin_Build_VST - -//============================================================================== -/* These files come with the Steinberg VST SDK - to get them, you'll need to - visit the Steinberg website and jump through some hoops to sign up as a - VST developer. - - Then, you'll need to make sure your include path contains your "vstsdk2.3" or - "vstsdk2.4" directory. - - Note that the JUCE_USE_VSTSDK_2_4 macro should be defined in JucePluginCharacteristics.h -*/ -#if JUCE_USE_VSTSDK_2_4 - // VSTSDK V2.4 includes.. - #include "public.sdk/source/vst2.x/audioeffectx.h" - #include "public.sdk/source/vst2.x/aeffeditor.h" - #include "public.sdk/source/vst2.x/audioeffectx.cpp" - #include "public.sdk/source/vst2.x/audioeffect.cpp" - - #if JUCE_LINUX - #define __cdecl - #endif - - #if ! VST_2_4_EXTENSIONS - #error // You're probably trying to include the wrong VSTSDK version - make sure your include path matches the JUCE_USE_VSTSDK_2_4 flag - #endif - -#else - // VSTSDK V2.3 includes.. - #include "source/common/audioeffectx.h" - #include "source/common/AEffEditor.hpp" - #include "source/common/audioeffectx.cpp" - #include "source/common/AudioEffect.cpp" - - #if (! VST_2_3_EXTENSIONS) || VST_2_4_EXTENSIONS - #error // You're probably trying to include the wrong VSTSDK version - make sure your include path matches the JUCE_USE_VSTSDK_2_4 flag - #endif - - typedef long VstInt32; - typedef long VstIntPtr; - enum Vst2StringConstants - { - kVstMaxNameLen = 64, - kVstMaxLabelLen = 64, - kVstMaxShortLabelLen = 8, - kVstMaxCategLabelLen = 24, - kVstMaxFileNameLen = 100 - }; - - enum VstSmpteFrameRate - { - kVstSmpte24fps = 0, ///< 24 fps - kVstSmpte25fps = 1, ///< 25 fps - kVstSmpte2997fps = 2, ///< 29.97 fps - kVstSmpte30fps = 3, ///< 30 fps - kVstSmpte2997dfps = 4, ///< 29.97 drop - kVstSmpte30dfps = 5, ///< 30 drop - kVstSmpteFilm16mm = 6, ///< Film 16mm - kVstSmpteFilm35mm = 7, ///< Film 35mm - kVstSmpte239fps = 10, ///< HDTV: 23.976 fps - kVstSmpte249fps = 11, ///< HDTV: 24.976 fps - kVstSmpte599fps = 12, ///< HDTV: 59.94 fps - kVstSmpte60fps = 13 ///< HDTV: 60 fps - }; -#endif - -//============================================================================== -#ifdef _MSC_VER - #pragma pack (push, 8) -#endif - -#include "../juce_PluginHeaders.h" - - -#ifdef _MSC_VER - #pragma pack (pop) -#endif - -#undef MemoryBlock - -class JuceVSTWrapper; -static bool recursionCheck = false; -static JUCE_NAMESPACE::uint32 lastMasterIdleCall = 0; - -BEGIN_JUCE_NAMESPACE - extern void juce_callAnyTimersSynchronously(); - - #if JUCE_MAC - extern void initialiseMac(); - extern void juce_setCurrentExecutableFileNameFromBundleId (const String& bundleId) throw(); - extern void* attachComponentToWindowRef (Component* component, void* windowRef); - extern void detachComponentFromWindowRef (Component* component, void* nsWindow); - extern void setNativeHostWindowSize (void* nsWindow, Component* editorComp, int newWidth, int newHeight); - extern void checkWindowVisibility (void* nsWindow, Component* component); - #endif - - #if JUCE_LINUX - extern Display* display; - extern bool juce_postMessageToSystemQueue (void* message); - #endif -END_JUCE_NAMESPACE - - -//============================================================================== -#if JUCE_WIN32 - -static HWND findMDIParentOf (HWND w) -{ - const int frameThickness = GetSystemMetrics (SM_CYFIXEDFRAME); - - while (w != 0) - { - HWND parent = GetParent (w); - - if (parent == 0) - break; - - TCHAR windowType [32]; - zeromem (windowType, sizeof (windowType)); - GetClassName (parent, windowType, 31); - - if (String (windowType).equalsIgnoreCase (T("MDIClient"))) - { - w = parent; - break; - } - - RECT windowPos; - GetWindowRect (w, &windowPos); - - RECT parentPos; - GetWindowRect (parent, &parentPos); - - const int dw = (parentPos.right - parentPos.left) - (windowPos.right - windowPos.left); - const int dh = (parentPos.bottom - parentPos.top) - (windowPos.bottom - windowPos.top); - - if (dw > 100 || dh > 100) - break; - - w = parent; - - if (dw == 2 * frameThickness) - break; - } - - return w; -} - -//============================================================================== -#elif JUCE_LINUX - -class SharedMessageThread : public Thread -{ -public: - SharedMessageThread() - : Thread (T("VstMessageThread")) - { - startThread (7); - } - - ~SharedMessageThread() - { - signalThreadShouldExit(); - JUCEApplication::quit(); - waitForThreadToExit (5000); - clearSingletonInstance(); - } - - void run() - { - MessageManager* const messageManager = MessageManager::getInstance(); - - const Thread::ThreadID originalThreadId = messageManager->getCurrentMessageThread(); - messageManager->setCurrentMessageThread (Thread::getCurrentThreadId()); - - while ((! threadShouldExit()) && messageManager->runDispatchLoopUntil (250)) - { - } - - messageManager->setCurrentMessageThread (originalThreadId); - } - - juce_DeclareSingleton (SharedMessageThread, false) -}; - - -#endif - -//============================================================================== -// A component to hold the AudioProcessorEditor, and cope with some housekeeping -// chores when it changes or repaints. -class EditorCompWrapper : public Component, - public AsyncUpdater -{ - JuceVSTWrapper* wrapper; - -public: - EditorCompWrapper (JuceVSTWrapper* const wrapper_, - AudioProcessorEditor* const editor) - : wrapper (wrapper_) - { - setOpaque (true); - editor->setOpaque (true); - - setBounds (editor->getBounds()); - editor->setTopLeftPosition (0, 0); - addAndMakeVisible (editor); - -#if JUCE_WIN32 - addMouseListener (this, true); -#endif - } - - ~EditorCompWrapper() - { - deleteAllChildren(); - } - - void paint (Graphics& g) - { - } - - void paintOverChildren (Graphics& g) - { - // this causes an async call to masterIdle() to help - // creaky old DAWs like Nuendo repaint themselves while we're - // repainting. Otherwise they just seem to give up and sit there - // waiting. - triggerAsyncUpdate(); - } - - AudioProcessorEditor* getEditorComp() const - { - return dynamic_cast (getChildComponent (0)); - } - - void resized() - { - Component* const c = getChildComponent (0); - - if (c != 0) - c->setBounds (0, 0, getWidth(), getHeight()); - } - - void childBoundsChanged (Component* child); - void handleAsyncUpdate(); - -#if JUCE_WIN32 - void mouseDown (const MouseEvent&) - { - broughtToFront(); - } - - void broughtToFront() - { - // for hosts like nuendo, need to also pop the MDI container to the - // front when our comp is clicked on. - HWND parent = findMDIParentOf ((HWND) getWindowHandle()); - - if (parent != 0) - { - SetWindowPos (parent, - HWND_TOP, - 0, 0, 0, 0, - SWP_NOMOVE | SWP_NOSIZE); - } - } -#endif - - //============================================================================== - juce_UseDebuggingNewOperator -}; - -static VoidArray activePlugins; - - -//============================================================================== -/** - This wraps an AudioProcessor as an AudioEffectX... -*/ -class JuceVSTWrapper : public AudioEffectX, - private Timer, - public AudioProcessorListener, - public AudioPlayHead -{ -public: - //============================================================================== - JuceVSTWrapper (audioMasterCallback audioMaster, - AudioProcessor* const filter_) - : AudioEffectX (audioMaster, - filter_->getNumPrograms(), - filter_->getNumParameters()), - filter (filter_) - { - editorComp = 0; - chunkMemoryTime = 0; - isProcessing = false; - hasShutdown = false; - firstProcessCallback = true; - shouldDeleteEditor = false; - channels = 0; - speakerIn = kSpeakerArrEmpty; - speakerOut = kSpeakerArrEmpty; - speakerInChans = 0; - speakerOutChans = 0; - numInChans = JucePlugin_MaxNumInputChannels; - numOutChans = JucePlugin_MaxNumOutputChannels; - -#if JUCE_MAC || JUCE_LINUX - hostWindow = 0; -#endif - - filter->setPlayConfigDetails (numInChans, numOutChans, 0, 0); - - filter_->setPlayHead (this); - filter_->addListener (this); - - cEffect.flags |= effFlagsHasEditor; - cEffect.version = (long) (JucePlugin_VersionCode); - - setUniqueID ((int) (JucePlugin_VSTUniqueID)); - -#if JucePlugin_WantsMidiInput && ! JUCE_USE_VSTSDK_2_4 - wantEvents(); -#endif - - setNumInputs (numInChans); - setNumOutputs (numOutChans); - - canProcessReplacing (true); - -#if ! JUCE_USE_VSTSDK_2_4 - hasVu (false); - hasClip (false); -#endif - - isSynth ((JucePlugin_IsSynth) != 0); - noTail ((JucePlugin_SilenceInProducesSilenceOut) != 0); - setInitialDelay (filter->getLatencySamples()); - programsAreChunks (true); - - activePlugins.add (this); - } - - ~JuceVSTWrapper() - { - stopTimer(); - deleteEditor (false); - - hasShutdown = true; - - delete filter; - filter = 0; - - jassert (editorComp == 0); - - juce_free (channels); - channels = 0; - deleteTempChannels(); - - jassert (activePlugins.contains (this)); - activePlugins.removeValue (this); - - if (activePlugins.size() == 0) - { -#if JUCE_LINUX - SharedMessageThread::deleteInstance(); -#endif - shutdownJuce_GUI(); - } - } - - void open() - { - if (editorComp == 0) - { - AudioProcessorEditor* const ed = filter->createEditorIfNeeded(); - - if (ed != 0) - cEffect.flags |= effFlagsHasEditor; - else - cEffect.flags &= ~effFlagsHasEditor; - - filter->editorBeingDeleted (ed); - delete ed; - } - - startTimer (1000 / 4); - } - - void close() - { - jassert (! recursionCheck); - - stopTimer(); - deleteEditor (false); - } - - //============================================================================== - bool getEffectName (char* name) - { - String (JucePlugin_Name).copyToBuffer (name, 64); - return true; - } - - bool getVendorString (char* text) - { - String (JucePlugin_Manufacturer).copyToBuffer (text, 64); - return true; - } - - bool getProductString (char* text) - { - return getEffectName (text); - } - - VstInt32 getVendorVersion() - { - return JucePlugin_VersionCode; - } - - VstPlugCategory getPlugCategory() - { - return JucePlugin_VSTCategory; - } - - VstInt32 canDo (char* text) - { - VstInt32 result = 0; - - if (strcmp (text, "receiveVstEvents") == 0 - || strcmp (text, "receiveVstMidiEvent") == 0 - || strcmp (text, "receiveVstMidiEvents") == 0) - { -#if JucePlugin_WantsMidiInput - result = 1; -#else - result = -1; -#endif - } - else if (strcmp (text, "sendVstEvents") == 0 - || strcmp (text, "sendVstMidiEvent") == 0 - || strcmp (text, "sendVstMidiEvents") == 0) - { -#if JucePlugin_ProducesMidiOutput - result = 1; -#else - result = -1; -#endif - } - else if (strcmp (text, "receiveVstTimeInfo") == 0 - || strcmp (text, "conformsToWindowRules") == 0) - { - result = 1; - } - - return result; - } - - bool keysRequired() - { - return (JucePlugin_EditorRequiresKeyboardFocus) != 0; - } - - bool getInputProperties (VstInt32 index, VstPinProperties* properties) - { - if (filter == 0 || index >= JucePlugin_MaxNumInputChannels) - return false; - - const String name (filter->getInputChannelName ((int) index)); - - name.copyToBuffer (properties->label, kVstMaxLabelLen - 1); - name.copyToBuffer (properties->shortLabel, kVstMaxShortLabelLen - 1); - - if (speakerIn != kSpeakerArrEmpty) - { - properties->flags = kVstPinUseSpeaker; - properties->arrangementType = speakerIn; - } - else - { - properties->flags = kVstPinIsActive; - - if (filter->isInputChannelStereoPair ((int) index)) - properties->flags |= kVstPinIsStereo; - - properties->arrangementType = 0; - } - - return true; - } - - bool getOutputProperties (VstInt32 index, VstPinProperties* properties) - { - if (filter == 0 || index >= JucePlugin_MaxNumOutputChannels) - return false; - - const String name (filter->getOutputChannelName ((int) index)); - - name.copyToBuffer (properties->label, kVstMaxLabelLen - 1); - name.copyToBuffer (properties->shortLabel, kVstMaxShortLabelLen - 1); - - if (speakerOut != kSpeakerArrEmpty) - { - properties->flags = kVstPinUseSpeaker; - properties->arrangementType = speakerOut; - } - else - { - properties->flags = kVstPinIsActive; - - if (filter->isOutputChannelStereoPair ((int) index)) - properties->flags |= kVstPinIsStereo; - - properties->arrangementType = 0; - } - - return true; - } - - //============================================================================== - VstInt32 processEvents (VstEvents* events) - { -#if JucePlugin_WantsMidiInput - VSTMidiEventList::addEventsToMidiBuffer (events, midiEvents); - return 1; -#else - return 0; -#endif - } - - void process (float** inputs, float** outputs, VstInt32 numSamples) - { - const int numIn = numInChans; - const int numOut = numOutChans; - - AudioSampleBuffer temp (numIn, numSamples); - int i; - for (i = numIn; --i >= 0;) - memcpy (temp.getSampleData (i), outputs[i], sizeof (float) * numSamples); - - processReplacing (inputs, outputs, numSamples); - - AudioSampleBuffer dest (outputs, numOut, numSamples); - - for (i = jmin (numIn, numOut); --i >= 0;) - dest.addFrom (i, 0, temp, i, 0, numSamples); - } - - void processReplacing (float** inputs, float** outputs, VstInt32 numSamples) - { - if (firstProcessCallback) - { - firstProcessCallback = false; - - // if this fails, the host hasn't called resume() before processing - jassert (isProcessing); - - // (tragically, some hosts actually need this, although it's stupid to have - // to do it here..) - if (! isProcessing) - resume(); - - filter->setNonRealtime (getCurrentProcessLevel() == 4 /* kVstProcessLevelOffline */); - -#if JUCE_WIN32 - if (GetThreadPriority (GetCurrentThread()) <= THREAD_PRIORITY_NORMAL - && GetThreadPriority (GetCurrentThread()) >= THREAD_PRIORITY_LOWEST) - filter->setNonRealtime (true); -#endif - } - -#if JUCE_DEBUG && ! JucePlugin_ProducesMidiOutput - const int numMidiEventsComingIn = midiEvents.getNumEvents(); -#endif - - jassert (activePlugins.contains (this)); - - { - const ScopedLock sl (filter->getCallbackLock()); - - const int numIn = numInChans; - const int numOut = numOutChans; - - if (filter->isSuspended()) - { - for (int i = 0; i < numOut; ++i) - zeromem (outputs[i], sizeof (float) * numSamples); - } - else - { - int i; - for (i = 0; i < numOut; ++i) - { - float* chan = (float*) tempChannels.getUnchecked(i); - - if (chan == 0) - { - chan = outputs[i]; - - // if some output channels are disabled, some hosts supply the same buffer - // for multiple channels - this buggers up our method of copying the - // inputs over the outputs, so we need to create unique temp buffers in this case.. - for (int j = i; --j >= 0;) - { - if (outputs[j] == chan) - { - chan = (float*) juce_malloc (sizeof (float) * blockSize * 2); - tempChannels.set (i, chan); - break; - } - } - } - - if (i < numIn && chan != inputs[i]) - memcpy (chan, inputs[i], sizeof (float) * numSamples); - - channels[i] = chan; - } - - for (; i < numIn; ++i) - channels[i] = inputs[i]; - - AudioSampleBuffer chans (channels, jmax (numIn, numOut), numSamples); - - filter->processBlock (chans, midiEvents); - } - } - - if (! midiEvents.isEmpty()) - { -#if JucePlugin_ProducesMidiOutput - const int numEvents = midiEvents.getNumEvents(); - - outgoingEvents.ensureSize (numEvents); - outgoingEvents.clear(); - - const JUCE_NAMESPACE::uint8* midiEventData; - int midiEventSize, midiEventPosition; - MidiBuffer::Iterator i (midiEvents); - - while (i.getNextEvent (midiEventData, midiEventSize, midiEventPosition)) - { - jassert (midiEventPosition >= 0 && midiEventPosition < numSamples); - - outgoingEvents.addEvent (midiEventData, midiEventSize, midiEventPosition); - } - - sendVstEventsToHost (outgoingEvents.events); -#else - /* This assertion is caused when you've added some events to the - midiMessages array in your processBlock() method, which usually means - that you're trying to send them somewhere. But in this case they're - getting thrown away. - - If your plugin does want to send midi messages, you'll need to set - the JucePlugin_ProducesMidiOutput macro to 1 in your - JucePluginCharacteristics.h file. - - If you don't want to produce any midi output, then you should clear the - midiMessages array at the end of your processBlock() method, to - indicate that you don't want any of the events to be passed through - to the output. - */ - jassert (midiEvents.getNumEvents() <= numMidiEventsComingIn); -#endif - - midiEvents.clear(); - } - } - - //============================================================================== - VstInt32 startProcess () { return 0; } - VstInt32 stopProcess () { return 0;} - - void resume() - { - if (filter == 0) - return; - - isProcessing = true; - juce_free (channels); - channels = (float**) juce_calloc (sizeof (float*) * (numInChans + numOutChans)); - - double rate = getSampleRate(); - jassert (rate > 0); - if (rate <= 0.0) - rate = 44100.0; - - const int blockSize = getBlockSize(); - jassert (blockSize > 0); - - firstProcessCallback = true; - - filter->setNonRealtime (getCurrentProcessLevel() == 4 /* kVstProcessLevelOffline */); - - filter->setPlayConfigDetails (numInChans, numOutChans, - rate, blockSize); - - deleteTempChannels(); - - filter->prepareToPlay (rate, blockSize); - midiEvents.clear(); - - setInitialDelay (filter->getLatencySamples()); - - AudioEffectX::resume(); - -#if JucePlugin_ProducesMidiOutput - outgoingEvents.ensureSize (64); -#endif - -#if JucePlugin_WantsMidiInput && ! JUCE_USE_VSTSDK_2_4 - wantEvents(); -#endif - } - - void suspend() - { - if (filter == 0) - return; - - AudioEffectX::suspend(); - - filter->releaseResources(); - outgoingEvents.freeEvents(); - - isProcessing = false; - juce_free (channels); - channels = 0; - - deleteTempChannels(); - } - - bool getCurrentPosition (AudioPlayHead::CurrentPositionInfo& info) - { - const VstTimeInfo* const ti = getTimeInfo (kVstPpqPosValid - | kVstTempoValid - | kVstBarsValid - //| kVstCyclePosValid - | kVstTimeSigValid - | kVstSmpteValid - | kVstClockValid); - - if (ti == 0 || ti->sampleRate <= 0) - return false; - - if ((ti->flags & kVstTempoValid) != 0) - info.bpm = ti->tempo; - else - info.bpm = 0.0; - - if ((ti->flags & kVstTimeSigValid) != 0) - { - info.timeSigNumerator = ti->timeSigNumerator; - info.timeSigDenominator = ti->timeSigDenominator; - } - else - { - info.timeSigNumerator = 4; - info.timeSigDenominator = 4; - } - - info.timeInSeconds = ti->samplePos / ti->sampleRate; - - if ((ti->flags & kVstPpqPosValid) != 0) - info.ppqPosition = ti->ppqPos; - else - info.ppqPosition = 0.0; - - if ((ti->flags & kVstBarsValid) != 0) - info.ppqPositionOfLastBarStart = ti->barStartPos; - else - info.ppqPositionOfLastBarStart = 0.0; - - if ((ti->flags & kVstSmpteValid) != 0) - { - AudioPlayHead::FrameRateType rate = AudioPlayHead::fpsUnknown; - double fps = 1.0; - - switch (ti->smpteFrameRate) - { - case kVstSmpte24fps: - rate = AudioPlayHead::fps24; - fps = 24.0; - break; - - case kVstSmpte25fps: - rate = AudioPlayHead::fps25; - fps = 25.0; - break; - - case kVstSmpte2997fps: - rate = AudioPlayHead::fps2997; - fps = 29.97; - break; - - case kVstSmpte30fps: - rate = AudioPlayHead::fps30; - fps = 30.0; - break; - - case kVstSmpte2997dfps: - rate = AudioPlayHead::fps2997drop; - fps = 29.97; - break; - - case kVstSmpte30dfps: - rate = AudioPlayHead::fps30drop; - fps = 30.0; - break; - - case kVstSmpteFilm16mm: - case kVstSmpteFilm35mm: - fps = 24.0; - break; - - case kVstSmpte239fps: fps = 23.976; break; - case kVstSmpte249fps: fps = 24.976; break; - case kVstSmpte599fps: fps = 59.94; break; - case kVstSmpte60fps: fps = 60; break; - - default: - jassertfalse // unknown frame-rate.. - } - - info.frameRate = rate; - info.editOriginTime = ti->smpteOffset / (80.0 * fps); - } - else - { - info.frameRate = AudioPlayHead::fpsUnknown; - info.editOriginTime = 0; - } - - info.isRecording = (ti->flags & kVstTransportRecording) != 0; - info.isPlaying = (ti->flags & kVstTransportPlaying) != 0 || info.isRecording; - - return true; - } - - //============================================================================== - VstInt32 getProgram() - { - return filter != 0 ? filter->getCurrentProgram() : 0; - } - - void setProgram (VstInt32 program) - { - if (filter != 0) - filter->setCurrentProgram (program); - } - - void setProgramName (char* name) - { - if (filter != 0) - filter->changeProgramName (filter->getCurrentProgram(), name); - } - - void getProgramName (char* name) - { - if (filter != 0) - filter->getProgramName (filter->getCurrentProgram()).copyToBuffer (name, 24); - } - - bool getProgramNameIndexed (VstInt32 category, VstInt32 index, char* text) - { - if (filter != 0 && ((unsigned int) index) < (unsigned int) filter->getNumPrograms()) - { - filter->getProgramName (index).copyToBuffer (text, 24); - return true; - } - - return false; - } - - //============================================================================== - float getParameter (VstInt32 index) - { - if (filter == 0) - return 0.0f; - - jassert (((unsigned int) index) < (unsigned int) filter->getNumParameters()); - return filter->getParameter (index); - } - - void setParameter (VstInt32 index, float value) - { - if (filter != 0) - { - jassert (((unsigned int) index) < (unsigned int) filter->getNumParameters()); - filter->setParameter (index, value); - } - } - - void getParameterDisplay (VstInt32 index, char* text) - { - if (filter != 0) - { - jassert (((unsigned int) index) < (unsigned int) filter->getNumParameters()); - filter->getParameterText (index).copyToBuffer (text, 24); // length should technically be kVstMaxParamStrLen, which is 8, but hosts will normally allow a bit more. - } - } - - void getParameterName (VstInt32 index, char* text) - { - if (filter != 0) - { - jassert (((unsigned int) index) < (unsigned int) filter->getNumParameters()); - filter->getParameterName (index).copyToBuffer (text, 16); // length should technically be kVstMaxParamStrLen, which is 8, but hosts will normally allow a bit more. - } - } - - void audioProcessorParameterChanged (AudioProcessor*, int index, float newValue) - { - setParameterAutomated (index, newValue); - } - - void audioProcessorParameterChangeGestureBegin (AudioProcessor*, int index) - { - beginEdit (index); - } - - void audioProcessorParameterChangeGestureEnd (AudioProcessor*, int index) - { - endEdit (index); - } - - void audioProcessorChanged (AudioProcessor*) - { - updateDisplay(); - } - - bool canParameterBeAutomated (VstInt32 index) - { - return filter != 0 && filter->isParameterAutomatable ((int) index); - } - - bool setSpeakerArrangement (VstSpeakerArrangement* pluginInput, - VstSpeakerArrangement* pluginOutput) - { - const short channelConfigs[][2] = { JucePlugin_PreferredChannelConfigurations }; - - for (int i = 0; i < numElementsInArray (channelConfigs); ++i) - { - bool configMono = (channelConfigs[i][1] == 1) && (pluginOutput->type == kSpeakerArrMono); - bool configStereo = (channelConfigs[i][1] == 2) && (pluginOutput->type == kSpeakerArrStereo); - bool inCountMatches = (channelConfigs[i][0] == pluginInput->numChannels); - bool outCountMatches = (channelConfigs[i][1] == pluginOutput->numChannels); - - if ((configMono || configStereo) && inCountMatches && outCountMatches) - { - speakerIn = (VstSpeakerArrangementType) pluginInput->type; - speakerOut = (VstSpeakerArrangementType) pluginOutput->type; - speakerInChans = pluginInput->numChannels; - speakerOutChans = pluginOutput->numChannels; - - filter->setPlayConfigDetails (speakerInChans, speakerOutChans, - filter->getSampleRate(), - filter->getBlockSize()); - return true; - } - } - - return false; - } - - //============================================================================== - VstInt32 getChunk (void** data, bool onlyStoreCurrentProgramData) - { - if (filter == 0) - return 0; - - chunkMemory.setSize (0); - if (onlyStoreCurrentProgramData) - filter->getCurrentProgramStateInformation (chunkMemory); - else - filter->getStateInformation (chunkMemory); - - *data = (void*) chunkMemory; - - // because the chunk is only needed temporarily by the host (or at least you'd - // hope so) we'll give it a while and then free it in the timer callback. - chunkMemoryTime = JUCE_NAMESPACE::Time::getApproximateMillisecondCounter(); - - return chunkMemory.getSize(); - } - - VstInt32 setChunk (void* data, VstInt32 byteSize, bool onlyRestoreCurrentProgramData) - { - if (filter == 0) - return 0; - - chunkMemory.setSize (0); - chunkMemoryTime = 0; - - if (byteSize > 0 && data != 0) - { - if (onlyRestoreCurrentProgramData) - filter->setCurrentProgramStateInformation (data, byteSize); - else - filter->setStateInformation (data, byteSize); - } - - return 0; - } - - void timerCallback() - { - if (shouldDeleteEditor) - { - shouldDeleteEditor = false; - deleteEditor (true); - } - - if (chunkMemoryTime > 0 - && chunkMemoryTime < JUCE_NAMESPACE::Time::getApproximateMillisecondCounter() - 2000 - && ! recursionCheck) - { - chunkMemoryTime = 0; - chunkMemory.setSize (0); - } - -#if JUCE_MAC - if (hostWindow != 0) - checkWindowVisibility (hostWindow, editorComp); -#endif - - tryMasterIdle(); - } - - void tryMasterIdle() - { - if (Component::isMouseButtonDownAnywhere() - && ! recursionCheck) - { - const JUCE_NAMESPACE::uint32 now = JUCE_NAMESPACE::Time::getMillisecondCounter(); - - if (now > lastMasterIdleCall + 20 && editorComp != 0) - { - lastMasterIdleCall = now; - - recursionCheck = true; - masterIdle(); - recursionCheck = false; - } - } - } - - void doIdleCallback() - { - // (wavelab calls this on a separate thread and causes a deadlock).. - if (MessageManager::getInstance()->isThisTheMessageThread() - && ! recursionCheck) - { - recursionCheck = true; - - juce_callAnyTimersSynchronously(); - - for (int i = ComponentPeer::getNumPeers(); --i >= 0;) - ComponentPeer::getPeer (i)->performAnyPendingRepaintsNow(); - - recursionCheck = false; - } - } - - void createEditorComp() - { - if (hasShutdown || filter == 0) - return; - - if (editorComp == 0) - { - AudioProcessorEditor* const ed = filter->createEditorIfNeeded(); - - if (ed != 0) - { - cEffect.flags |= effFlagsHasEditor; - ed->setOpaque (true); - ed->setVisible (true); - - editorComp = new EditorCompWrapper (this, ed); - } - else - { - cEffect.flags &= ~effFlagsHasEditor; - } - } - - shouldDeleteEditor = false; - } - - void deleteEditor (bool canDeleteLaterIfModal) - { - PopupMenu::dismissAllActiveMenus(); - - jassert (! recursionCheck); - recursionCheck = true; - - if (editorComp != 0) - { - Component* const modalComponent = Component::getCurrentlyModalComponent(); - if (modalComponent != 0) - { - modalComponent->exitModalState (0); - - if (canDeleteLaterIfModal) - { - shouldDeleteEditor = true; - return; - } - } - -#if JUCE_MAC - if (hostWindow != 0) - { - detachComponentFromWindowRef (editorComp, hostWindow); - hostWindow = 0; - } -#endif - - filter->editorBeingDeleted (editorComp->getEditorComp()); - - deleteAndZero (editorComp); - - // there's some kind of component currently modal, but the host - // is trying to delete our plugin. You should try to avoid this happening.. - jassert (Component::getCurrentlyModalComponent() == 0); - } - -#if JUCE_LINUX - hostWindow = 0; -#endif - - recursionCheck = false; - } - - VstIntPtr dispatcher (VstInt32 opCode, VstInt32 index, VstIntPtr value, void* ptr, float opt) - { - if (hasShutdown) - return 0; - - if (opCode == effEditIdle) - { - doIdleCallback(); - return 0; - } - else if (opCode == effEditOpen) - { - jassert (! recursionCheck); - - deleteEditor (true); - createEditorComp(); - - if (editorComp != 0) - { - editorComp->setOpaque (true); - editorComp->setVisible (false); - -#if JUCE_WIN32 - editorComp->addToDesktop (0); - hostWindow = (HWND) ptr; - HWND editorWnd = (HWND) editorComp->getWindowHandle(); - SetParent (editorWnd, hostWindow); - - DWORD val = GetWindowLong (editorWnd, GWL_STYLE); - val = (val & ~WS_POPUP) | WS_CHILD; - SetWindowLong (editorWnd, GWL_STYLE, val); -#elif JUCE_LINUX - editorComp->addToDesktop (0); - hostWindow = (Window) ptr; - Window editorWnd = (Window) editorComp->getWindowHandle(); - XReparentWindow (display, editorWnd, hostWindow, 0, 0); -#else - hostWindow = attachComponentToWindowRef (editorComp, (WindowRef) ptr); -#endif - editorComp->setVisible (true); - - return 1; - } - } - else if (opCode == effEditClose) - { - deleteEditor (true); - return 0; - } - else if (opCode == effEditGetRect) - { - createEditorComp(); - - if (editorComp != 0) - { - editorSize.left = 0; - editorSize.top = 0; - editorSize.right = editorComp->getWidth(); - editorSize.bottom = editorComp->getHeight(); - - *((ERect**) ptr) = &editorSize; - - return (VstIntPtr) (pointer_sized_int) &editorSize; - } - else - { - return 0; - } - } - - return AudioEffectX::dispatcher (opCode, index, value, ptr, opt); - } - - void resizeHostWindow (int newWidth, int newHeight) - { - if (editorComp != 0) - { -#if ! JUCE_LINUX // linux hosts shouldn't be trusted! - if (! (canHostDo ("sizeWindow") && sizeWindow (newWidth, newHeight))) -#endif - { - // some hosts don't support the sizeWindow call, so do it manually.. -#if JUCE_MAC - setNativeHostWindowSize (hostWindow, editorComp, newWidth, newHeight); -#elif JUCE_LINUX - Window root; - int x, y; - unsigned int width, height, border, depth; - - XGetGeometry (display, hostWindow, &root, - &x, &y, &width, &height, &border, &depth); - - newWidth += (width + border) - editorComp->getWidth(); - newHeight += (height + border) - editorComp->getHeight(); - - XResizeWindow (display, hostWindow, newWidth, newHeight); -#else - int dw = 0; - int dh = 0; - const int frameThickness = GetSystemMetrics (SM_CYFIXEDFRAME); - - HWND w = (HWND) editorComp->getWindowHandle(); - - while (w != 0) - { - HWND parent = GetParent (w); - - if (parent == 0) - break; - - TCHAR windowType [32]; - zeromem (windowType, sizeof (windowType)); - GetClassName (parent, windowType, 31); - - if (String (windowType).equalsIgnoreCase (T("MDIClient"))) - break; - - RECT windowPos; - GetWindowRect (w, &windowPos); - - RECT parentPos; - GetWindowRect (parent, &parentPos); - - SetWindowPos (w, 0, 0, 0, - newWidth + dw, - newHeight + dh, - SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOZORDER | SWP_NOOWNERZORDER); - - dw = (parentPos.right - parentPos.left) - (windowPos.right - windowPos.left); - dh = (parentPos.bottom - parentPos.top) - (windowPos.bottom - windowPos.top); - - w = parent; - - if (dw == 2 * frameThickness) - break; - - if (dw > 100 || dh > 100) - w = 0; - } - - if (w != 0) - SetWindowPos (w, 0, 0, 0, - newWidth + dw, - newHeight + dh, - SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOZORDER | SWP_NOOWNERZORDER); -#endif - } - - if (editorComp->getPeer() != 0) - editorComp->getPeer()->handleMovedOrResized(); - } - } - - - //============================================================================== - juce_UseDebuggingNewOperator - -private: - AudioProcessor* filter; - JUCE_NAMESPACE::MemoryBlock chunkMemory; - JUCE_NAMESPACE::uint32 chunkMemoryTime; - EditorCompWrapper* editorComp; - ERect editorSize; - MidiBuffer midiEvents; - VSTMidiEventList outgoingEvents; - bool isProcessing; - bool hasShutdown; - bool firstProcessCallback; - int diffW, diffH; - VstSpeakerArrangementType speakerIn, speakerOut; - int speakerInChans, speakerOutChans; - int numInChans, numOutChans; - float** channels; - VoidArray tempChannels; // see note in processReplacing() - bool hasCreatedTempChannels; - bool shouldDeleteEditor; - - void deleteTempChannels() - { - int i; - for (i = tempChannels.size(); --i >= 0;) - juce_free (tempChannels.getUnchecked(i)); - - tempChannels.clear(); - - if (filter != 0) - tempChannels.insertMultiple (0, 0, filter->getNumInputChannels() + filter->getNumOutputChannels()); - - hasCreatedTempChannels = false; - } - - const String getHostName() - { - char host[256]; - zeromem (host, sizeof (host)); - getHostProductString (host); - return host; - } - -#if JUCE_MAC - void* hostWindow; -#elif JUCE_LINUX - Window hostWindow; -#else - HWND hostWindow; -#endif -}; - -//============================================================================== -void EditorCompWrapper::childBoundsChanged (Component* child) -{ - child->setTopLeftPosition (0, 0); - - const int cw = child->getWidth(); - const int ch = child->getHeight(); - - wrapper->resizeHostWindow (cw, ch); - setSize (cw, ch); - -#if JUCE_MAC - wrapper->resizeHostWindow (cw, ch); // (doing this a second time seems to be necessary in tracktion) -#endif -} - -void EditorCompWrapper::handleAsyncUpdate() -{ - wrapper->tryMasterIdle(); -} - -//============================================================================== -/** Somewhere in the codebase of your plugin, you need to implement this function - and make it create an instance of the filter subclass that you're building. -*/ -extern AudioProcessor* JUCE_CALLTYPE createPluginFilter(); - - -//============================================================================== -static AEffect* pluginEntryPoint (audioMasterCallback audioMaster) -{ - initialiseJuce_GUI(); - -#if JUCE_MAC && defined (JucePlugin_CFBundleIdentifier) - juce_setCurrentExecutableFileNameFromBundleId (JucePlugin_CFBundleIdentifier); -#endif - - try - { - if (audioMaster (0, audioMasterVersion, 0, 0, 0, 0) != 0) - { - AudioProcessor* const filter = createPluginFilter(); - - if (filter != 0) - { - JuceVSTWrapper* const wrapper = new JuceVSTWrapper (audioMaster, filter); - return wrapper->getAeffect(); - } - } - } - catch (...) - {} - - return 0; -} - - -//============================================================================== -// Mac startup code.. -#if JUCE_MAC - -extern "C" __attribute__ ((visibility("default"))) AEffect* VSTPluginMain (audioMasterCallback audioMaster) -{ - initialiseMac(); - return pluginEntryPoint (audioMaster); -} - -extern "C" __attribute__ ((visibility("default"))) AEffect* main_macho (audioMasterCallback audioMaster) -{ - initialiseMac(); - return pluginEntryPoint (audioMaster); -} - -//============================================================================== -// Linux startup code.. -#elif JUCE_LINUX - -extern "C" AEffect* VSTPluginMain (audioMasterCallback audioMaster) -{ - initialiseJuce_GUI(); - SharedMessageThread::getInstance(); - - return pluginEntryPoint (audioMaster); -} - -extern "C" __attribute__ ((visibility("default"))) AEffect* main_plugin (audioMasterCallback audioMaster) asm ("main"); - -extern "C" __attribute__ ((visibility("default"))) AEffect* main_plugin (audioMasterCallback audioMaster) -{ - return VSTPluginMain (audioMaster); -} - -__attribute__((constructor)) void myPluginInit() -{ - // don't put initialiseJuce_GUI here... it will crash ! -} - -__attribute__((destructor)) void myPluginFini() -{ - // don't put shutdownJuce_GUI here... it will crash ! -} - -//============================================================================== -// Win32 startup code.. -#else - -extern "C" __declspec (dllexport) AEffect* VSTPluginMain (audioMasterCallback audioMaster) -{ - return pluginEntryPoint (audioMaster); -} - -#ifndef _WIN64 // (can't compile this on win64, but it's not needed anyway with VST2.4) -extern "C" __declspec (dllexport) void* main (audioMasterCallback audioMaster) -{ - return (void*) pluginEntryPoint (audioMaster); -} -#endif - -#if JucePlugin_Build_RTAS -BOOL WINAPI DllMainVST (HINSTANCE instance, DWORD dwReason, LPVOID) -#else -extern "C" BOOL WINAPI DllMain (HINSTANCE instance, DWORD dwReason, LPVOID) -#endif -{ - if (dwReason == DLL_PROCESS_ATTACH) - PlatformUtilities::setCurrentModuleInstanceHandle (instance); - - return TRUE; -} - -#endif - -#endif +/* + ============================================================================== + + This file is part of the JUCE library - "Jules' Utility Class Extensions" + Copyright 2004-7 by Raw Material Software ltd. + + ------------------------------------------------------------------------------ + + JUCE can be redistributed and/or modified under the terms of the + GNU General Public License, as published by the Free Software Foundation; + either version 2 of the License, or (at your option) any later version. + + JUCE is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with JUCE; if not, visit www.gnu.org/licenses or write to the + Free Software Foundation, Inc., 59 Temple Place, Suite 330, + Boston, MA 02111-1307 USA + + ------------------------------------------------------------------------------ + + If you'd like to release a closed-source product which uses JUCE, commercial + licenses are also available: visit www.rawmaterialsoftware.com/juce for + more information. + + ============================================================================== +*/ + +#ifdef _MSC_VER + #pragma warning (disable : 4996) +#endif + +#ifdef _WIN32 + #include +#elif defined (LINUX) + #include + #include + #include + #undef KeyPress +#else + #include +#endif + +#ifdef PRAGMA_ALIGN_SUPPORTED + #undef PRAGMA_ALIGN_SUPPORTED + #define PRAGMA_ALIGN_SUPPORTED 1 +#endif + +#include "../juce_IncludeCharacteristics.h" + +#if JucePlugin_Build_VST + +//============================================================================== +/* These files come with the Steinberg VST SDK - to get them, you'll need to + visit the Steinberg website and jump through some hoops to sign up as a + VST developer. + + Then, you'll need to make sure your include path contains your "vstsdk2.3" or + "vstsdk2.4" directory. + + Note that the JUCE_USE_VSTSDK_2_4 macro should be defined in JucePluginCharacteristics.h +*/ +#if JUCE_USE_VSTSDK_2_4 + #ifdef __GNUC__ + #define __cdecl + #endif + + // VSTSDK V2.4 includes.. + #include "public.sdk/source/vst2.x/audioeffectx.h" + #include "public.sdk/source/vst2.x/aeffeditor.h" + #include "public.sdk/source/vst2.x/audioeffectx.cpp" + #include "public.sdk/source/vst2.x/audioeffect.cpp" + + #if ! VST_2_4_EXTENSIONS + #error // You're probably trying to include the wrong VSTSDK version - make sure your include path matches the JUCE_USE_VSTSDK_2_4 flag + #endif + +#else + // VSTSDK V2.3 includes.. + #include "source/common/audioeffectx.h" + #include "source/common/AEffEditor.hpp" + #include "source/common/audioeffectx.cpp" + #include "source/common/AudioEffect.cpp" + + #if (! VST_2_3_EXTENSIONS) || VST_2_4_EXTENSIONS + #error // You're probably trying to include the wrong VSTSDK version - make sure your include path matches the JUCE_USE_VSTSDK_2_4 flag + #endif + + #define __aeffect__ // (needed for juce_VSTMidiEventList.h to work) + + typedef long VstInt32; + typedef long VstIntPtr; + enum Vst2StringConstants + { + kVstMaxNameLen = 64, + kVstMaxLabelLen = 64, + kVstMaxShortLabelLen = 8, + kVstMaxCategLabelLen = 24, + kVstMaxFileNameLen = 100 + }; + + enum VstSmpteFrameRate + { + kVstSmpte24fps = 0, ///< 24 fps + kVstSmpte25fps = 1, ///< 25 fps + kVstSmpte2997fps = 2, ///< 29.97 fps + kVstSmpte30fps = 3, ///< 30 fps + kVstSmpte2997dfps = 4, ///< 29.97 drop + kVstSmpte30dfps = 5, ///< 30 drop + kVstSmpteFilm16mm = 6, ///< Film 16mm + kVstSmpteFilm35mm = 7, ///< Film 35mm + kVstSmpte239fps = 10, ///< HDTV: 23.976 fps + kVstSmpte249fps = 11, ///< HDTV: 24.976 fps + kVstSmpte599fps = 12, ///< HDTV: 59.94 fps + kVstSmpte60fps = 13 ///< HDTV: 60 fps + }; + + struct VstMidiSysexEvent + { + VstInt32 type; ///< #kVstSysexType + VstInt32 byteSize; ///< sizeof (VstMidiSysexEvent) + VstInt32 deltaFrames; ///< sample frames related to the current block start sample position + VstInt32 flags; ///< none defined yet (should be zero) + VstInt32 dumpBytes; ///< byte size of sysexDump + VstIntPtr resvd1; ///< zero (Reserved for future use) + char* sysexDump; ///< sysex dump + VstIntPtr resvd2; ///< zero (Reserved for future use) + }; + + typedef int VstSpeakerArrangementType; +#endif + +//============================================================================== +#ifdef _MSC_VER + #pragma pack (push, 8) +#endif + +#include "../juce_PluginHeaders.h" + + +#ifdef _MSC_VER + #pragma pack (pop) +#endif + +#undef MemoryBlock + +class JuceVSTWrapper; +static bool recursionCheck = false; +static JUCE_NAMESPACE::uint32 lastMasterIdleCall = 0; + +BEGIN_JUCE_NAMESPACE + extern void juce_callAnyTimersSynchronously(); + + #if JUCE_MAC + extern void initialiseMac(); + extern void juce_setCurrentExecutableFileNameFromBundleId (const String& bundleId) throw(); + extern void* attachComponentToWindowRef (Component* component, void* windowRef); + extern void detachComponentFromWindowRef (Component* component, void* nsWindow); + extern void setNativeHostWindowSize (void* nsWindow, Component* editorComp, int newWidth, int newHeight); + extern void checkWindowVisibility (void* nsWindow, Component* component); + #endif + + #if JUCE_LINUX + extern Display* display; + extern bool juce_postMessageToSystemQueue (void* message); + #endif +END_JUCE_NAMESPACE + + +//============================================================================== +#if JUCE_WIN32 + +static HWND findMDIParentOf (HWND w) +{ + const int frameThickness = GetSystemMetrics (SM_CYFIXEDFRAME); + + while (w != 0) + { + HWND parent = GetParent (w); + + if (parent == 0) + break; + + TCHAR windowType [32]; + zeromem (windowType, sizeof (windowType)); + GetClassName (parent, windowType, 31); + + if (String (windowType).equalsIgnoreCase (T("MDIClient"))) + { + w = parent; + break; + } + + RECT windowPos; + GetWindowRect (w, &windowPos); + + RECT parentPos; + GetWindowRect (parent, &parentPos); + + const int dw = (parentPos.right - parentPos.left) - (windowPos.right - windowPos.left); + const int dh = (parentPos.bottom - parentPos.top) - (windowPos.bottom - windowPos.top); + + if (dw > 100 || dh > 100) + break; + + w = parent; + + if (dw == 2 * frameThickness) + break; + } + + return w; +} + +//============================================================================== +#elif JUCE_LINUX + +class SharedMessageThread : public Thread +{ +public: + SharedMessageThread() + : Thread (T("VstMessageThread")) + { + startThread (7); + } + + ~SharedMessageThread() + { + signalThreadShouldExit(); + JUCEApplication::quit(); + waitForThreadToExit (5000); + clearSingletonInstance(); + } + + void run() + { + MessageManager* const messageManager = MessageManager::getInstance(); + + const Thread::ThreadID originalThreadId = messageManager->getCurrentMessageThread(); + messageManager->setCurrentMessageThread (Thread::getCurrentThreadId()); + + while ((! threadShouldExit()) && messageManager->runDispatchLoopUntil (250)) + { + } + + messageManager->setCurrentMessageThread (originalThreadId); + } + + juce_DeclareSingleton (SharedMessageThread, false) +}; + + +#endif + +//============================================================================== +// A component to hold the AudioProcessorEditor, and cope with some housekeeping +// chores when it changes or repaints. +class EditorCompWrapper : public Component, + public AsyncUpdater +{ + JuceVSTWrapper* wrapper; + +public: + EditorCompWrapper (JuceVSTWrapper* const wrapper_, + AudioProcessorEditor* const editor) + : wrapper (wrapper_) + { + setOpaque (true); + editor->setOpaque (true); + + setBounds (editor->getBounds()); + editor->setTopLeftPosition (0, 0); + addAndMakeVisible (editor); + +#if JUCE_WIN32 + addMouseListener (this, true); +#endif + } + + ~EditorCompWrapper() + { + deleteAllChildren(); + } + + void paint (Graphics& g) + { + } + + void paintOverChildren (Graphics& g) + { + // this causes an async call to masterIdle() to help + // creaky old DAWs like Nuendo repaint themselves while we're + // repainting. Otherwise they just seem to give up and sit there + // waiting. + triggerAsyncUpdate(); + } + + AudioProcessorEditor* getEditorComp() const + { + return dynamic_cast (getChildComponent (0)); + } + + void resized() + { + Component* const c = getChildComponent (0); + + if (c != 0) + c->setBounds (0, 0, getWidth(), getHeight()); + } + + void childBoundsChanged (Component* child); + void handleAsyncUpdate(); + +#if JUCE_WIN32 + void mouseDown (const MouseEvent&) + { + broughtToFront(); + } + + void broughtToFront() + { + // for hosts like nuendo, need to also pop the MDI container to the + // front when our comp is clicked on. + HWND parent = findMDIParentOf ((HWND) getWindowHandle()); + + if (parent != 0) + { + SetWindowPos (parent, + HWND_TOP, + 0, 0, 0, 0, + SWP_NOMOVE | SWP_NOSIZE); + } + } +#endif + + //============================================================================== + juce_UseDebuggingNewOperator +}; + +static VoidArray activePlugins; + + +//============================================================================== +/** + This wraps an AudioProcessor as an AudioEffectX... +*/ +class JuceVSTWrapper : public AudioEffectX, + private Timer, + public AudioProcessorListener, + public AudioPlayHead +{ +public: + //============================================================================== + JuceVSTWrapper (audioMasterCallback audioMaster, + AudioProcessor* const filter_) + : AudioEffectX (audioMaster, + filter_->getNumPrograms(), + filter_->getNumParameters()), + filter (filter_) + { + editorComp = 0; + chunkMemoryTime = 0; + isProcessing = false; + hasShutdown = false; + firstProcessCallback = true; + shouldDeleteEditor = false; + channels = 0; + speakerIn = kSpeakerArrEmpty; + speakerOut = kSpeakerArrEmpty; + speakerInChans = 0; + speakerOutChans = 0; + numInChans = JucePlugin_MaxNumInputChannels; + numOutChans = JucePlugin_MaxNumOutputChannels; + +#if JUCE_MAC || JUCE_LINUX + hostWindow = 0; +#endif + + filter->setPlayConfigDetails (numInChans, numOutChans, 0, 0); + + filter_->setPlayHead (this); + filter_->addListener (this); + + cEffect.flags |= effFlagsHasEditor; + cEffect.version = (long) (JucePlugin_VersionCode); + + setUniqueID ((int) (JucePlugin_VSTUniqueID)); + +#if JucePlugin_WantsMidiInput && ! JUCE_USE_VSTSDK_2_4 + wantEvents(); +#endif + + setNumInputs (numInChans); + setNumOutputs (numOutChans); + + canProcessReplacing (true); + +#if ! JUCE_USE_VSTSDK_2_4 + hasVu (false); + hasClip (false); +#endif + + isSynth ((JucePlugin_IsSynth) != 0); + noTail ((JucePlugin_SilenceInProducesSilenceOut) != 0); + setInitialDelay (filter->getLatencySamples()); + programsAreChunks (true); + + activePlugins.add (this); + } + + ~JuceVSTWrapper() + { + stopTimer(); + deleteEditor (false); + + hasShutdown = true; + + delete filter; + filter = 0; + + jassert (editorComp == 0); + + juce_free (channels); + channels = 0; + deleteTempChannels(); + + jassert (activePlugins.contains (this)); + activePlugins.removeValue (this); + + if (activePlugins.size() == 0) + { +#if JUCE_LINUX + SharedMessageThread::deleteInstance(); +#endif + shutdownJuce_GUI(); + } + } + + void open() + { + if (editorComp == 0) + { + AudioProcessorEditor* const ed = filter->createEditorIfNeeded(); + + if (ed != 0) + cEffect.flags |= effFlagsHasEditor; + else + cEffect.flags &= ~effFlagsHasEditor; + + filter->editorBeingDeleted (ed); + delete ed; + } + + startTimer (1000 / 4); + } + + void close() + { + jassert (! recursionCheck); + + stopTimer(); + deleteEditor (false); + } + + //============================================================================== + bool getEffectName (char* name) + { + String (JucePlugin_Name).copyToBuffer (name, 64); + return true; + } + + bool getVendorString (char* text) + { + String (JucePlugin_Manufacturer).copyToBuffer (text, 64); + return true; + } + + bool getProductString (char* text) + { + return getEffectName (text); + } + + VstInt32 getVendorVersion() + { + return JucePlugin_VersionCode; + } + + VstPlugCategory getPlugCategory() + { + return JucePlugin_VSTCategory; + } + + VstInt32 canDo (char* text) + { + VstInt32 result = 0; + + if (strcmp (text, "receiveVstEvents") == 0 + || strcmp (text, "receiveVstMidiEvent") == 0 + || strcmp (text, "receiveVstMidiEvents") == 0) + { +#if JucePlugin_WantsMidiInput + result = 1; +#else + result = -1; +#endif + } + else if (strcmp (text, "sendVstEvents") == 0 + || strcmp (text, "sendVstMidiEvent") == 0 + || strcmp (text, "sendVstMidiEvents") == 0) + { +#if JucePlugin_ProducesMidiOutput + result = 1; +#else + result = -1; +#endif + } + else if (strcmp (text, "receiveVstTimeInfo") == 0 + || strcmp (text, "conformsToWindowRules") == 0) + { + result = 1; + } + + return result; + } + + bool keysRequired() + { + return (JucePlugin_EditorRequiresKeyboardFocus) != 0; + } + + bool getInputProperties (VstInt32 index, VstPinProperties* properties) + { + if (filter == 0 || index >= JucePlugin_MaxNumInputChannels) + return false; + + const String name (filter->getInputChannelName ((int) index)); + + name.copyToBuffer (properties->label, kVstMaxLabelLen - 1); + name.copyToBuffer (properties->shortLabel, kVstMaxShortLabelLen - 1); + + if (speakerIn != kSpeakerArrEmpty) + { + properties->flags = kVstPinUseSpeaker; + properties->arrangementType = speakerIn; + } + else + { + properties->flags = kVstPinIsActive; + + if (filter->isInputChannelStereoPair ((int) index)) + properties->flags |= kVstPinIsStereo; + + properties->arrangementType = 0; + } + + return true; + } + + bool getOutputProperties (VstInt32 index, VstPinProperties* properties) + { + if (filter == 0 || index >= JucePlugin_MaxNumOutputChannels) + return false; + + const String name (filter->getOutputChannelName ((int) index)); + + name.copyToBuffer (properties->label, kVstMaxLabelLen - 1); + name.copyToBuffer (properties->shortLabel, kVstMaxShortLabelLen - 1); + + if (speakerOut != kSpeakerArrEmpty) + { + properties->flags = kVstPinUseSpeaker; + properties->arrangementType = speakerOut; + } + else + { + properties->flags = kVstPinIsActive; + + if (filter->isOutputChannelStereoPair ((int) index)) + properties->flags |= kVstPinIsStereo; + + properties->arrangementType = 0; + } + + return true; + } + + //============================================================================== + VstInt32 processEvents (VstEvents* events) + { +#if JucePlugin_WantsMidiInput + VSTMidiEventList::addEventsToMidiBuffer (events, midiEvents); + return 1; +#else + return 0; +#endif + } + + void process (float** inputs, float** outputs, VstInt32 numSamples) + { + const int numIn = numInChans; + const int numOut = numOutChans; + + AudioSampleBuffer temp (numIn, numSamples); + int i; + for (i = numIn; --i >= 0;) + memcpy (temp.getSampleData (i), outputs[i], sizeof (float) * numSamples); + + processReplacing (inputs, outputs, numSamples); + + AudioSampleBuffer dest (outputs, numOut, numSamples); + + for (i = jmin (numIn, numOut); --i >= 0;) + dest.addFrom (i, 0, temp, i, 0, numSamples); + } + + void processReplacing (float** inputs, float** outputs, VstInt32 numSamples) + { + if (firstProcessCallback) + { + firstProcessCallback = false; + + // if this fails, the host hasn't called resume() before processing + jassert (isProcessing); + + // (tragically, some hosts actually need this, although it's stupid to have + // to do it here..) + if (! isProcessing) + resume(); + + filter->setNonRealtime (getCurrentProcessLevel() == 4 /* kVstProcessLevelOffline */); + +#if JUCE_WIN32 + if (GetThreadPriority (GetCurrentThread()) <= THREAD_PRIORITY_NORMAL + && GetThreadPriority (GetCurrentThread()) >= THREAD_PRIORITY_LOWEST) + filter->setNonRealtime (true); +#endif + } + +#if JUCE_DEBUG && ! JucePlugin_ProducesMidiOutput + const int numMidiEventsComingIn = midiEvents.getNumEvents(); +#endif + + jassert (activePlugins.contains (this)); + + { + const ScopedLock sl (filter->getCallbackLock()); + + const int numIn = numInChans; + const int numOut = numOutChans; + + if (filter->isSuspended()) + { + for (int i = 0; i < numOut; ++i) + zeromem (outputs[i], sizeof (float) * numSamples); + } + else + { + int i; + for (i = 0; i < numOut; ++i) + { + float* chan = (float*) tempChannels.getUnchecked(i); + + if (chan == 0) + { + chan = outputs[i]; + + // if some output channels are disabled, some hosts supply the same buffer + // for multiple channels - this buggers up our method of copying the + // inputs over the outputs, so we need to create unique temp buffers in this case.. + for (int j = i; --j >= 0;) + { + if (outputs[j] == chan) + { + chan = (float*) juce_malloc (sizeof (float) * blockSize * 2); + tempChannels.set (i, chan); + break; + } + } + } + + if (i < numIn && chan != inputs[i]) + memcpy (chan, inputs[i], sizeof (float) * numSamples); + + channels[i] = chan; + } + + for (; i < numIn; ++i) + channels[i] = inputs[i]; + + AudioSampleBuffer chans (channels, jmax (numIn, numOut), numSamples); + + filter->processBlock (chans, midiEvents); + } + } + + if (! midiEvents.isEmpty()) + { +#if JucePlugin_ProducesMidiOutput + const int numEvents = midiEvents.getNumEvents(); + + outgoingEvents.ensureSize (numEvents); + outgoingEvents.clear(); + + const JUCE_NAMESPACE::uint8* midiEventData; + int midiEventSize, midiEventPosition; + MidiBuffer::Iterator i (midiEvents); + + while (i.getNextEvent (midiEventData, midiEventSize, midiEventPosition)) + { + jassert (midiEventPosition >= 0 && midiEventPosition < numSamples); + + outgoingEvents.addEvent (midiEventData, midiEventSize, midiEventPosition); + } + + sendVstEventsToHost (outgoingEvents.events); +#else + /* This assertion is caused when you've added some events to the + midiMessages array in your processBlock() method, which usually means + that you're trying to send them somewhere. But in this case they're + getting thrown away. + + If your plugin does want to send midi messages, you'll need to set + the JucePlugin_ProducesMidiOutput macro to 1 in your + JucePluginCharacteristics.h file. + + If you don't want to produce any midi output, then you should clear the + midiMessages array at the end of your processBlock() method, to + indicate that you don't want any of the events to be passed through + to the output. + */ + jassert (midiEvents.getNumEvents() <= numMidiEventsComingIn); +#endif + + midiEvents.clear(); + } + } + + //============================================================================== + VstInt32 startProcess () { return 0; } + VstInt32 stopProcess () { return 0;} + + void resume() + { + if (filter == 0) + return; + + isProcessing = true; + juce_free (channels); + channels = (float**) juce_calloc (sizeof (float*) * (numInChans + numOutChans)); + + double rate = getSampleRate(); + jassert (rate > 0); + if (rate <= 0.0) + rate = 44100.0; + + const int blockSize = getBlockSize(); + jassert (blockSize > 0); + + firstProcessCallback = true; + + filter->setNonRealtime (getCurrentProcessLevel() == 4 /* kVstProcessLevelOffline */); + + filter->setPlayConfigDetails (numInChans, numOutChans, + rate, blockSize); + + deleteTempChannels(); + + filter->prepareToPlay (rate, blockSize); + midiEvents.clear(); + + setInitialDelay (filter->getLatencySamples()); + + AudioEffectX::resume(); + +#if JucePlugin_ProducesMidiOutput + outgoingEvents.ensureSize (64); +#endif + +#if JucePlugin_WantsMidiInput && ! JUCE_USE_VSTSDK_2_4 + wantEvents(); +#endif + } + + void suspend() + { + if (filter == 0) + return; + + AudioEffectX::suspend(); + + filter->releaseResources(); + outgoingEvents.freeEvents(); + + isProcessing = false; + juce_free (channels); + channels = 0; + + deleteTempChannels(); + } + + bool getCurrentPosition (AudioPlayHead::CurrentPositionInfo& info) + { + const VstTimeInfo* const ti = getTimeInfo (kVstPpqPosValid + | kVstTempoValid + | kVstBarsValid + //| kVstCyclePosValid + | kVstTimeSigValid + | kVstSmpteValid + | kVstClockValid); + + if (ti == 0 || ti->sampleRate <= 0) + return false; + + if ((ti->flags & kVstTempoValid) != 0) + info.bpm = ti->tempo; + else + info.bpm = 0.0; + + if ((ti->flags & kVstTimeSigValid) != 0) + { + info.timeSigNumerator = ti->timeSigNumerator; + info.timeSigDenominator = ti->timeSigDenominator; + } + else + { + info.timeSigNumerator = 4; + info.timeSigDenominator = 4; + } + + info.timeInSeconds = ti->samplePos / ti->sampleRate; + + if ((ti->flags & kVstPpqPosValid) != 0) + info.ppqPosition = ti->ppqPos; + else + info.ppqPosition = 0.0; + + if ((ti->flags & kVstBarsValid) != 0) + info.ppqPositionOfLastBarStart = ti->barStartPos; + else + info.ppqPositionOfLastBarStart = 0.0; + + if ((ti->flags & kVstSmpteValid) != 0) + { + AudioPlayHead::FrameRateType rate = AudioPlayHead::fpsUnknown; + double fps = 1.0; + + switch (ti->smpteFrameRate) + { + case kVstSmpte24fps: + rate = AudioPlayHead::fps24; + fps = 24.0; + break; + + case kVstSmpte25fps: + rate = AudioPlayHead::fps25; + fps = 25.0; + break; + + case kVstSmpte2997fps: + rate = AudioPlayHead::fps2997; + fps = 29.97; + break; + + case kVstSmpte30fps: + rate = AudioPlayHead::fps30; + fps = 30.0; + break; + + case kVstSmpte2997dfps: + rate = AudioPlayHead::fps2997drop; + fps = 29.97; + break; + + case kVstSmpte30dfps: + rate = AudioPlayHead::fps30drop; + fps = 30.0; + break; + + case kVstSmpteFilm16mm: + case kVstSmpteFilm35mm: + fps = 24.0; + break; + + case kVstSmpte239fps: fps = 23.976; break; + case kVstSmpte249fps: fps = 24.976; break; + case kVstSmpte599fps: fps = 59.94; break; + case kVstSmpte60fps: fps = 60; break; + + default: + jassertfalse // unknown frame-rate.. + } + + info.frameRate = rate; + info.editOriginTime = ti->smpteOffset / (80.0 * fps); + } + else + { + info.frameRate = AudioPlayHead::fpsUnknown; + info.editOriginTime = 0; + } + + info.isRecording = (ti->flags & kVstTransportRecording) != 0; + info.isPlaying = (ti->flags & kVstTransportPlaying) != 0 || info.isRecording; + + return true; + } + + //============================================================================== + VstInt32 getProgram() + { + return filter != 0 ? filter->getCurrentProgram() : 0; + } + + void setProgram (VstInt32 program) + { + if (filter != 0) + filter->setCurrentProgram (program); + } + + void setProgramName (char* name) + { + if (filter != 0) + filter->changeProgramName (filter->getCurrentProgram(), name); + } + + void getProgramName (char* name) + { + if (filter != 0) + filter->getProgramName (filter->getCurrentProgram()).copyToBuffer (name, 24); + } + + bool getProgramNameIndexed (VstInt32 category, VstInt32 index, char* text) + { + if (filter != 0 && ((unsigned int) index) < (unsigned int) filter->getNumPrograms()) + { + filter->getProgramName (index).copyToBuffer (text, 24); + return true; + } + + return false; + } + + //============================================================================== + float getParameter (VstInt32 index) + { + if (filter == 0) + return 0.0f; + + jassert (((unsigned int) index) < (unsigned int) filter->getNumParameters()); + return filter->getParameter (index); + } + + void setParameter (VstInt32 index, float value) + { + if (filter != 0) + { + jassert (((unsigned int) index) < (unsigned int) filter->getNumParameters()); + filter->setParameter (index, value); + } + } + + void getParameterDisplay (VstInt32 index, char* text) + { + if (filter != 0) + { + jassert (((unsigned int) index) < (unsigned int) filter->getNumParameters()); + filter->getParameterText (index).copyToBuffer (text, 24); // length should technically be kVstMaxParamStrLen, which is 8, but hosts will normally allow a bit more. + } + } + + void getParameterName (VstInt32 index, char* text) + { + if (filter != 0) + { + jassert (((unsigned int) index) < (unsigned int) filter->getNumParameters()); + filter->getParameterName (index).copyToBuffer (text, 16); // length should technically be kVstMaxParamStrLen, which is 8, but hosts will normally allow a bit more. + } + } + + void audioProcessorParameterChanged (AudioProcessor*, int index, float newValue) + { + setParameterAutomated (index, newValue); + } + + void audioProcessorParameterChangeGestureBegin (AudioProcessor*, int index) + { + beginEdit (index); + } + + void audioProcessorParameterChangeGestureEnd (AudioProcessor*, int index) + { + endEdit (index); + } + + void audioProcessorChanged (AudioProcessor*) + { + updateDisplay(); + } + + bool canParameterBeAutomated (VstInt32 index) + { + return filter != 0 && filter->isParameterAutomatable ((int) index); + } + + bool setSpeakerArrangement (VstSpeakerArrangement* pluginInput, + VstSpeakerArrangement* pluginOutput) + { + const short channelConfigs[][2] = { JucePlugin_PreferredChannelConfigurations }; + + for (int i = 0; i < numElementsInArray (channelConfigs); ++i) + { + bool configMono = (channelConfigs[i][1] == 1) && (pluginOutput->type == kSpeakerArrMono); + bool configStereo = (channelConfigs[i][1] == 2) && (pluginOutput->type == kSpeakerArrStereo); + bool inCountMatches = (channelConfigs[i][0] == pluginInput->numChannels); + bool outCountMatches = (channelConfigs[i][1] == pluginOutput->numChannels); + + if ((configMono || configStereo) && inCountMatches && outCountMatches) + { + speakerIn = (VstSpeakerArrangementType) pluginInput->type; + speakerOut = (VstSpeakerArrangementType) pluginOutput->type; + speakerInChans = pluginInput->numChannels; + speakerOutChans = pluginOutput->numChannels; + + filter->setPlayConfigDetails (speakerInChans, speakerOutChans, + filter->getSampleRate(), + filter->getBlockSize()); + return true; + } + } + + return false; + } + + //============================================================================== + VstInt32 getChunk (void** data, bool onlyStoreCurrentProgramData) + { + if (filter == 0) + return 0; + + chunkMemory.setSize (0); + if (onlyStoreCurrentProgramData) + filter->getCurrentProgramStateInformation (chunkMemory); + else + filter->getStateInformation (chunkMemory); + + *data = (void*) chunkMemory; + + // because the chunk is only needed temporarily by the host (or at least you'd + // hope so) we'll give it a while and then free it in the timer callback. + chunkMemoryTime = JUCE_NAMESPACE::Time::getApproximateMillisecondCounter(); + + return chunkMemory.getSize(); + } + + VstInt32 setChunk (void* data, VstInt32 byteSize, bool onlyRestoreCurrentProgramData) + { + if (filter == 0) + return 0; + + chunkMemory.setSize (0); + chunkMemoryTime = 0; + + if (byteSize > 0 && data != 0) + { + if (onlyRestoreCurrentProgramData) + filter->setCurrentProgramStateInformation (data, byteSize); + else + filter->setStateInformation (data, byteSize); + } + + return 0; + } + + void timerCallback() + { + if (shouldDeleteEditor) + { + shouldDeleteEditor = false; + deleteEditor (true); + } + + if (chunkMemoryTime > 0 + && chunkMemoryTime < JUCE_NAMESPACE::Time::getApproximateMillisecondCounter() - 2000 + && ! recursionCheck) + { + chunkMemoryTime = 0; + chunkMemory.setSize (0); + } + +#if JUCE_MAC + if (hostWindow != 0) + checkWindowVisibility (hostWindow, editorComp); +#endif + + tryMasterIdle(); + } + + void tryMasterIdle() + { + if (Component::isMouseButtonDownAnywhere() + && ! recursionCheck) + { + const JUCE_NAMESPACE::uint32 now = JUCE_NAMESPACE::Time::getMillisecondCounter(); + + if (now > lastMasterIdleCall + 20 && editorComp != 0) + { + lastMasterIdleCall = now; + + recursionCheck = true; + masterIdle(); + recursionCheck = false; + } + } + } + + void doIdleCallback() + { + // (wavelab calls this on a separate thread and causes a deadlock).. + if (MessageManager::getInstance()->isThisTheMessageThread() + && ! recursionCheck) + { + recursionCheck = true; + + juce_callAnyTimersSynchronously(); + + for (int i = ComponentPeer::getNumPeers(); --i >= 0;) + ComponentPeer::getPeer (i)->performAnyPendingRepaintsNow(); + + recursionCheck = false; + } + } + + void createEditorComp() + { + if (hasShutdown || filter == 0) + return; + + if (editorComp == 0) + { + AudioProcessorEditor* const ed = filter->createEditorIfNeeded(); + + if (ed != 0) + { + cEffect.flags |= effFlagsHasEditor; + ed->setOpaque (true); + ed->setVisible (true); + + editorComp = new EditorCompWrapper (this, ed); + } + else + { + cEffect.flags &= ~effFlagsHasEditor; + } + } + + shouldDeleteEditor = false; + } + + void deleteEditor (bool canDeleteLaterIfModal) + { + PopupMenu::dismissAllActiveMenus(); + + jassert (! recursionCheck); + recursionCheck = true; + + if (editorComp != 0) + { + Component* const modalComponent = Component::getCurrentlyModalComponent(); + if (modalComponent != 0) + { + modalComponent->exitModalState (0); + + if (canDeleteLaterIfModal) + { + shouldDeleteEditor = true; + return; + } + } + +#if JUCE_MAC + if (hostWindow != 0) + { + detachComponentFromWindowRef (editorComp, hostWindow); + hostWindow = 0; + } +#endif + + filter->editorBeingDeleted (editorComp->getEditorComp()); + + deleteAndZero (editorComp); + + // there's some kind of component currently modal, but the host + // is trying to delete our plugin. You should try to avoid this happening.. + jassert (Component::getCurrentlyModalComponent() == 0); + } + +#if JUCE_LINUX + hostWindow = 0; +#endif + + recursionCheck = false; + } + + VstIntPtr dispatcher (VstInt32 opCode, VstInt32 index, VstIntPtr value, void* ptr, float opt) + { + if (hasShutdown) + return 0; + + if (opCode == effEditIdle) + { + doIdleCallback(); + return 0; + } + else if (opCode == effEditOpen) + { + jassert (! recursionCheck); + + deleteEditor (true); + createEditorComp(); + + if (editorComp != 0) + { + editorComp->setOpaque (true); + editorComp->setVisible (false); + +#if JUCE_WIN32 + editorComp->addToDesktop (0); + hostWindow = (HWND) ptr; + HWND editorWnd = (HWND) editorComp->getWindowHandle(); + SetParent (editorWnd, hostWindow); + + DWORD val = GetWindowLong (editorWnd, GWL_STYLE); + val = (val & ~WS_POPUP) | WS_CHILD; + SetWindowLong (editorWnd, GWL_STYLE, val); +#elif JUCE_LINUX + editorComp->addToDesktop (0); + hostWindow = (Window) ptr; + Window editorWnd = (Window) editorComp->getWindowHandle(); + XReparentWindow (display, editorWnd, hostWindow, 0, 0); +#else + hostWindow = attachComponentToWindowRef (editorComp, (WindowRef) ptr); +#endif + editorComp->setVisible (true); + + return 1; + } + } + else if (opCode == effEditClose) + { + deleteEditor (true); + return 0; + } + else if (opCode == effEditGetRect) + { + createEditorComp(); + + if (editorComp != 0) + { + editorSize.left = 0; + editorSize.top = 0; + editorSize.right = editorComp->getWidth(); + editorSize.bottom = editorComp->getHeight(); + + *((ERect**) ptr) = &editorSize; + + return (VstIntPtr) (pointer_sized_int) &editorSize; + } + else + { + return 0; + } + } + + return AudioEffectX::dispatcher (opCode, index, value, ptr, opt); + } + + void resizeHostWindow (int newWidth, int newHeight) + { + if (editorComp != 0) + { +#if ! JUCE_LINUX // linux hosts shouldn't be trusted! + if (! (canHostDo ("sizeWindow") && sizeWindow (newWidth, newHeight))) +#endif + { + // some hosts don't support the sizeWindow call, so do it manually.. +#if JUCE_MAC + setNativeHostWindowSize (hostWindow, editorComp, newWidth, newHeight); +#elif JUCE_LINUX + Window root; + int x, y; + unsigned int width, height, border, depth; + + XGetGeometry (display, hostWindow, &root, + &x, &y, &width, &height, &border, &depth); + + newWidth += (width + border) - editorComp->getWidth(); + newHeight += (height + border) - editorComp->getHeight(); + + XResizeWindow (display, hostWindow, newWidth, newHeight); +#else + int dw = 0; + int dh = 0; + const int frameThickness = GetSystemMetrics (SM_CYFIXEDFRAME); + + HWND w = (HWND) editorComp->getWindowHandle(); + + while (w != 0) + { + HWND parent = GetParent (w); + + if (parent == 0) + break; + + TCHAR windowType [32]; + zeromem (windowType, sizeof (windowType)); + GetClassName (parent, windowType, 31); + + if (String (windowType).equalsIgnoreCase (T("MDIClient"))) + break; + + RECT windowPos; + GetWindowRect (w, &windowPos); + + RECT parentPos; + GetWindowRect (parent, &parentPos); + + SetWindowPos (w, 0, 0, 0, + newWidth + dw, + newHeight + dh, + SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOZORDER | SWP_NOOWNERZORDER); + + dw = (parentPos.right - parentPos.left) - (windowPos.right - windowPos.left); + dh = (parentPos.bottom - parentPos.top) - (windowPos.bottom - windowPos.top); + + w = parent; + + if (dw == 2 * frameThickness) + break; + + if (dw > 100 || dh > 100) + w = 0; + } + + if (w != 0) + SetWindowPos (w, 0, 0, 0, + newWidth + dw, + newHeight + dh, + SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOZORDER | SWP_NOOWNERZORDER); +#endif + } + + if (editorComp->getPeer() != 0) + editorComp->getPeer()->handleMovedOrResized(); + } + } + + + //============================================================================== + juce_UseDebuggingNewOperator + +private: + AudioProcessor* filter; + JUCE_NAMESPACE::MemoryBlock chunkMemory; + JUCE_NAMESPACE::uint32 chunkMemoryTime; + EditorCompWrapper* editorComp; + ERect editorSize; + MidiBuffer midiEvents; + VSTMidiEventList outgoingEvents; + bool isProcessing; + bool hasShutdown; + bool firstProcessCallback; + int diffW, diffH; + VstSpeakerArrangementType speakerIn, speakerOut; + int speakerInChans, speakerOutChans; + int numInChans, numOutChans; + float** channels; + VoidArray tempChannels; // see note in processReplacing() + bool hasCreatedTempChannels; + bool shouldDeleteEditor; + + void deleteTempChannels() + { + int i; + for (i = tempChannels.size(); --i >= 0;) + juce_free (tempChannels.getUnchecked(i)); + + tempChannels.clear(); + + if (filter != 0) + tempChannels.insertMultiple (0, 0, filter->getNumInputChannels() + filter->getNumOutputChannels()); + + hasCreatedTempChannels = false; + } + + const String getHostName() + { + char host[256]; + zeromem (host, sizeof (host)); + getHostProductString (host); + return host; + } + +#if JUCE_MAC + void* hostWindow; +#elif JUCE_LINUX + Window hostWindow; +#else + HWND hostWindow; +#endif +}; + +//============================================================================== +void EditorCompWrapper::childBoundsChanged (Component* child) +{ + child->setTopLeftPosition (0, 0); + + const int cw = child->getWidth(); + const int ch = child->getHeight(); + + wrapper->resizeHostWindow (cw, ch); + setSize (cw, ch); + +#if JUCE_MAC + wrapper->resizeHostWindow (cw, ch); // (doing this a second time seems to be necessary in tracktion) +#endif +} + +void EditorCompWrapper::handleAsyncUpdate() +{ + wrapper->tryMasterIdle(); +} + +//============================================================================== +/** Somewhere in the codebase of your plugin, you need to implement this function + and make it create an instance of the filter subclass that you're building. +*/ +extern AudioProcessor* JUCE_CALLTYPE createPluginFilter(); + + +//============================================================================== +static AEffect* pluginEntryPoint (audioMasterCallback audioMaster) +{ + initialiseJuce_GUI(); + +#if JUCE_MAC && defined (JucePlugin_CFBundleIdentifier) + juce_setCurrentExecutableFileNameFromBundleId (JucePlugin_CFBundleIdentifier); +#endif + + try + { + if (audioMaster (0, audioMasterVersion, 0, 0, 0, 0) != 0) + { + AudioProcessor* const filter = createPluginFilter(); + + if (filter != 0) + { + JuceVSTWrapper* const wrapper = new JuceVSTWrapper (audioMaster, filter); + return wrapper->getAeffect(); + } + } + } + catch (...) + {} + + return 0; +} + + +//============================================================================== +// Mac startup code.. +#if JUCE_MAC + +extern "C" __attribute__ ((visibility("default"))) AEffect* VSTPluginMain (audioMasterCallback audioMaster) +{ + initialiseMac(); + return pluginEntryPoint (audioMaster); +} + +extern "C" __attribute__ ((visibility("default"))) AEffect* main_macho (audioMasterCallback audioMaster) +{ + initialiseMac(); + return pluginEntryPoint (audioMaster); +} + +//============================================================================== +// Linux startup code.. +#elif JUCE_LINUX + +extern "C" AEffect* VSTPluginMain (audioMasterCallback audioMaster) +{ + initialiseJuce_GUI(); + SharedMessageThread::getInstance(); + + return pluginEntryPoint (audioMaster); +} + +extern "C" __attribute__ ((visibility("default"))) AEffect* main_plugin (audioMasterCallback audioMaster) asm ("main"); + +extern "C" __attribute__ ((visibility("default"))) AEffect* main_plugin (audioMasterCallback audioMaster) +{ + return VSTPluginMain (audioMaster); +} + +__attribute__((constructor)) void myPluginInit() +{ + // don't put initialiseJuce_GUI here... it will crash ! +} + +__attribute__((destructor)) void myPluginFini() +{ + // don't put shutdownJuce_GUI here... it will crash ! +} + +//============================================================================== +// Win32 startup code.. +#else + +extern "C" __declspec (dllexport) AEffect* VSTPluginMain (audioMasterCallback audioMaster) +{ + return pluginEntryPoint (audioMaster); +} + +#ifndef _WIN64 // (can't compile this on win64, but it's not needed anyway with VST2.4) +extern "C" __declspec (dllexport) void* main (audioMasterCallback audioMaster) +{ + return (void*) pluginEntryPoint (audioMaster); +} +#endif + +#if JucePlugin_Build_RTAS +BOOL WINAPI DllMainVST (HINSTANCE instance, DWORD dwReason, LPVOID) +#else +extern "C" BOOL WINAPI DllMain (HINSTANCE instance, DWORD dwReason, LPVOID) +#endif +{ + if (dwReason == DLL_PROCESS_ATTACH) + PlatformUtilities::setCurrentModuleInstanceHandle (instance); + + return TRUE; +} + +#endif + +#endif diff --git a/extras/example projects/example_project_for_Mac/juce_application.xcodeproj/project.pbxproj b/extras/example projects/example_project_for_Mac/juce_application.xcodeproj/project.pbxproj index 90d8b0f5b7..8e6d7eef2b 100644 --- a/extras/example projects/example_project_for_Mac/juce_application.xcodeproj/project.pbxproj +++ b/extras/example projects/example_project_for_Mac/juce_application.xcodeproj/project.pbxproj @@ -11,6 +11,7 @@ 841083D50DB36EA400AB8583 /* MainComponent.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 841083D30DB36EA400AB8583 /* MainComponent.cpp */; }; 841084880DB374E700AB8583 /* juce.xcconfig in Resources */ = {isa = PBXBuildFile; fileRef = 841084870DB374E700AB8583 /* juce.xcconfig */; }; 841136A00D0480DE0054B790 /* OpenGL.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 8411369F0D0480DE0054B790 /* OpenGL.framework */; }; + 84204DA50FDEFA3800FA4ABC /* Carbon.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 84204DA40FDEFA3800FA4ABC /* Carbon.framework */; }; 846EC7870EB607050080CCFF /* QTKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 846EC7860EB607050080CCFF /* QTKit.framework */; }; 84F30CD108FEAAA20087E26C /* Main.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 84F30CD008FEAAA20087E26C /* Main.cpp */; }; 84F30CED08FEAD7A0087E26C /* CoreAudio.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 84F30CEC08FEAD7A0087E26C /* CoreAudio.framework */; }; @@ -34,6 +35,7 @@ 841083D40DB36EA400AB8583 /* MainComponent.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = MainComponent.h; path = ../common/MainComponent.h; sourceTree = SOURCE_ROOT; }; 841084870DB374E700AB8583 /* juce.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = juce.xcconfig; path = ../../../build/macosx/juce.xcconfig; sourceTree = SOURCE_ROOT; }; 8411369F0D0480DE0054B790 /* OpenGL.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = OpenGL.framework; path = /System/Library/Frameworks/OpenGL.framework; sourceTree = ""; }; + 84204DA40FDEFA3800FA4ABC /* Carbon.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Carbon.framework; path = System/Library/Frameworks/Carbon.framework; sourceTree = SDKROOT; }; 846EC7860EB607050080CCFF /* QTKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = QTKit.framework; path = /System/Library/Frameworks/QTKit.framework; sourceTree = ""; }; 84F30CD008FEAAA20087E26C /* Main.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = Main.cpp; path = ../common/Main.cpp; sourceTree = SOURCE_ROOT; }; 84F30CEC08FEAD7A0087E26C /* CoreAudio.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreAudio.framework; path = /System/Library/Frameworks/CoreAudio.framework; sourceTree = ""; }; @@ -64,6 +66,7 @@ 84FBB8880E06CCE900B52196 /* AudioUnit.framework in Frameworks */, 84FBB88D0E06CD0100B52196 /* WebKit.framework in Frameworks */, 846EC7870EB607050080CCFF /* QTKit.framework in Frameworks */, + 84204DA50FDEFA3800FA4ABC /* Carbon.framework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -115,6 +118,7 @@ 20286C32FDCF999611CA2CEA /* External Frameworks and Libraries */ = { isa = PBXGroup; children = ( + 84204DA40FDEFA3800FA4ABC /* Carbon.framework */, 84FBB8870E06CCE900B52196 /* AudioUnit.framework */, 84FBB8720E06CC5D00B52196 /* Cocoa.framework */, 4A9504CAFFE6A41611CA0CBA /* CoreServices.framework */, diff --git a/extras/juce demo/build/win32_vc8/jucedemo.vcproj b/extras/juce demo/build/win32_vc8/jucedemo.vcproj index c50c23f2ed..75c528e676 100644 --- a/extras/juce demo/build/win32_vc8/jucedemo.vcproj +++ b/extras/juce demo/build/win32_vc8/jucedemo.vcproj @@ -107,9 +107,6 @@ - @@ -148,7 +145,7 @@ Name="VCCLCompilerTool" Optimization="0" PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS" - MinimalRebuild="true" + MinimalRebuild="false" BasicRuntimeChecks="3" RuntimeLibrary="1" BufferSecurityCheck="true" @@ -176,7 +173,6 @@ - diff --git a/juce_amalgamated.cpp b/juce_amalgamated.cpp index 3e2202be0d..d122ff6b4e 100644 --- a/juce_amalgamated.cpp +++ b/juce_amalgamated.cpp @@ -568,6 +568,46 @@ #pragma warning (pop) #endif +/** A simple COM smart pointer. + Avoids having to include ATL just to get one of these. +*/ +template +class ComSmartPtr +{ +public: + ComSmartPtr() throw() : p (0) {} + ComSmartPtr (T* const p_) : p (p_) { if (p_ != 0) p_->AddRef(); } + ComSmartPtr (const ComSmartPtr& p_) : p (p_.p) { if (p != 0) p->AddRef(); } + ~ComSmartPtr() { if (p != 0) p->Release(); } + + operator T*() const throw() { return p; } + T& operator*() const throw() { return *p; } + T** operator&() throw() { return &p; } + T* operator->() const throw() { return p; } + + T* operator= (T* const newP) + { + if (newP != 0) + newP->AddRef(); + + if (p != 0) + p->Release(); + + p = newP; + return newP; + } + + T* operator= (const ComSmartPtr& newP) { return operator= (newP.p); } + + HRESULT CoCreateInstance (REFCLSID rclsid, DWORD dwClsContext) + { + operator= (0); + return ::CoCreateInstance (rclsid, 0, dwClsContext, __uuidof(T), (void**) &p); + } + + T* p; +}; + #endif // __JUCE_WIN32_NATIVEINCLUDES_JUCEHEADER__ /********* End of inlined file: juce_win32_NativeIncludes.h *********/ @@ -7655,7 +7695,7 @@ bool StreamingSocket::isLocal() const throw() DatagramSocket::DatagramSocket (const int localPortNumber) : portNumber (0), handle (-1), - connected (false), + connected (true), serverAddress (0) { #if JUCE_WIN32 @@ -17803,12 +17843,12 @@ class AiffAudioFormatWriter : public AudioFormatWriter public: AiffAudioFormatWriter (OutputStream* out, - const double sampleRate, + const double sampleRate_, const unsigned int chans, const int bits) : AudioFormatWriter (out, aiffFormatName, - sampleRate, + sampleRate_, chans, bits), lengthInSamples (0), @@ -23300,9 +23340,17 @@ void AudioDeviceManager::setDefaultMidiOutput (const String& deviceName) { if (defaultMidiOutputName != deviceName) { + SortedSet oldCallbacks; + + { + const ScopedLock sl (audioCallbackLock); + oldCallbacks = callbacks; + callbacks.clear(); + } + if (currentAudioDevice != 0) - for (int i = callbacks.size(); --i >= 0;) - callbacks.getUnchecked(i)->audioDeviceStopped(); + for (int i = oldCallbacks.size(); --i >= 0;) + oldCallbacks.getUnchecked(i)->audioDeviceStopped(); deleteAndZero (defaultMidiOutput); defaultMidiOutputName = deviceName; @@ -23311,8 +23359,13 @@ void AudioDeviceManager::setDefaultMidiOutput (const String& deviceName) defaultMidiOutput = MidiOutput::openDevice (MidiOutput::getDevices().indexOf (deviceName)); if (currentAudioDevice != 0) - for (int i = callbacks.size(); --i >= 0;) - callbacks.getUnchecked(i)->audioDeviceAboutToStart (currentAudioDevice); + for (int i = oldCallbacks.size(); --i >= 0;) + oldCallbacks.getUnchecked(i)->audioDeviceAboutToStart (currentAudioDevice); + + { + const ScopedLock sl (audioCallbackLock); + callbacks = oldCallbacks; + } updateXml(); sendChangeMessage (this); @@ -39550,7 +39603,7 @@ void Component::updateMouseCursor() const throw() sendFakeMouseMove(); } -void Component::internalUpdateMouseCursor (const bool forcedUpdate) throw() +void Component::internalUpdateMouseCursor (bool forcedUpdate) throw() { ComponentPeer* const peer = getPeer(); @@ -39563,6 +39616,7 @@ void Component::internalUpdateMouseCursor (const bool forcedUpdate) throw() || ! isCursorVisibleUntilOffscreen)) { mc = MouseCursor::NoCursor; + forcedUpdate = true; } static void* currentCursorHandle = 0; @@ -42841,7 +42895,7 @@ void DrawableButton::paintButton (Graphics& g, g.setFont ((float) textH); g.setColour (Colours::black.withAlpha (isEnabled() ? 1.0f : 0.4f)); - g.drawFittedText (getName(), + g.drawFittedText (getButtonText(), 2, getHeight() - textH - 1, getWidth() - 4, textH, Justification::centred, 1); @@ -43046,8 +43100,8 @@ END_JUCE_NAMESPACE BEGIN_JUCE_NAMESPACE -ImageButton::ImageButton (const String& text) - : Button (text), +ImageButton::ImageButton (const String& text_) + : Button (text_), scaleImageToFit (true), preserveProportions (true), alphaThreshold (0), @@ -43446,11 +43500,11 @@ END_JUCE_NAMESPACE BEGIN_JUCE_NAMESPACE -ToolbarButton::ToolbarButton (const int itemId, +ToolbarButton::ToolbarButton (const int itemId_, const String& buttonText, Drawable* const normalImage_, Drawable* const toggledOnImage_) - : ToolbarItemComponent (itemId, buttonText, true), + : ToolbarItemComponent (itemId_, buttonText, true), normalImage (normalImage_), toggledOnImage (toggledOnImage_) { @@ -48160,12 +48214,12 @@ void TableListBox::paintListBoxItem (int, Graphics&, int, int, bool) { } -Component* TableListBox::refreshComponentForRow (int rowNumber, bool isRowSelected, Component* existingComponentToUpdate) +Component* TableListBox::refreshComponentForRow (int rowNumber, bool isRowSelected_, Component* existingComponentToUpdate) { if (existingComponentToUpdate == 0) existingComponentToUpdate = new TableListRowComp (*this); - ((TableListRowComp*) existingComponentToUpdate)->update (rowNumber, isRowSelected); + ((TableListRowComp*) existingComponentToUpdate)->update (rowNumber, isRowSelected_); return existingComponentToUpdate; } @@ -57148,6 +57202,7 @@ void ComponentAnimator::animateComponent (Component* const component, { at = new AnimationTask (component); tasks.add (at); + sendChangeMessage (this); } at->msElapsed = 0; @@ -57187,6 +57242,7 @@ void ComponentAnimator::cancelAllAnimations (const bool moveComponentsToTheirFin delete at; tasks.remove (i); + sendChangeMessage (this); } } @@ -57202,6 +57258,7 @@ void ComponentAnimator::cancelAnimation (Component* const component, tasks.removeValue (at); delete at; + sendChangeMessage (this); } } @@ -57217,6 +57274,11 @@ const Rectangle ComponentAnimator::getComponentDestination (Component* const com return Rectangle(); } +bool ComponentAnimator::isAnimating (Component* component) const +{ + return findTaskFor (component) != 0; +} + void ComponentAnimator::timerCallback() { const uint32 timeNow = Time::getMillisecondCounter(); @@ -57234,6 +57296,7 @@ void ComponentAnimator::timerCallback() { tasks.remove (i); delete at; + sendChangeMessage (this); } } @@ -57888,7 +57951,7 @@ void MultiDocumentPanel::addWindow (Component* component) } bool MultiDocumentPanel::addDocument (Component* const component, - const Colour& backgroundColour, + const Colour& docColour, const bool deleteWhenRemoved) { // If you try passing a full DocumentWindow or ResizableWindow in here, you'll end up @@ -57900,7 +57963,7 @@ bool MultiDocumentPanel::addDocument (Component* const component, components.add (component); component->setComponentProperty (T("mdiDocumentDelete_"), deleteWhenRemoved); - component->setComponentProperty (T("mdiDocumentBkg_"), backgroundColour); + component->setComponentProperty (T("mdiDocumentBkg_"), docColour); component->addComponentListener (this); if (mode == FloatingWindows) @@ -57933,14 +57996,14 @@ bool MultiDocumentPanel::addDocument (Component* const component, Array temp (components); for (int i = 0; i < temp.size(); ++i) - tabComponent->addTab (temp[i]->getName(), backgroundColour, temp[i], false); + tabComponent->addTab (temp[i]->getName(), docColour, temp[i], false); resized(); } else { if (tabComponent != 0) - tabComponent->addTab (component->getName(), backgroundColour, component, false); + tabComponent->addTab (component->getName(), docColour, component, false); else addAndMakeVisible (component); } @@ -70390,9 +70453,9 @@ class MagnifyingPeer : public ComponentPeer { public: - MagnifyingPeer (Component* const component, + MagnifyingPeer (Component* const component_, MagnifierComponent* const magnifierComp_) - : ComponentPeer (component, 0), + : ComponentPeer (component_, 0), magnifierComp (magnifierComp_) { } @@ -87970,65 +88033,65 @@ void PositionedRectangle::decodeSizeString (const String& s, uint8& mode, double } void PositionedRectangle::applyPosAndSize (double& xOut, double& wOut, - const double x, const double w, - const uint8 xMode, const uint8 wMode, + const double x_, const double w_, + const uint8 xMode_, const uint8 wMode_, const int parentPos, const int parentSize) const throw() { - if (wMode == proportionalSize) - wOut = roundDoubleToInt (w * parentSize); - else if (wMode == parentSizeMinusAbsolute) - wOut = jmax (0, parentSize - roundDoubleToInt (w)); + if (wMode_ == proportionalSize) + wOut = roundDoubleToInt (w_ * parentSize); + else if (wMode_ == parentSizeMinusAbsolute) + wOut = jmax (0, parentSize - roundDoubleToInt (w_)); else - wOut = roundDoubleToInt (w); - - if ((xMode & proportionOfParentSize) != 0) - xOut = parentPos + x * parentSize; - else if ((xMode & absoluteFromParentBottomRight) != 0) - xOut = (parentPos + parentSize) - x; - else if ((xMode & absoluteFromParentCentre) != 0) - xOut = x + (parentPos + parentSize / 2); + wOut = roundDoubleToInt (w_); + + if ((xMode_ & proportionOfParentSize) != 0) + xOut = parentPos + x_ * parentSize; + else if ((xMode_ & absoluteFromParentBottomRight) != 0) + xOut = (parentPos + parentSize) - x_; + else if ((xMode_ & absoluteFromParentCentre) != 0) + xOut = x_ + (parentPos + parentSize / 2); else - xOut = x + parentPos; + xOut = x_ + parentPos; - if ((xMode & anchorAtRightOrBottom) != 0) + if ((xMode_ & anchorAtRightOrBottom) != 0) xOut -= wOut; - else if ((xMode & anchorAtCentre) != 0) + else if ((xMode_ & anchorAtCentre) != 0) xOut -= wOut / 2; } void PositionedRectangle::updatePosAndSize (double& xOut, double& wOut, - double x, const double w, - const uint8 xMode, const uint8 wMode, + double x_, const double w_, + const uint8 xMode_, const uint8 wMode_, const int parentPos, const int parentSize) const throw() { - if (wMode == proportionalSize) + if (wMode_ == proportionalSize) { if (parentSize > 0) - wOut = w / parentSize; + wOut = w_ / parentSize; } - else if (wMode == parentSizeMinusAbsolute) - wOut = parentSize - w; + else if (wMode_ == parentSizeMinusAbsolute) + wOut = parentSize - w_; else - wOut = w; + wOut = w_; - if ((xMode & anchorAtRightOrBottom) != 0) - x += w; - else if ((xMode & anchorAtCentre) != 0) - x += w / 2; + if ((xMode_ & anchorAtRightOrBottom) != 0) + x_ += w_; + else if ((xMode_ & anchorAtCentre) != 0) + x_ += w_ / 2; - if ((xMode & proportionOfParentSize) != 0) + if ((xMode_ & proportionOfParentSize) != 0) { if (parentSize > 0) - xOut = (x - parentPos) / parentSize; + xOut = (x_ - parentPos) / parentSize; } - else if ((xMode & absoluteFromParentBottomRight) != 0) - xOut = (parentPos + parentSize) - x; - else if ((xMode & absoluteFromParentCentre) != 0) - xOut = x - (parentPos + parentSize / 2); + else if ((xMode_ & absoluteFromParentBottomRight) != 0) + xOut = (parentPos + parentSize) - x_; + else if ((xMode_ & absoluteFromParentCentre) != 0) + xOut = x_ - (parentPos + parentSize / 2); else - xOut = x - parentPos; + xOut = x_ - parentPos; } END_JUCE_NAMESPACE @@ -241899,11 +241962,10 @@ const File File::getLinkedTarget() const throw() else if (getFileExtension() != T(".lnk")) return result; - IShellLink* shellLink = 0; - if (SUCCEEDED (CoCreateInstance (CLSID_ShellLink, 0, CLSCTX_INPROC_SERVER, - IID_IShellLink, (LPVOID*) &shellLink))) + ComSmartPtr shellLink; + if (SUCCEEDED (shellLink.CoCreateInstance (CLSID_ShellLink, CLSCTX_INPROC_SERVER))) { - IPersistFile* persistFile; + ComSmartPtr persistFile; if (SUCCEEDED (shellLink->QueryInterface (IID_IPersistFile, (LPVOID*) &persistFile))) { if (SUCCEEDED (persistFile->Load ((const WCHAR*) p, STGM_READ)) @@ -241915,11 +241977,7 @@ const File File::getLinkedTarget() const throw() if (SUCCEEDED (shellLink->GetPath (resolvedPath, MAX_PATH, &winFindData, SLGP_UNCPRIORITY))) result = File (resolvedPath); } - - persistFile->Release(); } - - shellLink->Release(); } return result; @@ -246627,7 +246685,7 @@ static int CALLBACK browseCallbackProc (HWND hWnd, UINT msg, LPARAM lParam, LPAR return 0; } -void juce_setWindowStyleBit (HWND h, int styleType, int feature, bool bitIsSet) throw(); +void juce_setWindowStyleBit (HWND h, const int styleType, const int feature, const bool bitIsSet) throw(); static UINT_PTR CALLBACK openCallback (HWND hdlg, UINT uiMsg, WPARAM /*wParam*/, LPARAM lParam) { @@ -255520,6 +255578,7 @@ END_JUCE_NAMESPACE #include #include #include +#include #define U_ISOFS_SUPER_MAGIC (short) 0x9660 // linux/iso_fs.h #define U_MSDOS_SUPER_MAGIC (short) 0x4d44 // linux/msdos_fs.h @@ -256180,6 +256239,15 @@ const File File::getSpecialLocation (const SpecialLocationType type) case currentExecutableFile: case currentApplicationFile: + if (! executableFile.exists()) + { + Dl_info executableInfo; + dladdr ((const void*) juce_getFileTimes, &executableInfo); + + if (executableInfo.dli_fname != 0) + executableFile = File (String (executableInfo.dli_fname)); + } + // if this fails, it's probably because juce_setCurrentExecutableFileName() // was never called to set the filename - this should be done by the juce // main() function, so maybe you've hacked it to use your own custom main()? @@ -261939,8 +262007,6 @@ public: int ls, ps; const uint8* const pixels = lockPixelDataReadOnly (0, 0, getWidth(), getHeight(), ls, ps); - jassert (! isARGB()) - for (int y = sy; y < sy + dh; ++y) { const uint8* p = pixels + y * ls + sx * ps; @@ -263233,16 +263299,16 @@ private: { int netHints [2]; int numHints = 0; - netHints[numHints] = XInternAtom (display, "_KDE_NET_WM_WINDOW_TYPE_OVERRIDE", True); - - if (netHints [numHints] != 0) - ++numHints; - if ((styleFlags & windowIsTemporary) != 0) netHints [numHints] = XInternAtom (display, "_NET_WM_WINDOW_TYPE_MENU", True); else netHints [numHints] = XInternAtom (display, "_NET_WM_WINDOW_TYPE_NORMAL", True); + if (netHints [numHints] != 0) + ++numHints; + + netHints[numHints] = XInternAtom (display, "_KDE_NET_WM_WINDOW_TYPE_OVERRIDE", True); + if (netHints [numHints] != 0) ++numHints; @@ -266948,6 +267014,9 @@ END_JUCE_NAMESPACE - (void) rightMouseDown: (NSEvent*) ev; - (void) rightMouseDragged: (NSEvent*) ev; - (void) rightMouseUp: (NSEvent*) ev; +- (void) otherMouseDown: (NSEvent*) ev; +- (void) otherMouseDragged: (NSEvent*) ev; +- (void) otherMouseUp: (NSEvent*) ev; - (void) scrollWheel: (NSEvent*) ev; - (BOOL) acceptsFirstMouse: (NSEvent*) ev; - (void) frameChanged: (NSNotification*) n; @@ -267206,6 +267275,21 @@ END_JUCE_NAMESPACE [self mouseUp: ev]; } +- (void) otherMouseDown: (NSEvent*) ev +{ + [self mouseDown: ev]; +} + +- (void) otherMouseDragged: (NSEvent*) ev +{ + [self mouseDragged: ev]; +} + +- (void) otherMouseUp: (NSEvent*) ev +{ + [self mouseUp: ev]; +} + - (void) scrollWheel: (NSEvent*) ev { if (owner != 0) @@ -271079,6 +271163,7 @@ void MessageManager::stopDispatchLoop() { quitMessagePosted = true; [NSApp stop: nil]; + [NSApp activateIgnoringOtherApps: YES]; // (if the app is inactive, it sits there and ignores the quit request until the next time it gets activated) } static bool isEventBlockedByModalComps (NSEvent* e) diff --git a/juce_amalgamated.h b/juce_amalgamated.h index 083bb91053..dcd60ea7be 100644 --- a/juce_amalgamated.h +++ b/juce_amalgamated.h @@ -3281,8 +3281,8 @@ public: @see ArrayAllocationBase */ - OwnedArray (const int granularity = juceDefaultArrayGranularity) throw() - : ArrayAllocationBase (granularity), + OwnedArray (const int granularity_ = juceDefaultArrayGranularity) throw() + : ArrayAllocationBase (granularity_), numUsed (0) { } @@ -4557,8 +4557,8 @@ public: @see ArrayAllocationBase */ - Array (const int granularity = juceDefaultArrayGranularity) throw() - : ArrayAllocationBase (granularity), + Array (const int granularity_ = juceDefaultArrayGranularity) throw() + : ArrayAllocationBase (granularity_), numUsed (0) { } @@ -10474,8 +10474,8 @@ public: @see ArrayAllocationBase */ - SortedSet (const int granularity = juceDefaultArrayGranularity) throw() - : ArrayAllocationBase (granularity), + SortedSet (const int granularity_ = juceDefaultArrayGranularity) throw() + : ArrayAllocationBase (granularity_), numUsed (0) { } @@ -42387,8 +42387,12 @@ private: You'll need to make sure the animator object isn't deleted before it finishes moving the components. + + The class is a ChangeBroadcaster and sends a notification when any components + start or finish being animated. */ -class JUCE_API ComponentAnimator : private Timer +class JUCE_API ComponentAnimator : public ChangeBroadcaster, + private Timer { public: @@ -42458,6 +42462,10 @@ public: */ const Rectangle getComponentDestination (Component* const component); + /** Returns true if the specified component is currently being animated. + */ + bool isAnimating (Component* component) const; + juce_UseDebuggingNewOperator private: diff --git a/src/juce_appframework/audio/audio_file_formats/juce_AiffAudioFormat.cpp b/src/juce_appframework/audio/audio_file_formats/juce_AiffAudioFormat.cpp index 4170ba299a..657f240f64 100644 --- a/src/juce_appframework/audio/audio_file_formats/juce_AiffAudioFormat.cpp +++ b/src/juce_appframework/audio/audio_file_formats/juce_AiffAudioFormat.cpp @@ -621,12 +621,12 @@ class AiffAudioFormatWriter : public AudioFormatWriter public: //============================================================================== AiffAudioFormatWriter (OutputStream* out, - const double sampleRate, + const double sampleRate_, const unsigned int chans, const int bits) : AudioFormatWriter (out, aiffFormatName, - sampleRate, + sampleRate_, chans, bits), lengthInSamples (0), diff --git a/src/juce_appframework/audio/devices/juce_AudioDeviceManager.cpp b/src/juce_appframework/audio/devices/juce_AudioDeviceManager.cpp index a843415376..c07033861d 100644 --- a/src/juce_appframework/audio/devices/juce_AudioDeviceManager.cpp +++ b/src/juce_appframework/audio/devices/juce_AudioDeviceManager.cpp @@ -863,9 +863,17 @@ void AudioDeviceManager::setDefaultMidiOutput (const String& deviceName) { if (defaultMidiOutputName != deviceName) { + SortedSet oldCallbacks; + + { + const ScopedLock sl (audioCallbackLock); + oldCallbacks = callbacks; + callbacks.clear(); + } + if (currentAudioDevice != 0) - for (int i = callbacks.size(); --i >= 0;) - callbacks.getUnchecked(i)->audioDeviceStopped(); + for (int i = oldCallbacks.size(); --i >= 0;) + oldCallbacks.getUnchecked(i)->audioDeviceStopped(); deleteAndZero (defaultMidiOutput); defaultMidiOutputName = deviceName; @@ -874,8 +882,13 @@ void AudioDeviceManager::setDefaultMidiOutput (const String& deviceName) defaultMidiOutput = MidiOutput::openDevice (MidiOutput::getDevices().indexOf (deviceName)); if (currentAudioDevice != 0) - for (int i = callbacks.size(); --i >= 0;) - callbacks.getUnchecked(i)->audioDeviceAboutToStart (currentAudioDevice); + for (int i = oldCallbacks.size(); --i >= 0;) + oldCallbacks.getUnchecked(i)->audioDeviceAboutToStart (currentAudioDevice); + + { + const ScopedLock sl (audioCallbackLock); + callbacks = oldCallbacks; + } updateXml(); sendChangeMessage (this); diff --git a/src/juce_appframework/gui/components/buttons/juce_DrawableButton.cpp b/src/juce_appframework/gui/components/buttons/juce_DrawableButton.cpp index 61a9038f75..c471dac1ab 100644 --- a/src/juce_appframework/gui/components/buttons/juce_DrawableButton.cpp +++ b/src/juce_appframework/gui/components/buttons/juce_DrawableButton.cpp @@ -196,7 +196,7 @@ void DrawableButton::paintButton (Graphics& g, g.setFont ((float) textH); g.setColour (Colours::black.withAlpha (isEnabled() ? 1.0f : 0.4f)); - g.drawFittedText (getName(), + g.drawFittedText (getButtonText(), 2, getHeight() - textH - 1, getWidth() - 4, textH, Justification::centred, 1); diff --git a/src/juce_appframework/gui/components/buttons/juce_ImageButton.cpp b/src/juce_appframework/gui/components/buttons/juce_ImageButton.cpp index 925cef62a7..d9a93be481 100644 --- a/src/juce_appframework/gui/components/buttons/juce_ImageButton.cpp +++ b/src/juce_appframework/gui/components/buttons/juce_ImageButton.cpp @@ -39,8 +39,8 @@ BEGIN_JUCE_NAMESPACE //============================================================================== -ImageButton::ImageButton (const String& text) - : Button (text), +ImageButton::ImageButton (const String& text_) + : Button (text_), scaleImageToFit (true), preserveProportions (true), alphaThreshold (0), diff --git a/src/juce_appframework/gui/components/buttons/juce_ToolbarButton.cpp b/src/juce_appframework/gui/components/buttons/juce_ToolbarButton.cpp index 20b95fd250..6a25f86788 100644 --- a/src/juce_appframework/gui/components/buttons/juce_ToolbarButton.cpp +++ b/src/juce_appframework/gui/components/buttons/juce_ToolbarButton.cpp @@ -40,11 +40,11 @@ BEGIN_JUCE_NAMESPACE //============================================================================== -ToolbarButton::ToolbarButton (const int itemId, +ToolbarButton::ToolbarButton (const int itemId_, const String& buttonText, Drawable* const normalImage_, Drawable* const toggledOnImage_) - : ToolbarItemComponent (itemId, buttonText, true), + : ToolbarItemComponent (itemId_, buttonText, true), normalImage (normalImage_), toggledOnImage (toggledOnImage_) { diff --git a/src/juce_appframework/gui/components/controls/juce_TableListBox.cpp b/src/juce_appframework/gui/components/controls/juce_TableListBox.cpp index c6d4cc35ce..17a14f07d0 100644 --- a/src/juce_appframework/gui/components/controls/juce_TableListBox.cpp +++ b/src/juce_appframework/gui/components/controls/juce_TableListBox.cpp @@ -432,12 +432,12 @@ void TableListBox::paintListBoxItem (int, Graphics&, int, int, bool) { } -Component* TableListBox::refreshComponentForRow (int rowNumber, bool isRowSelected, Component* existingComponentToUpdate) +Component* TableListBox::refreshComponentForRow (int rowNumber, bool isRowSelected_, Component* existingComponentToUpdate) { if (existingComponentToUpdate == 0) existingComponentToUpdate = new TableListRowComp (*this); - ((TableListRowComp*) existingComponentToUpdate)->update (rowNumber, isRowSelected); + ((TableListRowComp*) existingComponentToUpdate)->update (rowNumber, isRowSelected_); return existingComponentToUpdate; } diff --git a/src/juce_appframework/gui/components/juce_Component.cpp b/src/juce_appframework/gui/components/juce_Component.cpp index 3f85c591fa..ef7fe48776 100644 --- a/src/juce_appframework/gui/components/juce_Component.cpp +++ b/src/juce_appframework/gui/components/juce_Component.cpp @@ -1619,7 +1619,7 @@ void Component::updateMouseCursor() const throw() sendFakeMouseMove(); } -void Component::internalUpdateMouseCursor (const bool forcedUpdate) throw() +void Component::internalUpdateMouseCursor (bool forcedUpdate) throw() { ComponentPeer* const peer = getPeer(); @@ -1632,6 +1632,7 @@ void Component::internalUpdateMouseCursor (const bool forcedUpdate) throw() || ! isCursorVisibleUntilOffscreen)) { mc = MouseCursor::NoCursor; + forcedUpdate = true; } static void* currentCursorHandle = 0; diff --git a/src/juce_appframework/gui/components/layout/juce_ComponentAnimator.cpp b/src/juce_appframework/gui/components/layout/juce_ComponentAnimator.cpp index 2268ae3467..ff9ae9208f 100644 --- a/src/juce_appframework/gui/components/layout/juce_ComponentAnimator.cpp +++ b/src/juce_appframework/gui/components/layout/juce_ComponentAnimator.cpp @@ -142,6 +142,7 @@ void ComponentAnimator::animateComponent (Component* const component, { at = new AnimationTask (component); tasks.add (at); + sendChangeMessage (this); } at->msElapsed = 0; @@ -181,6 +182,7 @@ void ComponentAnimator::cancelAllAnimations (const bool moveComponentsToTheirFin delete at; tasks.remove (i); + sendChangeMessage (this); } } @@ -196,6 +198,7 @@ void ComponentAnimator::cancelAnimation (Component* const component, tasks.removeValue (at); delete at; + sendChangeMessage (this); } } @@ -211,6 +214,11 @@ const Rectangle ComponentAnimator::getComponentDestination (Component* const com return Rectangle(); } +bool ComponentAnimator::isAnimating (Component* component) const +{ + return findTaskFor (component) != 0; +} + void ComponentAnimator::timerCallback() { const uint32 timeNow = Time::getMillisecondCounter(); @@ -228,6 +236,7 @@ void ComponentAnimator::timerCallback() { tasks.remove (i); delete at; + sendChangeMessage (this); } } diff --git a/src/juce_appframework/gui/components/layout/juce_ComponentAnimator.h b/src/juce_appframework/gui/components/layout/juce_ComponentAnimator.h index 4bab3eddb2..33a6fa106e 100644 --- a/src/juce_appframework/gui/components/layout/juce_ComponentAnimator.h +++ b/src/juce_appframework/gui/components/layout/juce_ComponentAnimator.h @@ -34,6 +34,7 @@ #include "../juce_Component.h" #include "../juce_ComponentDeletionWatcher.h" +#include "../../../events/juce_ChangeBroadcaster.h" #include "../../../events/juce_Timer.h" @@ -49,8 +50,12 @@ You'll need to make sure the animator object isn't deleted before it finishes moving the components. + + The class is a ChangeBroadcaster and sends a notification when any components + start or finish being animated. */ -class JUCE_API ComponentAnimator : private Timer +class JUCE_API ComponentAnimator : public ChangeBroadcaster, + private Timer { public: //============================================================================== @@ -121,6 +126,9 @@ public: */ const Rectangle getComponentDestination (Component* const component); + /** Returns true if the specified component is currently being animated. + */ + bool isAnimating (Component* component) const; //============================================================================== juce_UseDebuggingNewOperator diff --git a/src/juce_appframework/gui/components/layout/juce_MultiDocumentPanel.cpp b/src/juce_appframework/gui/components/layout/juce_MultiDocumentPanel.cpp index de185fdc1f..c05342d49d 100644 --- a/src/juce_appframework/gui/components/layout/juce_MultiDocumentPanel.cpp +++ b/src/juce_appframework/gui/components/layout/juce_MultiDocumentPanel.cpp @@ -179,7 +179,7 @@ void MultiDocumentPanel::addWindow (Component* component) } bool MultiDocumentPanel::addDocument (Component* const component, - const Colour& backgroundColour, + const Colour& docColour, const bool deleteWhenRemoved) { // If you try passing a full DocumentWindow or ResizableWindow in here, you'll end up @@ -191,7 +191,7 @@ bool MultiDocumentPanel::addDocument (Component* const component, components.add (component); component->setComponentProperty (T("mdiDocumentDelete_"), deleteWhenRemoved); - component->setComponentProperty (T("mdiDocumentBkg_"), backgroundColour); + component->setComponentProperty (T("mdiDocumentBkg_"), docColour); component->addComponentListener (this); if (mode == FloatingWindows) @@ -224,14 +224,14 @@ bool MultiDocumentPanel::addDocument (Component* const component, Array temp (components); for (int i = 0; i < temp.size(); ++i) - tabComponent->addTab (temp[i]->getName(), backgroundColour, temp[i], false); + tabComponent->addTab (temp[i]->getName(), docColour, temp[i], false); resized(); } else { if (tabComponent != 0) - tabComponent->addTab (component->getName(), backgroundColour, component, false); + tabComponent->addTab (component->getName(), docColour, component, false); else addAndMakeVisible (component); } diff --git a/src/juce_appframework/gui/components/special/juce_MagnifierComponent.cpp b/src/juce_appframework/gui/components/special/juce_MagnifierComponent.cpp index f8e822cc68..21869bbeb2 100644 --- a/src/juce_appframework/gui/components/special/juce_MagnifierComponent.cpp +++ b/src/juce_appframework/gui/components/special/juce_MagnifierComponent.cpp @@ -42,9 +42,9 @@ class MagnifyingPeer : public ComponentPeer { public: //============================================================================== - MagnifyingPeer (Component* const component, + MagnifyingPeer (Component* const component_, MagnifierComponent* const magnifierComp_) - : ComponentPeer (component, 0), + : ComponentPeer (component_, 0), magnifierComp (magnifierComp_) { } diff --git a/src/juce_appframework/gui/graphics/geometry/juce_PositionedRectangle.cpp b/src/juce_appframework/gui/graphics/geometry/juce_PositionedRectangle.cpp index 1c9bb1740a..a3abcabdad 100644 --- a/src/juce_appframework/gui/graphics/geometry/juce_PositionedRectangle.cpp +++ b/src/juce_appframework/gui/graphics/geometry/juce_PositionedRectangle.cpp @@ -335,65 +335,65 @@ void PositionedRectangle::decodeSizeString (const String& s, uint8& mode, double } void PositionedRectangle::applyPosAndSize (double& xOut, double& wOut, - const double x, const double w, - const uint8 xMode, const uint8 wMode, + const double x_, const double w_, + const uint8 xMode_, const uint8 wMode_, const int parentPos, const int parentSize) const throw() { - if (wMode == proportionalSize) - wOut = roundDoubleToInt (w * parentSize); - else if (wMode == parentSizeMinusAbsolute) - wOut = jmax (0, parentSize - roundDoubleToInt (w)); + if (wMode_ == proportionalSize) + wOut = roundDoubleToInt (w_ * parentSize); + else if (wMode_ == parentSizeMinusAbsolute) + wOut = jmax (0, parentSize - roundDoubleToInt (w_)); else - wOut = roundDoubleToInt (w); - - if ((xMode & proportionOfParentSize) != 0) - xOut = parentPos + x * parentSize; - else if ((xMode & absoluteFromParentBottomRight) != 0) - xOut = (parentPos + parentSize) - x; - else if ((xMode & absoluteFromParentCentre) != 0) - xOut = x + (parentPos + parentSize / 2); + wOut = roundDoubleToInt (w_); + + if ((xMode_ & proportionOfParentSize) != 0) + xOut = parentPos + x_ * parentSize; + else if ((xMode_ & absoluteFromParentBottomRight) != 0) + xOut = (parentPos + parentSize) - x_; + else if ((xMode_ & absoluteFromParentCentre) != 0) + xOut = x_ + (parentPos + parentSize / 2); else - xOut = x + parentPos; + xOut = x_ + parentPos; - if ((xMode & anchorAtRightOrBottom) != 0) + if ((xMode_ & anchorAtRightOrBottom) != 0) xOut -= wOut; - else if ((xMode & anchorAtCentre) != 0) + else if ((xMode_ & anchorAtCentre) != 0) xOut -= wOut / 2; } void PositionedRectangle::updatePosAndSize (double& xOut, double& wOut, - double x, const double w, - const uint8 xMode, const uint8 wMode, + double x_, const double w_, + const uint8 xMode_, const uint8 wMode_, const int parentPos, const int parentSize) const throw() { - if (wMode == proportionalSize) + if (wMode_ == proportionalSize) { if (parentSize > 0) - wOut = w / parentSize; + wOut = w_ / parentSize; } - else if (wMode == parentSizeMinusAbsolute) - wOut = parentSize - w; + else if (wMode_ == parentSizeMinusAbsolute) + wOut = parentSize - w_; else - wOut = w; + wOut = w_; - if ((xMode & anchorAtRightOrBottom) != 0) - x += w; - else if ((xMode & anchorAtCentre) != 0) - x += w / 2; + if ((xMode_ & anchorAtRightOrBottom) != 0) + x_ += w_; + else if ((xMode_ & anchorAtCentre) != 0) + x_ += w_ / 2; - if ((xMode & proportionOfParentSize) != 0) + if ((xMode_ & proportionOfParentSize) != 0) { if (parentSize > 0) - xOut = (x - parentPos) / parentSize; + xOut = (x_ - parentPos) / parentSize; } - else if ((xMode & absoluteFromParentBottomRight) != 0) - xOut = (parentPos + parentSize) - x; - else if ((xMode & absoluteFromParentCentre) != 0) - xOut = x - (parentPos + parentSize / 2); + else if ((xMode_ & absoluteFromParentBottomRight) != 0) + xOut = (parentPos + parentSize) - x_; + else if ((xMode_ & absoluteFromParentCentre) != 0) + xOut = x_ - (parentPos + parentSize / 2); else - xOut = x - parentPos; + xOut = x_ - parentPos; } END_JUCE_NAMESPACE diff --git a/src/juce_core/containers/juce_Array.h b/src/juce_core/containers/juce_Array.h index cb691ecc36..c9197fc5b7 100644 --- a/src/juce_core/containers/juce_Array.h +++ b/src/juce_core/containers/juce_Array.h @@ -70,8 +70,8 @@ public: @see ArrayAllocationBase */ - Array (const int granularity = juceDefaultArrayGranularity) throw() - : ArrayAllocationBase (granularity), + Array (const int granularity_ = juceDefaultArrayGranularity) throw() + : ArrayAllocationBase (granularity_), numUsed (0) { } diff --git a/src/juce_core/containers/juce_OwnedArray.h b/src/juce_core/containers/juce_OwnedArray.h index fc6869b0a0..56af038c42 100644 --- a/src/juce_core/containers/juce_OwnedArray.h +++ b/src/juce_core/containers/juce_OwnedArray.h @@ -71,8 +71,8 @@ public: @see ArrayAllocationBase */ - OwnedArray (const int granularity = juceDefaultArrayGranularity) throw() - : ArrayAllocationBase (granularity), + OwnedArray (const int granularity_ = juceDefaultArrayGranularity) throw() + : ArrayAllocationBase (granularity_), numUsed (0) { } diff --git a/src/juce_core/containers/juce_SortedSet.h b/src/juce_core/containers/juce_SortedSet.h index e7b83a6f83..382a103f47 100644 --- a/src/juce_core/containers/juce_SortedSet.h +++ b/src/juce_core/containers/juce_SortedSet.h @@ -76,8 +76,8 @@ public: @see ArrayAllocationBase */ - SortedSet (const int granularity = juceDefaultArrayGranularity) throw() - : ArrayAllocationBase (granularity), + SortedSet (const int granularity_ = juceDefaultArrayGranularity) throw() + : ArrayAllocationBase (granularity_), numUsed (0) { } diff --git a/src/juce_core/io/network/juce_Socket.cpp b/src/juce_core/io/network/juce_Socket.cpp index 9bfb21a286..961e85cd04 100644 --- a/src/juce_core/io/network/juce_Socket.cpp +++ b/src/juce_core/io/network/juce_Socket.cpp @@ -504,7 +504,7 @@ bool StreamingSocket::isLocal() const throw() DatagramSocket::DatagramSocket (const int localPortNumber) : portNumber (0), handle (-1), - connected (false), + connected (true), serverAddress (0) { #if JUCE_WIN32