From bf501e1fda0876e281efc23dcaf2d3fdd77b91f1 Mon Sep 17 00:00:00 2001 From: jules Date: Fri, 13 Feb 2009 13:08:34 +0000 Subject: [PATCH] Fix for multithreaded Mac OpenGL components; better responding to shutdown messages on Windows; a couple of small VST tweaks; fixed a typo in the AudioDeviceManager and made it close and reopen the audio device while the midi output is being changed; changed AlertWindow to give more control over the desktop window style; fixed a small bug in Graphics; changed SparseSet to avoid an overflow error; stopped BufferedInputStream locking up when its source stream fails; added a case-sensitivity option to StringPairArray and LocalisedStrings. --- .../juce_mac_OpenGLComponent.mm | 116 ++++++++++--- .../juce_win32_Windowing.cpp | 11 +- .../wrapper/VST/juce_VST_Wrapper.cpp | 22 ++- juce_amalgamated.cpp | 154 +++++++++++++++--- juce_amalgamated.h | 33 +++- .../audio/devices/juce_AudioDeviceManager.cpp | 8 +- .../components/windows/juce_AlertWindow.cpp | 5 + .../gui/components/windows/juce_AlertWindow.h | 2 + .../gui/graphics/contexts/juce_Graphics.cpp | 2 +- .../containers/juce_ArrayAllocationBase.h | 1 + src/juce_core/containers/juce_SparseSet.h | 21 ++- .../io/streams/juce_BufferedInputStream.cpp | 4 + src/juce_core/text/juce_LocalisedStrings.cpp | 5 + src/juce_core/text/juce_LocalisedStrings.h | 7 + src/juce_core/text/juce_StringPairArray.cpp | 5 + src/juce_core/text/juce_StringPairArray.h | 5 + 16 files changed, 333 insertions(+), 68 deletions(-) diff --git a/build/macosx/platform_specific_code/juce_mac_OpenGLComponent.mm b/build/macosx/platform_specific_code/juce_mac_OpenGLComponent.mm index 700a274b8f..bee6d3cc23 100644 --- a/build/macosx/platform_specific_code/juce_mac_OpenGLComponent.mm +++ b/build/macosx/platform_specific_code/juce_mac_OpenGLComponent.mm @@ -33,6 +33,88 @@ // compiled on its own). #if JUCE_INCLUDED_FILE && JUCE_OPENGL +END_JUCE_NAMESPACE + +//============================================================================== +@interface ThreadSafeNSOpenGLView : NSOpenGLView +{ + CriticalSection* contextLock; + bool needsUpdate; +} + +- (id) initWithFrame: (NSRect) frameRect pixelFormat: (NSOpenGLPixelFormat*) format; +- (bool) makeActive; +- (void) makeInactive; +- (void) reshape; +@end + +@implementation ThreadSafeNSOpenGLView + +- (id) initWithFrame: (NSRect) frameRect + pixelFormat: (NSOpenGLPixelFormat*) format +{ + contextLock = new CriticalSection(); + self = [super initWithFrame: frameRect pixelFormat: format]; + + if (self != nil) + [[NSNotificationCenter defaultCenter] addObserver: self + selector: @selector (_surfaceNeedsUpdate:) + name: NSViewGlobalFrameDidChangeNotification + object: self]; + return self; +} + +- (void) dealloc +{ + [[NSNotificationCenter defaultCenter] removeObserver: self]; + delete contextLock; + [super dealloc]; +} + +- (bool) makeActive +{ + const ScopedLock sl (*contextLock); + + if ([self openGLContext] == 0) + return false; + + [[self openGLContext] makeCurrentContext]; + + if (needsUpdate) + { + [super update]; + needsUpdate = false; + } + + return true; +} + +- (void) makeInactive +{ + const ScopedLock sl (*contextLock); + [NSOpenGLContext clearCurrentContext]; +} + +- (void) _surfaceNeedsUpdate: (NSNotification*) notification +{ + const ScopedLock sl (*contextLock); + needsUpdate = true; +} + +- (void) update +{ + const ScopedLock sl (*contextLock); + needsUpdate = true; +} + +- (void) reshape +{ + const ScopedLock sl (*contextLock); + needsUpdate = true; +} + +@end +BEGIN_JUCE_NAMESPACE //============================================================================== class WindowedGLContext : public OpenGLContext @@ -50,6 +132,7 @@ public: int n = 0; attribs[n++] = NSOpenGLPFADoubleBuffer; attribs[n++] = NSOpenGLPFAAccelerated; + attribs[n++] = NSOpenGLPFAMPSafe; // NSOpenGLPFAAccelerated, NSOpenGLPFAMultiScreen, NSOpenGLPFASingleRenderer attribs[n++] = NSOpenGLPFAColorSize; attribs[n++] = (NSOpenGLPixelFormatAttribute) jmax (pixelFormat.redBits, pixelFormat.greenBits, @@ -67,7 +150,6 @@ public: pixelFormat.accumulationBufferAlphaBits); // xxx not sure how to do fullSceneAntiAliasingNumSamples.. - attribs[n++] = NSOpenGLPFASampleBuffers; attribs[n++] = (NSOpenGLPixelFormatAttribute) 1; attribs[n++] = NSOpenGLPFAClosestPolicy; @@ -77,21 +159,13 @@ public: NSOpenGLPixelFormat* format = [[NSOpenGLPixelFormat alloc] initWithAttributes: attribs]; - NSOpenGLView* view - = [[NSOpenGLView alloc] initWithFrame: NSMakeRect (0, 0, 100.0f, 100.0f) - pixelFormat: format]; - - if (sharedContext != 0) - { - renderContext = [[NSOpenGLContext alloc] initWithFormat: format - shareContext: sharedContext]; - [view setOpenGLContext: renderContext]; - [renderContext setView: view]; - } - else - { - renderContext = [view openGLContext]; - } + view = [[ThreadSafeNSOpenGLView alloc] initWithFrame: NSMakeRect (0, 0, 100.0f, 100.0f) + pixelFormat: format]; + + renderContext = [[[NSOpenGLContext alloc] initWithFormat: format + shareContext: sharedContext] autorelease]; + [view setOpenGLContext: renderContext]; + [renderContext setView: view]; [format release]; @@ -108,15 +182,13 @@ public: bool makeActive() const throw() { jassert (renderContext != 0); - [renderContext makeCurrentContext]; - return renderContext != 0; + [view makeActive]; + return isActive(); } bool makeInactive() const throw() { - if (! isActive()) - [NSOpenGLContext clearCurrentContext]; - + [view makeInactive]; return true; } @@ -134,7 +206,6 @@ public: void swapBuffers() { - glFlush(); [renderContext flushBuffer]; } @@ -173,6 +244,7 @@ public: juce_UseDebuggingNewOperator NSOpenGLContext* renderContext; + ThreadSafeNSOpenGLView* view; private: OpenGLPixelFormat pixelFormat; diff --git a/build/win32/platform_specific_code/juce_win32_Windowing.cpp b/build/win32/platform_specific_code/juce_win32_Windowing.cpp index c85e4b3a17..ace941ab49 100644 --- a/build/win32/platform_specific_code/juce_win32_Windowing.cpp +++ b/build/win32/platform_specific_code/juce_win32_Windowing.cpp @@ -2033,9 +2033,18 @@ private: return 0; case WM_QUIT: - JUCEApplication::quit(); + if (JUCEApplication::getInstance() != 0) + JUCEApplication::getInstance()->systemRequestedQuit(); return 0; + case WM_QUERYENDSESSION: + if (JUCEApplication::getInstance() != 0) + { + JUCEApplication::getInstance()->systemRequestedQuit(); + return MessageManager::getInstance()->hasStopMessageBeenSent(); + } + return TRUE; + //============================================================================== case WM_TRAYNOTIFY: if (component->isCurrentlyBlockedByAnotherModalComponent()) diff --git a/extras/audio plugins/wrapper/VST/juce_VST_Wrapper.cpp b/extras/audio plugins/wrapper/VST/juce_VST_Wrapper.cpp index f94bbaac81..699fbfaf3d 100644 --- a/extras/audio plugins/wrapper/VST/juce_VST_Wrapper.cpp +++ b/extras/audio plugins/wrapper/VST/juce_VST_Wrapper.cpp @@ -69,12 +69,26 @@ #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 @@ -966,7 +980,13 @@ public: bool setSpeakerArrangement (VstSpeakerArrangement* pluginInput, VstSpeakerArrangement* pluginOutput) { - // if this method isn't implemented, nuendo4 + cubase4 crash when you've got multiple channels.. + if (numInChans != pluginInput->numChannels + || numOutChans != pluginOutput->numChannels) + { + setNumInputs (pluginInput->numChannels); + setNumOutputs (pluginOutput->numChannels); + ioChanged(); + } numInChans = pluginInput->numChannels; numOutChans = pluginOutput->numChannels; diff --git a/juce_amalgamated.cpp b/juce_amalgamated.cpp index aa2b1c5e54..c3bf356524 100644 --- a/juce_amalgamated.cpp +++ b/juce_amalgamated.cpp @@ -8029,8 +8029,12 @@ int BufferedInputStream::read (void* destBuffer, int maxBytesToRead) destBuffer = (void*) (((char*) destBuffer) + bytesAvailable); } + const int64 oldLastReadPos = lastReadPos; ensureBuffered(); + if (oldLastReadPos == lastReadPos) + break; // if ensureBuffered() failed to read any more data, bail out + if (isExhausted()) break; } @@ -9749,6 +9753,11 @@ void LocalisedStrings::loadFromText (const String& fileContents) throw() } } +void LocalisedStrings::setIgnoresCase (const bool shouldIgnoreCase) throw() +{ + translations.setIgnoresCase (shouldIgnoreCase); +} + static CriticalSection currentMappingsLock; static LocalisedStrings* currentMappings = 0; @@ -12592,6 +12601,11 @@ void StringPairArray::remove (const int index) throw() values.remove (index); } +void StringPairArray::setIgnoresCase (const bool shouldIgnoreCase) throw() +{ + ignoreCase = shouldIgnoreCase; +} + void StringPairArray::minimiseStorageOverheads() throw() { keys.minimiseStorageOverheads(); @@ -22363,7 +22377,7 @@ const String AudioDeviceManager::setAudioDeviceSetup (const AudioDeviceSetup& ne const String newOutputDeviceName (numOutputChansNeeded == 0 ? String::empty : newSetup.outputDeviceName); if (currentSetup.inputDeviceName != newInputDeviceName - || currentSetup.inputDeviceName != newOutputDeviceName + || currentSetup.outputDeviceName != newOutputDeviceName || currentAudioDevice == 0) { deleteCurrentDevice(); @@ -22813,12 +22827,18 @@ void AudioDeviceManager::setDefaultMidiOutput (const String& deviceName) { if (defaultMidiOutputName != deviceName) { + if (currentCallback != 0 && currentAudioDevice != 0) + currentCallback->audioDeviceStopped(); + deleteAndZero (defaultMidiOutput); defaultMidiOutputName = deviceName; if (deviceName.isNotEmpty()) defaultMidiOutput = MidiOutput::openDevice (MidiOutput::getDevices().indexOf (deviceName)); + if (currentCallback != 0 && currentAudioDevice != 0) + currentCallback->audioDeviceAboutToStart (currentAudioDevice); + updateXml(); sendChangeMessage (this); } @@ -71675,6 +71695,11 @@ void AlertWindow::lookAndFeelChanged() setDropShadowEnabled ((flags & ComponentPeer::windowHasDropShadow) != 0); } +int AlertWindow::getDesktopWindowStyleFlags() const +{ + return getLookAndFeel().getAlertBoxWindowFlags(); +} + struct AlertWindowInfo { String title, message, button1, button2, button3; @@ -76036,7 +76061,7 @@ void Graphics::strokePath (const Path& path, const PathStrokeType& strokeType, const AffineTransform& transform) const throw() { - if (! state->colour.isTransparent()) + if ((! state->colour.isTransparent()) || state->brush != 0) { Path stroke; strokeType.createStrokedPath (stroke, path, transform); @@ -244183,9 +244208,18 @@ private: return 0; case WM_QUIT: - JUCEApplication::quit(); + if (JUCEApplication::getInstance() != 0) + JUCEApplication::getInstance()->systemRequestedQuit(); return 0; + case WM_QUERYENDSESSION: + if (JUCEApplication::getInstance() != 0) + { + JUCEApplication::getInstance()->systemRequestedQuit(); + return MessageManager::getInstance()->hasStopMessageBeenSent(); + } + return TRUE; + case WM_TRAYNOTIFY: if (component->isCurrentlyBlockedByAnotherModalComponent()) { @@ -267842,6 +267876,88 @@ void AppleRemoteDevice::handleCallbackInternal() // compiled on its own). #if JUCE_INCLUDED_FILE && JUCE_OPENGL +END_JUCE_NAMESPACE + +@interface ThreadSafeNSOpenGLView : NSOpenGLView +{ + CriticalSection* contextLock; + bool needsUpdate; +} + +- (id) initWithFrame: (NSRect) frameRect pixelFormat: (NSOpenGLPixelFormat*) format; +- (bool) makeActive; +- (void) makeInactive; +- (void) reshape; +@end + +@implementation ThreadSafeNSOpenGLView + +- (id) initWithFrame: (NSRect) frameRect + pixelFormat: (NSOpenGLPixelFormat*) format +{ + contextLock = new CriticalSection(); + self = [super initWithFrame: frameRect pixelFormat: format]; + + if (self != nil) + [[NSNotificationCenter defaultCenter] addObserver: self + selector: @selector (_surfaceNeedsUpdate:) + name: NSViewGlobalFrameDidChangeNotification + object: self]; + return self; +} + +- (void) dealloc +{ + [[NSNotificationCenter defaultCenter] removeObserver: self]; + delete contextLock; + [super dealloc]; +} + +- (bool) makeActive +{ + const ScopedLock sl (*contextLock); + + if ([self openGLContext] == 0) + return false; + + [[self openGLContext] makeCurrentContext]; + + if (needsUpdate) + { + [super update]; + needsUpdate = false; + } + + return true; +} + +- (void) makeInactive +{ + const ScopedLock sl (*contextLock); + [NSOpenGLContext clearCurrentContext]; +} + +- (void) _surfaceNeedsUpdate: (NSNotification*) notification +{ + const ScopedLock sl (*contextLock); + needsUpdate = true; +} + +- (void) update +{ + const ScopedLock sl (*contextLock); + needsUpdate = true; +} + +- (void) reshape +{ + const ScopedLock sl (*contextLock); + needsUpdate = true; +} + +@end +BEGIN_JUCE_NAMESPACE + class WindowedGLContext : public OpenGLContext { public: @@ -267857,6 +267973,7 @@ public: int n = 0; attribs[n++] = NSOpenGLPFADoubleBuffer; attribs[n++] = NSOpenGLPFAAccelerated; + attribs[n++] = NSOpenGLPFAMPSafe; // NSOpenGLPFAAccelerated, NSOpenGLPFAMultiScreen, NSOpenGLPFASingleRenderer attribs[n++] = NSOpenGLPFAColorSize; attribs[n++] = (NSOpenGLPixelFormatAttribute) jmax (pixelFormat.redBits, pixelFormat.greenBits, @@ -267874,7 +267991,6 @@ public: pixelFormat.accumulationBufferAlphaBits); // xxx not sure how to do fullSceneAntiAliasingNumSamples.. - attribs[n++] = NSOpenGLPFASampleBuffers; attribs[n++] = (NSOpenGLPixelFormatAttribute) 1; attribs[n++] = NSOpenGLPFAClosestPolicy; @@ -267884,21 +268000,13 @@ public: NSOpenGLPixelFormat* format = [[NSOpenGLPixelFormat alloc] initWithAttributes: attribs]; - NSOpenGLView* view - = [[NSOpenGLView alloc] initWithFrame: NSMakeRect (0, 0, 100.0f, 100.0f) - pixelFormat: format]; + view = [[ThreadSafeNSOpenGLView alloc] initWithFrame: NSMakeRect (0, 0, 100.0f, 100.0f) + pixelFormat: format]; - if (sharedContext != 0) - { - renderContext = [[NSOpenGLContext alloc] initWithFormat: format - shareContext: sharedContext]; - [view setOpenGLContext: renderContext]; - [renderContext setView: view]; - } - else - { - renderContext = [view openGLContext]; - } + renderContext = [[[NSOpenGLContext alloc] initWithFormat: format + shareContext: sharedContext] autorelease]; + [view setOpenGLContext: renderContext]; + [renderContext setView: view]; [format release]; @@ -267915,15 +268023,13 @@ public: bool makeActive() const throw() { jassert (renderContext != 0); - [renderContext makeCurrentContext]; - return renderContext != 0; + [view makeActive]; + return isActive(); } bool makeInactive() const throw() { - if (! isActive()) - [NSOpenGLContext clearCurrentContext]; - + [view makeInactive]; return true; } @@ -267941,7 +268047,6 @@ public: void swapBuffers() { - glFlush(); [renderContext flushBuffer]; } @@ -267979,6 +268084,7 @@ public: juce_UseDebuggingNewOperator NSOpenGLContext* renderContext; + ThreadSafeNSOpenGLView* view; private: OpenGLPixelFormat pixelFormat; diff --git a/juce_amalgamated.h b/juce_amalgamated.h index e789e7a876..1cf3ce1229 100644 --- a/juce_amalgamated.h +++ b/juce_amalgamated.h @@ -2783,6 +2783,7 @@ protected: numAllocated (0), granularity (granularity_) { + jassert (granularity > 0); } /** Destructor. */ @@ -8102,6 +8103,10 @@ public: */ void remove (const int index) throw(); + /** Indicates whether to use a case-insensitive search when looking up a key string. + */ + void setIgnoresCase (const bool shouldIgnoreCase) throw(); + /** Reduces the amount of storage being used by the array. Arrays typically allocate slightly more storage than they need, and after @@ -11214,23 +11219,26 @@ public: { jassert (numValuesToRemove >= 0); - if (numValuesToRemove != 0 + if (numValuesToRemove >= 0 && firstValue < values.getLast()) { const bool onAtStart = contains (firstValue - 1); - Type lastValue = firstValue + numValuesToRemove; - - if (lastValue < firstValue) // possible if the signed arithmetic wraps around - lastValue = values.getLast(); - + const Type lastValue = firstValue + jmin (numValuesToRemove, values.getLast() - firstValue); const bool onAtEnd = contains (lastValue); for (int i = values.size(); --i >= 0;) { - if (values.getUnchecked(i) >= firstValue - && values.getUnchecked(i) <= lastValue) + if (values.getUnchecked(i) <= lastValue) { - values.remove (i); + while (values.getUnchecked(i) >= firstValue) + { + values.remove (i); + + if (--i < 0) + break; + } + + break; } } @@ -13693,6 +13701,11 @@ public: */ const StringArray getCountryCodes() const throw() { return countryCodes; } + /** Indicates whether to use a case-insensitive search when looking up a string. + This defaults to true. + */ + void setIgnoresCase (const bool shouldIgnoreCase) throw(); + juce_UseDebuggingNewOperator private: @@ -50713,6 +50726,8 @@ protected: void lookAndFeelChanged(); /** @internal */ void userTriedToCloseWindow(); + /** @internal */ + int getDesktopWindowStyleFlags() const; private: String text; diff --git a/src/juce_appframework/audio/devices/juce_AudioDeviceManager.cpp b/src/juce_appframework/audio/devices/juce_AudioDeviceManager.cpp index 6aedfceaec..2047c62edc 100644 --- a/src/juce_appframework/audio/devices/juce_AudioDeviceManager.cpp +++ b/src/juce_appframework/audio/devices/juce_AudioDeviceManager.cpp @@ -379,7 +379,7 @@ const String AudioDeviceManager::setAudioDeviceSetup (const AudioDeviceSetup& ne const String newOutputDeviceName (numOutputChansNeeded == 0 ? String::empty : newSetup.outputDeviceName); if (currentSetup.inputDeviceName != newInputDeviceName - || currentSetup.inputDeviceName != newOutputDeviceName + || currentSetup.outputDeviceName != newOutputDeviceName || currentAudioDevice == 0) { deleteCurrentDevice(); @@ -832,12 +832,18 @@ void AudioDeviceManager::setDefaultMidiOutput (const String& deviceName) { if (defaultMidiOutputName != deviceName) { + if (currentCallback != 0 && currentAudioDevice != 0) + currentCallback->audioDeviceStopped(); + deleteAndZero (defaultMidiOutput); defaultMidiOutputName = deviceName; if (deviceName.isNotEmpty()) defaultMidiOutput = MidiOutput::openDevice (MidiOutput::getDevices().indexOf (deviceName)); + if (currentCallback != 0 && currentAudioDevice != 0) + currentCallback->audioDeviceAboutToStart (currentAudioDevice); + updateXml(); sendChangeMessage (this); } diff --git a/src/juce_appframework/gui/components/windows/juce_AlertWindow.cpp b/src/juce_appframework/gui/components/windows/juce_AlertWindow.cpp index 25dcae39fb..b0b14af060 100644 --- a/src/juce_appframework/gui/components/windows/juce_AlertWindow.cpp +++ b/src/juce_appframework/gui/components/windows/juce_AlertWindow.cpp @@ -591,6 +591,11 @@ void AlertWindow::lookAndFeelChanged() setDropShadowEnabled ((flags & ComponentPeer::windowHasDropShadow) != 0); } +int AlertWindow::getDesktopWindowStyleFlags() const +{ + return getLookAndFeel().getAlertBoxWindowFlags(); +} + //============================================================================== struct AlertWindowInfo { diff --git a/src/juce_appframework/gui/components/windows/juce_AlertWindow.h b/src/juce_appframework/gui/components/windows/juce_AlertWindow.h index 2c04c1da4d..10df1ee1cf 100644 --- a/src/juce_appframework/gui/components/windows/juce_AlertWindow.h +++ b/src/juce_appframework/gui/components/windows/juce_AlertWindow.h @@ -339,6 +339,8 @@ protected: void lookAndFeelChanged(); /** @internal */ void userTriedToCloseWindow(); + /** @internal */ + int getDesktopWindowStyleFlags() const; private: String text; diff --git a/src/juce_appframework/gui/graphics/contexts/juce_Graphics.cpp b/src/juce_appframework/gui/graphics/contexts/juce_Graphics.cpp index 7ea2bd01a1..fc9e06f85e 100644 --- a/src/juce_appframework/gui/graphics/contexts/juce_Graphics.cpp +++ b/src/juce_appframework/gui/graphics/contexts/juce_Graphics.cpp @@ -429,7 +429,7 @@ void Graphics::strokePath (const Path& path, const PathStrokeType& strokeType, const AffineTransform& transform) const throw() { - if (! state->colour.isTransparent()) + if ((! state->colour.isTransparent()) || state->brush != 0) { Path stroke; strokeType.createStrokedPath (stroke, path, transform); diff --git a/src/juce_core/containers/juce_ArrayAllocationBase.h b/src/juce_core/containers/juce_ArrayAllocationBase.h index 3377d947f3..1c84bdbcdc 100644 --- a/src/juce_core/containers/juce_ArrayAllocationBase.h +++ b/src/juce_core/containers/juce_ArrayAllocationBase.h @@ -65,6 +65,7 @@ protected: numAllocated (0), granularity (granularity_) { + jassert (granularity > 0); } /** Destructor. */ diff --git a/src/juce_core/containers/juce_SparseSet.h b/src/juce_core/containers/juce_SparseSet.h index 36936221d2..13806e839a 100644 --- a/src/juce_core/containers/juce_SparseSet.h +++ b/src/juce_core/containers/juce_SparseSet.h @@ -225,23 +225,26 @@ public: { jassert (numValuesToRemove >= 0); - if (numValuesToRemove != 0 + if (numValuesToRemove >= 0 && firstValue < values.getLast()) { const bool onAtStart = contains (firstValue - 1); - Type lastValue = firstValue + numValuesToRemove; - - if (lastValue < firstValue) // possible if the signed arithmetic wraps around - lastValue = values.getLast(); - + const Type lastValue = firstValue + jmin (numValuesToRemove, values.getLast() - firstValue); const bool onAtEnd = contains (lastValue); for (int i = values.size(); --i >= 0;) { - if (values.getUnchecked(i) >= firstValue - && values.getUnchecked(i) <= lastValue) + if (values.getUnchecked(i) <= lastValue) { - values.remove (i); + while (values.getUnchecked(i) >= firstValue) + { + values.remove (i); + + if (--i < 0) + break; + } + + break; } } diff --git a/src/juce_core/io/streams/juce_BufferedInputStream.cpp b/src/juce_core/io/streams/juce_BufferedInputStream.cpp index 77581076c4..260dbaaf01 100644 --- a/src/juce_core/io/streams/juce_BufferedInputStream.cpp +++ b/src/juce_core/io/streams/juce_BufferedInputStream.cpp @@ -153,8 +153,12 @@ int BufferedInputStream::read (void* destBuffer, int maxBytesToRead) destBuffer = (void*) (((char*) destBuffer) + bytesAvailable); } + const int64 oldLastReadPos = lastReadPos; ensureBuffered(); + if (oldLastReadPos == lastReadPos) + break; // if ensureBuffered() failed to read any more data, bail out + if (isExhausted()) break; } diff --git a/src/juce_core/text/juce_LocalisedStrings.cpp b/src/juce_core/text/juce_LocalisedStrings.cpp index e7f7830808..c1d6625f4c 100644 --- a/src/juce_core/text/juce_LocalisedStrings.cpp +++ b/src/juce_core/text/juce_LocalisedStrings.cpp @@ -124,6 +124,11 @@ void LocalisedStrings::loadFromText (const String& fileContents) throw() } } +void LocalisedStrings::setIgnoresCase (const bool shouldIgnoreCase) throw() +{ + translations.setIgnoresCase (shouldIgnoreCase); +} + //============================================================================== static CriticalSection currentMappingsLock; static LocalisedStrings* currentMappings = 0; diff --git a/src/juce_core/text/juce_LocalisedStrings.h b/src/juce_core/text/juce_LocalisedStrings.h index 523c84ee44..a53a25067d 100644 --- a/src/juce_core/text/juce_LocalisedStrings.h +++ b/src/juce_core/text/juce_LocalisedStrings.h @@ -181,6 +181,13 @@ public: */ const StringArray getCountryCodes() const throw() { return countryCodes; } + + //============================================================================== + /** Indicates whether to use a case-insensitive search when looking up a string. + This defaults to true. + */ + void setIgnoresCase (const bool shouldIgnoreCase) throw(); + //============================================================================== juce_UseDebuggingNewOperator diff --git a/src/juce_core/text/juce_StringPairArray.cpp b/src/juce_core/text/juce_StringPairArray.cpp index 29da9fd04a..95987ecb22 100644 --- a/src/juce_core/text/juce_StringPairArray.cpp +++ b/src/juce_core/text/juce_StringPairArray.cpp @@ -130,6 +130,11 @@ void StringPairArray::remove (const int index) throw() values.remove (index); } +void StringPairArray::setIgnoresCase (const bool shouldIgnoreCase) throw() +{ + ignoreCase = shouldIgnoreCase; +} + void StringPairArray::minimiseStorageOverheads() throw() { keys.minimiseStorageOverheads(); diff --git a/src/juce_core/text/juce_StringPairArray.h b/src/juce_core/text/juce_StringPairArray.h index 0293b5e9ac..88beca11ae 100644 --- a/src/juce_core/text/juce_StringPairArray.h +++ b/src/juce_core/text/juce_StringPairArray.h @@ -138,6 +138,11 @@ public: */ void remove (const int index) throw(); + //============================================================================== + /** Indicates whether to use a case-insensitive search when looking up a key string. + */ + void setIgnoresCase (const bool shouldIgnoreCase) throw(); + //============================================================================== /** Reduces the amount of storage being used by the array.