1
0
Fork 0
mirror of https://github.com/juce-framework/JUCE.git synced 2026-01-13 00:04:19 +00:00

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.

This commit is contained in:
jules 2009-02-13 13:08:34 +00:00
parent 68dba8605d
commit bf501e1fda
16 changed files with 332 additions and 67 deletions

View file

@ -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];
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];
@ -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;

View file

@ -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())

View file

@ -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;

View file

@ -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;

View file

@ -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;

View file

@ -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);
}

View file

@ -591,6 +591,11 @@ void AlertWindow::lookAndFeelChanged()
setDropShadowEnabled ((flags & ComponentPeer::windowHasDropShadow) != 0);
}
int AlertWindow::getDesktopWindowStyleFlags() const
{
return getLookAndFeel().getAlertBoxWindowFlags();
}
//==============================================================================
struct AlertWindowInfo
{

View file

@ -339,6 +339,8 @@ protected:
void lookAndFeelChanged();
/** @internal */
void userTriedToCloseWindow();
/** @internal */
int getDesktopWindowStyleFlags() const;
private:
String text;

View file

@ -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);

View file

@ -65,6 +65,7 @@ protected:
numAllocated (0),
granularity (granularity_)
{
jassert (granularity > 0);
}
/** Destructor. */

View file

@ -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;
}
}

View file

@ -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;
}

View file

@ -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;

View file

@ -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

View file

@ -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();

View file

@ -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.