From 35a4b5085fbc58675b5248eadea25fb846d29475 Mon Sep 17 00:00:00 2001 From: Julian Storer Date: Wed, 27 Jan 2010 20:28:38 +0000 Subject: [PATCH] Updated Timer code to avoid a rare messaging problem. Fixed a couple of minor build errors. Rearranged the atomic functions and added a new compare-and-swap operation. Added a thread-priority tweak to WASAPI. Removed MS-specific classes from the web browser component. --- build/macosx/Juce.xcodeproj/project.pbxproj | 4 + juce.h | 8 - juce_Config.h | 4 +- juce_amalgamated.cpp | 383 ++++++++++-------- juce_amalgamated.h | 191 ++------- .../formats/juce_AudioUnitPluginFormat.mm | 4 +- src/containers/juce_MemoryBlock.cpp | 9 +- src/containers/juce_MemoryBlock.h | 4 + src/core/juce_Atomic.h | 180 ++------ src/core/juce_SystemStats.cpp | 6 - src/events/juce_Timer.cpp | 326 ++++++++------- .../filebrowser/juce_FileBrowserComponent.h | 2 +- .../juce_ChoicePropertyComponent.cpp | 15 +- .../properties/juce_ChoicePropertyComponent.h | 16 +- .../windows/juce_win32_NativeIncludes.h | 1 + src/native/windows/juce_win32_Threads.cpp | 11 + src/native/windows/juce_win32_WASAPI.cpp | 18 + .../juce_win32_WebBrowserComponent.cpp | 17 +- 18 files changed, 559 insertions(+), 640 deletions(-) diff --git a/build/macosx/Juce.xcodeproj/project.pbxproj b/build/macosx/Juce.xcodeproj/project.pbxproj index e1aa05e2b1..11a29e15c7 100644 --- a/build/macosx/Juce.xcodeproj/project.pbxproj +++ b/build/macosx/Juce.xcodeproj/project.pbxproj @@ -4214,6 +4214,7 @@ COPY_PHASE_STRIP = NO; GCC_DYNAMIC_NO_PIC = NO; GCC_OPTIMIZATION_LEVEL = 0; + GCC_SYMBOLS_PRIVATE_EXTERN = NO; GCC_VERSION = 4.2; PREBINDING = NO; SDKROOT = iphoneos3.0; @@ -4226,6 +4227,7 @@ COPY_PHASE_STRIP = YES; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; GCC_ENABLE_FIX_AND_CONTINUE = NO; + GCC_SYMBOLS_PRIVATE_EXTERN = NO; PREBINDING = NO; SDKROOT = iphoneos3.0; ZERO_LINK = NO; @@ -4235,6 +4237,7 @@ 84A487F808A22DD800752A2B /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { + GCC_SYMBOLS_PRIVATE_EXTERN = NO; GCC_WARN_NON_VIRTUAL_DESTRUCTOR = YES; GCC_WARN_TYPECHECK_CALLS_TO_PRINTF = YES; MACOSX_DEPLOYMENT_TARGET = 10.4; @@ -4245,6 +4248,7 @@ 84A487F908A22DD800752A2B /* Release */ = { isa = XCBuildConfiguration; buildSettings = { + GCC_SYMBOLS_PRIVATE_EXTERN = NO; GCC_WARN_TYPECHECK_CALLS_TO_PRINTF = YES; STRIP_STYLE = "non-global"; }; diff --git a/juce.h b/juce.h index 9b06d5c915..cbf0fd9f32 100644 --- a/juce.h +++ b/juce.h @@ -47,10 +47,6 @@ BEGIN_JUCE_NAMESPACE #pragma warning (disable: 4786) // (old vc6 warning about long class names) #endif -#if JUCE_MAC || JUCE_IPHONE - #pragma align=natural -#endif - // this is where all the class header files get brought in.. #include "src/juce_core_includes.h" @@ -65,10 +61,6 @@ BEGIN_JUCE_NAMESPACE #pragma pack (pop) #endif -#if JUCE_MAC || JUCE_IPHONE - #pragma align=reset -#endif - END_JUCE_NAMESPACE diff --git a/juce_Config.h b/juce_Config.h index d37eb8490c..7f9c2f7dc9 100644 --- a/juce_Config.h +++ b/juce_Config.h @@ -41,7 +41,7 @@ //============================================================================= /** JUCE_FORCE_DEBUG: Normally, JUCE_DEBUG is set to 1 or 0 based on compiler and - project settings, but if you define this value, you can override this can force + project settings, but if you define this value, you can override this to force it to be true or false. */ #ifndef JUCE_FORCE_DEBUG @@ -123,7 +123,7 @@ #define JUCE_USE_FLAC 1 #endif -/** JUCE_USE_OGGBORBIS: Enables the Ogg-Vorbis audio codec classes (available on all platforms). +/** JUCE_USE_OGGVORBIS: Enables the Ogg-Vorbis audio codec classes (available on all platforms). If your app doesn't need to read Ogg-Vorbis files, you might want to disable this to reduce the size of your codebase and build time. */ diff --git a/juce_amalgamated.cpp b/juce_amalgamated.cpp index fcd63197df..c4b0a0eb31 100644 --- a/juce_amalgamated.cpp +++ b/juce_amalgamated.cpp @@ -361,6 +361,7 @@ #include #include #include + #include #include #endif @@ -1350,12 +1351,6 @@ void JUCE_PUBLIC_FUNCTION initialiseJuce_NonGUI() jassert (ByteOrder::swap ((uint16) 0x1122) == 0x2211); jassert (ByteOrder::swap ((uint32) 0x11223344) == 0x44332211); - // quick test to make sure the run-time lib doesn't crash on freeing a null-pointer. - SystemStats* nullPointer = 0; - juce_free (nullPointer); - delete[] nullPointer; - delete nullPointer; - // Some quick stream tests.. int randomInt = Random::getSystemRandom().nextInt(); int64 randomInt64 = Random::getSystemRandom().nextInt64(); @@ -2937,8 +2932,7 @@ MemoryBlock& MemoryBlock::operator= (const MemoryBlock& other) throw() bool MemoryBlock::operator== (const MemoryBlock& other) const throw() { - return (size == other.size) - && (memcmp (data, other.data, size) == 0); + return matches (other.data, other.size); } bool MemoryBlock::operator!= (const MemoryBlock& other) const throw() @@ -2946,6 +2940,12 @@ bool MemoryBlock::operator!= (const MemoryBlock& other) const throw() return ! operator== (other); } +bool MemoryBlock::matches (const void* dataToCompare, size_t dataSize) const throw() +{ + return size == dataSize + && memcmp (data, dataToCompare, size) == 0; +} + // this will resize the block to this size void MemoryBlock::setSize (const size_t newSize, const bool initialiseToZero) throw() @@ -30191,8 +30191,8 @@ private: { for (int i = 0; i < supportedChannelsSize / sizeof (AUChannelInfo); ++i) { - numIns = jmax (numIns, supportedChannels[i].inChannels); - numOuts = jmax (numOuts, supportedChannels[i].outChannels); + numIns = jmax (numIns, (int) supportedChannels[i].inChannels); + numOuts = jmax (numOuts, (int) supportedChannels[i].outChannels); } } else @@ -38011,16 +38011,168 @@ class InternalTimerThread : private Thread, private DeletedAtShutdown, private AsyncUpdater { +public: + InternalTimerThread() + : Thread ("Juce Timer"), + firstTimer (0), + callbackNeeded (false) + { + triggerAsyncUpdate(); + } + + ~InternalTimerThread() throw() + { + stopThread (4000); + + jassert (instance == this || instance == 0); + if (instance == this) + instance = 0; + } + + void run() + { + uint32 lastTime = Time::getMillisecondCounter(); + + while (! threadShouldExit()) + { + const uint32 now = Time::getMillisecondCounter(); + + if (now <= lastTime) + { + wait (2); + continue; + } + + const int elapsed = now - lastTime; + lastTime = now; + + lock.enter(); + decrementAllCounters (elapsed); + const int timeUntilFirstTimer = (firstTimer != 0) ? firstTimer->countdownMs + : 1000; + lock.exit(); + + if (timeUntilFirstTimer <= 0) + { + if (callbackNeeded.set (true)) + { + postMessage (new Message()); + + const uint32 messageDeliveryTimeout = now + 2000; + + while (callbackNeeded.get()) + { + wait (4); + + if (threadShouldExit()) + return; + + if (Time::getMillisecondCounter() > messageDeliveryTimeout) + break; + } + } + } + else + { + // don't wait for too long because running this loop also helps keep the + // Time::getApproximateMillisecondTimer value stay up-to-date + wait (jlimit (1, 50, timeUntilFirstTimer)); + } + } + } + + void handleMessage (const Message&) + { + const ScopedLock sl (lock); + + while (firstTimer != 0 && firstTimer->countdownMs <= 0) + { + Timer* const t = firstTimer; + t->countdownMs = t->periodMs; + + removeTimer (t); + addTimer (t); + + const ScopedUnlock ul (lock); + + JUCE_TRY + { + t->timerCallback(); + } + JUCE_CATCH_EXCEPTION + } + + callbackNeeded.set (false); + } + + static void callAnyTimersSynchronously() + { + if (InternalTimerThread::instance != 0) + { + const Message m; + InternalTimerThread::instance->handleMessage (m); + } + } + + static inline void add (Timer* const tim) throw() + { + if (instance == 0) + instance = new InternalTimerThread(); + + const ScopedLock sl (instance->lock); + instance->addTimer (tim); + } + + static inline void remove (Timer* const tim) throw() + { + if (instance != 0) + { + const ScopedLock sl (instance->lock); + instance->removeTimer (tim); + } + } + + static inline void resetCounter (Timer* const tim, + const int newCounter) throw() + { + if (instance != 0) + { + tim->countdownMs = newCounter; + tim->periodMs = newCounter; + + if ((tim->next != 0 && tim->next->countdownMs < tim->countdownMs) + || (tim->previous != 0 && tim->previous->countdownMs > tim->countdownMs)) + { + const ScopedLock sl (instance->lock); + instance->removeTimer (tim); + instance->addTimer (tim); + } + } + } + private: friend class Timer; static InternalTimerThread* instance; static CriticalSection lock; - Timer* volatile firstTimer; - bool volatile callbackNeeded; - InternalTimerThread (const InternalTimerThread&); - const InternalTimerThread& operator= (const InternalTimerThread&); + class AtomicBool + { + public: + AtomicBool (const bool value) throw() : value (static_cast (value)) {} + ~AtomicBool() throw() {} + + bool get() const throw() { return value != 0; } + bool set (const bool newValue) { return Atomic::compareAndExchange (value, newValue ? 1 : 0, value) != 0; } + + private: + int32 value; + + AtomicBool (const AtomicBool&); + AtomicBool& operator= (const AtomicBool&); + }; + + AtomicBool callbackNeeded; void addTimer (Timer* const t) throw() { @@ -38123,146 +38275,8 @@ private: startThread (7); } -public: - InternalTimerThread() - : Thread ("Juce Timer"), - firstTimer (0), - callbackNeeded (false) - { - triggerAsyncUpdate(); - } - - ~InternalTimerThread() throw() - { - stopThread (4000); - - jassert (instance == this || instance == 0); - if (instance == this) - instance = 0; - } - - void run() - { - uint32 lastTime = Time::getMillisecondCounter(); - - while (! threadShouldExit()) - { - uint32 now = Time::getMillisecondCounter(); - - if (now <= lastTime) - { - wait (2); - continue; - } - - const int elapsed = now - lastTime; - lastTime = now; - - lock.enter(); - decrementAllCounters (elapsed); - const int timeUntilFirstTimer = (firstTimer != 0) ? firstTimer->countdownMs - : 1000; - lock.exit(); - - if (timeUntilFirstTimer <= 0) - { - callbackNeeded = true; - postMessage (new Message()); - - // sometimes, our message could get discarded by the OS (particularly when running as an RTAS when the app has a modal loop), - // so this is how long to wait before assuming the message has been lost and trying again. - const uint32 messageDeliveryTimeout = now + 2000; - - while (callbackNeeded) - { - wait (4); - - if (threadShouldExit()) - return; - - now = Time::getMillisecondCounter(); - - if (now > messageDeliveryTimeout) - break; - } - } - else - { - // don't wait for too long because running this loop also helps keep the - // Time::getApproximateMillisecondTimer value stay up-to-date - wait (jlimit (1, 50, timeUntilFirstTimer)); - } - } - } - - void handleMessage (const Message&) - { - const ScopedLock sl (lock); - - while (firstTimer != 0 && firstTimer->countdownMs <= 0) - { - Timer* const t = firstTimer; - t->countdownMs = t->periodMs; - - removeTimer (t); - addTimer (t); - - const ScopedUnlock ul (lock); - - JUCE_TRY - { - t->timerCallback(); - } - JUCE_CATCH_EXCEPTION - } - - callbackNeeded = false; - } - - static void callAnyTimersSynchronously() - { - if (InternalTimerThread::instance != 0) - { - const Message m; - InternalTimerThread::instance->handleMessage (m); - } - } - - static inline void add (Timer* const tim) throw() - { - if (instance == 0) - instance = new InternalTimerThread(); - - const ScopedLock sl (instance->lock); - instance->addTimer (tim); - } - - static inline void remove (Timer* const tim) throw() - { - if (instance != 0) - { - const ScopedLock sl (instance->lock); - instance->removeTimer (tim); - } - } - - static inline void resetCounter (Timer* const tim, - const int newCounter) throw() - { - if (instance != 0) - { - tim->countdownMs = newCounter; - tim->periodMs = newCounter; - - if ((tim->next != 0 && tim->next->countdownMs < tim->countdownMs) - || (tim->previous != 0 && tim->previous->countdownMs > tim->countdownMs)) - { - const ScopedLock sl (instance->lock); - instance->removeTimer (tim); - instance->addTimer (tim); - } - } - } + InternalTimerThread (const InternalTimerThread&); + InternalTimerThread& operator= (const InternalTimerThread&); }; InternalTimerThread* InternalTimerThread::instance = 0; @@ -70888,12 +70902,13 @@ ChoicePropertyComponent::ChoicePropertyComponent (const String& name) ChoicePropertyComponent::ChoicePropertyComponent (const Value& valueToControl, const String& name, - const StringArray& choices_) + const StringArray& choices_, + const Array * choiceIDs) : PropertyComponent (name), choices (choices_), comboBox (0) { - createComboBox(); + createComboBox (choiceIDs); comboBox->getSelectedIdAsValue().referTo (valueToControl); } @@ -70903,14 +70918,18 @@ ChoicePropertyComponent::~ChoicePropertyComponent() deleteAllChildren(); } -void ChoicePropertyComponent::createComboBox() +void ChoicePropertyComponent::createComboBox (const Array * choiceIDs) { + // The array of IDs must contain the same number of values as the choices list! + jassert (choiceIDs == 0 || choiceIDs->size() == choices.size()); + addAndMakeVisible (comboBox = new ComboBox (String::empty)); for (int i = 0; i < choices.size(); ++i) { if (choices[i].isNotEmpty()) - comboBox->addItem (choices[i], i + 1); + comboBox->addItem (choices[i], choiceIDs == 0 ? (i + 1) + : ((*choiceIDs)[i])); else comboBox->addSeparator(); } @@ -70937,7 +70956,7 @@ void ChoicePropertyComponent::refresh() { if (comboBox == 0) { - createComboBox(); + createComboBox (0); comboBox->addListener (this); } @@ -212362,6 +212381,17 @@ int SystemStats::getPageSize() throw() extern HWND juce_messageWindowHandle; #endif +#if ! JUCE_USE_INTRINSICS +// In newer compilers, the inline versions of these are used (in juce_Atomic.h), but in +// older ones we have to actually call the ops as win32 functions.. +void Atomic::increment (int32& variable) { InterlockedIncrement (reinterpret_cast (&variable)); } +int32 Atomic::incrementAndReturn (int32& variable) { return InterlockedIncrement (reinterpret_cast (&variable)); } +void Atomic::decrement (int32& variable) { InterlockedDecrement (reinterpret_cast (&variable)); } +int32 Atomic::decrementAndReturn (int32& variable) { return InterlockedDecrement (reinterpret_cast (&variable)); } +int32 Atomic::compareAndExchange (int32& destination, int32 newValue, int32 oldValue) + { return InterlockedCompareExchange (reinterpret_cast (&destination), newValue, oldValue); } +#endif + CriticalSection::CriticalSection() throw() { // (just to check the MS haven't changed this structure and broken things...) @@ -219239,10 +219269,18 @@ public: if (browser != 0) { LPSAFEARRAY sa = 0; - _variant_t flags, frame, postDataVar, headersVar; + + VARIANT flags, frame, postDataVar, headersVar; // (_variant_t isn't available in all compilers) + VariantInit (&flags); + VariantInit (&frame); + VariantInit (&postDataVar); + VariantInit (&headersVar); if (headers != 0) - headersVar = (const tchar*) headers->joinIntoString ("\r\n"); + { + V_VT (&headersVar) = VT_BSTR; + V_BSTR (&headersVar) = SysAllocString ((const tchar*) headers->joinIntoString ("\r\n")); + } if (postData != 0 && postData->getSize() > 0) { @@ -219275,6 +219313,11 @@ public: if (sa != 0) SafeArrayDestroy (sa); + + VariantClear (&flags); + VariantClear (&frame); + VariantClear (&postDataVar); + VariantClear (&headersVar); } } @@ -227197,8 +227240,26 @@ public: } } + void setMMThreadPriority() + { + DynamicLibraryLoader dll ("avrt.dll"); + DynamicLibraryImport (AvSetMmThreadCharacteristics, avSetMmThreadCharacteristics, HANDLE, dll, (LPCTSTR, LPDWORD)) + DynamicLibraryImport (AvSetMmThreadPriority, avSetMmThreadPriority, HANDLE, dll, (HANDLE, AVRT_PRIORITY)) + + if (avSetMmThreadCharacteristics != 0 && avSetMmThreadPriority != 0) + { + DWORD dummy = 0; + HANDLE h = avSetMmThreadCharacteristics (_T("Pro Audio"), &dummy); + + if (h != 0) + avSetMmThreadPriority (h, AVRT_PRIORITY_NORMAL); + } + } + void run() { + setMMThreadPriority(); + const int bufferSize = currentBufferSizeSamples; HANDLE events[2]; diff --git a/juce_amalgamated.h b/juce_amalgamated.h index 9819d31103..b889ca2633 100644 --- a/juce_amalgamated.h +++ b/juce_amalgamated.h @@ -1445,10 +1445,6 @@ BEGIN_JUCE_NAMESPACE #pragma warning (disable: 4786) // (old vc6 warning about long class names) #endif -#if JUCE_MAC || JUCE_IPHONE - #pragma align=natural -#endif - // this is where all the class header files get brought in.. /********* Start of inlined file: juce_core_includes.h *********/ @@ -2701,6 +2697,8 @@ public: bool operator!= (const MemoryBlock& other) const throw(); + bool matches (const void* data, size_t dataSize) const throw(); + template operator DataType*() const throw() { return (DataType*) data; } @@ -4364,165 +4362,49 @@ private: class JUCE_API Atomic { public: - static void increment (int& variable); + static void increment (int32& variable); - static int incrementAndReturn (int& variable); + static int32 incrementAndReturn (int32& variable); - static void decrement (int& variable); + static void decrement (int32& variable); - static int decrementAndReturn (int& variable); + static int32 decrementAndReturn (int32& variable); + + static int32 compareAndExchange (int32& destination, int32 newValue, int32 requiredCurrentValue); }; #if (JUCE_MAC || JUCE_IPHONE) // Mac and iPhone... -#include -inline void Atomic::increment (int& variable) { OSAtomicIncrement32 ((int32_t*) &variable); } -inline int Atomic::incrementAndReturn (int& variable) { return OSAtomicIncrement32 ((int32_t*) &variable); } -inline void Atomic::decrement (int& variable) { OSAtomicDecrement32 ((int32_t*) &variable); } -inline int Atomic::decrementAndReturn (int& variable) { return OSAtomicDecrement32 ((int32_t*) &variable); } +inline void Atomic::increment (int32& variable) { OSAtomicIncrement32 ((volatile int32_t*) &variable); } +inline int32 Atomic::incrementAndReturn (int32& variable) { return OSAtomicIncrement32 ((volatile int32_t*) &variable); } +inline void Atomic::decrement (int32& variable) { OSAtomicDecrement32 ((volatile int32_t*) &variable); } +inline int32 Atomic::decrementAndReturn (int32& variable) { return OSAtomicDecrement32 ((volatile int32_t*) &variable); } +inline int32 Atomic::compareAndExchange (int32& destination, int32 newValue, int32 oldValue) + { return OSAtomicCompareAndSwap32Barrier (oldValue, newValue, (volatile int32_t*) &destination); } -#elif JUCE_GCC +#elif JUCE_GCC // Linux... -#if JUCE_USE_GCC_ATOMIC_INTRINSICS // Linux with intrinsics... +inline void Atomic::increment (int32& variable) { __sync_add_and_fetch (&variable, 1); } +inline int32 Atomic::incrementAndReturn (int32& variable) { return __sync_add_and_fetch (&variable, 1); } +inline void Atomic::decrement (int32& variable) { __sync_add_and_fetch (&variable, -1); } +inline int32 Atomic::decrementAndReturn (int32& variable) { return __sync_add_and_fetch (&variable, -1); } +inline int32 Atomic::compareAndExchange (int32& destination, int32 newValue, int32 oldValue) + { return __sync_val_compare_and_swap (&destination, oldValue, newValue); } -inline void Atomic::increment (int& variable) { __sync_add_and_fetch (&variable, 1); } -inline int Atomic::incrementAndReturn (int& variable) { return __sync_add_and_fetch (&variable, 1); } -inline void Atomic::decrement (int& variable) { __sync_add_and_fetch (&variable, -1); } -inline int Atomic::decrementAndReturn (int& variable) { return __sync_add_and_fetch (&variable, -1); } - -#else // Linux without intrinsics... - -inline void Atomic::increment (int& variable) -{ - __asm__ __volatile__ ( - #if JUCE_64BIT - "lock incl (%%rax)" - : - : "a" (&variable) - : "cc", "memory"); - #else - "lock incl %0" - : "=m" (variable) - : "m" (variable)); - #endif -} - -inline int Atomic::incrementAndReturn (int& variable) -{ - int result; - - __asm__ __volatile__ ( - #if JUCE_64BIT - "lock xaddl %%ebx, (%%rax) \n\ - incl %%ebx" - : "=b" (result) - : "a" (&variable), "b" (1) - : "cc", "memory"); - #else - "lock xaddl %%eax, (%%ecx) \n\ - incl %%eax" - : "=a" (result) - : "c" (&variable), "a" (1) - : "memory"); - #endif - - return result; -} - -inline void Atomic::decrement (int& variable) -{ - __asm__ __volatile__ ( - #if JUCE_64BIT - "lock decl (%%rax)" - : - : "a" (&variable) - : "cc", "memory"); - #else - "lock decl %0" - : "=m" (variable) - : "m" (variable)); - #endif -} - -inline int Atomic::decrementAndReturn (int& variable) -{ - int result; - - __asm__ __volatile__ ( - #if JUCE_64BIT - "lock xaddl %%ebx, (%%rax) \n\ - decl %%ebx" - : "=b" (result) - : "a" (&variable), "b" (-1) - : "cc", "memory"); - #else - "lock xaddl %%eax, (%%ecx) \n\ - decl %%eax" - : "=a" (result) - : "c" (&variable), "a" (-1) - : "memory"); - #endif - return result; -} -#endif - -#elif JUCE_USE_INTRINSICS // Windows with intrinsics... +#elif JUCE_USE_INTRINSICS // Windows... +// (If JUCE_USE_INTRINSICS isn't enabled, a fallback version of these methods is +// declared in juce_win32_Threads.cpp) #pragma intrinsic (_InterlockedIncrement) #pragma intrinsic (_InterlockedDecrement) +#pragma intrinsic (_InterlockedCompareExchange) -inline void Atomic::increment (int& variable) { _InterlockedIncrement (reinterpret_cast (&variable)); } -inline int Atomic::incrementAndReturn (int& variable) { return _InterlockedIncrement (reinterpret_cast (&variable)); } -inline void Atomic::decrement (int& variable) { _InterlockedDecrement (reinterpret_cast (&variable)); } -inline int Atomic::decrementAndReturn (int& variable) { return _InterlockedDecrement (reinterpret_cast (&variable)); } - -#else // Windows without intrinsics... - -inline void Atomic::increment (int& variable) -{ - __asm { - mov ecx, dword ptr [variable] - lock inc dword ptr [ecx] - } -} - -inline int Atomic::incrementAndReturn (int& variable) -{ - int result; - - __asm { - mov ecx, dword ptr [variable] - mov eax, 1 - lock xadd dword ptr [ecx], eax - inc eax - mov result, eax - } - - return result; -} - -inline void Atomic::decrement (int& variable) -{ - __asm { - mov ecx, dword ptr [variable] - lock dec dword ptr [ecx] - } -} - -inline int Atomic::decrementAndReturn (int& variable) -{ - int result; - - __asm { - mov ecx, dword ptr [variable] - mov eax, -1 - lock xadd dword ptr [ecx], eax - dec eax - mov result, eax - } - - return result; -} +inline void Atomic::increment (int32& variable) { _InterlockedIncrement (reinterpret_cast (&variable)); } +inline int32 Atomic::incrementAndReturn (int32& variable) { return _InterlockedIncrement (reinterpret_cast (&variable)); } +inline void Atomic::decrement (int32& variable) { _InterlockedDecrement (reinterpret_cast (&variable)); } +inline int32 Atomic::decrementAndReturn (int32& variable) { return _InterlockedDecrement (reinterpret_cast (&variable)); } +inline int32 Atomic::compareAndExchange (int32& destination, int32 newValue, int32 oldValue) + { return _InterlockedCompareExchange (reinterpret_cast (&destination), newValue, oldValue); } #endif @@ -5118,7 +5000,7 @@ public: // avoids getting warning messages about the parameter being unused lock.enter(); - sortArray (comparator, (ObjectClass*) data.elements, 0, size() - 1, retainOrderOfEquivalentItems); + sortArray (comparator, (ObjectClass**) data.elements, 0, size() - 1, retainOrderOfEquivalentItems); lock.exit(); } @@ -25219,7 +25101,8 @@ protected: public: ChoicePropertyComponent (const Value& valueToControl, const String& propertyName, - const StringArray& choices); + const StringArray& choices, + const Array * choiceIDs = 0); ~ChoicePropertyComponent(); @@ -25240,7 +25123,7 @@ protected: private: ComboBox* comboBox; - void createComboBox(); + void createComboBox (const Array * choiceIDs); ChoicePropertyComponent (const ChoicePropertyComponent&); const ChoicePropertyComponent& operator= (const ChoicePropertyComponent&); @@ -27620,10 +27503,6 @@ public: #pragma pack (pop) #endif -#if JUCE_MAC || JUCE_IPHONE - #pragma align=reset -#endif - END_JUCE_NAMESPACE #ifndef DONT_SET_USING_JUCE_NAMESPACE diff --git a/src/audio/plugins/formats/juce_AudioUnitPluginFormat.mm b/src/audio/plugins/formats/juce_AudioUnitPluginFormat.mm index 4c0eb8718d..20c9f44911 100644 --- a/src/audio/plugins/formats/juce_AudioUnitPluginFormat.mm +++ b/src/audio/plugins/formats/juce_AudioUnitPluginFormat.mm @@ -351,8 +351,8 @@ private: { for (int i = 0; i < supportedChannelsSize / sizeof (AUChannelInfo); ++i) { - numIns = jmax (numIns, supportedChannels[i].inChannels); - numOuts = jmax (numOuts, supportedChannels[i].outChannels); + numIns = jmax (numIns, (int) supportedChannels[i].inChannels); + numOuts = jmax (numOuts, (int) supportedChannels[i].outChannels); } } else diff --git a/src/containers/juce_MemoryBlock.cpp b/src/containers/juce_MemoryBlock.cpp index 80f1208e65..a14a28ef38 100644 --- a/src/containers/juce_MemoryBlock.cpp +++ b/src/containers/juce_MemoryBlock.cpp @@ -98,8 +98,7 @@ MemoryBlock& MemoryBlock::operator= (const MemoryBlock& other) throw() //============================================================================== bool MemoryBlock::operator== (const MemoryBlock& other) const throw() { - return (size == other.size) - && (memcmp (data, other.data, size) == 0); + return matches (other.data, other.size); } bool MemoryBlock::operator!= (const MemoryBlock& other) const throw() @@ -107,6 +106,12 @@ bool MemoryBlock::operator!= (const MemoryBlock& other) const throw() return ! operator== (other); } +bool MemoryBlock::matches (const void* dataToCompare, size_t dataSize) const throw() +{ + return size == dataSize + && memcmp (data, dataToCompare, size) == 0; +} + //============================================================================== // this will resize the block to this size void MemoryBlock::setSize (const size_t newSize, diff --git a/src/containers/juce_MemoryBlock.h b/src/containers/juce_MemoryBlock.h index ffb355ef90..a4cff3429e 100644 --- a/src/containers/juce_MemoryBlock.h +++ b/src/containers/juce_MemoryBlock.h @@ -83,6 +83,10 @@ public: */ bool operator!= (const MemoryBlock& other) const throw(); + /** Returns true if the data in this MemoryBlock matches the raw bytes passed-in. + */ + bool matches (const void* data, size_t dataSize) const throw(); + //============================================================================== /** Returns a pointer to the data, casting it to any type of primitive data required. diff --git a/src/core/juce_Atomic.h b/src/core/juce_Atomic.h index 51d9d9e585..4018bc19c4 100644 --- a/src/core/juce_Atomic.h +++ b/src/core/juce_Atomic.h @@ -34,174 +34,60 @@ class JUCE_API Atomic { public: /** Increments an integer in a thread-safe way. */ - static void increment (int& variable); + static void increment (int32& variable); /** Increments an integer in a thread-safe way and returns its new value. */ - static int incrementAndReturn (int& variable); + static int32 incrementAndReturn (int32& variable); /** Decrements an integer in a thread-safe way. */ - static void decrement (int& variable); + static void decrement (int32& variable); /** Decrements an integer in a thread-safe way and returns its new value. */ - static int decrementAndReturn (int& variable); + static int32 decrementAndReturn (int32& variable); + + /** If the current value of destination is equal to requiredCurrentValue, this + will set it to newValue; otherwise, it will leave it unchanged. + @returns the new value of destination + */ + static int32 compareAndExchange (int32& destination, int32 newValue, int32 requiredCurrentValue); }; //============================================================================== #if (JUCE_MAC || JUCE_IPHONE) // Mac and iPhone... -#include -inline void Atomic::increment (int& variable) { OSAtomicIncrement32 ((int32_t*) &variable); } -inline int Atomic::incrementAndReturn (int& variable) { return OSAtomicIncrement32 ((int32_t*) &variable); } -inline void Atomic::decrement (int& variable) { OSAtomicDecrement32 ((int32_t*) &variable); } -inline int Atomic::decrementAndReturn (int& variable) { return OSAtomicDecrement32 ((int32_t*) &variable); } +inline void Atomic::increment (int32& variable) { OSAtomicIncrement32 ((volatile int32_t*) &variable); } +inline int32 Atomic::incrementAndReturn (int32& variable) { return OSAtomicIncrement32 ((volatile int32_t*) &variable); } +inline void Atomic::decrement (int32& variable) { OSAtomicDecrement32 ((volatile int32_t*) &variable); } +inline int32 Atomic::decrementAndReturn (int32& variable) { return OSAtomicDecrement32 ((volatile int32_t*) &variable); } +inline int32 Atomic::compareAndExchange (int32& destination, int32 newValue, int32 oldValue) + { return OSAtomicCompareAndSwap32Barrier (oldValue, newValue, (volatile int32_t*) &destination); } -#elif JUCE_GCC +#elif JUCE_GCC // Linux... //============================================================================== -#if JUCE_USE_GCC_ATOMIC_INTRINSICS // Linux with intrinsics... - -inline void Atomic::increment (int& variable) { __sync_add_and_fetch (&variable, 1); } -inline int Atomic::incrementAndReturn (int& variable) { return __sync_add_and_fetch (&variable, 1); } -inline void Atomic::decrement (int& variable) { __sync_add_and_fetch (&variable, -1); } -inline int Atomic::decrementAndReturn (int& variable) { return __sync_add_and_fetch (&variable, -1); } +inline void Atomic::increment (int32& variable) { __sync_add_and_fetch (&variable, 1); } +inline int32 Atomic::incrementAndReturn (int32& variable) { return __sync_add_and_fetch (&variable, 1); } +inline void Atomic::decrement (int32& variable) { __sync_add_and_fetch (&variable, -1); } +inline int32 Atomic::decrementAndReturn (int32& variable) { return __sync_add_and_fetch (&variable, -1); } +inline int32 Atomic::compareAndExchange (int32& destination, int32 newValue, int32 oldValue) + { return __sync_val_compare_and_swap (&destination, oldValue, newValue); } //============================================================================== -#else // Linux without intrinsics... - -inline void Atomic::increment (int& variable) -{ - __asm__ __volatile__ ( - #if JUCE_64BIT - "lock incl (%%rax)" - : - : "a" (&variable) - : "cc", "memory"); - #else - "lock incl %0" - : "=m" (variable) - : "m" (variable)); - #endif -} - -inline int Atomic::incrementAndReturn (int& variable) -{ - int result; - - __asm__ __volatile__ ( - #if JUCE_64BIT - "lock xaddl %%ebx, (%%rax) \n\ - incl %%ebx" - : "=b" (result) - : "a" (&variable), "b" (1) - : "cc", "memory"); - #else - "lock xaddl %%eax, (%%ecx) \n\ - incl %%eax" - : "=a" (result) - : "c" (&variable), "a" (1) - : "memory"); - #endif - - return result; -} - -inline void Atomic::decrement (int& variable) -{ - __asm__ __volatile__ ( - #if JUCE_64BIT - "lock decl (%%rax)" - : - : "a" (&variable) - : "cc", "memory"); - #else - "lock decl %0" - : "=m" (variable) - : "m" (variable)); - #endif -} - -inline int Atomic::decrementAndReturn (int& variable) -{ - int result; - - __asm__ __volatile__ ( - #if JUCE_64BIT - "lock xaddl %%ebx, (%%rax) \n\ - decl %%ebx" - : "=b" (result) - : "a" (&variable), "b" (-1) - : "cc", "memory"); - #else - "lock xaddl %%eax, (%%ecx) \n\ - decl %%eax" - : "=a" (result) - : "c" (&variable), "a" (-1) - : "memory"); - #endif - return result; -} -#endif - -//============================================================================== -#elif JUCE_USE_INTRINSICS // Windows with intrinsics... +#elif JUCE_USE_INTRINSICS // Windows... +// (If JUCE_USE_INTRINSICS isn't enabled, a fallback version of these methods is +// declared in juce_win32_Threads.cpp) #pragma intrinsic (_InterlockedIncrement) #pragma intrinsic (_InterlockedDecrement) +#pragma intrinsic (_InterlockedCompareExchange) -inline void Atomic::increment (int& variable) { _InterlockedIncrement (reinterpret_cast (&variable)); } -inline int Atomic::incrementAndReturn (int& variable) { return _InterlockedIncrement (reinterpret_cast (&variable)); } -inline void Atomic::decrement (int& variable) { _InterlockedDecrement (reinterpret_cast (&variable)); } -inline int Atomic::decrementAndReturn (int& variable) { return _InterlockedDecrement (reinterpret_cast (&variable)); } - -//============================================================================== -#else // Windows without intrinsics... - -inline void Atomic::increment (int& variable) -{ - __asm { - mov ecx, dword ptr [variable] - lock inc dword ptr [ecx] - } -} - -inline int Atomic::incrementAndReturn (int& variable) -{ - int result; - - __asm { - mov ecx, dword ptr [variable] - mov eax, 1 - lock xadd dword ptr [ecx], eax - inc eax - mov result, eax - } - - return result; -} - -inline void Atomic::decrement (int& variable) -{ - __asm { - mov ecx, dword ptr [variable] - lock dec dword ptr [ecx] - } -} - -inline int Atomic::decrementAndReturn (int& variable) -{ - int result; - - __asm { - mov ecx, dword ptr [variable] - mov eax, -1 - lock xadd dword ptr [ecx], eax - dec eax - mov result, eax - } - - return result; -} +inline void Atomic::increment (int32& variable) { _InterlockedIncrement (reinterpret_cast (&variable)); } +inline int32 Atomic::incrementAndReturn (int32& variable) { return _InterlockedIncrement (reinterpret_cast (&variable)); } +inline void Atomic::decrement (int32& variable) { _InterlockedDecrement (reinterpret_cast (&variable)); } +inline int32 Atomic::decrementAndReturn (int32& variable) { return _InterlockedDecrement (reinterpret_cast (&variable)); } +inline int32 Atomic::compareAndExchange (int32& destination, int32 newValue, int32 oldValue) + { return _InterlockedCompareExchange (reinterpret_cast (&destination), newValue, oldValue); } #endif diff --git a/src/core/juce_SystemStats.cpp b/src/core/juce_SystemStats.cpp index ffd8e4fbc2..7205cbbc61 100644 --- a/src/core/juce_SystemStats.cpp +++ b/src/core/juce_SystemStats.cpp @@ -79,12 +79,6 @@ void JUCE_PUBLIC_FUNCTION initialiseJuce_NonGUI() jassert (ByteOrder::swap ((uint16) 0x1122) == 0x2211); jassert (ByteOrder::swap ((uint32) 0x11223344) == 0x44332211); - // quick test to make sure the run-time lib doesn't crash on freeing a null-pointer. - SystemStats* nullPointer = 0; - juce_free (nullPointer); - delete[] nullPointer; - delete nullPointer; - // Some quick stream tests.. int randomInt = Random::getSystemRandom().nextInt(); int64 randomInt64 = Random::getSystemRandom().nextInt64(); diff --git a/src/events/juce_Timer.cpp b/src/events/juce_Timer.cpp index daa8c5197e..b6c1eed71f 100644 --- a/src/events/juce_Timer.cpp +++ b/src/events/juce_Timer.cpp @@ -44,17 +44,193 @@ class InternalTimerThread : private Thread, private DeletedAtShutdown, private AsyncUpdater { +public: + InternalTimerThread() + : Thread ("Juce Timer"), + firstTimer (0), + callbackNeeded (false) + { + triggerAsyncUpdate(); + } + + ~InternalTimerThread() throw() + { + stopThread (4000); + + jassert (instance == this || instance == 0); + if (instance == this) + instance = 0; + } + + void run() + { + uint32 lastTime = Time::getMillisecondCounter(); + + while (! threadShouldExit()) + { + const uint32 now = Time::getMillisecondCounter(); + + if (now <= lastTime) + { + wait (2); + continue; + } + + const int elapsed = now - lastTime; + lastTime = now; + + lock.enter(); + decrementAllCounters (elapsed); + const int timeUntilFirstTimer = (firstTimer != 0) ? firstTimer->countdownMs + : 1000; + lock.exit(); + + if (timeUntilFirstTimer <= 0) + { + /* If we managed to set the atomic boolean to true then send a message, this is needed + as a memory barrier so the message won't be sent before callbackNeeded is set to true, + but if it fails it means the message-thread changed the value from under us so at least + some processing is happenening and we can just loop around and try again + */ + if (callbackNeeded.set (true)) + { + postMessage (new Message()); + + /* Sometimes our message can get discarded by the OS (e.g. when running as an RTAS + when the app has a modal loop), so this is how long to wait before assuming the + message has been lost and trying again. + */ + const uint32 messageDeliveryTimeout = now + 2000; + + while (callbackNeeded.get()) + { + wait (4); + + if (threadShouldExit()) + return; + + if (Time::getMillisecondCounter() > messageDeliveryTimeout) + break; + } + } + } + else + { + // don't wait for too long because running this loop also helps keep the + // Time::getApproximateMillisecondTimer value stay up-to-date + wait (jlimit (1, 50, timeUntilFirstTimer)); + } + } + } + + void handleMessage (const Message&) + { + const ScopedLock sl (lock); + + while (firstTimer != 0 && firstTimer->countdownMs <= 0) + { + Timer* const t = firstTimer; + t->countdownMs = t->periodMs; + + removeTimer (t); + addTimer (t); + + const ScopedUnlock ul (lock); + + JUCE_TRY + { + t->timerCallback(); + } + JUCE_CATCH_EXCEPTION + } + + /* This is needed as a memory barrier to make sure all processing of current timers is done + before the boolean is set. This set should never fail since if it was false in the first place, + we wouldn't get a message (so it can't be changed from false to true from under us), and if we + get a message then the value is true and the other thread can only set it to true again and + we will get another callback to set it to false. + */ + callbackNeeded.set (false); + } + + static void callAnyTimersSynchronously() + { + if (InternalTimerThread::instance != 0) + { + const Message m; + InternalTimerThread::instance->handleMessage (m); + } + } + + static inline void add (Timer* const tim) throw() + { + if (instance == 0) + instance = new InternalTimerThread(); + + const ScopedLock sl (instance->lock); + instance->addTimer (tim); + } + + static inline void remove (Timer* const tim) throw() + { + if (instance != 0) + { + const ScopedLock sl (instance->lock); + instance->removeTimer (tim); + } + } + + static inline void resetCounter (Timer* const tim, + const int newCounter) throw() + { + if (instance != 0) + { + tim->countdownMs = newCounter; + tim->periodMs = newCounter; + + if ((tim->next != 0 && tim->next->countdownMs < tim->countdownMs) + || (tim->previous != 0 && tim->previous->countdownMs > tim->countdownMs)) + { + const ScopedLock sl (instance->lock); + instance->removeTimer (tim); + instance->addTimer (tim); + } + } + } + private: friend class Timer; static InternalTimerThread* instance; static CriticalSection lock; - Timer* volatile firstTimer; - bool volatile callbackNeeded; - InternalTimerThread (const InternalTimerThread&); - const InternalTimerThread& operator= (const InternalTimerThread&); + //============================================================================== + class AtomicBool + { + public: + AtomicBool (const bool value) throw() : value (static_cast (value)) {} + ~AtomicBool() throw() {} + bool get() const throw() { return value != 0; } + bool set (const bool newValue) { return Atomic::compareAndExchange (value, newValue ? 1 : 0, value) != 0; } + + /*bool setIfNotAlreadyThisValue (const bool newValue) + { + int32 valueNew = newValue ? 1 : 0; + int32 valueCurrent = 1 - valueNew; + return Atomic::compareAndExchange (value, valueNew, valueCurrent); + }*/ + + private: + int32 value; + + AtomicBool (const AtomicBool&); + AtomicBool& operator= (const AtomicBool&); + }; + + AtomicBool callbackNeeded; + + //============================================================================== void addTimer (Timer* const t) throw() { #ifdef JUCE_DEBUG @@ -156,146 +332,8 @@ private: startThread (7); } -public: - InternalTimerThread() - : Thread ("Juce Timer"), - firstTimer (0), - callbackNeeded (false) - { - triggerAsyncUpdate(); - } - - ~InternalTimerThread() throw() - { - stopThread (4000); - - jassert (instance == this || instance == 0); - if (instance == this) - instance = 0; - } - - void run() - { - uint32 lastTime = Time::getMillisecondCounter(); - - while (! threadShouldExit()) - { - uint32 now = Time::getMillisecondCounter(); - - if (now <= lastTime) - { - wait (2); - continue; - } - - const int elapsed = now - lastTime; - lastTime = now; - - lock.enter(); - decrementAllCounters (elapsed); - const int timeUntilFirstTimer = (firstTimer != 0) ? firstTimer->countdownMs - : 1000; - lock.exit(); - - if (timeUntilFirstTimer <= 0) - { - callbackNeeded = true; - postMessage (new Message()); - - // sometimes, our message could get discarded by the OS (particularly when running as an RTAS when the app has a modal loop), - // so this is how long to wait before assuming the message has been lost and trying again. - const uint32 messageDeliveryTimeout = now + 2000; - - while (callbackNeeded) - { - wait (4); - - if (threadShouldExit()) - return; - - now = Time::getMillisecondCounter(); - - if (now > messageDeliveryTimeout) - break; - } - } - else - { - // don't wait for too long because running this loop also helps keep the - // Time::getApproximateMillisecondTimer value stay up-to-date - wait (jlimit (1, 50, timeUntilFirstTimer)); - } - } - } - - void handleMessage (const Message&) - { - const ScopedLock sl (lock); - - while (firstTimer != 0 && firstTimer->countdownMs <= 0) - { - Timer* const t = firstTimer; - t->countdownMs = t->periodMs; - - removeTimer (t); - addTimer (t); - - const ScopedUnlock ul (lock); - - JUCE_TRY - { - t->timerCallback(); - } - JUCE_CATCH_EXCEPTION - } - - callbackNeeded = false; - } - - static void callAnyTimersSynchronously() - { - if (InternalTimerThread::instance != 0) - { - const Message m; - InternalTimerThread::instance->handleMessage (m); - } - } - - static inline void add (Timer* const tim) throw() - { - if (instance == 0) - instance = new InternalTimerThread(); - - const ScopedLock sl (instance->lock); - instance->addTimer (tim); - } - - static inline void remove (Timer* const tim) throw() - { - if (instance != 0) - { - const ScopedLock sl (instance->lock); - instance->removeTimer (tim); - } - } - - static inline void resetCounter (Timer* const tim, - const int newCounter) throw() - { - if (instance != 0) - { - tim->countdownMs = newCounter; - tim->periodMs = newCounter; - - if ((tim->next != 0 && tim->next->countdownMs < tim->countdownMs) - || (tim->previous != 0 && tim->previous->countdownMs > tim->countdownMs)) - { - const ScopedLock sl (instance->lock); - instance->removeTimer (tim); - instance->addTimer (tim); - } - } - } + InternalTimerThread (const InternalTimerThread&); + InternalTimerThread& operator= (const InternalTimerThread&); }; InternalTimerThread* InternalTimerThread::instance = 0; diff --git a/src/gui/components/filebrowser/juce_FileBrowserComponent.h b/src/gui/components/filebrowser/juce_FileBrowserComponent.h index b05aa4f566..ac569c7dc2 100644 --- a/src/gui/components/filebrowser/juce_FileBrowserComponent.h +++ b/src/gui/components/filebrowser/juce_FileBrowserComponent.h @@ -127,7 +127,7 @@ public: This may be different from getCurrentFile(), which returns the value that is shown in the filename box, and if there are multiple selections, this will only return one of them. - @see getCurrentFile + @see getSelectedFile */ const File getHighlightedFile() const throw(); diff --git a/src/gui/components/properties/juce_ChoicePropertyComponent.cpp b/src/gui/components/properties/juce_ChoicePropertyComponent.cpp index dd1808faf3..06ebec21c3 100644 --- a/src/gui/components/properties/juce_ChoicePropertyComponent.cpp +++ b/src/gui/components/properties/juce_ChoicePropertyComponent.cpp @@ -39,12 +39,13 @@ ChoicePropertyComponent::ChoicePropertyComponent (const String& name) ChoicePropertyComponent::ChoicePropertyComponent (const Value& valueToControl, const String& name, - const StringArray& choices_) + const StringArray& choices_, + const Array * choiceIDs) : PropertyComponent (name), choices (choices_), comboBox (0) { - createComboBox(); + createComboBox (choiceIDs); comboBox->getSelectedIdAsValue().referTo (valueToControl); } @@ -55,14 +56,18 @@ ChoicePropertyComponent::~ChoicePropertyComponent() } //============================================================================== -void ChoicePropertyComponent::createComboBox() +void ChoicePropertyComponent::createComboBox (const Array * choiceIDs) { + // The array of IDs must contain the same number of values as the choices list! + jassert (choiceIDs == 0 || choiceIDs->size() == choices.size()); + addAndMakeVisible (comboBox = new ComboBox (String::empty)); for (int i = 0; i < choices.size(); ++i) { if (choices[i].isNotEmpty()) - comboBox->addItem (choices[i], i + 1); + comboBox->addItem (choices[i], choiceIDs == 0 ? (i + 1) + : ((*choiceIDs)[i])); else comboBox->addSeparator(); } @@ -90,7 +95,7 @@ void ChoicePropertyComponent::refresh() { if (comboBox == 0) { - createComboBox(); + createComboBox (0); comboBox->addListener (this); } diff --git a/src/gui/components/properties/juce_ChoicePropertyComponent.h b/src/gui/components/properties/juce_ChoicePropertyComponent.h index 1658caa7cd..56873c800b 100644 --- a/src/gui/components/properties/juce_ChoicePropertyComponent.h +++ b/src/gui/components/properties/juce_ChoicePropertyComponent.h @@ -63,12 +63,20 @@ protected: public: /** Creates the component. - Your subclass's constructor must add a list of options to the choices - member variable. + @param valueToControl the value that the combo box will read and control + @param propertyName the name of the property + @param choices the list of possible values that the user can choose between + @param choiceIDs if this is 0, then the value corresponding to each item in the + 'choices' StringArray is simply its index + 1. But if the + choiceIDs parameter is specified, it lets you provide a set + of IDs for each item in the choices list. If you use this + parameter, it must contain the same number of elements as + the choices list. */ ChoicePropertyComponent (const Value& valueToControl, const String& propertyName, - const StringArray& choices); + const StringArray& choices, + const Array * choiceIDs = 0); /** Destructor. */ ~ChoicePropertyComponent(); @@ -113,7 +121,7 @@ protected: private: ComboBox* comboBox; - void createComboBox(); + void createComboBox (const Array * choiceIDs); ChoicePropertyComponent (const ChoicePropertyComponent&); const ChoicePropertyComponent& operator= (const ChoicePropertyComponent&); diff --git a/src/native/windows/juce_win32_NativeIncludes.h b/src/native/windows/juce_win32_NativeIncludes.h index edc22f23f7..a121da5306 100644 --- a/src/native/windows/juce_win32_NativeIncludes.h +++ b/src/native/windows/juce_win32_NativeIncludes.h @@ -142,6 +142,7 @@ #include #include #include + #include #include #endif diff --git a/src/native/windows/juce_win32_Threads.cpp b/src/native/windows/juce_win32_Threads.cpp index fbb787437c..9553ff40dd 100644 --- a/src/native/windows/juce_win32_Threads.cpp +++ b/src/native/windows/juce_win32_Threads.cpp @@ -31,6 +31,17 @@ extern HWND juce_messageWindowHandle; #endif +//============================================================================== +#if ! JUCE_USE_INTRINSICS +// In newer compilers, the inline versions of these are used (in juce_Atomic.h), but in +// older ones we have to actually call the ops as win32 functions.. +void Atomic::increment (int32& variable) { InterlockedIncrement (reinterpret_cast (&variable)); } +int32 Atomic::incrementAndReturn (int32& variable) { return InterlockedIncrement (reinterpret_cast (&variable)); } +void Atomic::decrement (int32& variable) { InterlockedDecrement (reinterpret_cast (&variable)); } +int32 Atomic::decrementAndReturn (int32& variable) { return InterlockedDecrement (reinterpret_cast (&variable)); } +int32 Atomic::compareAndExchange (int32& destination, int32 newValue, int32 oldValue) + { return InterlockedCompareExchange (reinterpret_cast (&destination), newValue, oldValue); } +#endif //============================================================================== CriticalSection::CriticalSection() throw() diff --git a/src/native/windows/juce_win32_WASAPI.cpp b/src/native/windows/juce_win32_WASAPI.cpp index 25aa8b0ac8..c203606c4f 100644 --- a/src/native/windows/juce_win32_WASAPI.cpp +++ b/src/native/windows/juce_win32_WASAPI.cpp @@ -780,8 +780,26 @@ public: } } + void setMMThreadPriority() + { + DynamicLibraryLoader dll ("avrt.dll"); + DynamicLibraryImport (AvSetMmThreadCharacteristics, avSetMmThreadCharacteristics, HANDLE, dll, (LPCTSTR, LPDWORD)) + DynamicLibraryImport (AvSetMmThreadPriority, avSetMmThreadPriority, HANDLE, dll, (HANDLE, AVRT_PRIORITY)) + + if (avSetMmThreadCharacteristics != 0 && avSetMmThreadPriority != 0) + { + DWORD dummy = 0; + HANDLE h = avSetMmThreadCharacteristics (_T("Pro Audio"), &dummy); + + if (h != 0) + avSetMmThreadPriority (h, AVRT_PRIORITY_NORMAL); + } + } + void run() { + setMMThreadPriority(); + const int bufferSize = currentBufferSizeSamples; HANDLE events[2]; diff --git a/src/native/windows/juce_win32_WebBrowserComponent.cpp b/src/native/windows/juce_win32_WebBrowserComponent.cpp index eb7aa69b55..efaed6f15f 100644 --- a/src/native/windows/juce_win32_WebBrowserComponent.cpp +++ b/src/native/windows/juce_win32_WebBrowserComponent.cpp @@ -79,10 +79,18 @@ public: if (browser != 0) { LPSAFEARRAY sa = 0; - _variant_t flags, frame, postDataVar, headersVar; + + VARIANT flags, frame, postDataVar, headersVar; // (_variant_t isn't available in all compilers) + VariantInit (&flags); + VariantInit (&frame); + VariantInit (&postDataVar); + VariantInit (&headersVar); if (headers != 0) - headersVar = (const tchar*) headers->joinIntoString ("\r\n"); + { + V_VT (&headersVar) = VT_BSTR; + V_BSTR (&headersVar) = SysAllocString ((const tchar*) headers->joinIntoString ("\r\n")); + } if (postData != 0 && postData->getSize() > 0) { @@ -115,6 +123,11 @@ public: if (sa != 0) SafeArrayDestroy (sa); + + VariantClear (&flags); + VariantClear (&frame); + VariantClear (&postDataVar); + VariantClear (&headersVar); } }