@@ -26,12 +26,12 @@ namespace MidiBufferHelpers | |||
{ | |||
inline int getEventTime (const void* const d) noexcept | |||
{ | |||
return *static_cast<const int32*> (d); | |||
return readUnaligned<int32> (d); | |||
} | |||
inline uint16 getEventDataSize (const void* const d) noexcept | |||
{ | |||
return *reinterpret_cast<const uint16*> (static_cast<const char*> (d) + sizeof (int32)); | |||
return readUnaligned<uint16> (static_cast<const char*> (d) + sizeof (int32)); | |||
} | |||
inline uint16 getEventTotalSize (const void* const d) noexcept | |||
@@ -124,8 +124,8 @@ void MidiBuffer::addEvent (const void* const newData, const int maxBytes, const | |||
data.insertMultiple (offset, 0, (int) newItemSize); | |||
uint8* const d = data.begin() + offset; | |||
*reinterpret_cast<int32*> (d) = sampleNumber; | |||
*reinterpret_cast<uint16*> (d + 4) = (uint16) numBytes; | |||
writeUnaligned<int32> (d, sampleNumber); | |||
writeUnaligned<uint16> (d + 4, static_cast<uint16> (numBytes)); | |||
memcpy (d + 6, newData, (size_t) numBytes); | |||
} | |||
} | |||
@@ -538,10 +538,10 @@ SynthesiserVoice* Synthesiser::findVoiceToSteal (SynthesiserSound* soundToPlay, | |||
{ | |||
SynthesiserVoice* const voice = voices.getUnchecked (i); | |||
jassert (voice->isVoiceActive()); // We wouldn't be here otherwise | |||
if (voice->canPlaySound (soundToPlay)) | |||
{ | |||
jassert (voice->isVoiceActive()); // We wouldn't be here otherwise | |||
VoiceAgeSorter sorter; | |||
usableVoices.addSorted (sorter, voice); | |||
@@ -1282,6 +1282,8 @@ void AudioProcessorGraph::setPlayHead (AudioPlayHead* audioPlayHead) | |||
{ | |||
const ScopedLock sl (getCallbackLock()); | |||
AudioProcessor::setPlayHead (audioPlayHead); | |||
for (int i = 0; i < nodes.size(); ++i) | |||
nodes.getUnchecked(i)->getProcessor()->setPlayHead (audioPlayHead); | |||
} | |||
@@ -1584,8 +1584,8 @@ struct JavascriptEngine::RootObject : public DynamicObject | |||
static var Math_range (Args a) { return isInt (a, 0) ? var (jlimit (getInt (a, 1), getInt (a, 2), getInt (a, 0))) : var (jlimit (getDouble (a, 1), getDouble (a, 2), getDouble (a, 0))); } | |||
static var Math_min (Args a) { return (isInt (a, 0) && isInt (a, 1)) ? var (jmin (getInt (a, 0), getInt (a, 1))) : var (jmin (getDouble (a, 0), getDouble (a, 1))); } | |||
static var Math_max (Args a) { return (isInt (a, 0) && isInt (a, 1)) ? var (jmax (getInt (a, 0), getInt (a, 1))) : var (jmax (getDouble (a, 0), getDouble (a, 1))); } | |||
static var Math_toDegrees (Args a) { return (180.0 / double_Pi) * getDouble (a, 0); } | |||
static var Math_toRadians (Args a) { return (double_Pi / 180.0) * getDouble (a, 0); } | |||
static var Math_toDegrees (Args a) { return radiansToDegrees (getDouble (a, 0)); } | |||
static var Math_toRadians (Args a) { return degreesToRadians (getDouble (a, 0)); } | |||
static var Math_sin (Args a) { return sin (getDouble (a, 0)); } | |||
static var Math_asin (Args a) { return asin (getDouble (a, 0)); } | |||
static var Math_cos (Args a) { return cos (getDouble (a, 0)); } | |||
@@ -354,6 +354,15 @@ const double double_Pi = 3.1415926535897932384626433832795; | |||
const float float_Pi = 3.14159265358979323846f; | |||
/** Converts an angle in degrees to radians. */ | |||
template <typename FloatType> | |||
inline FloatType degreesToRadians (FloatType degrees) noexcept { return degrees * static_cast<FloatType> (double_Pi / 180.0); } | |||
/** Converts an angle in radians to degrees. */ | |||
template <typename FloatType> | |||
inline FloatType radiansToDegrees (FloatType radians) noexcept { return radians * static_cast<FloatType> (180.0 / double_Pi); } | |||
//============================================================================== | |||
/** The isfinite() method seems to vary between platforms, so this is a | |||
platform-independent function for it. | |||
@@ -477,16 +486,14 @@ inline int roundFloatToInt (const float value) noexcept | |||
} | |||
//============================================================================== | |||
/** Returns true if the specified integer is a power-of-two. | |||
*/ | |||
/** Returns true if the specified integer is a power-of-two. */ | |||
template <typename IntegerType> | |||
bool isPowerOfTwo (IntegerType value) | |||
{ | |||
return (value & (value - 1)) == 0; | |||
} | |||
/** Returns the smallest power-of-two which is equal to or greater than the given integer. | |||
*/ | |||
/** Returns the smallest power-of-two which is equal to or greater than the given integer. */ | |||
inline int nextPowerOfTwo (int n) noexcept | |||
{ | |||
--n; | |||
@@ -533,6 +540,7 @@ NumericType square (NumericType n) noexcept | |||
return n * n; | |||
} | |||
//============================================================================== | |||
#if JUCE_INTEL || defined (DOXYGEN) | |||
/** This macro can be applied to a float variable to check whether it contains a denormalised | |||
@@ -64,6 +64,24 @@ inline int getAddressDifference (Type1* pointer1, Type2* pointer2) noexcept { r | |||
template <class Type> | |||
inline Type* createCopyIfNotNull (const Type* objectToCopy) { return objectToCopy != nullptr ? new Type (*objectToCopy) : nullptr; } | |||
//============================================================================== | |||
/** A handy function to read un-aligned memory without a performance penalty or bus-error. */ | |||
template <typename Type> | |||
inline Type readUnaligned (const void* srcPtr) noexcept | |||
{ | |||
Type value; | |||
memcpy (&value, srcPtr, sizeof (Type)); | |||
return value; | |||
} | |||
/** A handy function to write un-aligned memory without a performance penalty or bus-error. */ | |||
template <typename Type> | |||
inline void writeUnaligned (void* dstPtr, Type value) noexcept | |||
{ | |||
memcpy (dstPtr, &value, sizeof(Type)); | |||
} | |||
//============================================================================== | |||
#if JUCE_MAC || JUCE_IOS || DOXYGEN | |||
@@ -227,8 +227,14 @@ private: | |||
//============================================================================== | |||
#if defined (__arm__) | |||
#define JUCE_ARM_SOFT_FLOAT_ABI __attribute__ ((pcs("aapcs"))) | |||
#else | |||
#define JUCE_ARM_SOFT_FLOAT_ABI | |||
#endif | |||
#define JUCE_JNI_CALLBACK(className, methodName, returnType, params) \ | |||
extern "C" __attribute__ ((visibility("default"))) returnType JUCE_JOIN_MACRO (JUCE_JOIN_MACRO (Java_, className), _ ## methodName) params | |||
extern "C" __attribute__ ((visibility("default"))) JUCE_ARM_SOFT_FLOAT_ABI returnType JUCE_JOIN_MACRO (JUCE_JOIN_MACRO (Java_, className), _ ## methodName) params | |||
//============================================================================== | |||
class AndroidSystem | |||
@@ -987,7 +987,7 @@ void JUCE_CALLTYPE Thread::setCurrentThreadAffinityMask (const uint32 affinityMa | |||
if ((affinityMask & (1 << i)) != 0) | |||
CPU_SET (i, &affinity); | |||
#if (! JUCE_LINUX) || ((__GLIBC__ * 1000 + __GLIBC_MINOR__) >= 2004) | |||
#if (! JUCE_ANDROID) && ((! JUCE_LINUX) || ((__GLIBC__ * 1000 + __GLIBC_MINOR__) >= 2004)) | |||
pthread_setaffinity_np (pthread_self(), sizeof (cpu_set_t), &affinity); | |||
#else | |||
// NB: this call isn't really correct because it sets the affinity of the process, | |||
@@ -795,18 +795,19 @@ public: | |||
connected (false), ownsPipe (createPipe), shouldStop (false) | |||
{ | |||
if (createPipe) | |||
{ | |||
pipeH = CreateNamedPipe (filename.toWideCharPointer(), | |||
PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED, 0, | |||
PIPE_UNLIMITED_INSTANCES, 4096, 4096, 0, 0); | |||
if (GetLastError() == ERROR_ALREADY_EXISTS) | |||
closePipeHandle(); | |||
} | |||
} | |||
~Pimpl() | |||
{ | |||
disconnectPipe(); | |||
if (pipeH != INVALID_HANDLE_VALUE) | |||
CloseHandle (pipeH); | |||
closePipeHandle(); | |||
CloseHandle (cancelEvent); | |||
} | |||
@@ -868,6 +869,16 @@ public: | |||
} | |||
} | |||
void closePipeHandle() | |||
{ | |||
if (pipeH != INVALID_HANDLE_VALUE) | |||
{ | |||
disconnectPipe(); | |||
CloseHandle (pipeH); | |||
pipeH = INVALID_HANDLE_VALUE; | |||
} | |||
} | |||
int read (void* destBuffer, const int maxBytesToRead, const int timeOutMilliseconds) | |||
{ | |||
while (connect (timeOutMilliseconds)) | |||
@@ -113,11 +113,11 @@ | |||
#if _MSC_VER >= 1800 | |||
#define JUCE_COMPILER_SUPPORTS_INITIALIZER_LISTS 1 | |||
#define JUCE_COMPILER_SUPPORTS_VARIADIC_TEMPLATES 1 | |||
#define JUCE_DELETED_FUNCTION = delete | |||
#endif | |||
#if _MSC_VER >= 1900 | |||
#define JUCE_COMPILER_SUPPORTS_NOEXCEPT 1 | |||
#define JUCE_DELETED_FUNCTION = delete | |||
#endif | |||
#endif | |||
@@ -63,8 +63,8 @@ | |||
//============================================================================== | |||
#if JUCE_IOS || JUCE_LINUX || JUCE_ANDROID || JUCE_PPC | |||
/** This will try to break into the debugger if the app is currently being debugged. | |||
If called by an app that's not being debugged, the behaiour isn't defined - it may crash or not, depending | |||
on the platform. | |||
If called by an app that's not being debugged, the behaviour isn't defined - it may | |||
crash or not, depending on the platform. | |||
@see jassert() | |||
*/ | |||
#define juce_breakDebugger { ::kill (0, SIGTRAP); } | |||
@@ -328,7 +328,7 @@ void ZipFile::sortEntriesByFilename() | |||
//============================================================================== | |||
void ZipFile::init() | |||
{ | |||
ScopedPointer <InputStream> toDelete; | |||
ScopedPointer<InputStream> toDelete; | |||
InputStream* in = inputStream; | |||
if (inputSource != nullptr) | |||
@@ -358,7 +358,7 @@ void ZipFile::init() | |||
if (pos + 46 > size) | |||
break; | |||
const char* const buffer = static_cast <const char*> (headerData.getData()) + pos; | |||
const char* const buffer = static_cast<const char*> (headerData.getData()) + pos; | |||
const int fileNameLen = ByteOrder::littleEndianShort (buffer + 28); | |||
@@ -40,7 +40,7 @@ | |||
class JUCE_API ZipFile | |||
{ | |||
public: | |||
/** Creates a ZipFile based for a file. */ | |||
/** Creates a ZipFile to read a specific file. */ | |||
explicit ZipFile (const File& file); | |||
//============================================================================== | |||
@@ -91,15 +91,12 @@ public: | |||
int getNumEntries() const noexcept; | |||
/** Returns a structure that describes one of the entries in the zip file. | |||
This may return zero if the index is out of range. | |||
@see ZipFile::ZipEntry | |||
*/ | |||
const ZipEntry* getEntry (int index) const noexcept; | |||
/** Returns the index of the first entry with a given filename. | |||
This uses a case-sensitive comparison to look for a filename in the | |||
list of entries. It might return -1 if no match is found. | |||
@@ -116,8 +113,7 @@ public: | |||
*/ | |||
const ZipEntry* getEntry (const String& fileName) const noexcept; | |||
/** Sorts the list of entries, based on the filename. | |||
*/ | |||
/** Sorts the list of entries, based on the filename. */ | |||
void sortEntriesByFilename(); | |||
//============================================================================== | |||
@@ -128,6 +124,11 @@ public: | |||
The stream must not be used after the ZipFile object that created | |||
has been deleted. | |||
Note that if the ZipFile was created with a user-supplied InputStream object, | |||
then all the streams which are created by this method will by trying to share | |||
the same source stream, so cannot be safely used on multiple threads! (But if | |||
you create the ZipFile from a File or InputSource, then it is safe to do this). | |||
*/ | |||
InputStream* createStreamForEntry (int index); | |||
@@ -138,6 +139,11 @@ public: | |||
The stream must not be used after the ZipFile object that created | |||
has been deleted. | |||
Note that if the ZipFile was created with a user-supplied InputStream object, | |||
then all the streams which are created by this method will by trying to share | |||
the same source stream, so cannot be safely used on multiple threads! (But if | |||
you create the ZipFile from a File or InputSource, then it is safe to do this). | |||
*/ | |||
InputStream* createStreamForEntry (const ZipEntry& entry); | |||
@@ -194,7 +200,7 @@ public: | |||
will be stored for this file. | |||
*/ | |||
void addFile (const File& fileToAdd, int compressionLevel, | |||
const String& storedPathName = String::empty); | |||
const String& storedPathName = String()); | |||
/** Adds a file while should be added to the archive. | |||
@@ -233,11 +239,11 @@ private: | |||
friend class ZipInputStream; | |||
friend class ZipEntryHolder; | |||
OwnedArray <ZipEntryHolder> entries; | |||
OwnedArray<ZipEntryHolder> entries; | |||
CriticalSection lock; | |||
InputStream* inputStream; | |||
ScopedPointer <InputStream> streamToDelete; | |||
ScopedPointer <InputSource> inputSource; | |||
ScopedPointer<InputStream> streamToDelete; | |||
ScopedPointer<InputSource> inputSource; | |||
#if JUCE_DEBUG | |||
struct OpenStreamCounter | |||
@@ -111,11 +111,13 @@ public: | |||
static JUCEApplication* JUCE_CALLTYPE getInstance() noexcept; | |||
//============================================================================== | |||
#if DOXYGEN | |||
/** Returns the application's name. */ | |||
virtual const String getApplicationName() = 0; | |||
/** Returns the application's version number. */ | |||
virtual const String getApplicationVersion() = 0; | |||
#endif | |||
/** Checks whether multiple instances of the app are allowed. | |||
@@ -333,7 +333,6 @@ bool operator!= (const Desktop::Displays::Display& d1, const Desktop::Displays:: | |||
void Desktop::Displays::init (Desktop& desktop) | |||
{ | |||
findDisplays (desktop.getGlobalScaleFactor()); | |||
jassert (displays.size() > 0); | |||
} | |||
void Desktop::Displays::refresh() | |||
@@ -342,7 +341,6 @@ void Desktop::Displays::refresh() | |||
oldDisplays.swapWith (displays); | |||
init (Desktop::getInstance()); | |||
jassert (displays.size() > 0); | |||
if (oldDisplays != displays) | |||
{ | |||
@@ -272,7 +272,7 @@ public: | |||
if (parseNextNumber (d, num, false)) | |||
{ | |||
const float angle = num.getFloatValue() * (180.0f / float_Pi); | |||
const float angle = degreesToRadians (num.getFloatValue()); | |||
if (parseNextNumber (d, num, false)) | |||
{ | |||
@@ -1221,15 +1221,15 @@ private: | |||
} | |||
else if (t.startsWithIgnoreCase ("rotate")) | |||
{ | |||
trans = AffineTransform::rotation (numbers[0] / (180.0f / float_Pi), numbers[1], numbers[2]); | |||
trans = AffineTransform::rotation (degreesToRadians (numbers[0]), numbers[1], numbers[2]); | |||
} | |||
else if (t.startsWithIgnoreCase ("skewX")) | |||
{ | |||
trans = AffineTransform::shear (std::tan (numbers[0] * (float_Pi / 180.0f)), 0.0f); | |||
trans = AffineTransform::shear (std::tan (degreesToRadians (numbers[0])), 0.0f); | |||
} | |||
else if (t.startsWithIgnoreCase ("skewY")) | |||
{ | |||
trans = AffineTransform::shear (0.0f, std::tan (numbers[0] * (float_Pi / 180.0f))); | |||
trans = AffineTransform::shear (0.0f, std::tan (degreesToRadians (numbers[0]))); | |||
} | |||
result = trans.followedBy (result); | |||
@@ -1219,7 +1219,7 @@ public: | |||
getLookAndFeel().drawPopupMenuSectionHeader (g, getLocalBounds(), getName()); | |||
} | |||
void getIdealSize (int& idealWidth, int& idealHeight) | |||
void getIdealSize (int& idealWidth, int& idealHeight) override | |||
{ | |||
getLookAndFeel().getIdealPopupMenuItemSize (getName(), false, -1, idealWidth, idealHeight); | |||
idealHeight += idealHeight / 2; | |||
@@ -1698,9 +1698,9 @@ void PopupMenu::CustomComponent::setHighlighted (bool shouldBeHighlighted) | |||
void PopupMenu::CustomComponent::triggerMenuItem() | |||
{ | |||
if (HelperClasses::ItemComponent* const mic = dynamic_cast<HelperClasses::ItemComponent*> (getParentComponent())) | |||
if (HelperClasses::ItemComponent* const mic = findParentComponentOfClass<HelperClasses::ItemComponent>()) | |||
{ | |||
if (HelperClasses::MenuWindow* const pmw = dynamic_cast<HelperClasses::MenuWindow*> (mic->getParentComponent())) | |||
if (HelperClasses::MenuWindow* const pmw = mic->findParentComponentOfClass<HelperClasses::MenuWindow>()) | |||
{ | |||
pmw->dismissMenu (&mic->itemInfo); | |||
} | |||
@@ -135,7 +135,7 @@ static void addZenityArgs (StringArray& args, String& separator, | |||
tokens.addTokens (filters, ";,|", "\""); | |||
for (int i = 0; i < tokens.size(); ++i) | |||
args.add ("--file-filter='" + tokens[i] + "'"); | |||
args.add ("--file-filter=" + tokens[i]); | |||
} | |||
if (file.isDirectory()) | |||
@@ -2320,6 +2320,10 @@ public: | |||
XEvent nextEvent; | |||
ScopedXLock xlock; | |||
// if we have opengl contexts then just repaint them all | |||
// regardless if this is really necessary | |||
repaintOpenGLContexts (); | |||
if (exposeEvent.window != windowH) | |||
{ | |||
Window child; | |||
@@ -2509,6 +2513,28 @@ public: | |||
return currentScaleFactor; | |||
} | |||
//=============================================================================== | |||
void addOpenGLRepaintListener (Component* dummy) | |||
{ | |||
if (dummy != nullptr) | |||
glRepaintListeners.addIfNotAlreadyThere (dummy); | |||
} | |||
void removeOpenGLRepaintListener (Component* dummy) | |||
{ | |||
if (dummy != nullptr) | |||
glRepaintListeners.removeAllInstancesOf (dummy); | |||
} | |||
void repaintOpenGLContexts() | |||
{ | |||
for (int i = 0; i < glRepaintListeners.size(); ++i) | |||
{ | |||
if (Component* c = glRepaintListeners [i]) | |||
c->handleCommandMessage (0); | |||
} | |||
} | |||
//============================================================================== | |||
bool dontRepaint; | |||
@@ -2668,6 +2694,7 @@ private: | |||
BorderSize<int> windowBorder; | |||
bool isAlwaysOnTop; | |||
double currentScaleFactor; | |||
Array<Component*> glRepaintListeners; | |||
enum { KeyPressEventType = 2 }; | |||
struct MotifWmHints | |||
@@ -4125,6 +4152,18 @@ Rectangle<int> juce_LinuxScaledToPhysicalBounds(ComponentPeer* peer, const Recta | |||
return retval; | |||
} | |||
void juce_LinuxAddRepaintListener (ComponentPeer* peer, Component* dummy) | |||
{ | |||
if (LinuxComponentPeer* linuxPeer = dynamic_cast<LinuxComponentPeer*> (peer)) | |||
linuxPeer->addOpenGLRepaintListener (dummy); | |||
} | |||
void juce_LinuxRemoveRepaintListener (ComponentPeer* peer, Component* dummy) | |||
{ | |||
if (LinuxComponentPeer* linuxPeer = dynamic_cast<LinuxComponentPeer*> (peer)) | |||
linuxPeer->removeOpenGLRepaintListener (dummy); | |||
} | |||
//============================================================================== | |||
#if JUCE_MODAL_LOOPS_PERMITTED | |||
void JUCE_CALLTYPE NativeMessageBox::showMessageBox (AlertWindow::AlertIconType iconType, | |||
@@ -218,8 +218,6 @@ void FileChooser::showPlatformDialog (Array<File>& results, const String& title_ | |||
info.customComponent->enterModalState(); | |||
} | |||
const StringRef separatorTokens (";,|"); | |||
const size_t filterSpaceNumChars = 2048; | |||
HeapBlock<WCHAR> filters; | |||
filters.calloc (filterSpaceNumChars); | |||
@@ -228,7 +226,7 @@ void FileChooser::showPlatformDialog (Array<File>& results, const String& title_ | |||
((filterSpaceNumChars - 1) * sizeof (WCHAR) - bytesWritten)); | |||
for (int i = 0; i < filterSpaceNumChars; ++i) | |||
if (separatorTokens.text.indexOf ((juce_wchar) filters[i]) >= 0) | |||
if (filters[i] == '|') | |||
filters[i] = 0; | |||
OPENFILENAMEW of = { 0 }; | |||
@@ -255,7 +253,7 @@ void FileChooser::showPlatformDialog (Array<File>& results, const String& title_ | |||
if (isSaveDialogue) | |||
{ | |||
StringArray tokens; | |||
tokens.addTokens (filter, separatorTokens, "\"'"); | |||
tokens.addTokens (filter, ";,", "\"'"); | |||
tokens.trim(); | |||
tokens.removeEmptyStrings(); | |||