diff --git a/source/modules/juce_audio_basics/buffers/juce_FloatVectorOperations.cpp b/source/modules/juce_audio_basics/buffers/juce_FloatVectorOperations.cpp index a232ec988..308ac8457 100644 --- a/source/modules/juce_audio_basics/buffers/juce_FloatVectorOperations.cpp +++ b/source/modules/juce_audio_basics/buffers/juce_FloatVectorOperations.cpp @@ -412,7 +412,7 @@ void JUCE_CALLTYPE FloatVectorOperations::copy (double* dest, const double* src, void JUCE_CALLTYPE FloatVectorOperations::copyWithMultiply (float* dest, const float* src, float multiplier, int num) noexcept { #if JUCE_USE_VDSP_FRAMEWORK - vDSP_vsmul (src, 1, &multiplier, dest, 1, num); + vDSP_vsmul (src, 1, &multiplier, dest, 1, (vDSP_Length) num); #else JUCE_PERFORM_VEC_OP_SRC_DEST (dest[i] = src[i] * multiplier, Mode::mul (mult, s), JUCE_LOAD_SRC, JUCE_INCREMENT_SRC_DEST, @@ -423,7 +423,7 @@ void JUCE_CALLTYPE FloatVectorOperations::copyWithMultiply (float* dest, const f void JUCE_CALLTYPE FloatVectorOperations::copyWithMultiply (double* dest, const double* src, double multiplier, int num) noexcept { #if JUCE_USE_VDSP_FRAMEWORK - vDSP_vsmulD (src, 1, &multiplier, dest, 1, num); + vDSP_vsmulD (src, 1, &multiplier, dest, 1, (vDSP_Length) num); #else JUCE_PERFORM_VEC_OP_SRC_DEST (dest[i] = src[i] * multiplier, Mode::mul (mult, s), JUCE_LOAD_SRC, JUCE_INCREMENT_SRC_DEST, @@ -446,7 +446,7 @@ void JUCE_CALLTYPE FloatVectorOperations::add (double* dest, double amount, int void JUCE_CALLTYPE FloatVectorOperations::add (float* dest, const float* src, int num) noexcept { #if JUCE_USE_VDSP_FRAMEWORK - vDSP_vadd (src, 1, dest, 1, dest, 1, num); + vDSP_vadd (src, 1, dest, 1, dest, 1, (vDSP_Length) num); #else JUCE_PERFORM_VEC_OP_SRC_DEST (dest[i] += src[i], Mode::add (d, s), JUCE_LOAD_SRC_DEST, JUCE_INCREMENT_SRC_DEST, ) #endif @@ -455,7 +455,7 @@ void JUCE_CALLTYPE FloatVectorOperations::add (float* dest, const float* src, in void JUCE_CALLTYPE FloatVectorOperations::add (double* dest, const double* src, int num) noexcept { #if JUCE_USE_VDSP_FRAMEWORK - vDSP_vaddD (src, 1, dest, 1, dest, 1, num); + vDSP_vaddD (src, 1, dest, 1, dest, 1, (vDSP_Length) num); #else JUCE_PERFORM_VEC_OP_SRC_DEST (dest[i] += src[i], Mode::add (d, s), JUCE_LOAD_SRC_DEST, JUCE_INCREMENT_SRC_DEST, ) #endif @@ -464,7 +464,7 @@ void JUCE_CALLTYPE FloatVectorOperations::add (double* dest, const double* src, void JUCE_CALLTYPE FloatVectorOperations::subtract (float* dest, const float* src, int num) noexcept { #if JUCE_USE_VDSP_FRAMEWORK - vDSP_vsub (src, 1, dest, 1, dest, 1, num); + vDSP_vsub (src, 1, dest, 1, dest, 1, (vDSP_Length) num); #else JUCE_PERFORM_VEC_OP_SRC_DEST (dest[i] -= src[i], Mode::sub (d, s), JUCE_LOAD_SRC_DEST, JUCE_INCREMENT_SRC_DEST, ) #endif @@ -473,7 +473,7 @@ void JUCE_CALLTYPE FloatVectorOperations::subtract (float* dest, const float* sr void JUCE_CALLTYPE FloatVectorOperations::subtract (double* dest, const double* src, int num) noexcept { #if JUCE_USE_VDSP_FRAMEWORK - vDSP_vsubD (src, 1, dest, 1, dest, 1, num); + vDSP_vsubD (src, 1, dest, 1, dest, 1, (vDSP_Length) num); #else JUCE_PERFORM_VEC_OP_SRC_DEST (dest[i] -= src[i], Mode::sub (d, s), JUCE_LOAD_SRC_DEST, JUCE_INCREMENT_SRC_DEST, ) #endif @@ -496,7 +496,7 @@ void JUCE_CALLTYPE FloatVectorOperations::addWithMultiply (double* dest, const d void JUCE_CALLTYPE FloatVectorOperations::multiply (float* dest, const float* src, int num) noexcept { #if JUCE_USE_VDSP_FRAMEWORK - vDSP_vmul (src, 1, dest, 1, dest, 1, num); + vDSP_vmul (src, 1, dest, 1, dest, 1, (vDSP_Length) num); #else JUCE_PERFORM_VEC_OP_SRC_DEST (dest[i] *= src[i], Mode::mul (d, s), JUCE_LOAD_SRC_DEST, JUCE_INCREMENT_SRC_DEST, ) #endif @@ -505,7 +505,7 @@ void JUCE_CALLTYPE FloatVectorOperations::multiply (float* dest, const float* sr void JUCE_CALLTYPE FloatVectorOperations::multiply (double* dest, const double* src, int num) noexcept { #if JUCE_USE_VDSP_FRAMEWORK - vDSP_vmulD (src, 1, dest, 1, dest, 1, num); + vDSP_vmulD (src, 1, dest, 1, dest, 1, (vDSP_Length) num); #else JUCE_PERFORM_VEC_OP_SRC_DEST (dest[i] *= src[i], Mode::mul (d, s), JUCE_LOAD_SRC_DEST, JUCE_INCREMENT_SRC_DEST, ) #endif @@ -514,7 +514,7 @@ void JUCE_CALLTYPE FloatVectorOperations::multiply (double* dest, const double* void JUCE_CALLTYPE FloatVectorOperations::multiply (float* dest, float multiplier, int num) noexcept { #if JUCE_USE_VDSP_FRAMEWORK - vDSP_vsmul (dest, 1, &multiplier, dest, 1, num); + vDSP_vsmul (dest, 1, &multiplier, dest, 1, (vDSP_Length) num); #else JUCE_PERFORM_VEC_OP_DEST (dest[i] *= multiplier, Mode::mul (d, mult), JUCE_LOAD_DEST, const Mode::ParallelType mult = Mode::load1 (multiplier);) @@ -524,7 +524,7 @@ void JUCE_CALLTYPE FloatVectorOperations::multiply (float* dest, float multiplie void JUCE_CALLTYPE FloatVectorOperations::multiply (double* dest, double multiplier, int num) noexcept { #if JUCE_USE_VDSP_FRAMEWORK - vDSP_vsmulD (dest, 1, &multiplier, dest, 1, num); + vDSP_vsmulD (dest, 1, &multiplier, dest, 1, (vDSP_Length) num); #else JUCE_PERFORM_VEC_OP_DEST (dest[i] *= multiplier, Mode::mul (d, mult), JUCE_LOAD_DEST, const Mode::ParallelType mult = Mode::load1 (multiplier);) @@ -643,8 +643,8 @@ public: const int range = random.nextBool() ? 500 : 10; const int num = random.nextInt (range) + 1; - HeapBlock buffer1 (num + 16), buffer2 (num + 16); - HeapBlock buffer3 (num + 16); + HeapBlock buffer1 ((size_t) num + 16), buffer2 ((size_t) num + 16); + HeapBlock buffer3 ((size_t) num + 16); #if JUCE_ARM ValueType* const data1 = buffer1; diff --git a/source/modules/juce_audio_basics/midi/juce_MidiBuffer.cpp b/source/modules/juce_audio_basics/midi/juce_MidiBuffer.cpp index 0a6a1f916..43ab4c175 100644 --- a/source/modules/juce_audio_basics/midi/juce_MidiBuffer.cpp +++ b/source/modules/juce_audio_basics/midi/juce_MidiBuffer.cpp @@ -210,7 +210,7 @@ bool MidiBuffer::Iterator::getNextEvent (const uint8* &midiData, int& numBytes, const int itemSize = MidiBufferHelpers::getEventDataSize (data); numBytes = itemSize; midiData = data + sizeof (int32) + sizeof (uint16); - data += sizeof (int32) + sizeof (uint16) + itemSize; + data += sizeof (int32) + sizeof (uint16) + (size_t) itemSize; return true; } @@ -223,7 +223,7 @@ bool MidiBuffer::Iterator::getNextEvent (MidiMessage& result, int& samplePositio samplePosition = MidiBufferHelpers::getEventTime (data); const int itemSize = MidiBufferHelpers::getEventDataSize (data); result = MidiMessage (data + sizeof (int32) + sizeof (uint16), itemSize, samplePosition); - data += sizeof (int32) + sizeof (uint16) + itemSize; + data += sizeof (int32) + sizeof (uint16) + (size_t) itemSize; return true; } diff --git a/source/modules/juce_audio_basics/midi/juce_MidiMessage.cpp b/source/modules/juce_audio_basics/midi/juce_MidiMessage.cpp index 18733a30d..bf5e19e9a 100644 --- a/source/modules/juce_audio_basics/midi/juce_MidiMessage.cpp +++ b/source/modules/juce_audio_basics/midi/juce_MidiMessage.cpp @@ -129,7 +129,7 @@ MidiMessage::MidiMessage (const MidiMessage& other) { if (other.allocatedData != nullptr) { - allocatedData.malloc (size); + allocatedData.malloc ((size_t) size); memcpy (allocatedData, other.allocatedData, (size_t) size); } else @@ -143,7 +143,7 @@ MidiMessage::MidiMessage (const MidiMessage& other, const double newTimeStamp) { if (other.allocatedData != nullptr) { - allocatedData.malloc (size); + allocatedData.malloc ((size_t) size); memcpy (allocatedData, other.allocatedData, (size_t) size); } else @@ -255,7 +255,7 @@ MidiMessage& MidiMessage::operator= (const MidiMessage& other) if (other.allocatedData != nullptr) { - allocatedData.malloc (size); + allocatedData.malloc ((size_t) size); memcpy (allocatedData, other.allocatedData, (size_t) size); } else @@ -297,7 +297,7 @@ uint8* MidiMessage::allocateSpace (int bytes) { if (bytes > 4) { - allocatedData.malloc (bytes); + allocatedData.malloc ((size_t) bytes); return allocatedData; } diff --git a/source/modules/juce_audio_basics/sources/juce_ResamplingAudioSource.cpp b/source/modules/juce_audio_basics/sources/juce_ResamplingAudioSource.cpp index 52fc7302e..44c3dada0 100644 --- a/source/modules/juce_audio_basics/sources/juce_ResamplingAudioSource.cpp +++ b/source/modules/juce_audio_basics/sources/juce_ResamplingAudioSource.cpp @@ -47,23 +47,28 @@ void ResamplingAudioSource::setResamplingRatio (const double samplesInPerOutputS ratio = jmax (0.0, samplesInPerOutputSample); } -void ResamplingAudioSource::prepareToPlay (int samplesPerBlockExpected, - double sampleRate) +void ResamplingAudioSource::prepareToPlay (int samplesPerBlockExpected, double sampleRate) { const SpinLock::ScopedLockType sl (ratioLock); input->prepareToPlay (samplesPerBlockExpected, sampleRate); buffer.setSize (numChannels, roundToInt (samplesPerBlockExpected * ratio) + 32); - buffer.clear(); - sampsInBuffer = 0; - bufferPos = 0; - subSampleOffset = 0.0; filterStates.calloc ((size_t) numChannels); srcBuffers.calloc ((size_t) numChannels); destBuffers.calloc ((size_t) numChannels); createLowPass (ratio); + + flushBuffers(); +} + +void ResamplingAudioSource::flushBuffers() +{ + buffer.clear(); + bufferPos = 0; + sampsInBuffer = 0; + subSampleOffset = 0.0; resetFilters(); } diff --git a/source/modules/juce_audio_basics/sources/juce_ResamplingAudioSource.h b/source/modules/juce_audio_basics/sources/juce_ResamplingAudioSource.h index 20886e68b..09d27a875 100644 --- a/source/modules/juce_audio_basics/sources/juce_ResamplingAudioSource.h +++ b/source/modules/juce_audio_basics/sources/juce_ResamplingAudioSource.h @@ -66,6 +66,9 @@ public: */ double getResamplingRatio() const noexcept { return ratio; } + /** Clears any buffers and filters that the resampler is using. */ + void flushBuffers(); + //============================================================================== void prepareToPlay (int samplesPerBlockExpected, double sampleRate) override; void releaseResources() override; diff --git a/source/modules/juce_audio_devices/native/juce_mac_CoreAudio.cpp b/source/modules/juce_audio_devices/native/juce_mac_CoreAudio.cpp index e51dd7c0a..d7044eb13 100644 --- a/source/modules/juce_audio_devices/native/juce_mac_CoreAudio.cpp +++ b/source/modules/juce_audio_devices/native/juce_mac_CoreAudio.cpp @@ -233,7 +233,7 @@ public: size = sizeof (nameNSString); pa.mSelector = kAudioObjectPropertyElementName; - pa.mElement = chanNum + 1; + pa.mElement = (AudioObjectPropertyElement) chanNum + 1; if (AudioObjectGetPropertyData (deviceID, &pa, 0, nullptr, &size, &nameNSString) == noErr) { @@ -394,7 +394,7 @@ public: if (OK (AudioObjectGetPropertyData (deviceID, &pa, 0, nullptr, &size, &sr))) sampleRate = sr; - UInt32 framesPerBuf = bufferSize; + UInt32 framesPerBuf = (UInt32) bufferSize; size = sizeof (framesPerBuf); pa.mSelector = kAudioDevicePropertyBufferFrameSize; AudioObjectGetPropertyData (deviceID, &pa, 0, nullptr, &size, &framesPerBuf); diff --git a/source/modules/juce_audio_devices/sources/juce_AudioTransportSource.cpp b/source/modules/juce_audio_devices/sources/juce_AudioTransportSource.cpp index e923b4618..feb58a983 100644 --- a/source/modules/juce_audio_devices/sources/juce_AudioTransportSource.cpp +++ b/source/modules/juce_audio_devices/sources/juce_AudioTransportSource.cpp @@ -182,6 +182,10 @@ void AudioTransportSource::setNextReadPosition (int64 newPosition) newPosition = (int64) (newPosition * sourceSampleRate / sampleRate); positionableSource->setNextReadPosition (newPosition); + + if (resamplerSource != nullptr) + resamplerSource->flushBuffers(); + inputStreamEOF = false; } } diff --git a/source/modules/juce_audio_formats/format/juce_AudioFormatReader.cpp b/source/modules/juce_audio_formats/format/juce_AudioFormatReader.cpp index 501e33921..071f82508 100644 --- a/source/modules/juce_audio_formats/format/juce_AudioFormatReader.cpp +++ b/source/modules/juce_audio_formats/format/juce_AudioFormatReader.cpp @@ -162,7 +162,7 @@ void AudioFormatReader::read (AudioSampleBuffer* buffer, } else { - HeapBlock chans (numTargetChannels); + HeapBlock chans ((size_t) numTargetChannels); readChannels (*this, chans, buffer, startSample, numSamples, readerStartSample, numTargetChannels); } diff --git a/source/modules/juce_audio_processors/format_types/juce_AudioUnitPluginFormat.mm b/source/modules/juce_audio_processors/format_types/juce_AudioUnitPluginFormat.mm index a4e58b164..fb19e8b6e 100644 --- a/source/modules/juce_audio_processors/format_types/juce_AudioUnitPluginFormat.mm +++ b/source/modules/juce_audio_processors/format_types/juce_AudioUnitPluginFormat.mm @@ -972,16 +972,11 @@ private: for (int i = 0; i < parameters.size(); ++i) { - const ParamInfo& p = *parameters.getUnchecked(i); - - AudioUnitParameter paramToAdd; - paramToAdd.mAudioUnit = audioUnit; - paramToAdd.mParameterID = p.paramID; - paramToAdd.mScope = kAudioUnitScope_Global; - paramToAdd.mElement = 0; - AudioUnitEvent event; - event.mArgument.mParameter = paramToAdd; + event.mArgument.mParameter.mAudioUnit = audioUnit; + event.mArgument.mParameter.mParameterID = parameters.getUnchecked(i)->paramID; + event.mArgument.mParameter.mScope = kAudioUnitScope_Global; + event.mArgument.mParameter.mElement = 0; event.mEventType = kAudioUnitEvent_ParameterValueChange; AUEventListenerAddEventType (eventListenerRef, nullptr, &event); @@ -992,6 +987,16 @@ private: event.mEventType = kAudioUnitEvent_EndParameterChangeGesture; AUEventListenerAddEventType (eventListenerRef, nullptr, &event); } + + // Add a listener for program changes + AudioUnitEvent event; + event.mArgument.mProperty.mAudioUnit = audioUnit; + event.mArgument.mProperty.mPropertyID = kAudioUnitProperty_PresentPreset; + event.mArgument.mProperty.mScope = kAudioUnitScope_Global; + event.mArgument.mProperty.mElement = 0; + + event.mEventType = kAudioUnitEvent_PropertyChange; + AUEventListenerAddEventType (eventListenerRef, nullptr, &event); } } @@ -1022,6 +1027,7 @@ private: break; default: + sendAllParametersChangedEvents(); break; } } diff --git a/source/modules/juce_audio_processors/juce_audio_processors.cpp b/source/modules/juce_audio_processors/juce_audio_processors.cpp index 78d338767..43934d6ca 100644 --- a/source/modules/juce_audio_processors/juce_audio_processors.cpp +++ b/source/modules/juce_audio_processors/juce_audio_processors.cpp @@ -112,27 +112,24 @@ struct AutoResizingNSViewComponentWithParent : public AutoResizingNSViewCompone setView (v); [v release]; - startTimer (100); + startTimer (30); } - void timerCallback() override + NSView* getChildView() const { if (NSView* parent = (NSView*) getView()) - { if ([[parent subviews] count] > 0) - { - if (NSView* child = [[parent subviews] objectAtIndex: 0]) - { - NSRect f = [parent frame]; - NSSize newSize = [child frame].size; - - if (f.size.width != newSize.width || f.size.height != newSize.height) - { - f.size = newSize; - [parent setFrame: f]; - } - } - } + return [[parent subviews] objectAtIndex: 0]; + + return nil; + } + + void timerCallback() override + { + if (NSView* child = getChildView()) + { + stopTimer(); + setView (child); } } }; diff --git a/source/modules/juce_audio_processors/processors/juce_AudioProcessor.h b/source/modules/juce_audio_processors/processors/juce_AudioProcessor.h index 92542b9b2..6d663fd28 100644 --- a/source/modules/juce_audio_processors/processors/juce_AudioProcessor.h +++ b/source/modules/juce_audio_processors/processors/juce_AudioProcessor.h @@ -289,9 +289,9 @@ public: filter will return an empty buffer, but won't block the audio thread like it would do if you use the getCallbackLock() critical section to synchronise access. - If you're going to use this, your processBlock() method must call isSuspended() and - check whether it's suspended or not. If it is, then it should skip doing any real - processing, either emitting silence or passing the input through unchanged. + Any code that calls processBlock() should call isSuspended() before doing so, and + if the processor is suspended, it should avoid the call and emit silence or + whatever is appropriate. @see getCallbackLock */ diff --git a/source/modules/juce_audio_processors/processors/juce_AudioProcessorGraph.h b/source/modules/juce_audio_processors/processors/juce_AudioProcessorGraph.h index 5e44b1d02..d94468235 100644 --- a/source/modules/juce_audio_processors/processors/juce_AudioProcessorGraph.h +++ b/source/modules/juce_audio_processors/processors/juce_AudioProcessorGraph.h @@ -396,7 +396,6 @@ private: Array renderingOps; friend class AudioGraphIOProcessor; - friend class CarlaPluginInstance; AudioSampleBuffer* currentAudioInputBuffer; AudioSampleBuffer currentAudioOutputBuffer; MidiBuffer* currentMidiInputBuffer; diff --git a/source/modules/juce_core/containers/juce_ReferenceCountedArray.h b/source/modules/juce_core/containers/juce_ReferenceCountedArray.h index 8de5ec9c5..d33343d95 100644 --- a/source/modules/juce_core/containers/juce_ReferenceCountedArray.h +++ b/source/modules/juce_core/containers/juce_ReferenceCountedArray.h @@ -72,7 +72,7 @@ public: const ScopedLockType lock (other.getLock()); numUsed = other.size(); data.setAllocatedSize (numUsed); - memcpy (data.elements, other.getRawDataPointer(), numUsed * sizeof (ObjectClass*)); + memcpy (data.elements, other.getRawDataPointer(), (size_t) numUsed * sizeof (ObjectClass*)); for (int i = numUsed; --i >= 0;) if (ObjectClass* o = data.elements[i]) diff --git a/source/modules/juce_core/javascript/juce_Javascript.cpp b/source/modules/juce_core/javascript/juce_Javascript.cpp index 16641d64a..af99a84eb 100644 --- a/source/modules/juce_core/javascript/juce_Javascript.cpp +++ b/source/modules/juce_core/javascript/juce_Javascript.cpp @@ -543,14 +543,14 @@ struct JavascriptEngine::RootObject : public DynamicObject struct DivideOp : public BinaryOperator { DivideOp (const CodeLocation& l, ExpPtr& a, ExpPtr& b) noexcept : BinaryOperator (l, a, b, TokenTypes::divide) {} - var getWithDoubles (double a, double b) const override { return a / b; } - var getWithInts (int64 a, int64 b) const override { return a / b; } + var getWithDoubles (double a, double b) const override { return b != 0 ? a / b : std::numeric_limits::infinity(); } + var getWithInts (int64 a, int64 b) const override { return b != 0 ? var (a / b) : var (std::numeric_limits::infinity()); } }; struct ModuloOp : public BinaryOperator { ModuloOp (const CodeLocation& l, ExpPtr& a, ExpPtr& b) noexcept : BinaryOperator (l, a, b, TokenTypes::modulo) {} - var getWithInts (int64 a, int64 b) const override { return a % b; } + var getWithInts (int64 a, int64 b) const override { return b != 0 ? var (a % b) : var (std::numeric_limits::infinity()); } }; struct BitwiseOrOp : public BinaryOperator @@ -843,7 +843,7 @@ struct JavascriptEngine::RootObject : public DynamicObject String::CharPointerType end (p); while (isIdentifierBody (*++end)) {} - const size_t len = end - p; + const size_t len = (size_t) (end - p); #define JUCE_JS_COMPARE_KEYWORD(name, str) if (len == sizeof (str) - 1 && matchToken (TokenTypes::name, len)) return TokenTypes::name; JUCE_JS_KEYWORDS (JUCE_JS_COMPARE_KEYWORD) diff --git a/source/modules/juce_core/maths/juce_BigInteger.cpp b/source/modules/juce_core/maths/juce_BigInteger.cpp index ba194145c..b1c42b6f8 100644 --- a/source/modules/juce_core/maths/juce_BigInteger.cpp +++ b/source/modules/juce_core/maths/juce_BigInteger.cpp @@ -311,37 +311,24 @@ void BigInteger::negate() noexcept #pragma intrinsic (_BitScanReverse) #endif -namespace BitFunctions -{ - inline int countBitsInInt32 (uint32 n) noexcept - { - n -= ((n >> 1) & 0x55555555); - n = (((n >> 2) & 0x33333333) + (n & 0x33333333)); - n = (((n >> 4) + n) & 0x0f0f0f0f); - n += (n >> 8); - n += (n >> 16); - return (int) (n & 0x3f); - } - - inline int highestBitInInt (uint32 n) noexcept - { - jassert (n != 0); // (the built-in functions may not work for n = 0) - - #if JUCE_GCC - return 31 - __builtin_clz (n); - #elif JUCE_USE_INTRINSICS - unsigned long highest; - _BitScanReverse (&highest, n); - return (int) highest; - #else - n |= (n >> 1); - n |= (n >> 2); - n |= (n >> 4); - n |= (n >> 8); - n |= (n >> 16); - return countBitsInInt32 (n >> 1); - #endif - } +inline static int highestBitInInt (uint32 n) noexcept +{ + jassert (n != 0); // (the built-in functions may not work for n = 0) + + #if JUCE_GCC + return 31 - __builtin_clz (n); + #elif JUCE_USE_INTRINSICS + unsigned long highest; + _BitScanReverse (&highest, n); + return (int) highest; + #else + n |= (n >> 1); + n |= (n >> 2); + n |= (n >> 4); + n |= (n >> 8); + n |= (n >> 16); + return countBitsInInt32 (n >> 1); + #endif } int BigInteger::countNumberOfSetBits() const noexcept @@ -349,7 +336,7 @@ int BigInteger::countNumberOfSetBits() const noexcept int total = 0; for (int i = (int) bitToIndex (highestBit) + 1; --i >= 0;) - total += BitFunctions::countBitsInInt32 (values[i]); + total += countNumberOfBits (values[i]); return total; } @@ -361,7 +348,7 @@ int BigInteger::getHighestBit() const noexcept const uint32 n = values[i]; if (n != 0) - return BitFunctions::highestBitInInt (n) + (i << 5); + return highestBitInInt (n) + (i << 5); } return -1; diff --git a/source/modules/juce_core/maths/juce_MathsFunctions.h b/source/modules/juce_core/maths/juce_MathsFunctions.h index d62ed1794..d2d02b900 100644 --- a/source/modules/juce_core/maths/juce_MathsFunctions.h +++ b/source/modules/juce_core/maths/juce_MathsFunctions.h @@ -443,6 +443,23 @@ inline int nextPowerOfTwo (int n) noexcept return n + 1; } +/** Returns the number of bits in a 32-bit integer. */ +inline int countNumberOfBits (uint32 n) noexcept +{ + n -= ((n >> 1) & 0x55555555); + n = (((n >> 2) & 0x33333333) + (n & 0x33333333)); + n = (((n >> 4) + n) & 0x0f0f0f0f); + n += (n >> 8); + n += (n >> 16); + return (int) (n & 0x3f); +} + +/** Returns the number of bits in a 64-bit integer. */ +inline int countNumberOfBits (uint64 n) noexcept +{ + return countNumberOfBits ((uint32) n) + countNumberOfBits ((uint32) (n >> 32)); +} + /** Performs a modulo operation, but can cope with the dividend being negative. The divisor must be greater than zero. */ diff --git a/source/modules/juce_core/native/juce_android_JNIHelpers.h b/source/modules/juce_core/native/juce_android_JNIHelpers.h index 9d58ae671..8e8b07d3a 100644 --- a/source/modules/juce_core/native/juce_android_JNIHelpers.h +++ b/source/modules/juce_core/native/juce_android_JNIHelpers.h @@ -362,6 +362,12 @@ private: extern ThreadLocalJNIEnvHolder threadLocalJNIEnvHolder; +struct AndroidThreadScope +{ + AndroidThreadScope() { threadLocalJNIEnvHolder.attach(); } + ~AndroidThreadScope() { threadLocalJNIEnvHolder.detach(); } +}; + //============================================================================== #define JNI_CLASS_MEMBERS(METHOD, STATICMETHOD, FIELD, STATICFIELD) \ METHOD (createNewView, "createNewView", "(ZJ)L" JUCE_ANDROID_ACTIVITY_CLASSPATH "$ComponentPeerView;") \ diff --git a/source/modules/juce_core/native/juce_posix_SharedCode.h b/source/modules/juce_core/native/juce_posix_SharedCode.h index d7910d81d..914ff665f 100644 --- a/source/modules/juce_core/native/juce_posix_SharedCode.h +++ b/source/modules/juce_core/native/juce_posix_SharedCode.h @@ -849,12 +849,6 @@ extern "C" void* threadEntryProc (void* userData) JUCE_AUTORELEASEPOOL { #if JUCE_ANDROID - struct AndroidThreadScope - { - AndroidThreadScope() { threadLocalJNIEnvHolder.attach(); } - ~AndroidThreadScope() { threadLocalJNIEnvHolder.detach(); } - }; - const AndroidThreadScope androidEnv; #endif @@ -1169,15 +1163,23 @@ struct HighResolutionTimer::Pimpl { if (periodMs != newPeriod) { - stop(); - periodMs = newPeriod; + if (thread != pthread_self()) + { + stop(); - shouldStop = false; + periodMs = newPeriod; + shouldStop = false; - if (pthread_create (&thread, nullptr, timerThread, this) == 0) - setThreadToRealtime (thread, (uint64) newPeriod); + if (pthread_create (&thread, nullptr, timerThread, this) == 0) + setThreadToRealtime (thread, (uint64) newPeriod); + else + jassertfalse; + } else - jassertfalse; + { + periodMs = newPeriod; + shouldStop = false; + } } } @@ -1201,7 +1203,9 @@ private: static void* timerThread (void* param) { - #if ! JUCE_ANDROID + #if JUCE_ANDROID + const AndroidThreadScope androidEnv; + #else int dummy; pthread_setcancelstate (PTHREAD_CANCEL_ENABLE, &dummy); #endif @@ -1212,12 +1216,19 @@ private: void timerThread() { - Clock clock (periodMs); + int lastPeriod = periodMs; + Clock clock (lastPeriod); while (! shouldStop) { clock.wait(); owner.hiResTimerCallback(); + + if (lastPeriod != periodMs) + { + lastPeriod = periodMs; + clock = Clock (lastPeriod); + } } periodMs = 0; diff --git a/source/modules/juce_core/native/juce_win32_ComSmartPtr.h b/source/modules/juce_core/native/juce_win32_ComSmartPtr.h index a5cd043a7..0dc0efc20 100644 --- a/source/modules/juce_core/native/juce_win32_ComSmartPtr.h +++ b/source/modules/juce_core/native/juce_win32_ComSmartPtr.h @@ -29,8 +29,7 @@ #ifndef JUCE_WIN32_COMSMARTPTR_H_INCLUDED #define JUCE_WIN32_COMSMARTPTR_H_INCLUDED -// FIXME -#if 1 //! (defined (_MSC_VER) || defined (__uuidof)) +#if ! (defined (_MSC_VER) || defined (__uuidof)) template struct UUIDGetter { static CLSID get() { jassertfalse; return CLSID(); } }; #define __uuidof(x) UUIDGetter::get() #endif diff --git a/source/modules/juce_core/native/juce_win32_Network.cpp b/source/modules/juce_core/native/juce_win32_Network.cpp index e7af2c1b3..1b354532a 100644 --- a/source/modules/juce_core/native/juce_win32_Network.cpp +++ b/source/modules/juce_core/native/juce_win32_Network.cpp @@ -259,7 +259,8 @@ private: { const TCHAR* mimeTypes[] = { _T("*/*"), nullptr }; - DWORD flags = INTERNET_FLAG_RELOAD | INTERNET_FLAG_NO_CACHE_WRITE | INTERNET_FLAG_NO_COOKIES; + DWORD flags = INTERNET_FLAG_RELOAD | INTERNET_FLAG_NO_CACHE_WRITE | INTERNET_FLAG_NO_COOKIES + | INTERNET_FLAG_NO_AUTO_REDIRECT | SECURITY_SET_MASK; if (address.startsWithIgnoreCase ("https:")) flags |= INTERNET_FLAG_SECURE; // (this flag only seems necessary if the OS is running IE6 - @@ -270,6 +271,8 @@ private: if (request != 0) { + setSecurityFlags(); + INTERNET_BUFFERS buffers = { 0 }; buffers.dwStructSize = sizeof (INTERNET_BUFFERS); buffers.lpcszHeader = headers.toWideCharPointer(); @@ -313,6 +316,14 @@ private: close(); } + void setSecurityFlags() + { + DWORD dwFlags = 0, dwBuffLen = sizeof (DWORD); + InternetQueryOption (request, INTERNET_OPTION_SECURITY_FLAGS, &dwFlags, &dwBuffLen); + dwFlags |= SECURITY_FLAG_IGNORE_UNKNOWN_CA | SECURITY_SET_MASK; + InternetSetOption (request, INTERNET_OPTION_SECURITY_FLAGS, &dwFlags, sizeof (dwFlags)); + } + JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (WebInputStream) }; diff --git a/source/modules/juce_core/native/juce_win32_SystemStats.cpp b/source/modules/juce_core/native/juce_win32_SystemStats.cpp index 44065cdb8..901bc761f 100644 --- a/source/modules/juce_core/native/juce_win32_SystemStats.cpp +++ b/source/modules/juce_core/native/juce_win32_SystemStats.cpp @@ -253,9 +253,23 @@ public: HiResCounterHandler() : hiResTicksOffset (0) { - const MMRESULT res = timeBeginPeriod (1); + // This macro allows you to override the default timer-period + // used on Windows. By default this is set to 1, because that has + // always been the value used in JUCE apps, and changing it could + // affect the behaviour of existing code, but you may wish to make + // it larger (or set it to 0 to use the system default) to make your + // app less demanding on the CPU. + // For more info, see win32 documentation about the timeBeginPeriod + // function. + #ifndef JUCE_WIN32_TIMER_PERIOD + #define JUCE_WIN32_TIMER_PERIOD 1 + #endif + + #if JUCE_WIN32_TIMER_PERIOD > 0 + const MMRESULT res = timeBeginPeriod (JUCE_WIN32_TIMER_PERIOD); (void) res; jassert (res == TIMERR_NOERROR); + #endif LARGE_INTEGER f; QueryPerformanceFrequency (&f); diff --git a/source/modules/juce_core/network/juce_Socket.cpp b/source/modules/juce_core/network/juce_Socket.cpp index 2d5d1fec7..97d0e0fb6 100644 --- a/source/modules/juce_core/network/juce_Socket.cpp +++ b/source/modules/juce_core/network/juce_Socket.cpp @@ -378,7 +378,7 @@ void StreamingSocket::close() { // need to do this to interrupt the accept() function.. StreamingSocket temp; - temp.connect ("localhost", portNumber, 1000); + temp.connect (IPAddress::local().toString(), portNumber, 1000); } } diff --git a/source/modules/juce_core/streams/juce_MemoryInputStream.cpp b/source/modules/juce_core/streams/juce_MemoryInputStream.cpp index 19b10524a..82b2d141e 100644 --- a/source/modules/juce_core/streams/juce_MemoryInputStream.cpp +++ b/source/modules/juce_core/streams/juce_MemoryInputStream.cpp @@ -60,7 +60,7 @@ MemoryInputStream::~MemoryInputStream() int64 MemoryInputStream::getTotalLength() { - return dataSize; + return (int64) dataSize; } int MemoryInputStream::read (void* const buffer, const int howMany) @@ -89,7 +89,7 @@ bool MemoryInputStream::setPosition (const int64 pos) int64 MemoryInputStream::getPosition() { - return position; + return (int64) position; } diff --git a/source/modules/juce_core/streams/juce_MemoryOutputStream.h b/source/modules/juce_core/streams/juce_MemoryOutputStream.h index 95d7be40c..61cc85c34 100644 --- a/source/modules/juce_core/streams/juce_MemoryOutputStream.h +++ b/source/modules/juce_core/streams/juce_MemoryOutputStream.h @@ -114,7 +114,7 @@ public: void flush(); bool write (const void*, size_t) override; - int64 getPosition() override { return position; } + int64 getPosition() override { return (int64) position; } bool setPosition (int64) override; int writeFromInputStream (InputStream&, int64 maxNumBytesToWrite) override; bool writeRepeatedByte (uint8 byte, size_t numTimesToRepeat) override; diff --git a/source/modules/juce_core/system/juce_StandardHeader.h b/source/modules/juce_core/system/juce_StandardHeader.h index edd6a54dd..f9627cad6 100644 --- a/source/modules/juce_core/system/juce_StandardHeader.h +++ b/source/modules/juce_core/system/juce_StandardHeader.h @@ -36,7 +36,7 @@ */ #define JUCE_MAJOR_VERSION 3 #define JUCE_MINOR_VERSION 0 -#define JUCE_BUILDNUMBER 6 +#define JUCE_BUILDNUMBER 7 /** Current Juce version number. diff --git a/source/modules/juce_core/system/juce_SystemStats.cpp b/source/modules/juce_core/system/juce_SystemStats.cpp index f0621dc6b..6b5656900 100644 --- a/source/modules/juce_core/system/juce_SystemStats.cpp +++ b/source/modules/juce_core/system/juce_SystemStats.cpp @@ -97,7 +97,7 @@ String SystemStats::getStackBacktrace() { String result; - #if JUCE_ANDROID || JUCE_MINGW || JUCE_HAIKU || JUCE_MAC + #if JUCE_ANDROID || JUCE_MINGW || JUCE_HAIKU jassertfalse; // sorry, not implemented yet! #elif JUCE_WINDOWS diff --git a/source/modules/juce_core/text/juce_String.cpp b/source/modules/juce_core/text/juce_String.cpp index a335ba1be..1dce72309 100644 --- a/source/modules/juce_core/text/juce_String.cpp +++ b/source/modules/juce_core/text/juce_String.cpp @@ -558,7 +558,7 @@ struct HashGenerator Type result = Type(); while (! t.isEmpty()) - result = multiplier * result + t.getAndAdvance(); + result = ((Type) multiplier) * result + (Type) t.getAndAdvance(); return result; } diff --git a/source/modules/juce_core/text/juce_String.h b/source/modules/juce_core/text/juce_String.h index b3a45ae60..4873bd9dd 100644 --- a/source/modules/juce_core/text/juce_String.h +++ b/source/modules/juce_core/text/juce_String.h @@ -167,7 +167,7 @@ public: typedef CharPointer_UTF32 CharPointerType; #elif (JUCE_STRING_UTF_TYPE == 16) typedef CharPointer_UTF16 CharPointerType; - #elif (JUCE_STRING_UTF_TYPE == 8) + #elif (DOXYGEN || JUCE_STRING_UTF_TYPE == 8) typedef CharPointer_UTF8 CharPointerType; #else #error "You must set the value of JUCE_STRING_UTF_TYPE to be either 8, 16, or 32!" diff --git a/source/modules/juce_core/zip/juce_ZipFile.cpp b/source/modules/juce_core/zip/juce_ZipFile.cpp index e0abb2d5f..9a3faf9bc 100644 --- a/source/modules/juce_core/zip/juce_ZipFile.cpp +++ b/source/modules/juce_core/zip/juce_ZipFile.cpp @@ -135,7 +135,7 @@ public: char buffer [30]; if (inputStream != nullptr - && inputStream->setPosition (zei.streamOffset) + && inputStream->setPosition ((int64) zei.streamOffset) && inputStream->read (buffer, 30) == 30 && ByteOrder::littleEndianInt (buffer) == 0x04034b50) { @@ -154,7 +154,7 @@ public: int64 getTotalLength() { - return zipEntryHolder.compressedSize; + return (int64) zipEntryHolder.compressedSize; } int read (void* buffer, int howMany) @@ -162,7 +162,7 @@ public: if (headerSize <= 0) return 0; - howMany = (int) jmin ((int64) howMany, (int64) (zipEntryHolder.compressedSize - pos)); + howMany = (int) jmin ((int64) howMany, ((int64) zipEntryHolder.compressedSize) - pos); if (inputStream == nullptr) return 0; @@ -172,12 +172,12 @@ public: if (inputStream == file.inputStream) { const ScopedLock sl (file.lock); - inputStream->setPosition (pos + zipEntryHolder.streamOffset + headerSize); + inputStream->setPosition (pos + (int64) zipEntryHolder.streamOffset + headerSize); num = inputStream->read (buffer, howMany); } else { - inputStream->setPosition (pos + zipEntryHolder.streamOffset + headerSize); + inputStream->setPosition (pos + (int64) zipEntryHolder.streamOffset + headerSize); num = inputStream->read (buffer, howMany); } diff --git a/source/modules/juce_data_structures/values/juce_Value.h b/source/modules/juce_data_structures/values/juce_Value.h index d67c173eb..49315a489 100644 --- a/source/modules/juce_data_structures/values/juce_Value.h +++ b/source/modules/juce_data_structures/values/juce_Value.h @@ -147,9 +147,9 @@ public: The listener is added to this specific Value object, and not to the shared object that it refers to. When this object is deleted, all the listeners will be lost, even if other references to the same Value still exist. So when you're - adding a listener, make sure that you add it to a ValueTree instance that will last + adding a listener, make sure that you add it to a Value instance that will last for as long as you need the listener. In general, you'd never want to add a listener - to a local stack-based ValueTree, but more likely to one that's a member variable. + to a local stack-based Value, but more likely to one that's a member variable. @see removeListener */ diff --git a/source/modules/juce_events/broadcasters/juce_AsyncUpdater.cpp b/source/modules/juce_events/broadcasters/juce_AsyncUpdater.cpp index de1220266..980eb4146 100644 --- a/source/modules/juce_events/broadcasters/juce_AsyncUpdater.cpp +++ b/source/modules/juce_events/broadcasters/juce_AsyncUpdater.cpp @@ -61,7 +61,9 @@ AsyncUpdater::~AsyncUpdater() void AsyncUpdater::triggerAsyncUpdate() { if (activeMessage->shouldDeliver.compareAndSetBool (1, 0)) - activeMessage->post(); + if (! activeMessage->post()) + cancelPendingUpdate(); // if the message queue fails, this avoids getting + // trapped waiting for the message to arrive } void AsyncUpdater::cancelPendingUpdate() noexcept diff --git a/source/modules/juce_events/interprocess/juce_InterprocessConnection.cpp b/source/modules/juce_events/interprocess/juce_InterprocessConnection.cpp index b1b72f79b..74f797d81 100644 --- a/source/modules/juce_events/interprocess/juce_InterprocessConnection.cpp +++ b/source/modules/juce_events/interprocess/juce_InterprocessConnection.cpp @@ -69,11 +69,9 @@ bool InterprocessConnection::connectToSocket (const String& hostName, thread->startThread(); return true; } - else - { - socket = nullptr; - return false; - } + + socket = nullptr; + return false; } bool InterprocessConnection::connectToPipe (const String& pipeName, const int timeoutMs) @@ -143,41 +141,43 @@ bool InterprocessConnection::isConnected() const String InterprocessConnection::getConnectedHostName() const { - if (pipe != nullptr) - return "localhost"; - - if (socket != nullptr) { - if (! socket->isLocal()) - return socket->getHostName(); + const ScopedLock sl (pipeAndSocketLock); + + if (pipe == nullptr && socket == nullptr) + return String(); - return "localhost"; + if (socket != nullptr && ! socket->isLocal()) + return socket->getHostName(); } - return String(); + return IPAddress::local().toString(); } //============================================================================== bool InterprocessConnection::sendMessage (const MemoryBlock& message) { - uint32 messageHeader[2]; - messageHeader [0] = ByteOrder::swapIfBigEndian (magicMessageHeader); - messageHeader [1] = ByteOrder::swapIfBigEndian ((uint32) message.getSize()); + uint32 messageHeader[2] = { ByteOrder::swapIfBigEndian (magicMessageHeader), + ByteOrder::swapIfBigEndian ((uint32) message.getSize()) }; MemoryBlock messageData (sizeof (messageHeader) + message.getSize()); messageData.copyFrom (messageHeader, 0, sizeof (messageHeader)); messageData.copyFrom (message.getData(), sizeof (messageHeader), message.getSize()); - int bytesWritten = 0; + return writeData (messageData.getData(), (int) messageData.getSize()) == (int) messageData.getSize(); +} +int InterprocessConnection::writeData (void* data, int dataSize) +{ const ScopedLock sl (pipeAndSocketLock); if (socket != nullptr) - bytesWritten = socket->write (messageData.getData(), (int) messageData.getSize()); - else if (pipe != nullptr) - bytesWritten = pipe->write (messageData.getData(), (int) messageData.getSize(), pipeReceiveMessageTimeout); + return socket->write (data, dataSize); + + if (pipe != nullptr) + return pipe->write (data, dataSize, pipeReceiveMessageTimeout); - return bytesWritten == (int) messageData.getSize(); + return 0; } //============================================================================== diff --git a/source/modules/juce_events/interprocess/juce_InterprocessConnection.h b/source/modules/juce_events/interprocess/juce_InterprocessConnection.h index 8f21a29b3..a88e8fdc5 100644 --- a/source/modules/juce_events/interprocess/juce_InterprocessConnection.h +++ b/source/modules/juce_events/interprocess/juce_InterprocessConnection.h @@ -201,6 +201,7 @@ private: friend struct ContainerDeletePolicy; ScopedPointer thread; void runThread(); + int writeData (void*, int); JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (InterprocessConnection) }; diff --git a/source/modules/juce_events/messages/juce_ApplicationBase.cpp b/source/modules/juce_events/messages/juce_ApplicationBase.cpp index 507823d1c..7a87fdbc6 100644 --- a/source/modules/juce_events/messages/juce_ApplicationBase.cpp +++ b/source/modules/juce_events/messages/juce_ApplicationBase.cpp @@ -138,7 +138,7 @@ String JUCEApplicationBase::getCommandLineParameters() { return String( #else -#if JUCE_WINDOWS +#if JUCE_WINDOWS && ! defined (_CONSOLE) String JUCE_CALLTYPE JUCEApplicationBase::getCommandLineParameters() { @@ -171,8 +171,13 @@ StringArray JUCE_CALLTYPE JUCEApplicationBase::getCommandLineParameterArray() extern void initialiseNSApplication(); #endif -extern const char* const* juce_argv; // declared in juce_core -extern int juce_argc; +#if JUCE_WINDOWS + const char* const* juce_argv = nullptr; + int juce_argc = 0; +#else + extern const char* const* juce_argv; // declared in juce_core + extern int juce_argc; +#endif String JUCEApplicationBase::getCommandLineParameters() { diff --git a/source/modules/juce_events/messages/juce_Initialisation.h b/source/modules/juce_events/messages/juce_Initialisation.h index 51993bf13..d3302dd74 100644 --- a/source/modules/juce_events/messages/juce_Initialisation.h +++ b/source/modules/juce_events/messages/juce_Initialisation.h @@ -92,18 +92,12 @@ public: juce::JUCEApplicationBase* juce_CreateApplication() { return new AppClass(); } #else - #if JUCE_WINDOWS - #if defined (WINAPI) || defined (_WINDOWS_) || defined(JUCE_MINGW) - #define JUCE_MAIN_FUNCTION int __stdcall WinMain (HINSTANCE, HINSTANCE, const LPSTR, int) - #elif defined (_UNICODE) - #define JUCE_MAIN_FUNCTION int __stdcall WinMain (void*, void*, const wchar_t*, int) - #else - #define JUCE_MAIN_FUNCTION int __stdcall WinMain (void*, void*, const char*, int) - #endif - #define JUCE_MAIN_FUNCTION_ARGS + #if JUCE_WINDOWS && ! defined (_CONSOLE) + #define JUCE_MAIN_FUNCTION int __stdcall WinMain (struct HINSTANCE__*, struct HINSTANCE__*, char*, int) + #define JUCE_MAIN_FUNCTION_ARGS #else - #define JUCE_MAIN_FUNCTION int main (int argc, char* argv[]) - #define JUCE_MAIN_FUNCTION_ARGS argc, (const char**) argv + #define JUCE_MAIN_FUNCTION int main (int argc, char* argv[]) + #define JUCE_MAIN_FUNCTION_ARGS argc, (const char**) argv #endif #define START_JUCE_APPLICATION(AppClass) \ diff --git a/source/modules/juce_events/messages/juce_MessageManager.cpp b/source/modules/juce_events/messages/juce_MessageManager.cpp index 9383d50b4..31e2710fc 100644 --- a/source/modules/juce_events/messages/juce_MessageManager.cpp +++ b/source/modules/juce_events/messages/juce_MessageManager.cpp @@ -66,12 +66,17 @@ void MessageManager::deleteInstance() } //============================================================================== -void MessageManager::MessageBase::post() +bool MessageManager::MessageBase::post() { MessageManager* const mm = MessageManager::instance; if (mm == nullptr || mm->quitMessagePosted || ! postMessageToSystemQueue (this)) + { Ptr deleter (this); // (this will delete messages that were just created with a 0 ref count) + return false; + } + + return true; } //============================================================================== @@ -158,9 +163,15 @@ void* MessageManager::callFunctionOnMessageThread (MessageCallbackFunction* cons jassert (! currentThreadHasLockedMessageManager()); const ReferenceCountedObjectPtr message (new AsyncFunctionCallback (func, parameter)); - message->post(); - message->finished.wait(); - return message->result; + + if (message->post()) + { + message->finished.wait(); + return message->result; + } + + jassertfalse; // the OS message queue failed to send the message! + return nullptr; } //============================================================================== @@ -275,7 +286,9 @@ bool MessageManagerLock::attemptLock (Thread* const threadToCheck, ThreadPoolJob } blockingMessage = new BlockingMessage(); - blockingMessage->post(); + + if (! blockingMessage->post()) + return false; while (! blockingMessage->lockedEvent.wait (20)) { diff --git a/source/modules/juce_events/messages/juce_MessageManager.h b/source/modules/juce_events/messages/juce_MessageManager.h index d50c35c58..9266d0503 100644 --- a/source/modules/juce_events/messages/juce_MessageManager.h +++ b/source/modules/juce_events/messages/juce_MessageManager.h @@ -170,7 +170,7 @@ public: virtual ~MessageBase() {} virtual void messageCallback() = 0; - void post(); + bool post(); typedef ReferenceCountedObjectPtr Ptr; diff --git a/source/modules/juce_gui_basics/components/juce_Component.cpp b/source/modules/juce_gui_basics/components/juce_Component.cpp index 54067ed57..303194bb4 100644 --- a/source/modules/juce_gui_basics/components/juce_Component.cpp +++ b/source/modules/juce_gui_basics/components/juce_Component.cpp @@ -1182,11 +1182,25 @@ void Component::setBounds (const int x, const int y, int w, int h) cachedImage->invalidateAll(); } + flags.isMoveCallbackPending = wasMoved; + flags.isResizeCallbackPending = wasResized; + if (flags.hasHeavyweightPeerFlag) if (ComponentPeer* const peer = getPeer()) peer->updateBounds(); - sendMovedResizedMessages (wasMoved, wasResized); + sendMovedResizedMessagesIfPending(); + } +} + +void Component::sendMovedResizedMessagesIfPending() +{ + if (flags.isMoveCallbackPending || flags.isResizeCallbackPending) + { + sendMovedResizedMessages (flags.isMoveCallbackPending, flags.isResizeCallbackPending); + + flags.isMoveCallbackPending = false; + flags.isResizeCallbackPending = false; } } @@ -2047,6 +2061,11 @@ void Component::paintComponentAndChildren (Graphics& g) void Component::paintEntireComponent (Graphics& g, const bool ignoreAlphaLevel) { + // If sizing a top-level-window and the OS paint message is delivered synchronously + // before resized() is called, then we'll invoke the callback here, to make sure + // the components inside have had a chance to sort their sizes out.. + sendMovedResizedMessagesIfPending(); + #if JUCE_DEBUG flags.isInsidePaintCall = true; #endif diff --git a/source/modules/juce_gui_basics/components/juce_Component.h b/source/modules/juce_gui_basics/components/juce_Component.h index f0d1ba5d3..85a9d0392 100644 --- a/source/modules/juce_gui_basics/components/juce_Component.h +++ b/source/modules/juce_gui_basics/components/juce_Component.h @@ -2306,6 +2306,8 @@ private: bool childCompFocusedFlag : 1; bool dontClipGraphicsFlag : 1; bool mouseDownWasBlocked : 1; + bool isMoveCallbackPending : 1; + bool isResizeCallbackPending : 1; #if JUCE_DEBUG bool isInsidePaintCall : 1; #endif @@ -2344,6 +2346,7 @@ private: void paintComponentAndChildren (Graphics&); void paintWithinParentContext (Graphics&); void sendMovedResizedMessages (bool wasMoved, bool wasResized); + void sendMovedResizedMessagesIfPending(); void repaintParent(); void sendFakeMouseMove() const; void takeKeyboardFocus (const FocusChangeType); diff --git a/source/modules/juce_gui_basics/layout/juce_TabbedButtonBar.cpp b/source/modules/juce_gui_basics/layout/juce_TabbedButtonBar.cpp index 67f46bc9a..ed5c02f07 100644 --- a/source/modules/juce_gui_basics/layout/juce_TabbedButtonBar.cpp +++ b/source/modules/juce_gui_basics/layout/juce_TabbedButtonBar.cpp @@ -287,7 +287,7 @@ void TabbedButtonBar::setTabName (const int tabIndex, const String& newName) } } -void TabbedButtonBar::removeTab (const int tabIndex) +void TabbedButtonBar::removeTab (const int tabIndex, const bool animate) { const int oldIndex = currentTabIndex; if (tabIndex == currentTabIndex) @@ -296,7 +296,7 @@ void TabbedButtonBar::removeTab (const int tabIndex) tabs.remove (tabIndex); setCurrentTabIndex (oldIndex); - resized(); + updateTabPositions (animate); } void TabbedButtonBar::moveTab (const int currentIndex, const int newIndex, const bool animate) diff --git a/source/modules/juce_gui_basics/layout/juce_TabbedButtonBar.h b/source/modules/juce_gui_basics/layout/juce_TabbedButtonBar.h index a9b256107..31afbadb1 100644 --- a/source/modules/juce_gui_basics/layout/juce_TabbedButtonBar.h +++ b/source/modules/juce_gui_basics/layout/juce_TabbedButtonBar.h @@ -212,7 +212,7 @@ public: void setTabName (int tabIndex, const String& newName); /** Gets rid of one of the tabs. */ - void removeTab (int tabIndex); + void removeTab (int tabIndex, bool animate = false); /** Moves a tab to a new index in the list. Pass -1 as the index to move it to the end of the list. diff --git a/source/modules/juce_gui_basics/layout/juce_Viewport.cpp b/source/modules/juce_gui_basics/layout/juce_Viewport.cpp index 04064ed90..282423387 100644 --- a/source/modules/juce_gui_basics/layout/juce_Viewport.cpp +++ b/source/modules/juce_gui_basics/layout/juce_Viewport.cpp @@ -346,15 +346,15 @@ void Viewport::mouseWheelMove (const MouseEvent& e, const MouseWheelDetails& whe Component::mouseWheelMove (e, wheel); } -static float rescaleMouseWheelDistance (float distance, int singleStepSize) noexcept +static int rescaleMouseWheelDistance (float distance, int singleStepSize) noexcept { if (distance == 0) return 0; distance *= 14.0f * singleStepSize; - return distance < 0 ? jmin (distance, -1.0f) - : jmax (distance, 1.0f); + return roundToInt (distance < 0 ? jmin (distance, -1.0f) + : jmax (distance, 1.0f)); } bool Viewport::useMouseWheelMoveIfNeeded (const MouseEvent& e, const MouseWheelDetails& wheel) @@ -366,26 +366,23 @@ bool Viewport::useMouseWheelMoveIfNeeded (const MouseEvent& e, const MouseWheelD if (canScrollHorz || canScrollVert) { - float wheelIncrementX = rescaleMouseWheelDistance (wheel.deltaX, singleStepX); - float wheelIncrementY = rescaleMouseWheelDistance (wheel.deltaY, singleStepY); + const int deltaX = rescaleMouseWheelDistance (wheel.deltaX, singleStepX); + const int deltaY = rescaleMouseWheelDistance (wheel.deltaY, singleStepY); Point pos (getViewPosition()); - if (wheelIncrementX != 0 && wheelIncrementY != 0 && canScrollHorz && canScrollVert) + if (deltaX != 0 && deltaY != 0 && canScrollHorz && canScrollVert) { - pos.setX (pos.x - roundToInt (wheelIncrementX)); - pos.setY (pos.y - roundToInt (wheelIncrementY)); + pos.x -= deltaX; + pos.y -= deltaY; } - else if (canScrollHorz && (wheelIncrementX != 0 || e.mods.isShiftDown() || ! canScrollVert)) + else if (canScrollHorz && (deltaX != 0 || e.mods.isShiftDown() || ! canScrollVert)) { - if (wheelIncrementX == 0 && ! canScrollVert) - wheelIncrementX = wheelIncrementY; - - pos.setX (pos.x - roundToInt (wheelIncrementX)); + pos.x -= deltaX != 0 ? deltaX : deltaY; } - else if (canScrollVert && wheelIncrementY != 0) + else if (canScrollVert && deltaY != 0) { - pos.setY (pos.y - roundToInt (wheelIncrementY)); + pos.y -= deltaY; } if (pos != getViewPosition()) diff --git a/source/modules/juce_gui_basics/lookandfeel/juce_LookAndFeel_V2.cpp b/source/modules/juce_gui_basics/lookandfeel/juce_LookAndFeel_V2.cpp index ac9cd44d4..37dc12457 100644 --- a/source/modules/juce_gui_basics/lookandfeel/juce_LookAndFeel_V2.cpp +++ b/source/modules/juce_gui_basics/lookandfeel/juce_LookAndFeel_V2.cpp @@ -2357,6 +2357,10 @@ void LookAndFeel_V2::drawCallOutBoxBackground (CallOutBox& box, Graphics& g, g.strokePath (path, PathStrokeType (2.0f)); } +int LookAndFeel_V2::getCallOutBoxBorderSize (const CallOutBox&) +{ + return 20; +} //============================================================================== AttributedString LookAndFeel_V2::createFileChooserHeaderText (const String& title, diff --git a/source/modules/juce_gui_basics/lookandfeel/juce_LookAndFeel_V2.h b/source/modules/juce_gui_basics/lookandfeel/juce_LookAndFeel_V2.h index eb9395be1..f728df3be 100644 --- a/source/modules/juce_gui_basics/lookandfeel/juce_LookAndFeel_V2.h +++ b/source/modules/juce_gui_basics/lookandfeel/juce_LookAndFeel_V2.h @@ -285,6 +285,7 @@ public: //============================================================================== void drawCallOutBoxBackground (CallOutBox&, Graphics&, const Path& path, Image& cachedImage) override; + int getCallOutBoxBorderSize (const CallOutBox&) override; //============================================================================== void drawLevelMeter (Graphics&, int width, int height, float level) override; diff --git a/source/modules/juce_gui_basics/mouse/juce_MouseInputSource.cpp b/source/modules/juce_gui_basics/mouse/juce_MouseInputSource.cpp index 46698bd70..8bed5afa8 100644 --- a/source/modules/juce_gui_basics/mouse/juce_MouseInputSource.cpp +++ b/source/modules/juce_gui_basics/mouse/juce_MouseInputSource.cpp @@ -274,7 +274,7 @@ public: sendMouseDrag (*current, newScreenPos + unboundedMouseOffset, time); if (isUnboundedMouseModeOn) - handleUnboundedDrag (current); + handleUnboundedDrag (*current); } else { @@ -399,7 +399,8 @@ public: { // when released, return the mouse to within the component's bounds if (Component* current = getComponentUnderMouse()) - setScreenPosition (current->getScreenBounds().toFloat().getConstrainedPoint (lastScreenPos)); + setScreenPosition (current->getScreenBounds().toFloat() + .getConstrainedPoint (ScalingHelpers::unscaledScreenPosToScaled (lastScreenPos))); } isUnboundedMouseModeOn = enable; @@ -409,21 +410,22 @@ public: } } - void handleUnboundedDrag (Component* current) + void handleUnboundedDrag (Component& current) { - const Rectangle screenArea (current->getParentMonitorArea().expanded (-2, -2).toFloat()); + const Rectangle componentScreenBounds + = ScalingHelpers::scaledScreenPosToUnscaled (current.getParentMonitorArea().reduced (2, 2).toFloat()); - if (! screenArea.contains (lastScreenPos)) + if (! componentScreenBounds.contains (lastScreenPos)) { - const Point componentCentre (current->getScreenBounds().toFloat().getCentre()); - unboundedMouseOffset += (lastScreenPos - componentCentre); + const Point componentCentre (current.getScreenBounds().toFloat().getCentre()); + unboundedMouseOffset += (lastScreenPos - ScalingHelpers::scaledScreenPosToUnscaled (componentCentre)); setScreenPosition (componentCentre); } else if (isCursorVisibleUntilOffscreen && (! unboundedMouseOffset.isOrigin()) - && screenArea.contains (lastScreenPos + unboundedMouseOffset)) + && componentScreenBounds.contains (lastScreenPos + unboundedMouseOffset)) { - setScreenPosition (lastScreenPos + unboundedMouseOffset); + MouseInputSource::setRawMousePosition (lastScreenPos + unboundedMouseOffset); unboundedMouseOffset = Point(); } } @@ -462,10 +464,9 @@ public: //============================================================================== const int index; const bool isMouseDevice; - Point lastScreenPos; + Point lastScreenPos, unboundedMouseOffset; // NB: these are unscaled coords ModifierKeys buttonState; - Point unboundedMouseOffset; bool isUnboundedMouseModeOn, isCursorVisibleUntilOffscreen; private: @@ -487,8 +488,8 @@ private: bool canBePartOfMultipleClickWith (const RecentMouseDown& other, const int maxTimeBetweenMs) const { return time - other.time < RelativeTime::milliseconds (maxTimeBetweenMs) - && abs (position.x - other.position.x) < 8 - && abs (position.y - other.position.y) < 8 + && std::abs (position.x - other.position.x) < 8 + && std::abs (position.y - other.position.y) < 8 && buttons == other.buttons && peerID == other.peerID; } diff --git a/source/modules/juce_gui_basics/native/juce_linux_FileChooser.cpp b/source/modules/juce_gui_basics/native/juce_linux_FileChooser.cpp index fb5a4113d..d50092c40 100644 --- a/source/modules/juce_gui_basics/native/juce_linux_FileChooser.cpp +++ b/source/modules/juce_gui_basics/native/juce_linux_FileChooser.cpp @@ -42,99 +42,134 @@ bool FileChooser::isPlatformDialogAvailable() #endif } -void FileChooser::showPlatformDialog (Array& results, - const String& title, - const File& file, - const String& filters, - bool isDirectory, - bool /* selectsFiles */, - bool isSave, - bool /* warnAboutOverwritingExistingFiles */, - bool selectMultipleFiles, - FilePreviewComponent* /* previewComponent */) +static uint64 getTopWindowID() noexcept { - String separator; - StringArray args; + if (TopLevelWindow* top = TopLevelWindow::getActiveTopLevelWindow()) + return (uint64) (pointer_sized_uint) top->getWindowHandle(); - const File previousWorkingDirectory (File::getCurrentWorkingDirectory()); - const bool isKdeFullSession = SystemStats::getEnvironmentVariable ("KDE_FULL_SESSION", String::empty) - .equalsIgnoreCase ("true"); + return 0; +} - if (exeIsAvailable ("kdialog") && (isKdeFullSession || ! exeIsAvailable ("zenity"))) - { - // use kdialog for KDE sessions or if zenity is missing - args.add ("kdialog"); +static bool isKdeFullSession() +{ + return SystemStats::getEnvironmentVariable ("KDE_FULL_SESSION", String()) + .equalsIgnoreCase ("true"); +} - if (title.isNotEmpty()) - args.add ("--title=" + title); +static void addKDialogArgs (StringArray& args, String& separator, + const String& title, const File& file, const String& filters, + bool isDirectory, bool isSave, bool selectMultipleFiles) +{ + args.add ("kdialog"); - if (selectMultipleFiles) - { - separator = "\n"; - args.add ("--multiple"); - args.add ("--separate-output"); - args.add ("--getopenfilename"); - } - else - { - if (isSave) args.add ("--getsavefilename"); - else if (isDirectory) args.add ("--getexistingdirectory"); - else args.add ("--getopenfilename"); - } + if (title.isNotEmpty()) + args.add ("--title=" + title); - String startPath; + if (selectMultipleFiles) + { + separator = "\n"; + args.add ("--multiple"); + args.add ("--separate-output"); + args.add ("--getopenfilename"); + } + else + { + if (isSave) args.add ("--getsavefilename"); + else if (isDirectory) args.add ("--getexistingdirectory"); + else args.add ("--getopenfilename"); + } - if (file.exists()) - { - startPath = file.getFullPathName(); - } - else if (file.getParentDirectory().exists()) - { - startPath = file.getParentDirectory().getFullPathName(); - } - else - { - startPath = File::getSpecialLocation (File::userHomeDirectory).getFullPathName(); + if (uint64 topWindowID = getTopWindowID()) + { + args.add ("--attach"); + args.add (String (topWindowID)); + } - if (isSave) - startPath += "/" + file.getFileName(); - } + File startPath; - args.add (startPath); - args.add (filters.replaceCharacter (';', ' ')); + if (file.exists()) + { + startPath = file; + } + else if (file.getParentDirectory().exists()) + { + startPath = file.getParentDirectory(); } else { - // zenity - args.add ("zenity"); - args.add ("--file-selection"); + startPath = File::getSpecialLocation (File::userHomeDirectory); - if (title.isNotEmpty()) - args.add ("--title=" + title); + if (isSave) + startPath = startPath.getChildFile (file.getFileName()); + } - if (selectMultipleFiles) - { - separator = ":"; - args.add ("--multiple"); - args.add ("--separator=" + separator); - } - else - { - if (isDirectory) args.add ("--directory"); - if (isSave) args.add ("--save"); - } + args.add (startPath.getFullPathName()); + args.add (filters.replaceCharacter (';', ' ')); +} + +static void addZenityArgs (StringArray& args, String& separator, + const String& title, const File& file, const String& filters, + bool isDirectory, bool isSave, bool selectMultipleFiles) +{ + args.add ("zenity"); + args.add ("--file-selection"); + + if (title.isNotEmpty()) + args.add ("--title=" + title); - if (file.isDirectory()) - file.setAsCurrentWorkingDirectory(); - else if (file.getParentDirectory().exists()) - file.getParentDirectory().setAsCurrentWorkingDirectory(); - else - File::getSpecialLocation (File::userHomeDirectory).setAsCurrentWorkingDirectory(); + if (selectMultipleFiles) + { + separator = ":"; + args.add ("--multiple"); + args.add ("--separator=" + separator); + } + else + { + if (isDirectory) args.add ("--directory"); + if (isSave) args.add ("--save"); + } + + if (filters.isNotEmpty() && filters != "*" && filters != "*.*") + { + args.add ("--file-filter"); + args.add (filters.replaceCharacter (';', ' ')); - if (! file.getFileName().isEmpty()) - args.add ("--filename=" + file.getFileName()); + args.add ("--file-filter"); + args.add ("All files | *"); } + if (file.isDirectory()) + file.setAsCurrentWorkingDirectory(); + else if (file.getParentDirectory().exists()) + file.getParentDirectory().setAsCurrentWorkingDirectory(); + else + File::getSpecialLocation (File::userHomeDirectory).setAsCurrentWorkingDirectory(); + + if (! file.getFileName().isEmpty()) + args.add ("--filename=" + file.getFileName()); + + // supplying the window ID of the topmost window makes sure that Zenity pops up.. + if (uint64 topWindowID = getTopWindowID()) + setenv ("WINDOWID", String (topWindowID).toRawUTF8(), true); +} + +void FileChooser::showPlatformDialog (Array& results, + const String& title, const File& file, const String& filters, + bool isDirectory, bool /* selectsFiles */, + bool isSave, bool /* warnAboutOverwritingExistingFiles */, + bool selectMultipleFiles, FilePreviewComponent*) +{ + const File previousWorkingDirectory (File::getCurrentWorkingDirectory()); + + StringArray args; + String separator; + + // use kdialog for KDE sessions or if zenity is missing + if (exeIsAvailable ("kdialog") && (isKdeFullSession() || ! exeIsAvailable ("zenity"))) + addKDialogArgs (args, separator, title, file, filters, isDirectory, isSave, selectMultipleFiles); + else + addZenityArgs (args, separator, title, file, filters, isDirectory, isSave, selectMultipleFiles); + args.add ("2>/dev/null"); // (to avoid logging info ending up in the results) ChildProcess child; diff --git a/source/modules/juce_gui_basics/native/juce_linux_Windowing.cpp b/source/modules/juce_gui_basics/native/juce_linux_Windowing.cpp index 4cbb70709..e45a593e6 100644 --- a/source/modules/juce_gui_basics/native/juce_linux_Windowing.cpp +++ b/source/modules/juce_gui_basics/native/juce_linux_Windowing.cpp @@ -33,17 +33,18 @@ struct Atoms { Atoms() { - Protocols = getIfExists ("WM_PROTOCOLS"); - ProtocolList [TAKE_FOCUS] = getIfExists ("WM_TAKE_FOCUS"); - ProtocolList [DELETE_WINDOW] = getIfExists ("WM_DELETE_WINDOW"); - ProtocolList [PING] = getIfExists ("_NET_WM_PING"); - ChangeState = getIfExists ("WM_CHANGE_STATE"); - State = getIfExists ("WM_STATE"); - UserTime = getCreating ("_NET_WM_USER_TIME"); - ActiveWin = getCreating ("_NET_ACTIVE_WINDOW"); - Pid = getCreating ("_NET_WM_PID"); - WindowType = getIfExists ("_NET_WM_WINDOW_TYPE"); - WindowState = getIfExists ("_NET_WM_STATE"); + protocols = getIfExists ("WM_PROTOCOLS"); + protocolList [TAKE_FOCUS] = getIfExists ("WM_TAKE_FOCUS"); + protocolList [DELETE_WINDOW] = getIfExists ("WM_DELETE_WINDOW"); + protocolList [PING] = getIfExists ("_NET_WM_PING"); + changeState = getIfExists ("WM_CHANGE_STATE"); + state = getIfExists ("WM_STATE"); + userTime = getCreating ("_NET_WM_USER_TIME"); + activeWin = getCreating ("_NET_ACTIVE_WINDOW"); + pid = getCreating ("_NET_WM_PID"); + windowType = getIfExists ("_NET_WM_WINDOW_TYPE"); + windowState = getIfExists ("_NET_WM_STATE"); + compositingManager = getCreating ("_NET_WM_CM_S0"); XdndAware = getCreating ("XdndAware"); XdndEnter = getCreating ("XdndEnter"); @@ -88,8 +89,8 @@ struct Atoms PING = 2 }; - Atom Protocols, ProtocolList[3], ChangeState, State, UserTime, - ActiveWin, Pid, WindowType, WindowState, + Atom protocols, protocolList[3], changeState, state, userTime, + activeWin, pid, windowType, windowState, compositingManager, XdndAware, XdndEnter, XdndLeave, XdndPosition, XdndStatus, XdndDrop, XdndFinished, XdndSelection, XdndTypeList, XdndActionList, XdndActionDescription, XdndActionCopy, XdndActionPrivate, @@ -314,6 +315,11 @@ namespace XRender return xRenderQueryVersion != nullptr; } + static bool hasCompositingWindowManager() + { + return XGetSelectionOwner (display, Atoms::get().compositingManager) != 0; + } + static XRenderPictFormat* findPictureFormat() { ScopedXLock xlock; @@ -915,7 +921,7 @@ public: clientMsg.window = windowH; clientMsg.type = ClientMessage; clientMsg.format = 32; - clientMsg.message_type = Atoms::get().WindowState; + clientMsg.message_type = Atoms::get().windowState; clientMsg.data.l[0] = 0; // Remove clientMsg.data.l[1] = fs; clientMsg.data.l[2] = 0; @@ -1002,7 +1008,7 @@ public: clientMsg.window = windowH; clientMsg.type = ClientMessage; clientMsg.format = 32; - clientMsg.message_type = Atoms::get().ChangeState; + clientMsg.message_type = Atoms::get().changeState; clientMsg.data.l[0] = IconicState; ScopedXLock xlock; @@ -1018,10 +1024,10 @@ public: { ScopedXLock xlock; const Atoms& atoms = Atoms::get(); - GetXProperty prop (windowH, atoms.State, 0, 64, false, atoms.State); + GetXProperty prop (windowH, atoms.state, 0, 64, false, atoms.state); return prop.success - && prop.actualType == atoms.State + && prop.actualType == atoms.state && prop.actualFormat == 32 && prop.numItems > 0 && ((unsigned long*) prop.data)[0] == IconicState; @@ -1152,7 +1158,7 @@ public: ev.xclient.type = ClientMessage; ev.xclient.serial = 0; ev.xclient.send_event = True; - ev.xclient.message_type = Atoms::get().ActiveWin; + ev.xclient.message_type = Atoms::get().activeWin; ev.xclient.window = windowH; ev.xclient.format = 32; ev.xclient.data.l[0] = 2; @@ -1178,10 +1184,7 @@ public: void toBehind (ComponentPeer* other) override { - LinuxComponentPeer* const otherPeer = dynamic_cast (other); - jassert (otherPeer != nullptr); // wrong type of window? - - if (otherPeer != nullptr) + if (LinuxComponentPeer* const otherPeer = dynamic_cast (other)) { setMinimised (false); @@ -1190,6 +1193,8 @@ public: ScopedXLock xlock; XRestackWindows (display, newStack, 2); } + else + jassertfalse; // wrong type of window? } bool isFocused() const override @@ -1221,7 +1226,7 @@ public: void repaint (const Rectangle& area) override { - repainter->repaint (area.getIntersection (component.getLocalBounds())); + repainter->repaint (area.getIntersection (bounds.withZeroOrigin())); } void performAnyPendingRepaintsNow() override @@ -1699,11 +1704,11 @@ public: { const Atoms& atoms = Atoms::get(); - if (clientMsg.message_type == atoms.Protocols && clientMsg.format == 32) + if (clientMsg.message_type == atoms.protocols && clientMsg.format == 32) { const Atom atom = (Atom) clientMsg.data.l[0]; - if (atom == atoms.ProtocolList [Atoms::PING]) + if (atom == atoms.protocolList [Atoms::PING]) { Window root = RootWindow (display, DefaultScreen (display)); @@ -1712,7 +1717,7 @@ public: XSendEvent (display, root, False, NoEventMask, &event); XFlush (display); } - else if (atom == atoms.ProtocolList [Atoms::TAKE_FOCUS]) + else if (atom == atoms.protocolList [Atoms::TAKE_FOCUS]) { if ((getStyleFlags() & juce::ComponentPeer::windowIgnoresKeyPresses) == 0) { @@ -1727,7 +1732,7 @@ public: } } } - else if (atom == atoms.ProtocolList [Atoms::DELETE_WINDOW]) + else if (atom == atoms.protocolList [Atoms::DELETE_WINDOW]) { handleUserClosingWindow(); } @@ -2168,7 +2173,7 @@ private: netHints[1] = Atoms::getIfExists ("_KDE_NET_WM_WINDOW_TYPE_OVERRIDE"); - xchangeProperty (windowH, Atoms::get().WindowType, XA_ATOM, 32, &netHints, 2); + xchangeProperty (windowH, Atoms::get().windowType, XA_ATOM, 32, &netHints, 2); int numHints = 0; @@ -2179,7 +2184,7 @@ private: netHints [numHints++] = Atoms::getIfExists ("_NET_WM_STATE_ABOVE"); if (numHints > 0) - xchangeProperty (windowH, Atoms::get().WindowState, XA_ATOM, 32, &netHints, numHints); + xchangeProperty (windowH, Atoms::get().windowState, XA_ATOM, 32, &netHints, numHints); } void createWindow (Window parentToAddTo) @@ -2256,10 +2261,10 @@ private: // Associate the PID, allowing to be shut down when something goes wrong unsigned long pid = getpid(); - xchangeProperty (windowH, atoms.Pid, XA_CARDINAL, 32, &pid, 1); + xchangeProperty (windowH, atoms.pid, XA_CARDINAL, 32, &pid, 1); // Set window manager protocols - xchangeProperty (windowH, atoms.Protocols, XA_ATOM, 32, atoms.ProtocolList, 2); + xchangeProperty (windowH, atoms.protocols, XA_ATOM, 32, atoms.protocolList, 2); // Set drag and drop flags xchangeProperty (windowH, atoms.XdndTypeList, XA_ATOM, 32, atoms.allowedMimeTypes, numElementsInArray (atoms.allowedMimeTypes)); @@ -2316,7 +2321,7 @@ private: long getUserTime() const { - GetXProperty prop (windowH, Atoms::get().UserTime, 0, 65536, false, XA_CARDINAL); + GetXProperty prop (windowH, Atoms::get().userTime, 0, 65536, false, XA_CARDINAL); return prop.success ? *(long*) prop.data : 0; } @@ -3116,11 +3121,17 @@ bool MouseInputSource::SourceList::addSource() bool Desktop::canUseSemiTransparentWindows() noexcept { - int matchedDepth = 0; - const int desiredDepth = 32; + #if JUCE_USE_XRENDER + if (XRender::hasCompositingWindowManager()) + { + int matchedDepth = 0, desiredDepth = 32; - return Visuals::findVisualFormat (desiredDepth, matchedDepth) != 0 - && (matchedDepth == desiredDepth); + return Visuals::findVisualFormat (desiredDepth, matchedDepth) != 0 + && matchedDepth == desiredDepth; + } + #endif + + return false; } Point MouseInputSource::getCurrentRawMousePosition() @@ -3366,7 +3377,7 @@ void* MouseCursor::createStandardMouseCursor (MouseCursor::StandardCursorType ty void MouseCursor::showInWindow (ComponentPeer* peer) const { - if (LinuxComponentPeer* const lp = dynamic_cast (peer)) + if (LinuxComponentPeer* const lp = dynamic_cast (peer)) lp->showMouseCursor ((Cursor) getHandle()); } @@ -3390,7 +3401,7 @@ bool DragAndDropContainer::performExternalDragDropOfFiles (const StringArray& fi if (MouseInputSource* draggingSource = Desktop::getInstance().getDraggingMouseSource(0)) if (Component* sourceComp = draggingSource->getComponentUnderMouse()) - if (LinuxComponentPeer* const lp = dynamic_cast (sourceComp->getPeer())) + if (LinuxComponentPeer* const lp = dynamic_cast (sourceComp->getPeer())) return lp->externalDragFileInit (files, canMoveFiles); // This method must be called in response to a component's mouseDown or mouseDrag event! @@ -3405,7 +3416,7 @@ bool DragAndDropContainer::performExternalDragDropOfText (const String& text) if (MouseInputSource* draggingSource = Desktop::getInstance().getDraggingMouseSource(0)) if (Component* sourceComp = draggingSource->getComponentUnderMouse()) - if (LinuxComponentPeer* const lp = dynamic_cast (sourceComp->getPeer())) + if (LinuxComponentPeer* const lp = dynamic_cast (sourceComp->getPeer())) return lp->externalDragTextInit (text); // This method must be called in response to a component's mouseDown or mouseDrag event! diff --git a/source/modules/juce_gui_basics/native/juce_mac_NSViewComponentPeer.mm b/source/modules/juce_gui_basics/native/juce_mac_NSViewComponentPeer.mm index 32f1c2657..7ade4d6bb 100644 --- a/source/modules/juce_gui_basics/native/juce_mac_NSViewComponentPeer.mm +++ b/source/modules/juce_gui_basics/native/juce_mac_NSViewComponentPeer.mm @@ -390,16 +390,36 @@ public: return ComponentPeer::isKioskMode(); } + static bool isWindowAtPoint (NSWindow* w, NSPoint screenPoint) + { + #if defined (MAC_OS_X_VERSION_10_6) && MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_6 + if ([NSWindow respondsToSelector: @selector (windowNumberAtPoint:belowWindowWithWindowNumber:)]) + return [NSWindow windowNumberAtPoint: screenPoint belowWindowWithWindowNumber: 0] == [w windowNumber]; + #endif + + return true; + } + bool contains (Point localPos, bool trueIfInAChildWindow) const override { - NSRect frameRect = [view frame]; + NSRect viewFrame = [view frame]; - if (! (isPositiveAndBelow (localPos.getX(), (int) frameRect.size.width) - && isPositiveAndBelow (localPos.getY(), (int) frameRect.size.height))) + if (! (isPositiveAndBelow (localPos.getX(), (int) viewFrame.size.width) + && isPositiveAndBelow (localPos.getY(), (int) viewFrame.size.height))) return false; - NSView* v = [view hitTest: NSMakePoint (frameRect.origin.x + localPos.getX(), - frameRect.origin.y + frameRect.size.height - localPos.getY())]; + if (NSWindow* const viewWindow = [view window]) + { + const NSRect windowFrame = [viewWindow frame]; + const NSPoint screenPoint = NSMakePoint (windowFrame.origin.x + localPos.getX(), + windowFrame.origin.y + windowFrame.size.height - localPos.getY()); + + if (! isWindowAtPoint (viewWindow, screenPoint)) + return false; + } + + NSView* v = [view hitTest: NSMakePoint (viewFrame.origin.x + localPos.getX(), + viewFrame.origin.y + viewFrame.size.height - localPos.getY())]; return trueIfInAChildWindow ? (v != nil) : (v == view); @@ -553,19 +573,11 @@ public: { currentModifiers = currentModifiers.withoutMouseButtons(); - #if defined (MAC_OS_X_VERSION_10_6) && MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_6 - if ([NSWindow respondsToSelector: @selector (windowNumberAtPoint:belowWindowWithWindowNumber:)] - && [NSWindow windowNumberAtPoint: [[ev window] convertBaseToScreen: [ev locationInWindow]] - belowWindowWithWindowNumber: 0] != [window windowNumber]) - { + if (isWindowAtPoint ([ev window], [[ev window] convertBaseToScreen: [ev locationInWindow]])) + sendMouseEvent (ev); + else // moved into another window which overlaps this one, so trigger an exit handleMouseEvent (0, Point (-1.0f, -1.0f), currentModifiers, getMouseTime (ev)); - } - else - #endif - { - sendMouseEvent (ev); - } showArrowCursorIfNeeded(); } @@ -1013,7 +1025,7 @@ public: static Point getMousePos (NSEvent* e, NSView* view) { NSPoint p = [view convertPoint: [e locationInWindow] fromView: nil]; - return Point (p.x, [view frame].size.height - p.y); + return Point ((float) p.x, (float) ([view frame].size.height - p.y)); } static int getModifierForButtonNumber (const NSInteger num) diff --git a/source/modules/juce_gui_basics/native/juce_mac_Windowing.mm b/source/modules/juce_gui_basics/native/juce_mac_Windowing.mm index 9dfde47cc..8f5330459 100644 --- a/source/modules/juce_gui_basics/native/juce_mac_Windowing.mm +++ b/source/modules/juce_gui_basics/native/juce_mac_Windowing.mm @@ -214,7 +214,7 @@ Point MouseInputSource::getCurrentRawMousePosition() JUCE_AUTORELEASEPOOL { const NSPoint p ([NSEvent mouseLocation]); - return Point (p.x, getMainScreenHeight() - p.y); + return Point ((float) p.x, (float) (getMainScreenHeight() - p.y)); } } diff --git a/source/modules/juce_gui_basics/positioning/juce_RelativeRectangle.h b/source/modules/juce_gui_basics/positioning/juce_RelativeRectangle.h index b8afbe01a..fc5ad456a 100644 --- a/source/modules/juce_gui_basics/positioning/juce_RelativeRectangle.h +++ b/source/modules/juce_gui_basics/positioning/juce_RelativeRectangle.h @@ -81,8 +81,9 @@ public: bool isDynamic() const; /** Returns a string which represents this point. - This returns a comma-separated list of coordinates, in the order left, top, right, bottom. For details of - the string syntax used by the coordinates, see the RelativeCoordinate constructor notes. + This returns a comma-separated list of coordinates, in the order left, top, right, bottom. + If you're using this to position a Component, then see the notes for + Component::setBounds (const RelativeRectangle&) for details of the syntax used. The string that is returned can be passed to the RelativeRectangle constructor to recreate the rectangle. */ String toString() const; diff --git a/source/modules/juce_gui_basics/widgets/juce_Label.cpp b/source/modules/juce_gui_basics/widgets/juce_Label.cpp index 727aacfb8..778425e30 100644 --- a/source/modules/juce_gui_basics/widgets/juce_Label.cpp +++ b/source/modules/juce_gui_basics/widgets/juce_Label.cpp @@ -289,11 +289,22 @@ bool Label::isBeingEdited() const noexcept return editor != nullptr; } +static void copyColourIfSpecified (Label& l, TextEditor& ed, int colourID, int targetColourID) +{ + if (l.isColourSpecified (colourID) || l.getLookAndFeel().isColourSpecified (colourID)) + ed.setColour (targetColourID, l.findColour (colourID)); +} + TextEditor* Label::createEditorComponent() { TextEditor* const ed = new TextEditor (getName()); ed->applyFontToAllText (getLookAndFeel().getLabelFont (*this)); copyAllExplicitColoursTo (*ed); + + copyColourIfSpecified (*this, *ed, textWhenEditingColourId, TextEditor::textColourId); + copyColourIfSpecified (*this, *ed, backgroundWhenEditingColourId, TextEditor::backgroundColourId); + copyColourIfSpecified (*this, *ed, outlineWhenEditingColourId, TextEditor::outlineColourId); + return ed; } diff --git a/source/modules/juce_gui_basics/widgets/juce_Label.h b/source/modules/juce_gui_basics/widgets/juce_Label.h index a0e2f80c3..e47fb681e 100644 --- a/source/modules/juce_gui_basics/widgets/juce_Label.h +++ b/source/modules/juce_gui_basics/widgets/juce_Label.h @@ -101,10 +101,13 @@ public: */ enum ColourIds { - backgroundColourId = 0x1000280, /**< The background colour to fill the label with. */ - textColourId = 0x1000281, /**< The colour for the text. */ - outlineColourId = 0x1000282 /**< An optional colour to use to draw a border around the label. - Leave this transparent to not have an outline. */ + backgroundColourId = 0x1000280, /**< The background colour to fill the label with. */ + textColourId = 0x1000281, /**< The colour for the text. */ + outlineColourId = 0x1000282, /**< An optional colour to use to draw a border around the label. + Leave this transparent to not have an outline. */ + backgroundWhenEditingColourId = 0x1000283, /**< The background colour when the label is being edited. */ + textWhenEditingColourId = 0x1000284, /**< The colour for the text when the label is being edited. */ + outlineWhenEditingColourId = 0x1000285 /**< An optional border colour when the label is being edited. */ }; //============================================================================== diff --git a/source/modules/juce_gui_basics/widgets/juce_Slider.cpp b/source/modules/juce_gui_basics/widgets/juce_Slider.cpp index 13e267d50..d72509f1d 100644 --- a/source/modules/juce_gui_basics/widgets/juce_Slider.cpp +++ b/source/modules/juce_gui_basics/widgets/juce_Slider.cpp @@ -667,7 +667,7 @@ public: if (isTwoValue || isThreeValue) { - const float mousePos = (float) (isVertical() ? e.y : e.x); + const float mousePos = isVertical() ? e.position.y : e.position.x; const float normalPosDistance = std::abs (getLinearSliderPos (currentValue.getValue()) - mousePos); const float minPosDistance = std::abs (getLinearSliderPos (valueMin.getValue()) - 0.1f - mousePos); @@ -689,10 +689,10 @@ public: //============================================================================== void handleRotaryDrag (const MouseEvent& e) { - const int dx = e.x - sliderRect.getCentreX(); - const int dy = e.y - sliderRect.getCentreY(); + const float dx = e.position.x - sliderRect.getCentreX(); + const float dy = e.position.y - sliderRect.getCentreY(); - if (dx * dx + dy * dy > 25) + if (dx * dx + dy * dy > 25.0f) { double angle = std::atan2 ((double) dx, (double) -dy); while (angle < 0.0) @@ -736,7 +736,7 @@ public: void handleAbsoluteDrag (const MouseEvent& e) { - const int mousePos = (isHorizontal() || style == RotaryHorizontalDrag) ? e.x : e.y; + const float mousePos = (isHorizontal() || style == RotaryHorizontalDrag) ? e.position.x : e.position.y; double newPos = (mousePos - sliderRegionStart) / (double) sliderRegionSize; if (style == RotaryHorizontalDrag @@ -781,7 +781,7 @@ public: void handleVelocityDrag (const MouseEvent& e) { const float mouseDiff = style == RotaryHorizontalVerticalDrag - ? (e.x - mousePosWhenLastDragged.x) + (mousePosWhenLastDragged.y - e.y) + ? (e.position.x - mousePosWhenLastDragged.x) + (mousePosWhenLastDragged.y - e.position.y) : (isHorizontal() || style == RotaryHorizontalDrag || (style == IncDecButtons && incDecDragDirectionIsHorizontal())) @@ -789,7 +789,7 @@ public: : e.position.y - mousePosWhenLastDragged.y; const double maxSpeed = jmax (200, sliderRegionSize); - double speed = jlimit (0.0, maxSpeed, (double) abs (mouseDiff)); + double speed = jlimit (0.0, maxSpeed, (double) std::abs (mouseDiff)); if (speed != 0) { @@ -981,29 +981,45 @@ public: } } + double getMouseWheelDelta (double value, double wheelAmount) + { + if (style == IncDecButtons) + return interval * wheelAmount; + + const double proportionDelta = wheelAmount * 0.15f; + const double currentPos = owner.valueToProportionOfLength (value); + return owner.proportionOfLengthToValue (jlimit (0.0, 1.0, currentPos + proportionDelta)) - value; + } + bool mouseWheelMove (const MouseEvent& e, const MouseWheelDetails& wheel) { if (scrollWheelEnabled && style != TwoValueHorizontal && style != TwoValueVertical) { - if (maximum > minimum && ! e.mods.isAnyMouseButtonDown()) + // sometimes duplicate wheel events seem to be sent, so since we're going to + // bump the value by a minimum of the interval, avoid doing this twice.. + if (e.eventTime != lastMouseWheelTime) { - if (valueBox != nullptr) - valueBox->hideEditor (false); + lastMouseWheelTime = e.eventTime; + + if (maximum > minimum && ! e.mods.isAnyMouseButtonDown()) + { + if (valueBox != nullptr) + valueBox->hideEditor (false); - const double value = (double) currentValue.getValue(); - const double proportionDelta = (wheel.deltaX != 0 ? -wheel.deltaX : wheel.deltaY) - * (wheel.isReversed ? -0.15f : 0.15f); - const double currentPos = owner.valueToProportionOfLength (value); - const double newValue = owner.proportionOfLengthToValue (jlimit (0.0, 1.0, currentPos + proportionDelta)); + const double value = (double) currentValue.getValue(); + const double delta = getMouseWheelDelta (value, (wheel.deltaX != 0 ? -wheel.deltaX : wheel.deltaY) + * (wheel.isReversed ? -1.0f : 1.0f)); - double delta = (newValue != value) ? jmax (std::abs (newValue - value), interval) : 0; - if (value > newValue) - delta = -delta; + if (delta != 0) + { + const double newValue = value + jmax (interval, std::abs (delta)) * (delta < 0 ? -1.0 : 1.0); - DragInProgress drag (*this); - setValue (owner.snapValue (value + delta, notDragging), sendNotificationSync); + DragInProgress drag (*this); + setValue (owner.snapValue (newValue, notDragging), sendNotificationSync); + } + } } return true; @@ -1236,6 +1252,7 @@ public: int sliderRegionStart, sliderRegionSize; int sliderBeingDragged; int pixelsForFullDragExtent; + Time lastMouseWheelTime; Rectangle sliderRect; ScopedPointer currentDrag; diff --git a/source/modules/juce_gui_basics/windows/juce_CallOutBox.cpp b/source/modules/juce_gui_basics/windows/juce_CallOutBox.cpp index 9b877fee5..39cc28b8e 100644 --- a/source/modules/juce_gui_basics/windows/juce_CallOutBox.cpp +++ b/source/modules/juce_gui_basics/windows/juce_CallOutBox.cpp @@ -91,7 +91,7 @@ void CallOutBox::setArrowSize (const float newSize) int CallOutBox::getBorderSize() const noexcept { - return jmax (20, (int) arrowSize); + return jmax (getLookAndFeel().getCallOutBoxBorderSize (*this), (int) arrowSize); } void CallOutBox::paint (Graphics& g) diff --git a/source/modules/juce_gui_basics/windows/juce_CallOutBox.h b/source/modules/juce_gui_basics/windows/juce_CallOutBox.h index a87a52cfb..8f574c1a7 100644 --- a/source/modules/juce_gui_basics/windows/juce_CallOutBox.h +++ b/source/modules/juce_gui_basics/windows/juce_CallOutBox.h @@ -130,6 +130,7 @@ public: virtual ~LookAndFeelMethods() {} virtual void drawCallOutBoxBackground (CallOutBox&, Graphics&, const Path&, Image& cachedImage) = 0; + virtual int getCallOutBoxBorderSize (const CallOutBox&) = 0; }; //============================================================================== diff --git a/source/modules/juce_gui_extra/misc/juce_LiveConstantEditor.cpp b/source/modules/juce_gui_extra/misc/juce_LiveConstantEditor.cpp index 79ae59ec8..1b88add1a 100644 --- a/source/modules/juce_gui_extra/misc/juce_LiveConstantEditor.cpp +++ b/source/modules/juce_gui_extra/misc/juce_LiveConstantEditor.cpp @@ -117,8 +117,8 @@ LivePropertyEditorBase::LivePropertyEditorBase (LiveValueBase& v, CodeDocument& name.setFont (13.0f); name.setText (v.name, dontSendNotification); - valueEditor.setMultiLine (true); - valueEditor.setReturnKeyStartsNewLine (true); + valueEditor.setMultiLine (v.isString()); + valueEditor.setReturnKeyStartsNewLine (v.isString()); valueEditor.setText (v.getStringValue (wasHex), dontSendNotification); valueEditor.addListener (this); sourceEditor.setReadOnly (true); @@ -381,7 +381,7 @@ struct ColourEditorComp : public Component, Colour getColour() const { - return Colour ((int) parseInt (editor.value.getStringValue (false))); + return Colour ((uint32) parseInt (editor.value.getStringValue (false))); } void paint (Graphics& g) override diff --git a/source/modules/juce_gui_extra/misc/juce_LiveConstantEditor.h b/source/modules/juce_gui_extra/misc/juce_LiveConstantEditor.h index 5e3a49558..44c312cd1 100644 --- a/source/modules/juce_gui_extra/misc/juce_LiveConstantEditor.h +++ b/source/modules/juce_gui_extra/misc/juce_LiveConstantEditor.h @@ -53,7 +53,7 @@ namespace LiveConstantEditor inline void setFromString (double& v, const String& s) { v = parseDouble (s); } inline void setFromString (float& v, const String& s) { v = (float) parseDouble (s); } inline void setFromString (String& v, const String& s) { v = s; } - inline void setFromString (Colour& v, const String& s) { v = Colour ((int) parseInt (s)); } + inline void setFromString (Colour& v, const String& s) { v = Colour ((uint32) parseInt (s)); } template inline String getAsString (const Type& v, bool) { return String (v); } @@ -67,6 +67,9 @@ namespace LiveConstantEditor inline String getAsString (uint64 v, bool preferHex) { return intToString ((int64) v, preferHex); } inline String getAsString (Colour v, bool) { return intToString ((int) v.getARGB(), true); } + template struct isStringType { enum { value = 0 }; }; + template <> struct isStringType { enum { value = 1 }; }; + template inline String getAsCode (Type& v, bool preferHex) { return getAsString (v, preferHex); } inline String getAsCode (Colour v, bool) { return "Colour (0x" + String::toHexString ((int) v.getARGB()).paddedLeft ('0', 8) + ")"; } @@ -90,6 +93,7 @@ namespace LiveConstantEditor virtual String getCodeValue (bool preferHex) const = 0; virtual void setStringValue (const String&) = 0; virtual String getOriginalStringValue (bool preferHex) const = 0; + virtual bool isString() const = 0; String name, sourceFile; int sourceLine; @@ -175,6 +179,7 @@ namespace LiveConstantEditor String getCodeValue (bool preferHex) const override { return getAsCode (value, preferHex); } String getOriginalStringValue (bool preferHex) const override { return getAsString (originalValue, preferHex); } void setStringValue (const String& s) override { setFromString (value, s); } + bool isString() const override { return isStringType::value; } Type value, originalValue;