Browse Source

Fix for String copying thread-safety, and some minor compile issues.

tags/2021-05-28
Julian Storer 15 years ago
parent
commit
0d278483e4
19 changed files with 287 additions and 266 deletions
  1. +1
    -1
      juce.h
  2. +97
    -133
      juce_amalgamated.cpp
  3. +31
    -2
      juce_amalgamated.h
  4. +13
    -17
      src/audio/devices/juce_AudioDeviceManager.cpp
  5. +1
    -4
      src/containers/juce_PropertySet.cpp
  6. +15
    -0
      src/core/juce_Atomic.h
  7. +50
    -0
      src/core/juce_Initialisation.h
  8. +13
    -15
      src/gui/components/controls/juce_TableHeaderComponent.cpp
  9. +2
    -6
      src/gui/components/keyboard/juce_KeyPressMappingSet.cpp
  10. +3
    -4
      src/gui/components/properties/juce_PropertyPanel.cpp
  11. +1
    -1
      src/native/mac/juce_iphone_MiscUtilities.mm
  12. +3
    -3
      src/native/mac/juce_mac_FileChooser.mm
  13. +1
    -1
      src/native/mac/juce_mac_Fonts.mm
  14. +1
    -1
      src/native/windows/juce_win32_PlatformUtils.cpp
  15. +2
    -0
      src/native/windows/juce_win32_Threads.cpp
  16. +35
    -17
      src/native/windows/juce_win32_WASAPI.cpp
  17. +17
    -57
      src/text/juce_String.cpp
  18. +0
    -1
      src/text/juce_String.h
  19. +1
    -3
      src/utilities/juce_PropertiesFile.cpp

+ 1
- 1
juce.h View File

@@ -80,7 +80,7 @@ END_JUCE_NAMESPACE
of 3rd party header files, you may need to use the juce_WithoutMacros.h file - see of 3rd party header files, you may need to use the juce_WithoutMacros.h file - see
the comments in that file for more information. the comments in that file for more information.
*/ */
#if JUCE_MAC && ! JUCE_DONT_DEFINE_MACROS
#if (JUCE_MAC || JUCE_IPHONE) && ! JUCE_DONT_DEFINE_MACROS
#define Component JUCE_NAMESPACE::Component #define Component JUCE_NAMESPACE::Component
#define MemoryBlock JUCE_NAMESPACE::MemoryBlock #define MemoryBlock JUCE_NAMESPACE::MemoryBlock
#define Point JUCE_NAMESPACE::Point #define Point JUCE_NAMESPACE::Point


+ 97
- 133
juce_amalgamated.cpp View File

@@ -3459,12 +3459,9 @@ XmlElement* PropertySet::createXml (const String& nodeName) const throw()


for (int i = 0; i < properties.getAllKeys().size(); ++i) for (int i = 0; i < properties.getAllKeys().size(); ++i)
{ {
XmlElement* const e = new XmlElement (T("VALUE"));

XmlElement* const e = xml->createNewChildElement ("VALUE");
e->setAttribute (T("name"), properties.getAllKeys()[i]); e->setAttribute (T("name"), properties.getAllKeys()[i]);
e->setAttribute (T("val"), properties.getAllValues()[i]); e->setAttribute (T("val"), properties.getAllValues()[i]);

xml->addChildElement (e);
} }


return xml; return xml;
@@ -10414,12 +10411,6 @@ void juce_initialiseStrings()
decimalPoint = String::fromUTF8 ((const uint8*) localeconv()->decimal_point) [0]; decimalPoint = String::fromUTF8 ((const uint8*) localeconv()->decimal_point) [0];
} }


void String::deleteInternal() throw()
{
if (Atomic::decrementAndReturn (text->refCount) == 0)
juce_free (text);
}

void String::createInternal (const int numChars) throw() void String::createInternal (const int numChars) throw()
{ {
jassert (numChars > 0); jassert (numChars > 0);
@@ -10943,32 +10934,7 @@ int64 String::hashCode64() const throw()


const String& String::operator= (const tchar* const otherText) throw() const String& String::operator= (const tchar* const otherText) throw()
{ {
if (otherText != 0 && *otherText != 0)
{
const int otherLen = CharacterFunctions::length (otherText);

if (otherLen > 0)
{
// avoid resizing the memory block if the string is
// shrinking..
if (text->refCount > 1
|| otherLen > text->allocatedNumChars
|| otherLen <= (text->allocatedNumChars >> 1))
{
deleteInternal();
createInternal (otherLen);
}

memcpy (text->text, otherText, (otherLen + 1) * sizeof (tchar));

return *this;
}
}

deleteInternal();
text = &emptyString;
emptyString.refCount = safeEmptyStringRefCount;

operator= (String (otherText));
return *this; return *this;
} }


@@ -10976,12 +10942,14 @@ const String& String::operator= (const String& other) throw()
{ {
if (this != &other) if (this != &other)
{ {
Atomic::increment (other.text->refCount);
InternalRefCountedStringHolder* newText = other.text;
Atomic::increment (newText->refCount);


if (Atomic::decrementAndReturn (text->refCount) == 0)
juce_free (text);
InternalRefCountedStringHolder* oldText
= (InternalRefCountedStringHolder*) Atomic::swapPointers ((void* volatile*) &text, newText);


text = other.text;
if (Atomic::decrementAndReturn (oldText->refCount) == 0)
juce_free (oldText);
} }


return *this; return *this;
@@ -11625,47 +11593,36 @@ const String String::formatted (const tchar* const pf, ...) throw()


void String::vprintf (const tchar* const pf, va_list& args) throw() void String::vprintf (const tchar* const pf, va_list& args) throw()
{ {
tchar stackBuf [256];
unsigned int bufSize = 256;
tchar* buf = stackBuf;

deleteInternal();
int bufferSize = 256;
String result (bufferSize, 0);


do do
{ {
#if JUCE_LINUX && JUCE_64BIT #if JUCE_LINUX && JUCE_64BIT
va_list tempArgs; va_list tempArgs;
va_copy (tempArgs, args); va_copy (tempArgs, args);
const int num = CharacterFunctions::vprintf (buf, bufSize - 1, pf, tempArgs);
const int num = CharacterFunctions::vprintf (result.text->text, bufferSize - 1, pf, tempArgs);
va_end (tempArgs); va_end (tempArgs);
#else #else
const int num = CharacterFunctions::vprintf (buf, bufSize - 1, pf, args);
const int num = CharacterFunctions::vprintf (result.text->text, bufferSize - 1, pf, args);
#endif #endif


if (num > 0) if (num > 0)
{ {
createInternal (num);
memcpy (text->text, buf, (num + 1) * sizeof (tchar));
*this = result;
break; break;
} }
else if (num == 0) else if (num == 0)
{ {
text = &emptyString;
emptyString.refCount = safeEmptyStringRefCount;
*this = String::empty;
break; break;
} }


if (buf != stackBuf)
juce_free (buf);

bufSize += 256;
buf = (tchar*) juce_malloc (bufSize * sizeof (tchar));
bufferSize += 256;
result.preallocateStorage (bufferSize);
} }
while (bufSize < 65536); // this is a sanity check to avoid situations where vprintf repeatedly
// returns -1 because of an error rather than because it needs more space.

if (buf != stackBuf)
juce_free (buf);
while (bufferSize < 65536); // this is a sanity check to avoid situations where vprintf repeatedly
// returns -1 because of an error rather than because it needs more space.
} }


const String String::repeatedString (const tchar* const stringToRepeat, const String String::repeatedString (const tchar* const stringToRepeat,
@@ -18196,7 +18153,7 @@ bool PropertiesFile::save()


for (int i = 0; i < getAllProperties().size(); ++i) for (int i = 0; i < getAllProperties().size(); ++i)
{ {
XmlElement* const e = new XmlElement (propertyTagName);
XmlElement* const e = doc.createNewChildElement (propertyTagName);
e->setAttribute (T("name"), getAllProperties().getAllKeys() [i]); e->setAttribute (T("name"), getAllProperties().getAllKeys() [i]);


// if the value seems to contain xml, store it as such.. // if the value seems to contain xml, store it as such..
@@ -18207,8 +18164,6 @@ bool PropertiesFile::save()
e->addChildElement (childElement); e->addChildElement (childElement);
else else
e->setAttribute (T("val"), getAllProperties().getAllValues() [i]); e->setAttribute (T("val"), getAllProperties().getAllValues() [i]);

doc.addChildElement (e);
} }


return doc.writeToFile (file, String::empty); return doc.writeToFile (file, String::empty);
@@ -24556,32 +24511,30 @@ void AudioDeviceManager::restartLastAudioDevice()


void AudioDeviceManager::updateXml() void AudioDeviceManager::updateXml()
{ {
lastExplicitSettings = new XmlElement (T("DEVICESETUP"));
lastExplicitSettings = new XmlElement ("DEVICESETUP");


lastExplicitSettings->setAttribute (T("deviceType"), currentDeviceType);
lastExplicitSettings->setAttribute (T("audioOutputDeviceName"), currentSetup.outputDeviceName);
lastExplicitSettings->setAttribute (T("audioInputDeviceName"), currentSetup.inputDeviceName);
lastExplicitSettings->setAttribute ("deviceType", currentDeviceType);
lastExplicitSettings->setAttribute ("audioOutputDeviceName", currentSetup.outputDeviceName);
lastExplicitSettings->setAttribute ("audioInputDeviceName", currentSetup.inputDeviceName);


if (currentAudioDevice != 0) if (currentAudioDevice != 0)
{ {
lastExplicitSettings->setAttribute (T("audioDeviceRate"), currentAudioDevice->getCurrentSampleRate());
lastExplicitSettings->setAttribute ("audioDeviceRate", currentAudioDevice->getCurrentSampleRate());


if (currentAudioDevice->getDefaultBufferSize() != currentAudioDevice->getCurrentBufferSizeSamples()) if (currentAudioDevice->getDefaultBufferSize() != currentAudioDevice->getCurrentBufferSizeSamples())
lastExplicitSettings->setAttribute (T("audioDeviceBufferSize"), currentAudioDevice->getCurrentBufferSizeSamples());
lastExplicitSettings->setAttribute ("audioDeviceBufferSize", currentAudioDevice->getCurrentBufferSizeSamples());


if (! currentSetup.useDefaultInputChannels) if (! currentSetup.useDefaultInputChannels)
lastExplicitSettings->setAttribute (T("audioDeviceInChans"), currentSetup.inputChannels.toString (2));
lastExplicitSettings->setAttribute ("audioDeviceInChans", currentSetup.inputChannels.toString (2));


if (! currentSetup.useDefaultOutputChannels) if (! currentSetup.useDefaultOutputChannels)
lastExplicitSettings->setAttribute (T("audioDeviceOutChans"), currentSetup.outputChannels.toString (2));
lastExplicitSettings->setAttribute ("audioDeviceOutChans", currentSetup.outputChannels.toString (2));
} }


for (int i = 0; i < enabledMidiInputs.size(); ++i) for (int i = 0; i < enabledMidiInputs.size(); ++i)
{ {
XmlElement* const m = new XmlElement (T("MIDIINPUT"));
m->setAttribute (T("name"), enabledMidiInputs[i]->getName());

lastExplicitSettings->addChildElement (m);
XmlElement* const m = lastExplicitSettings->createNewChildElement ("MIDIINPUT");
m->setAttribute ("name", enabledMidiInputs[i]->getName());
} }


if (midiInsFromXml.size() > 0) if (midiInsFromXml.size() > 0)
@@ -24594,16 +24547,14 @@ void AudioDeviceManager::updateXml()
{ {
if (! availableMidiDevices.contains (midiInsFromXml[i], true)) if (! availableMidiDevices.contains (midiInsFromXml[i], true))
{ {
XmlElement* const m = new XmlElement (T("MIDIINPUT"));
m->setAttribute (T("name"), midiInsFromXml[i]);

lastExplicitSettings->addChildElement (m);
XmlElement* const m = lastExplicitSettings->createNewChildElement ("MIDIINPUT");
m->setAttribute ("name", midiInsFromXml[i]);
} }
} }
} }


if (defaultMidiOutputName.isNotEmpty()) if (defaultMidiOutputName.isNotEmpty())
lastExplicitSettings->setAttribute (T("defaultMidiOutput"), defaultMidiOutputName);
lastExplicitSettings->setAttribute ("defaultMidiOutput", defaultMidiOutputName);
} }


void AudioDeviceManager::addAudioCallback (AudioIODeviceCallback* newCallback) void AudioDeviceManager::addAudioCallback (AudioIODeviceCallback* newCallback)
@@ -50375,21 +50326,19 @@ const String TableHeaderComponent::toString() const
{ {
String s; String s;


XmlElement doc (T("TABLELAYOUT"));
XmlElement doc ("TABLELAYOUT");


doc.setAttribute (T("sortedCol"), getSortColumnId());
doc.setAttribute (T("sortForwards"), isSortedForwards());
doc.setAttribute ("sortedCol", getSortColumnId());
doc.setAttribute ("sortForwards", isSortedForwards());


for (int i = 0; i < columns.size(); ++i) for (int i = 0; i < columns.size(); ++i)
{ {
const ColumnInfo* const ci = columns.getUnchecked (i); const ColumnInfo* const ci = columns.getUnchecked (i);


XmlElement* const e = new XmlElement (T("COLUMN"));
doc.addChildElement (e);

e->setAttribute (T("id"), ci->id);
e->setAttribute (T("visible"), ci->isVisible());
e->setAttribute (T("width"), ci->width);
XmlElement* const e = doc.createNewChildElement ("COLUMN");
e->setAttribute ("id", ci->id);
e->setAttribute ("visible", ci->isVisible());
e->setAttribute ("width", ci->width);
} }


return doc.createDocument (String::empty, true, false); return doc.createDocument (String::empty, true, false);
@@ -50402,19 +50351,19 @@ void TableHeaderComponent::restoreFromString (const String& storedVersion)


int index = 0; int index = 0;


if (storedXml != 0 && storedXml->hasTagName (T("TABLELAYOUT")))
if (storedXml != 0 && storedXml->hasTagName ("TABLELAYOUT"))
{ {
forEachXmlChildElement (*storedXml, col) forEachXmlChildElement (*storedXml, col)
{ {
const int tabId = col->getIntAttribute (T("id"));
const int tabId = col->getIntAttribute ("id");


ColumnInfo* const ci = getInfoForId (tabId); ColumnInfo* const ci = getInfoForId (tabId);


if (ci != 0) if (ci != 0)
{ {
columns.move (columns.indexOf (ci), index); columns.move (columns.indexOf (ci), index);
ci->width = col->getIntAttribute (T("width"));
setColumnVisible (tabId, col->getBoolAttribute (T("visible")));
ci->width = col->getIntAttribute ("width");
setColumnVisible (tabId, col->getBoolAttribute ("visible"));
} }


++index; ++index;
@@ -50423,8 +50372,8 @@ void TableHeaderComponent::restoreFromString (const String& storedVersion)
columnsResized = true; columnsResized = true;
sendColumnsChanged(); sendColumnsChanged();


setSortColumnId (storedXml->getIntAttribute (T("sortedCol")),
storedXml->getBoolAttribute (T("sortForwards"), true));
setSortColumnId (storedXml->getIntAttribute ("sortedCol"),
storedXml->getBoolAttribute ("sortForwards", true));
} }
} }


@@ -60336,13 +60285,11 @@ XmlElement* KeyPressMappingSet::createXml (const bool saveDifferencesFromDefault
if (defaultSet == 0 if (defaultSet == 0
|| ! defaultSet->containsMapping (cm->commandID, cm->keypresses.getReference (j))) || ! defaultSet->containsMapping (cm->commandID, cm->keypresses.getReference (j)))
{ {
XmlElement* const map = new XmlElement (T("MAPPING"));
XmlElement* const map = doc->createNewChildElement ("MAPPING");


map->setAttribute (T("commandId"), String::toHexString ((int) cm->commandID)); map->setAttribute (T("commandId"), String::toHexString ((int) cm->commandID));
map->setAttribute (T("description"), commandManager->getDescriptionOfCommand (cm->commandID)); map->setAttribute (T("description"), commandManager->getDescriptionOfCommand (cm->commandID));
map->setAttribute (T("key"), cm->keypresses.getReference (j).getTextDescription()); map->setAttribute (T("key"), cm->keypresses.getReference (j).getTextDescription());

doc->addChildElement (map);
} }
} }
} }
@@ -60357,13 +60304,11 @@ XmlElement* KeyPressMappingSet::createXml (const bool saveDifferencesFromDefault
{ {
if (! containsMapping (cm->commandID, cm->keypresses.getReference (j))) if (! containsMapping (cm->commandID, cm->keypresses.getReference (j)))
{ {
XmlElement* const map = new XmlElement (T("UNMAPPING"));
XmlElement* const map = doc->createNewChildElement ("UNMAPPING");


map->setAttribute (T("commandId"), String::toHexString ((int) cm->commandID)); map->setAttribute (T("commandId"), String::toHexString ((int) cm->commandID));
map->setAttribute (T("description"), commandManager->getDescriptionOfCommand (cm->commandID)); map->setAttribute (T("description"), commandManager->getDescriptionOfCommand (cm->commandID));
map->setAttribute (T("key"), cm->keypresses.getReference (j).getTextDescription()); map->setAttribute (T("key"), cm->keypresses.getReference (j).getTextDescription());

doc->addChildElement (map);
} }
} }
} }
@@ -71423,10 +71368,9 @@ XmlElement* PropertyPanel::getOpennessState() const
{ {
if (sections[i].isNotEmpty()) if (sections[i].isNotEmpty())
{ {
XmlElement* const e = new XmlElement (T("SECTION"));
e->setAttribute (T("name"), sections[i]);
e->setAttribute (T("open"), isSectionOpen (i) ? 1 : 0);
xml->addChildElement (e);
XmlElement* const e = xml->createNewChildElement ("SECTION");
e->setAttribute ("name", sections[i]);
e->setAttribute ("open", isSectionOpen (i) ? 1 : 0);
} }
} }


@@ -212236,6 +212180,8 @@ int32 Atomic::compareAndExchange (int32& destination, int32 newValue, int32 oldV
{ return InterlockedCompareExchange (reinterpret_cast <volatile long*> (&destination), newValue, oldValue); } { return InterlockedCompareExchange (reinterpret_cast <volatile long*> (&destination), newValue, oldValue); }
#endif #endif


void* Atomic::swapPointers (void* volatile* value1, void* volatile value2) { return InterlockedExchangePointer (value1, value2); }

CriticalSection::CriticalSection() throw() CriticalSection::CriticalSection() throw()
{ {
// (just to check the MS haven't changed this structure and broken things...) // (just to check the MS haven't changed this structure and broken things...)
@@ -213949,7 +213895,7 @@ static HKEY findKeyForPath (String name,


if (createForWriting) if (createForWriting)
{ {
if (RegCreateKeyEx (rootKey, name, 0, L"", REG_OPTION_NON_VOLATILE,
if (RegCreateKeyEx (rootKey, name, 0, 0, REG_OPTION_NON_VOLATILE,
(KEY_WRITE | KEY_QUERY_VALUE), 0, &key, &result) == ERROR_SUCCESS) (KEY_WRITE | KEY_QUERY_VALUE), 0, &key, &result) == ERROR_SUCCESS)
return key; return key;
} }
@@ -226510,7 +226456,7 @@ static void wasapi_copyWavFormat (WAVEFORMATEXTENSIBLE& dest, const WAVEFORMATEX
class WASAPIDeviceBase class WASAPIDeviceBase
{ {
public: public:
WASAPIDeviceBase (const ComSmartPtr <IMMDevice>& device_)
WASAPIDeviceBase (const ComSmartPtr <IMMDevice>& device_, const bool useExclusiveMode_)
: device (device_), : device (device_),
sampleRate (0), sampleRate (0),
numChannels (0), numChannels (0),
@@ -226518,7 +226464,8 @@ public:
defaultSampleRate (0), defaultSampleRate (0),
minBufferSize (0), minBufferSize (0),
defaultBufferSize (0), defaultBufferSize (0),
latencySamples (0)
latencySamples (0),
useExclusiveMode (useExclusiveMode_)
{ {
clientEvent = CreateEvent (0, false, false, _T("JuceWASAPI")); clientEvent = CreateEvent (0, false, false, _T("JuceWASAPI"));


@@ -226555,7 +226502,8 @@ public:


format.Format.nSamplesPerSec = roundDoubleToInt (ratesToTest[i]); format.Format.nSamplesPerSec = roundDoubleToInt (ratesToTest[i]);


if (SUCCEEDED (tempClient->IsFormatSupported (AUDCLNT_SHAREMODE_SHARED, (WAVEFORMATEX*) &format, 0)))
if (SUCCEEDED (tempClient->IsFormatSupported (useExclusiveMode ? AUDCLNT_SHAREMODE_EXCLUSIVE : AUDCLNT_SHAREMODE_SHARED,
(WAVEFORMATEX*) &format, 0)))
if (! rates.contains (ratesToTest[i])) if (! rates.contains (ratesToTest[i]))
rates.addSorted (comparator, ratesToTest[i]); rates.addSorted (comparator, ratesToTest[i]);
} }
@@ -226616,6 +226564,7 @@ public:
double sampleRate, defaultSampleRate; double sampleRate, defaultSampleRate;
int numChannels, actualNumChannels; int numChannels, actualNumChannels;
int minBufferSize, defaultBufferSize, latencySamples; int minBufferSize, defaultBufferSize, latencySamples;
const bool useExclusiveMode;
Array <double> rates; Array <double> rates;
HANDLE clientEvent; HANDLE clientEvent;
BitArray channels; BitArray channels;
@@ -226673,7 +226622,8 @@ private:


WAVEFORMATEXTENSIBLE* nearestFormat = 0; WAVEFORMATEXTENSIBLE* nearestFormat = 0;


HRESULT hr = client->IsFormatSupported (AUDCLNT_SHAREMODE_SHARED, (WAVEFORMATEX*) &format, (WAVEFORMATEX**) &nearestFormat);
HRESULT hr = client->IsFormatSupported (useExclusiveMode ? AUDCLNT_SHAREMODE_EXCLUSIVE : AUDCLNT_SHAREMODE_SHARED,
(WAVEFORMATEX*) &format, useExclusiveMode ? 0 : (WAVEFORMATEX**) &nearestFormat);
logFailure (hr); logFailure (hr);


if (hr == S_FALSE && format.Format.nSamplesPerSec == nearestFormat->Format.nSamplesPerSec) if (hr == S_FALSE && format.Format.nSamplesPerSec == nearestFormat->Format.nSamplesPerSec)
@@ -226684,10 +226634,15 @@ private:


CoTaskMemFree (nearestFormat); CoTaskMemFree (nearestFormat);


REFERENCE_TIME defaultPeriod = 0, minPeriod = 0;
if (useExclusiveMode)
OK (client->GetDevicePeriod (&defaultPeriod, &minPeriod));

GUID session; GUID session;
if (hr == S_OK if (hr == S_OK
&& OK (client->Initialize (AUDCLNT_SHAREMODE_SHARED, AUDCLNT_STREAMFLAGS_EVENTCALLBACK,
0, 0, (WAVEFORMATEX*) &format, &session)))
&& OK (client->Initialize (useExclusiveMode ? AUDCLNT_SHAREMODE_EXCLUSIVE : AUDCLNT_SHAREMODE_SHARED,
AUDCLNT_STREAMFLAGS_EVENTCALLBACK,
defaultPeriod, defaultPeriod, (WAVEFORMATEX*) &format, &session)))
{ {
actualNumChannels = format.Format.nChannels; actualNumChannels = format.Format.nChannels;
const bool isFloat = format.Format.wFormatTag == WAVE_FORMAT_EXTENSIBLE && format.SubFormat == KSDATAFORMAT_SUBTYPE_IEEE_FLOAT; const bool isFloat = format.Format.wFormatTag == WAVE_FORMAT_EXTENSIBLE && format.SubFormat == KSDATAFORMAT_SUBTYPE_IEEE_FLOAT;
@@ -226706,8 +226661,8 @@ private:
class WASAPIInputDevice : public WASAPIDeviceBase class WASAPIInputDevice : public WASAPIDeviceBase
{ {
public: public:
WASAPIInputDevice (const ComSmartPtr <IMMDevice>& device_)
: WASAPIDeviceBase (device_),
WASAPIInputDevice (const ComSmartPtr <IMMDevice>& device_, const bool useExclusiveMode_)
: WASAPIDeviceBase (device_, useExclusiveMode_),
reservoir (1, 1) reservoir (1, 1)
{ {
} }
@@ -226851,8 +226806,8 @@ public:
class WASAPIOutputDevice : public WASAPIDeviceBase class WASAPIOutputDevice : public WASAPIDeviceBase
{ {
public: public:
WASAPIOutputDevice (const ComSmartPtr <IMMDevice>& device_)
: WASAPIDeviceBase (device_)
WASAPIOutputDevice (const ComSmartPtr <IMMDevice>& device_, const bool useExclusiveMode_)
: WASAPIDeviceBase (device_, useExclusiveMode_)
{ {
} }


@@ -226886,7 +226841,8 @@ public:
if (! OK (client->GetCurrentPadding (&padding))) if (! OK (client->GetCurrentPadding (&padding)))
return; return;


const int samplesToDo = jmin ((int) (actualBufferSize - padding), bufferSize);
int samplesToDo = useExclusiveMode ? bufferSize
: jmin ((int) (actualBufferSize - padding), bufferSize);


if (samplesToDo <= 0) if (samplesToDo <= 0)
{ {
@@ -226944,7 +226900,8 @@ class WASAPIAudioIODevice : public AudioIODevice,
public: public:
WASAPIAudioIODevice (const String& deviceName, WASAPIAudioIODevice (const String& deviceName,
const String& outputDeviceId_, const String& outputDeviceId_,
const String& inputDeviceId_)
const String& inputDeviceId_,
const bool useExclusiveMode_)
: AudioIODevice (deviceName, "Windows Audio"), : AudioIODevice (deviceName, "Windows Audio"),
Thread ("Juce WASAPI"), Thread ("Juce WASAPI"),
isOpen_ (false), isOpen_ (false),
@@ -226953,6 +226910,7 @@ public:
outputDeviceId (outputDeviceId_), outputDeviceId (outputDeviceId_),
inputDevice (0), inputDevice (0),
inputDeviceId (inputDeviceId_), inputDeviceId (inputDeviceId_),
useExclusiveMode (useExclusiveMode_),
currentBufferSizeSamples (0), currentBufferSizeSamples (0),
currentSampleRate (0), currentSampleRate (0),
callback (0) callback (0)
@@ -227205,8 +227163,8 @@ public:


while (! threadShouldExit()) while (! threadShouldExit())
{ {
const DWORD result = WaitForMultipleObjects (numEvents, events, true, 1000);
const DWORD result = useExclusiveMode ? WaitForSingleObject (inputDevice->clientEvent, 1000)
: WaitForMultipleObjects (numEvents, events, true, 1000);
if (result == WAIT_TIMEOUT) if (result == WAIT_TIMEOUT)
continue; continue;


@@ -227238,6 +227196,9 @@ public:
} }
} }


if (useExclusiveMode && WaitForSingleObject (outputDevice->clientEvent, 1000) == WAIT_TIMEOUT)
continue;

if (outputDevice != 0) if (outputDevice != 0)
outputDevice->copyBuffers ((const float**) outputBuffers, numOutputBuffers, bufferSize, *this); outputDevice->copyBuffers ((const float**) outputBuffers, numOutputBuffers, bufferSize, *this);
} }
@@ -227252,6 +227213,7 @@ private:
// Device stats... // Device stats...
WASAPIInputDevice* inputDevice; WASAPIInputDevice* inputDevice;
WASAPIOutputDevice* outputDevice; WASAPIOutputDevice* outputDevice;
const bool useExclusiveMode;
double defaultSampleRate; double defaultSampleRate;
int minBufferSize, defaultBufferSize; int minBufferSize, defaultBufferSize;
int latencyIn, latencyOut; int latencyIn, latencyOut;
@@ -227293,9 +227255,9 @@ private:
const EDataFlow flow = wasapi_getDataFlow (device); const EDataFlow flow = wasapi_getDataFlow (device);


if (deviceId == inputDeviceId && flow == eCapture) if (deviceId == inputDeviceId && flow == eCapture)
inputDevice = new WASAPIInputDevice (device);
inputDevice = new WASAPIInputDevice (device, useExclusiveMode);
else if (deviceId == outputDeviceId && flow == eRender) else if (deviceId == outputDeviceId && flow == eRender)
outputDevice = new WASAPIOutputDevice (device);
outputDevice = new WASAPIOutputDevice (device, useExclusiveMode);
} }


return (outputDeviceId.isEmpty() || (outputDevice != 0 && outputDevice->isOk())) return (outputDeviceId.isEmpty() || (outputDevice != 0 && outputDevice->isOk()))
@@ -227421,6 +227383,7 @@ public:
{ {
jassert (hasScanned); // need to call scanForDevices() before doing this jassert (hasScanned); // need to call scanForDevices() before doing this


const bool useExclusiveMode = false;
WASAPIAudioIODevice* d = 0; WASAPIAudioIODevice* d = 0;


const int outputIndex = outputDeviceNames.indexOf (outputDeviceName); const int outputIndex = outputDeviceNames.indexOf (outputDeviceName);
@@ -227431,7 +227394,8 @@ public:
d = new WASAPIAudioIODevice (outputDeviceName.isNotEmpty() ? outputDeviceName d = new WASAPIAudioIODevice (outputDeviceName.isNotEmpty() ? outputDeviceName
: inputDeviceName, : inputDeviceName,
outputDeviceIds [outputIndex], outputDeviceIds [outputIndex],
inputDeviceIds [inputIndex]);
inputDeviceIds [inputIndex],
useExclusiveMode);


if (! d->initialise()) if (! d->initialise())
deleteAndZero (d); deleteAndZero (d);
@@ -239295,7 +239259,7 @@ bool Desktop::isScreenSaverEnabled() throw()
return ! [[UIApplication sharedApplication] isIdleTimerDisabled]; return ! [[UIApplication sharedApplication] isIdleTimerDisabled];
} }


void juce_updateMultiMonitorInfo (Array <Rectangle>& monitorCoords, const bool clipToWorkArea)
void juce_updateMultiMonitorInfo (Array <Rectangle <int> >& monitorCoords, const bool clipToWorkArea)
{ {
const ScopedAutoReleasePool pool; const ScopedAutoReleasePool pool;
monitorCoords.clear(); monitorCoords.clear();
@@ -239611,7 +239575,7 @@ bool JUCE_CALLTYPE Process::isRunningUnderDebugger()
#define SUPPORT_10_4_FONTS 1 #define SUPPORT_10_4_FONTS 1
#define NEW_CGFONT_FUNCTIONS_UNAVAILABLE (CGFontCreateWithFontName == 0) #define NEW_CGFONT_FUNCTIONS_UNAVAILABLE (CGFontCreateWithFontName == 0)


#if MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_5
#if (MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_5) || JUCE_PPC
#define SUPPORT_ONLY_10_4_FONTS 1 #define SUPPORT_ONLY_10_4_FONTS 1
#endif #endif


@@ -241952,13 +241916,13 @@ using namespace JUCE_NAMESPACE;


- (BOOL) panel: (id) sender shouldShowFilename: (NSString*) filename - (BOOL) panel: (id) sender shouldShowFilename: (NSString*) filename
{ {
const String fname (nsStringToJuce (filename));
const File f (nsStringToJuce (filename));


for (int i = filters->size(); --i >= 0;) for (int i = filters->size(); --i >= 0;)
if (fname.matchesWildcard ((*filters)[i], true))
if (f.getFileName().matchesWildcard ((*filters)[i], true))
return true; return true;


return File (fname).isDirectory();
return f.isDirectory();
} }
@end @end


@@ -244046,7 +244010,7 @@ MidiInput* MidiInput::openDevice (int index, MidiInputCallback* callback)
#define SUPPORT_10_4_FONTS 1 #define SUPPORT_10_4_FONTS 1
#define NEW_CGFONT_FUNCTIONS_UNAVAILABLE (CGFontCreateWithFontName == 0) #define NEW_CGFONT_FUNCTIONS_UNAVAILABLE (CGFontCreateWithFontName == 0)


#if MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_5
#if (MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_5) || JUCE_PPC
#define SUPPORT_ONLY_10_4_FONTS 1 #define SUPPORT_ONLY_10_4_FONTS 1
#endif #endif


@@ -248173,13 +248137,13 @@ using namespace JUCE_NAMESPACE;


- (BOOL) panel: (id) sender shouldShowFilename: (NSString*) filename - (BOOL) panel: (id) sender shouldShowFilename: (NSString*) filename
{ {
const String fname (nsStringToJuce (filename));
const File f (nsStringToJuce (filename));


for (int i = filters->size(); --i >= 0;) for (int i = filters->size(); --i >= 0;)
if (fname.matchesWildcard ((*filters)[i], true))
if (f.getFileName().matchesWildcard ((*filters)[i], true))
return true; return true;


return File (fname).isDirectory();
return f.isDirectory();
} }
@end @end




+ 31
- 2
juce_amalgamated.h View File

@@ -1424,7 +1424,6 @@ private:
// internal constructor that preallocates a certain amount of memory // internal constructor that preallocates a certain amount of memory
String (const int numChars, const int dummyVariable) throw(); String (const int numChars, const int dummyVariable) throw();


void deleteInternal() throw();
void createInternal (const int numChars) throw(); void createInternal (const int numChars) throw();
void createInternal (const tchar* const text, const tchar* const textEnd) throw(); void createInternal (const tchar* const text, const tchar* const textEnd) throw();
void appendInternal (const tchar* const text, const int numExtraChars) throw(); void appendInternal (const tchar* const text, const int numExtraChars) throw();
@@ -3144,6 +3143,8 @@ public:
static int32 decrementAndReturn (int32& variable); static int32 decrementAndReturn (int32& variable);


static int32 compareAndExchange (int32& destination, int32 newValue, int32 requiredCurrentValue); static int32 compareAndExchange (int32& destination, int32 newValue, int32 requiredCurrentValue);

static void* swapPointers (void* volatile* value1, void* value2);
}; };


#if (JUCE_MAC || JUCE_IPHONE) // Mac and iPhone... #if (JUCE_MAC || JUCE_IPHONE) // Mac and iPhone...
@@ -3154,6 +3155,12 @@ inline void Atomic::decrement (int32& variable) { OSAtomicDecrement32 ((int32_
inline int32 Atomic::decrementAndReturn (int32& variable) { return OSAtomicDecrement32 ((int32_t*) &variable); } inline int32 Atomic::decrementAndReturn (int32& variable) { return OSAtomicDecrement32 ((int32_t*) &variable); }
inline int32 Atomic::compareAndExchange (int32& destination, int32 newValue, int32 oldValue) inline int32 Atomic::compareAndExchange (int32& destination, int32 newValue, int32 oldValue)
{ return OSAtomicCompareAndSwap32Barrier (oldValue, newValue, (int32_t*) &destination); } { return OSAtomicCompareAndSwap32Barrier (oldValue, newValue, (int32_t*) &destination); }
inline void* Atomic::swapPointers (void* volatile* value1, void* volatile value2)
{
void* currentVal = *value1;
while (! OSAtomicCompareAndSwapPtr (currentVal, value2, value1)) { currentVal = *value1; }
return currentVal;
}


#elif JUCE_LINUX // Linux... #elif JUCE_LINUX // Linux...


@@ -3163,6 +3170,12 @@ inline void Atomic::decrement (int32& variable) { __sync_add_and_fetch (&varia
inline int32 Atomic::decrementAndReturn (int32& variable) { return __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) inline int32 Atomic::compareAndExchange (int32& destination, int32 newValue, int32 oldValue)
{ return __sync_val_compare_and_swap (&destination, oldValue, newValue); } { return __sync_val_compare_and_swap (&destination, oldValue, newValue); }
inline void* Atomic::swapPointers (void* volatile* value1, void* volatile value2)
{
void* currentVal = *value1;
while (! __sync_bool_compare_and_swap (&value1, currentVal, value2)) { currentVal = *value1; }
return currentVal;
}


#elif JUCE_USE_INTRINSICS // Windows... #elif JUCE_USE_INTRINSICS // Windows...


@@ -6692,6 +6705,22 @@ void JUCE_PUBLIC_FUNCTION initialiseJuce_NonGUI();


void JUCE_PUBLIC_FUNCTION shutdownJuce_NonGUI(); void JUCE_PUBLIC_FUNCTION shutdownJuce_NonGUI();


class ScopedJuceInitialiser_NonGUI
{
public:
ScopedJuceInitialiser_NonGUI() { initialiseJuce_NonGUI(); }

~ScopedJuceInitialiser_NonGUI() { shutdownJuce_NonGUI(); }
};

class ScopedJuceInitialiser_GUI
{
public:
ScopedJuceInitialiser_GUI() { initialiseJuce_GUI(); }

~ScopedJuceInitialiser_GUI() { shutdownJuce_GUI(); }
};

#endif // __JUCE_INITIALISATION_JUCEHEADER__ #endif // __JUCE_INITIALISATION_JUCEHEADER__
/*** End of inlined file: juce_Initialisation.h ***/ /*** End of inlined file: juce_Initialisation.h ***/


@@ -28181,7 +28210,7 @@ END_JUCE_NAMESPACE
// defining DONT_SET_USING_JUCE_NAMESPACE, in case there are conflicts. // defining DONT_SET_USING_JUCE_NAMESPACE, in case there are conflicts.
using namespace JUCE_NAMESPACE; using namespace JUCE_NAMESPACE;


#if JUCE_MAC && ! JUCE_DONT_DEFINE_MACROS
#if (JUCE_MAC || JUCE_IPHONE) && ! JUCE_DONT_DEFINE_MACROS
#define Component JUCE_NAMESPACE::Component #define Component JUCE_NAMESPACE::Component
#define MemoryBlock JUCE_NAMESPACE::MemoryBlock #define MemoryBlock JUCE_NAMESPACE::MemoryBlock
#define Point JUCE_NAMESPACE::Point #define Point JUCE_NAMESPACE::Point


+ 13
- 17
src/audio/devices/juce_AudioDeviceManager.cpp View File

@@ -548,32 +548,30 @@ void AudioDeviceManager::restartLastAudioDevice()
void AudioDeviceManager::updateXml() void AudioDeviceManager::updateXml()
{ {
lastExplicitSettings = new XmlElement (T("DEVICESETUP"));
lastExplicitSettings = new XmlElement ("DEVICESETUP");
lastExplicitSettings->setAttribute (T("deviceType"), currentDeviceType);
lastExplicitSettings->setAttribute (T("audioOutputDeviceName"), currentSetup.outputDeviceName);
lastExplicitSettings->setAttribute (T("audioInputDeviceName"), currentSetup.inputDeviceName);
lastExplicitSettings->setAttribute ("deviceType", currentDeviceType);
lastExplicitSettings->setAttribute ("audioOutputDeviceName", currentSetup.outputDeviceName);
lastExplicitSettings->setAttribute ("audioInputDeviceName", currentSetup.inputDeviceName);
if (currentAudioDevice != 0) if (currentAudioDevice != 0)
{ {
lastExplicitSettings->setAttribute (T("audioDeviceRate"), currentAudioDevice->getCurrentSampleRate());
lastExplicitSettings->setAttribute ("audioDeviceRate", currentAudioDevice->getCurrentSampleRate());
if (currentAudioDevice->getDefaultBufferSize() != currentAudioDevice->getCurrentBufferSizeSamples()) if (currentAudioDevice->getDefaultBufferSize() != currentAudioDevice->getCurrentBufferSizeSamples())
lastExplicitSettings->setAttribute (T("audioDeviceBufferSize"), currentAudioDevice->getCurrentBufferSizeSamples());
lastExplicitSettings->setAttribute ("audioDeviceBufferSize", currentAudioDevice->getCurrentBufferSizeSamples());
if (! currentSetup.useDefaultInputChannels) if (! currentSetup.useDefaultInputChannels)
lastExplicitSettings->setAttribute (T("audioDeviceInChans"), currentSetup.inputChannels.toString (2));
lastExplicitSettings->setAttribute ("audioDeviceInChans", currentSetup.inputChannels.toString (2));
if (! currentSetup.useDefaultOutputChannels) if (! currentSetup.useDefaultOutputChannels)
lastExplicitSettings->setAttribute (T("audioDeviceOutChans"), currentSetup.outputChannels.toString (2));
lastExplicitSettings->setAttribute ("audioDeviceOutChans", currentSetup.outputChannels.toString (2));
} }
for (int i = 0; i < enabledMidiInputs.size(); ++i) for (int i = 0; i < enabledMidiInputs.size(); ++i)
{ {
XmlElement* const m = new XmlElement (T("MIDIINPUT"));
m->setAttribute (T("name"), enabledMidiInputs[i]->getName());
lastExplicitSettings->addChildElement (m);
XmlElement* const m = lastExplicitSettings->createNewChildElement ("MIDIINPUT");
m->setAttribute ("name", enabledMidiInputs[i]->getName());
} }
if (midiInsFromXml.size() > 0) if (midiInsFromXml.size() > 0)
@@ -586,16 +584,14 @@ void AudioDeviceManager::updateXml()
{ {
if (! availableMidiDevices.contains (midiInsFromXml[i], true)) if (! availableMidiDevices.contains (midiInsFromXml[i], true))
{ {
XmlElement* const m = new XmlElement (T("MIDIINPUT"));
m->setAttribute (T("name"), midiInsFromXml[i]);
lastExplicitSettings->addChildElement (m);
XmlElement* const m = lastExplicitSettings->createNewChildElement ("MIDIINPUT");
m->setAttribute ("name", midiInsFromXml[i]);
} }
} }
} }
if (defaultMidiOutputName.isNotEmpty()) if (defaultMidiOutputName.isNotEmpty())
lastExplicitSettings->setAttribute (T("defaultMidiOutput"), defaultMidiOutputName);
lastExplicitSettings->setAttribute ("defaultMidiOutput", defaultMidiOutputName);
} }
//============================================================================== //==============================================================================


+ 1
- 4
src/containers/juce_PropertySet.cpp View File

@@ -212,12 +212,9 @@ XmlElement* PropertySet::createXml (const String& nodeName) const throw()
for (int i = 0; i < properties.getAllKeys().size(); ++i) for (int i = 0; i < properties.getAllKeys().size(); ++i)
{ {
XmlElement* const e = new XmlElement (T("VALUE"));
XmlElement* const e = xml->createNewChildElement ("VALUE");
e->setAttribute (T("name"), properties.getAllKeys()[i]); e->setAttribute (T("name"), properties.getAllKeys()[i]);
e->setAttribute (T("val"), properties.getAllValues()[i]); e->setAttribute (T("val"), properties.getAllValues()[i]);
xml->addChildElement (e);
} }
return xml; return xml;


+ 15
- 0
src/core/juce_Atomic.h View File

@@ -50,6 +50,9 @@ public:
@returns the new value of destination @returns the new value of destination
*/ */
static int32 compareAndExchange (int32& destination, int32 newValue, int32 requiredCurrentValue); static int32 compareAndExchange (int32& destination, int32 newValue, int32 requiredCurrentValue);
/** This atomically sets *value1 to be value2, and returns the previous value of *value1. */
static void* swapPointers (void* volatile* value1, void* value2);
}; };
@@ -62,6 +65,12 @@ inline void Atomic::decrement (int32& variable) { OSAtomicDecrem
inline int32 Atomic::decrementAndReturn (int32& variable) { return OSAtomicDecrement32 ((int32_t*) &variable); } inline int32 Atomic::decrementAndReturn (int32& variable) { return OSAtomicDecrement32 ((int32_t*) &variable); }
inline int32 Atomic::compareAndExchange (int32& destination, int32 newValue, int32 oldValue) inline int32 Atomic::compareAndExchange (int32& destination, int32 newValue, int32 oldValue)
{ return OSAtomicCompareAndSwap32Barrier (oldValue, newValue, (int32_t*) &destination); } { return OSAtomicCompareAndSwap32Barrier (oldValue, newValue, (int32_t*) &destination); }
inline void* Atomic::swapPointers (void* volatile* value1, void* volatile value2)
{
void* currentVal = *value1;
while (! OSAtomicCompareAndSwapPtr (currentVal, value2, value1)) { currentVal = *value1; }
return currentVal;
}
#elif JUCE_LINUX // Linux... #elif JUCE_LINUX // Linux...
@@ -72,6 +81,12 @@ inline void Atomic::decrement (int32& variable) { __sync_add_and
inline int32 Atomic::decrementAndReturn (int32& variable) { return __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) inline int32 Atomic::compareAndExchange (int32& destination, int32 newValue, int32 oldValue)
{ return __sync_val_compare_and_swap (&destination, oldValue, newValue); } { return __sync_val_compare_and_swap (&destination, oldValue, newValue); }
inline void* Atomic::swapPointers (void* volatile* value1, void* volatile value2)
{
void* currentVal = *value1;
while (! __sync_bool_compare_and_swap (&value1, currentVal, value2)) { currentVal = *value1; }
return currentVal;
}
//============================================================================== //==============================================================================
#elif JUCE_USE_INTRINSICS // Windows... #elif JUCE_USE_INTRINSICS // Windows...


+ 50
- 0
src/core/juce_Initialisation.h View File

@@ -76,5 +76,55 @@ void JUCE_PUBLIC_FUNCTION initialiseJuce_NonGUI();
void JUCE_PUBLIC_FUNCTION shutdownJuce_NonGUI(); void JUCE_PUBLIC_FUNCTION shutdownJuce_NonGUI();
//==============================================================================
/** A utility object that helps you initialise and shutdown Juce correctly
using an RAII pattern.
When an instance of this class is created, it calls initialiseJuce_NonGUI(),
and when it's deleted, it calls shutdownJuce_NonGUI(), which lets you easily
make sure that these functions are matched correctly.
This class is particularly handy to use at the beginning of a console app's
main() function, because it'll take care of shutting down whenever you return
from the main() call.
@see ScopedJuceInitialiser_GUI
*/
class ScopedJuceInitialiser_NonGUI
{
public:
/** The constructor simply calls initialiseJuce_NonGUI(). */
ScopedJuceInitialiser_NonGUI() { initialiseJuce_NonGUI(); }
/** The destructor simply calls shutdownJuce_NonGUI(). */
~ScopedJuceInitialiser_NonGUI() { shutdownJuce_NonGUI(); }
};
//==============================================================================
/** A utility object that helps you initialise and shutdown Juce correctly
using an RAII pattern.
When an instance of this class is created, it calls initialiseJuce_GUI(),
and when it's deleted, it calls shutdownJuce_GUI(), which lets you easily
make sure that these functions are matched correctly.
This class is particularly handy to use at the beginning of a console app's
main() function, because it'll take care of shutting down whenever you return
from the main() call.
@see ScopedJuceInitialiser_NonGUI
*/
class ScopedJuceInitialiser_GUI
{
public:
/** The constructor simply calls initialiseJuce_GUI(). */
ScopedJuceInitialiser_GUI() { initialiseJuce_GUI(); }
/** The destructor simply calls shutdownJuce_GUI(). */
~ScopedJuceInitialiser_GUI() { shutdownJuce_GUI(); }
};
#endif // __JUCE_INITIALISATION_JUCEHEADER__ #endif // __JUCE_INITIALISATION_JUCEHEADER__

+ 13
- 15
src/gui/components/controls/juce_TableHeaderComponent.cpp View File

@@ -439,21 +439,19 @@ const String TableHeaderComponent::toString() const
{ {
String s; String s;
XmlElement doc (T("TABLELAYOUT"));
XmlElement doc ("TABLELAYOUT");
doc.setAttribute (T("sortedCol"), getSortColumnId());
doc.setAttribute (T("sortForwards"), isSortedForwards());
doc.setAttribute ("sortedCol", getSortColumnId());
doc.setAttribute ("sortForwards", isSortedForwards());
for (int i = 0; i < columns.size(); ++i) for (int i = 0; i < columns.size(); ++i)
{ {
const ColumnInfo* const ci = columns.getUnchecked (i); const ColumnInfo* const ci = columns.getUnchecked (i);
XmlElement* const e = new XmlElement (T("COLUMN"));
doc.addChildElement (e);
e->setAttribute (T("id"), ci->id);
e->setAttribute (T("visible"), ci->isVisible());
e->setAttribute (T("width"), ci->width);
XmlElement* const e = doc.createNewChildElement ("COLUMN");
e->setAttribute ("id", ci->id);
e->setAttribute ("visible", ci->isVisible());
e->setAttribute ("width", ci->width);
} }
return doc.createDocument (String::empty, true, false); return doc.createDocument (String::empty, true, false);
@@ -466,19 +464,19 @@ void TableHeaderComponent::restoreFromString (const String& storedVersion)
int index = 0; int index = 0;
if (storedXml != 0 && storedXml->hasTagName (T("TABLELAYOUT")))
if (storedXml != 0 && storedXml->hasTagName ("TABLELAYOUT"))
{ {
forEachXmlChildElement (*storedXml, col) forEachXmlChildElement (*storedXml, col)
{ {
const int tabId = col->getIntAttribute (T("id"));
const int tabId = col->getIntAttribute ("id");
ColumnInfo* const ci = getInfoForId (tabId); ColumnInfo* const ci = getInfoForId (tabId);
if (ci != 0) if (ci != 0)
{ {
columns.move (columns.indexOf (ci), index); columns.move (columns.indexOf (ci), index);
ci->width = col->getIntAttribute (T("width"));
setColumnVisible (tabId, col->getBoolAttribute (T("visible")));
ci->width = col->getIntAttribute ("width");
setColumnVisible (tabId, col->getBoolAttribute ("visible"));
} }
++index; ++index;
@@ -487,8 +485,8 @@ void TableHeaderComponent::restoreFromString (const String& storedVersion)
columnsResized = true; columnsResized = true;
sendColumnsChanged(); sendColumnsChanged();
setSortColumnId (storedXml->getIntAttribute (T("sortedCol")),
storedXml->getBoolAttribute (T("sortForwards"), true));
setSortColumnId (storedXml->getIntAttribute ("sortedCol"),
storedXml->getBoolAttribute ("sortForwards", true));
} }
} }


+ 2
- 6
src/gui/components/keyboard/juce_KeyPressMappingSet.cpp View File

@@ -298,13 +298,11 @@ XmlElement* KeyPressMappingSet::createXml (const bool saveDifferencesFromDefault
if (defaultSet == 0 if (defaultSet == 0
|| ! defaultSet->containsMapping (cm->commandID, cm->keypresses.getReference (j))) || ! defaultSet->containsMapping (cm->commandID, cm->keypresses.getReference (j)))
{ {
XmlElement* const map = new XmlElement (T("MAPPING"));
XmlElement* const map = doc->createNewChildElement ("MAPPING");
map->setAttribute (T("commandId"), String::toHexString ((int) cm->commandID)); map->setAttribute (T("commandId"), String::toHexString ((int) cm->commandID));
map->setAttribute (T("description"), commandManager->getDescriptionOfCommand (cm->commandID)); map->setAttribute (T("description"), commandManager->getDescriptionOfCommand (cm->commandID));
map->setAttribute (T("key"), cm->keypresses.getReference (j).getTextDescription()); map->setAttribute (T("key"), cm->keypresses.getReference (j).getTextDescription());
doc->addChildElement (map);
} }
} }
} }
@@ -319,13 +317,11 @@ XmlElement* KeyPressMappingSet::createXml (const bool saveDifferencesFromDefault
{ {
if (! containsMapping (cm->commandID, cm->keypresses.getReference (j))) if (! containsMapping (cm->commandID, cm->keypresses.getReference (j)))
{ {
XmlElement* const map = new XmlElement (T("UNMAPPING"));
XmlElement* const map = doc->createNewChildElement ("UNMAPPING");
map->setAttribute (T("commandId"), String::toHexString ((int) cm->commandID)); map->setAttribute (T("commandId"), String::toHexString ((int) cm->commandID));
map->setAttribute (T("description"), commandManager->getDescriptionOfCommand (cm->commandID)); map->setAttribute (T("description"), commandManager->getDescriptionOfCommand (cm->commandID));
map->setAttribute (T("key"), cm->keypresses.getReference (j).getTextDescription()); map->setAttribute (T("key"), cm->keypresses.getReference (j).getTextDescription());
doc->addChildElement (map);
} }
} }
} }


+ 3
- 4
src/gui/components/properties/juce_PropertyPanel.cpp View File

@@ -395,10 +395,9 @@ XmlElement* PropertyPanel::getOpennessState() const
{ {
if (sections[i].isNotEmpty()) if (sections[i].isNotEmpty())
{ {
XmlElement* const e = new XmlElement (T("SECTION"));
e->setAttribute (T("name"), sections[i]);
e->setAttribute (T("open"), isSectionOpen (i) ? 1 : 0);
xml->addChildElement (e);
XmlElement* const e = xml->createNewChildElement ("SECTION");
e->setAttribute ("name", sections[i]);
e->setAttribute ("open", isSectionOpen (i) ? 1 : 0);
} }
} }


+ 1
- 1
src/native/mac/juce_iphone_MiscUtilities.mm View File

@@ -181,7 +181,7 @@ bool Desktop::isScreenSaverEnabled() throw()
//============================================================================== //==============================================================================
void juce_updateMultiMonitorInfo (Array <Rectangle>& monitorCoords, const bool clipToWorkArea)
void juce_updateMultiMonitorInfo (Array <Rectangle <int> >& monitorCoords, const bool clipToWorkArea)
{ {
const ScopedAutoReleasePool pool; const ScopedAutoReleasePool pool;
monitorCoords.clear(); monitorCoords.clear();


+ 3
- 3
src/native/mac/juce_mac_FileChooser.mm View File

@@ -66,13 +66,13 @@ using namespace JUCE_NAMESPACE;
- (BOOL) panel: (id) sender shouldShowFilename: (NSString*) filename - (BOOL) panel: (id) sender shouldShowFilename: (NSString*) filename
{ {
const String fname (nsStringToJuce (filename));
const File f (nsStringToJuce (filename));
for (int i = filters->size(); --i >= 0;) for (int i = filters->size(); --i >= 0;)
if (fname.matchesWildcard ((*filters)[i], true))
if (f.getFileName().matchesWildcard ((*filters)[i], true))
return true; return true;
return File (fname).isDirectory();
return f.isDirectory();
} }
@end @end


+ 1
- 1
src/native/mac/juce_mac_Fonts.mm View File

@@ -31,7 +31,7 @@
#define SUPPORT_10_4_FONTS 1 #define SUPPORT_10_4_FONTS 1
#define NEW_CGFONT_FUNCTIONS_UNAVAILABLE (CGFontCreateWithFontName == 0) #define NEW_CGFONT_FUNCTIONS_UNAVAILABLE (CGFontCreateWithFontName == 0)
#if MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_5
#if (MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_5) || JUCE_PPC
#define SUPPORT_ONLY_10_4_FONTS 1 #define SUPPORT_ONLY_10_4_FONTS 1
#endif #endif


+ 1
- 1
src/native/windows/juce_win32_PlatformUtils.cpp View File

@@ -55,7 +55,7 @@ static HKEY findKeyForPath (String name,
if (createForWriting) if (createForWriting)
{ {
if (RegCreateKeyEx (rootKey, name, 0, L"", REG_OPTION_NON_VOLATILE,
if (RegCreateKeyEx (rootKey, name, 0, 0, REG_OPTION_NON_VOLATILE,
(KEY_WRITE | KEY_QUERY_VALUE), 0, &key, &result) == ERROR_SUCCESS) (KEY_WRITE | KEY_QUERY_VALUE), 0, &key, &result) == ERROR_SUCCESS)
return key; return key;
} }


+ 2
- 0
src/native/windows/juce_win32_Threads.cpp View File

@@ -43,6 +43,8 @@ int32 Atomic::compareAndExchange (int32& destination, int32 newValue, int32 oldV
{ return InterlockedCompareExchange (reinterpret_cast <volatile long*> (&destination), newValue, oldValue); } { return InterlockedCompareExchange (reinterpret_cast <volatile long*> (&destination), newValue, oldValue); }
#endif #endif
void* Atomic::swapPointers (void* volatile* value1, void* volatile value2) { return InterlockedExchangePointer (value1, value2); }
//============================================================================== //==============================================================================
CriticalSection::CriticalSection() throw() CriticalSection::CriticalSection() throw()
{ {


+ 35
- 17
src/native/windows/juce_win32_WASAPI.cpp View File

@@ -121,7 +121,7 @@ static void wasapi_copyWavFormat (WAVEFORMATEXTENSIBLE& dest, const WAVEFORMATEX
class WASAPIDeviceBase class WASAPIDeviceBase
{ {
public: public:
WASAPIDeviceBase (const ComSmartPtr <IMMDevice>& device_)
WASAPIDeviceBase (const ComSmartPtr <IMMDevice>& device_, const bool useExclusiveMode_)
: device (device_), : device (device_),
sampleRate (0), sampleRate (0),
numChannels (0), numChannels (0),
@@ -129,7 +129,8 @@ public:
defaultSampleRate (0), defaultSampleRate (0),
minBufferSize (0), minBufferSize (0),
defaultBufferSize (0), defaultBufferSize (0),
latencySamples (0)
latencySamples (0),
useExclusiveMode (useExclusiveMode_)
{ {
clientEvent = CreateEvent (0, false, false, _T("JuceWASAPI")); clientEvent = CreateEvent (0, false, false, _T("JuceWASAPI"));
@@ -166,7 +167,8 @@ public:
format.Format.nSamplesPerSec = roundDoubleToInt (ratesToTest[i]); format.Format.nSamplesPerSec = roundDoubleToInt (ratesToTest[i]);
if (SUCCEEDED (tempClient->IsFormatSupported (AUDCLNT_SHAREMODE_SHARED, (WAVEFORMATEX*) &format, 0)))
if (SUCCEEDED (tempClient->IsFormatSupported (useExclusiveMode ? AUDCLNT_SHAREMODE_EXCLUSIVE : AUDCLNT_SHAREMODE_SHARED,
(WAVEFORMATEX*) &format, 0)))
if (! rates.contains (ratesToTest[i])) if (! rates.contains (ratesToTest[i]))
rates.addSorted (comparator, ratesToTest[i]); rates.addSorted (comparator, ratesToTest[i]);
} }
@@ -227,6 +229,7 @@ public:
double sampleRate, defaultSampleRate; double sampleRate, defaultSampleRate;
int numChannels, actualNumChannels; int numChannels, actualNumChannels;
int minBufferSize, defaultBufferSize, latencySamples; int minBufferSize, defaultBufferSize, latencySamples;
const bool useExclusiveMode;
Array <double> rates; Array <double> rates;
HANDLE clientEvent; HANDLE clientEvent;
BitArray channels; BitArray channels;
@@ -284,7 +287,8 @@ private:
WAVEFORMATEXTENSIBLE* nearestFormat = 0; WAVEFORMATEXTENSIBLE* nearestFormat = 0;
HRESULT hr = client->IsFormatSupported (AUDCLNT_SHAREMODE_SHARED, (WAVEFORMATEX*) &format, (WAVEFORMATEX**) &nearestFormat);
HRESULT hr = client->IsFormatSupported (useExclusiveMode ? AUDCLNT_SHAREMODE_EXCLUSIVE : AUDCLNT_SHAREMODE_SHARED,
(WAVEFORMATEX*) &format, useExclusiveMode ? 0 : (WAVEFORMATEX**) &nearestFormat);
logFailure (hr); logFailure (hr);
if (hr == S_FALSE && format.Format.nSamplesPerSec == nearestFormat->Format.nSamplesPerSec) if (hr == S_FALSE && format.Format.nSamplesPerSec == nearestFormat->Format.nSamplesPerSec)
@@ -295,10 +299,15 @@ private:
CoTaskMemFree (nearestFormat); CoTaskMemFree (nearestFormat);
REFERENCE_TIME defaultPeriod = 0, minPeriod = 0;
if (useExclusiveMode)
OK (client->GetDevicePeriod (&defaultPeriod, &minPeriod));
GUID session; GUID session;
if (hr == S_OK if (hr == S_OK
&& OK (client->Initialize (AUDCLNT_SHAREMODE_SHARED, AUDCLNT_STREAMFLAGS_EVENTCALLBACK,
0, 0, (WAVEFORMATEX*) &format, &session)))
&& OK (client->Initialize (useExclusiveMode ? AUDCLNT_SHAREMODE_EXCLUSIVE : AUDCLNT_SHAREMODE_SHARED,
AUDCLNT_STREAMFLAGS_EVENTCALLBACK,
defaultPeriod, defaultPeriod, (WAVEFORMATEX*) &format, &session)))
{ {
actualNumChannels = format.Format.nChannels; actualNumChannels = format.Format.nChannels;
const bool isFloat = format.Format.wFormatTag == WAVE_FORMAT_EXTENSIBLE && format.SubFormat == KSDATAFORMAT_SUBTYPE_IEEE_FLOAT; const bool isFloat = format.Format.wFormatTag == WAVE_FORMAT_EXTENSIBLE && format.SubFormat == KSDATAFORMAT_SUBTYPE_IEEE_FLOAT;
@@ -318,8 +327,8 @@ private:
class WASAPIInputDevice : public WASAPIDeviceBase class WASAPIInputDevice : public WASAPIDeviceBase
{ {
public: public:
WASAPIInputDevice (const ComSmartPtr <IMMDevice>& device_)
: WASAPIDeviceBase (device_),
WASAPIInputDevice (const ComSmartPtr <IMMDevice>& device_, const bool useExclusiveMode_)
: WASAPIDeviceBase (device_, useExclusiveMode_),
reservoir (1, 1) reservoir (1, 1)
{ {
} }
@@ -464,8 +473,8 @@ public:
class WASAPIOutputDevice : public WASAPIDeviceBase class WASAPIOutputDevice : public WASAPIDeviceBase
{ {
public: public:
WASAPIOutputDevice (const ComSmartPtr <IMMDevice>& device_)
: WASAPIDeviceBase (device_)
WASAPIOutputDevice (const ComSmartPtr <IMMDevice>& device_, const bool useExclusiveMode_)
: WASAPIDeviceBase (device_, useExclusiveMode_)
{ {
} }
@@ -499,7 +508,8 @@ public:
if (! OK (client->GetCurrentPadding (&padding))) if (! OK (client->GetCurrentPadding (&padding)))
return; return;
const int samplesToDo = jmin ((int) (actualBufferSize - padding), bufferSize);
int samplesToDo = useExclusiveMode ? bufferSize
: jmin ((int) (actualBufferSize - padding), bufferSize);
if (samplesToDo <= 0) if (samplesToDo <= 0)
{ {
@@ -558,7 +568,8 @@ class WASAPIAudioIODevice : public AudioIODevice,
public: public:
WASAPIAudioIODevice (const String& deviceName, WASAPIAudioIODevice (const String& deviceName,
const String& outputDeviceId_, const String& outputDeviceId_,
const String& inputDeviceId_)
const String& inputDeviceId_,
const bool useExclusiveMode_)
: AudioIODevice (deviceName, "Windows Audio"), : AudioIODevice (deviceName, "Windows Audio"),
Thread ("Juce WASAPI"), Thread ("Juce WASAPI"),
isOpen_ (false), isOpen_ (false),
@@ -567,6 +578,7 @@ public:
outputDeviceId (outputDeviceId_), outputDeviceId (outputDeviceId_),
inputDevice (0), inputDevice (0),
inputDeviceId (inputDeviceId_), inputDeviceId (inputDeviceId_),
useExclusiveMode (useExclusiveMode_),
currentBufferSizeSamples (0), currentBufferSizeSamples (0),
currentSampleRate (0), currentSampleRate (0),
callback (0) callback (0)
@@ -820,8 +832,8 @@ public:
while (! threadShouldExit()) while (! threadShouldExit())
{ {
const DWORD result = WaitForMultipleObjects (numEvents, events, true, 1000);
const DWORD result = useExclusiveMode ? WaitForSingleObject (inputDevice->clientEvent, 1000)
: WaitForMultipleObjects (numEvents, events, true, 1000);
if (result == WAIT_TIMEOUT) if (result == WAIT_TIMEOUT)
continue; continue;
@@ -853,6 +865,9 @@ public:
} }
} }
if (useExclusiveMode && WaitForSingleObject (outputDevice->clientEvent, 1000) == WAIT_TIMEOUT)
continue;
if (outputDevice != 0) if (outputDevice != 0)
outputDevice->copyBuffers ((const float**) outputBuffers, numOutputBuffers, bufferSize, *this); outputDevice->copyBuffers ((const float**) outputBuffers, numOutputBuffers, bufferSize, *this);
} }
@@ -869,6 +884,7 @@ private:
// Device stats... // Device stats...
WASAPIInputDevice* inputDevice; WASAPIInputDevice* inputDevice;
WASAPIOutputDevice* outputDevice; WASAPIOutputDevice* outputDevice;
const bool useExclusiveMode;
double defaultSampleRate; double defaultSampleRate;
int minBufferSize, defaultBufferSize; int minBufferSize, defaultBufferSize;
int latencyIn, latencyOut; int latencyIn, latencyOut;
@@ -911,9 +927,9 @@ private:
const EDataFlow flow = wasapi_getDataFlow (device); const EDataFlow flow = wasapi_getDataFlow (device);
if (deviceId == inputDeviceId && flow == eCapture) if (deviceId == inputDeviceId && flow == eCapture)
inputDevice = new WASAPIInputDevice (device);
inputDevice = new WASAPIInputDevice (device, useExclusiveMode);
else if (deviceId == outputDeviceId && flow == eRender) else if (deviceId == outputDeviceId && flow == eRender)
outputDevice = new WASAPIOutputDevice (device);
outputDevice = new WASAPIOutputDevice (device, useExclusiveMode);
} }
return (outputDeviceId.isEmpty() || (outputDevice != 0 && outputDevice->isOk())) return (outputDeviceId.isEmpty() || (outputDevice != 0 && outputDevice->isOk()))
@@ -1043,6 +1059,7 @@ public:
{ {
jassert (hasScanned); // need to call scanForDevices() before doing this jassert (hasScanned); // need to call scanForDevices() before doing this
const bool useExclusiveMode = false;
WASAPIAudioIODevice* d = 0; WASAPIAudioIODevice* d = 0;
const int outputIndex = outputDeviceNames.indexOf (outputDeviceName); const int outputIndex = outputDeviceNames.indexOf (outputDeviceName);
@@ -1053,7 +1070,8 @@ public:
d = new WASAPIAudioIODevice (outputDeviceName.isNotEmpty() ? outputDeviceName d = new WASAPIAudioIODevice (outputDeviceName.isNotEmpty() ? outputDeviceName
: inputDeviceName, : inputDeviceName,
outputDeviceIds [outputIndex], outputDeviceIds [outputIndex],
inputDeviceIds [inputIndex]);
inputDeviceIds [inputIndex],
useExclusiveMode);
if (! d->initialise()) if (! d->initialise())
deleteAndZero (d); deleteAndZero (d);


+ 17
- 57
src/text/juce_String.cpp View File

@@ -56,12 +56,6 @@ void juce_initialiseStrings()
} }
//============================================================================== //==============================================================================
void String::deleteInternal() throw()
{
if (Atomic::decrementAndReturn (text->refCount) == 0)
juce_free (text);
}
void String::createInternal (const int numChars) throw() void String::createInternal (const int numChars) throw()
{ {
jassert (numChars > 0); jassert (numChars > 0);
@@ -592,32 +586,7 @@ int64 String::hashCode64() const throw()
//============================================================================== //==============================================================================
const String& String::operator= (const tchar* const otherText) throw() const String& String::operator= (const tchar* const otherText) throw()
{ {
if (otherText != 0 && *otherText != 0)
{
const int otherLen = CharacterFunctions::length (otherText);
if (otherLen > 0)
{
// avoid resizing the memory block if the string is
// shrinking..
if (text->refCount > 1
|| otherLen > text->allocatedNumChars
|| otherLen <= (text->allocatedNumChars >> 1))
{
deleteInternal();
createInternal (otherLen);
}
memcpy (text->text, otherText, (otherLen + 1) * sizeof (tchar));
return *this;
}
}
deleteInternal();
text = &emptyString;
emptyString.refCount = safeEmptyStringRefCount;
operator= (String (otherText));
return *this; return *this;
} }
@@ -625,12 +594,14 @@ const String& String::operator= (const String& other) throw()
{ {
if (this != &other) if (this != &other)
{ {
Atomic::increment (other.text->refCount);
InternalRefCountedStringHolder* newText = other.text;
Atomic::increment (newText->refCount);
if (Atomic::decrementAndReturn (text->refCount) == 0)
juce_free (text);
InternalRefCountedStringHolder* oldText
= (InternalRefCountedStringHolder*) Atomic::swapPointers ((void* volatile*) &text, newText);
text = other.text;
if (Atomic::decrementAndReturn (oldText->refCount) == 0)
juce_free (oldText);
} }
return *this; return *this;
@@ -1282,47 +1253,36 @@ const String String::formatted (const tchar* const pf, ...) throw()
//============================================================================== //==============================================================================
void String::vprintf (const tchar* const pf, va_list& args) throw() void String::vprintf (const tchar* const pf, va_list& args) throw()
{ {
tchar stackBuf [256];
unsigned int bufSize = 256;
tchar* buf = stackBuf;
deleteInternal();
int bufferSize = 256;
String result (bufferSize, 0);
do do
{ {
#if JUCE_LINUX && JUCE_64BIT #if JUCE_LINUX && JUCE_64BIT
va_list tempArgs; va_list tempArgs;
va_copy (tempArgs, args); va_copy (tempArgs, args);
const int num = CharacterFunctions::vprintf (buf, bufSize - 1, pf, tempArgs);
const int num = CharacterFunctions::vprintf (result.text->text, bufferSize - 1, pf, tempArgs);
va_end (tempArgs); va_end (tempArgs);
#else #else
const int num = CharacterFunctions::vprintf (buf, bufSize - 1, pf, args);
const int num = CharacterFunctions::vprintf (result.text->text, bufferSize - 1, pf, args);
#endif #endif
if (num > 0) if (num > 0)
{ {
createInternal (num);
memcpy (text->text, buf, (num + 1) * sizeof (tchar));
*this = result;
break; break;
} }
else if (num == 0) else if (num == 0)
{ {
text = &emptyString;
emptyString.refCount = safeEmptyStringRefCount;
*this = String::empty;
break; break;
} }
if (buf != stackBuf)
juce_free (buf);
bufSize += 256;
buf = (tchar*) juce_malloc (bufSize * sizeof (tchar));
bufferSize += 256;
result.preallocateStorage (bufferSize);
} }
while (bufSize < 65536); // this is a sanity check to avoid situations where vprintf repeatedly
// returns -1 because of an error rather than because it needs more space.
if (buf != stackBuf)
juce_free (buf);
while (bufferSize < 65536); // this is a sanity check to avoid situations where vprintf repeatedly
// returns -1 because of an error rather than because it needs more space.
} }
//============================================================================== //==============================================================================


+ 0
- 1
src/text/juce_String.h View File

@@ -1117,7 +1117,6 @@ private:
// internal constructor that preallocates a certain amount of memory // internal constructor that preallocates a certain amount of memory
String (const int numChars, const int dummyVariable) throw(); String (const int numChars, const int dummyVariable) throw();
void deleteInternal() throw();
void createInternal (const int numChars) throw(); void createInternal (const int numChars) throw();
void createInternal (const tchar* const text, const tchar* const textEnd) throw(); void createInternal (const tchar* const text, const tchar* const textEnd) throw();
void appendInternal (const tchar* const text, const int numExtraChars) throw(); void appendInternal (const tchar* const text, const int numExtraChars) throw();


+ 1
- 3
src/utilities/juce_PropertiesFile.cpp View File

@@ -164,7 +164,7 @@ bool PropertiesFile::save()
for (int i = 0; i < getAllProperties().size(); ++i) for (int i = 0; i < getAllProperties().size(); ++i)
{ {
XmlElement* const e = new XmlElement (propertyTagName);
XmlElement* const e = doc.createNewChildElement (propertyTagName);
e->setAttribute (T("name"), getAllProperties().getAllKeys() [i]); e->setAttribute (T("name"), getAllProperties().getAllKeys() [i]);
// if the value seems to contain xml, store it as such.. // if the value seems to contain xml, store it as such..
@@ -175,8 +175,6 @@ bool PropertiesFile::save()
e->addChildElement (childElement); e->addChildElement (childElement);
else else
e->setAttribute (T("val"), getAllProperties().getAllValues() [i]); e->setAttribute (T("val"), getAllProperties().getAllValues() [i]);
doc.addChildElement (e);
} }
return doc.writeToFile (file, String::empty); return doc.writeToFile (file, String::empty);


Loading…
Cancel
Save