diff --git a/extras/the jucer/build/mac/Jucer.xcodeproj/project.pbxproj b/extras/the jucer/build/mac/Jucer.xcodeproj/project.pbxproj index 706f734636..c0d52d3f44 100644 --- a/extras/the jucer/build/mac/Jucer.xcodeproj/project.pbxproj +++ b/extras/the jucer/build/mac/Jucer.xcodeproj/project.pbxproj @@ -524,6 +524,7 @@ buildSettings = { COPY_PHASE_STRIP = NO; GCC_OPTIMIZATION_LEVEL = 0; + GCC_PREPROCESSOR_DEFINITIONS = "DEBUG=1"; INFOPLIST_FILE = Info.plist; INSTALL_PATH = "$(HOME)/Applications"; PRODUCT_NAME = Jucer; diff --git a/juce_amalgamated.cpp b/juce_amalgamated.cpp index ff64544a67..abc3d95609 100644 --- a/juce_amalgamated.cpp +++ b/juce_amalgamated.cpp @@ -21718,20 +21718,15 @@ AudioFormatManager::AudioFormatManager() AudioFormatManager::~AudioFormatManager() { - clearFormats(); - clearSingletonInstance(); } -juce_ImplementSingleton (AudioFormatManager); - -void AudioFormatManager::registerFormat (AudioFormat* newFormat, - const bool makeThisTheDefaultFormat) +void AudioFormatManager::registerFormat (AudioFormat* newFormat, const bool makeThisTheDefaultFormat) { jassert (newFormat != 0); if (newFormat != 0) { -#if JUCE_DEBUG + #if JUCE_DEBUG for (int i = getNumKnownFormats(); --i >= 0;) { if (getKnownFormat (i)->getFormatName() == newFormat->getFormatName()) @@ -21739,7 +21734,7 @@ void AudioFormatManager::registerFormat (AudioFormat* newFormat, jassertfalse; // trying to add the same format twice! } } -#endif + #endif if (makeThisTheDefaultFormat) defaultFormatIndex = getNumKnownFormats(); @@ -21750,21 +21745,21 @@ void AudioFormatManager::registerFormat (AudioFormat* newFormat, void AudioFormatManager::registerBasicFormats() { -#if JUCE_MAC + #if JUCE_MAC registerFormat (new AiffAudioFormat(), true); registerFormat (new WavAudioFormat(), false); -#else + #else registerFormat (new WavAudioFormat(), true); registerFormat (new AiffAudioFormat(), false); -#endif + #endif -#if JUCE_USE_FLAC + #if JUCE_USE_FLAC registerFormat (new FlacAudioFormat(), false); -#endif + #endif -#if JUCE_USE_OGGVORBIS + #if JUCE_USE_OGGVORBIS registerFormat (new OggVorbisAudioFormat(), false); -#endif + #endif } void AudioFormatManager::clearFormats() @@ -22298,9 +22293,10 @@ public: for (int w = clip.getWidth(); --w >= 0;) { if (cacheData->isNonZero()) - g.drawVerticalLine (x++, jmax (midY - cacheData->maxValue * vscale - 0.3f, topY), - jmin (midY - cacheData->minValue * vscale + 0.3f, bottomY)); + g.drawVerticalLine (x, jmax (midY - cacheData->maxValue * vscale - 0.3f, topY), + jmin (midY - cacheData->minValue * vscale + 0.3f, bottomY)); + ++x; ++cacheData; } } @@ -41995,57 +41991,6 @@ void Component::internalMouseExit (MouseInputSource& source, const Point& r } } -class InternalDragRepeater : public Timer -{ -public: - InternalDragRepeater() - {} - - ~InternalDragRepeater() - { - clearSingletonInstance(); - } - - juce_DeclareSingleton_SingleThreaded_Minimal (InternalDragRepeater) - - void timerCallback() - { - Desktop& desktop = Desktop::getInstance(); - int numMiceDown = 0; - - for (int i = desktop.getNumMouseSources(); --i >= 0;) - { - MouseInputSource* const source = desktop.getMouseSource(i); - if (source->isDragging()) - { - source->triggerFakeMove(); - ++numMiceDown; - } - } - - if (numMiceDown == 0) - deleteInstance(); - } - -private: - JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (InternalDragRepeater); -}; - -juce_ImplementSingleton_SingleThreaded (InternalDragRepeater) - -void Component::beginDragAutoRepeat (const int interval) -{ - if (interval > 0) - { - if (InternalDragRepeater::getInstance()->getTimerInterval() != interval) - InternalDragRepeater::getInstance()->startTimer (interval); - } - else - { - InternalDragRepeater::deleteInstance(); - } -} - void Component::internalMouseDown (MouseInputSource& source, const Point& relativePos, const Time& time) { Desktop& desktop = Desktop::getInstance(); @@ -42254,7 +42199,15 @@ void Component::internalMouseWheel (MouseInputSource& source, const Point& void Component::sendFakeMouseMove() const { - Desktop::getInstance().getMainMouseSource().triggerFakeMove(); + MouseInputSource& mainMouse = Desktop::getInstance().getMainMouseSource(); + + if (! mainMouse.isDragging()) + mainMouse.triggerFakeMove(); +} + +void Component::beginDragAutoRepeat (const int interval) +{ + Desktop::getInstance().beginDragAutoRepeat (interval); } void Component::broughtToFront() @@ -42682,10 +42635,10 @@ ComponentPeer* Component::getPeer() const { if (flags.hasHeavyweightPeerFlag) return ComponentPeer::getPeerFor (this); - else if (parentComponent_ != 0) - return parentComponent_->getPeer(); - else + else if (parentComponent_ == 0) return 0; + + return parentComponent_->getPeer(); } Component::BailOutChecker::BailOutChecker (Component* const component1, Component* const component2_) @@ -42756,11 +42709,10 @@ extern void juce_updateMultiMonitorInfo (Array >& monitorCoords, void Desktop::refreshMonitorSizes() { - const Array > oldClipped (monitorCoordsClipped); - const Array > oldUnclipped (monitorCoordsUnclipped); + Array > oldClipped, oldUnclipped; + oldClipped.swapWithArray (monitorCoordsClipped); + oldUnclipped.swapWithArray (monitorCoordsUnclipped); - monitorCoordsClipped.clear(); - monitorCoordsUnclipped.clear(); juce_updateMultiMonitorInfo (monitorCoordsClipped, true); juce_updateMultiMonitorInfo (monitorCoordsUnclipped, false); jassert (monitorCoordsClipped.size() == monitorCoordsUnclipped.size()); @@ -42939,6 +42891,50 @@ MouseInputSource* Desktop::getDraggingMouseSource (int index) const throw() return 0; } +class MouseDragAutoRepeater : public Timer +{ +public: + MouseDragAutoRepeater() {} + + void timerCallback() + { + Desktop& desktop = Desktop::getInstance(); + int numMiceDown = 0; + + for (int i = desktop.getNumMouseSources(); --i >= 0;) + { + MouseInputSource* const source = desktop.getMouseSource(i); + if (source->isDragging()) + { + source->triggerFakeMove(); + ++numMiceDown; + } + } + + if (numMiceDown == 0) + desktop.beginDragAutoRepeat (0); + } + +private: + JUCE_DECLARE_NON_COPYABLE (MouseDragAutoRepeater); +}; + +void Desktop::beginDragAutoRepeat (const int interval) +{ + if (interval > 0) + { + if (dragRepeater == 0) + dragRepeater = new MouseDragAutoRepeater(); + + if (dragRepeater->getTimerInterval() != interval) + dragRepeater->startTimer (interval); + } + else + { + dragRepeater = 0; + } +} + void Desktop::addFocusChangeListener (FocusChangeListener* const listener) { focusListeners.add (listener); @@ -251648,7 +251644,7 @@ AudioIODeviceType* juce_createAudioIODeviceType_DirectSound() #if JUCE_INCLUDED_FILE && JUCE_WASAPI #ifndef WASAPI_ENABLE_LOGGING - #define WASAPI_ENABLE_LOGGING 1 + #define WASAPI_ENABLE_LOGGING 0 #endif namespace WasapiClasses @@ -251969,7 +251965,8 @@ public: reservoirCapacity = 16384; reservoir.setSize (actualNumChannels * reservoirCapacity * sizeof (float)); return openClient (newSampleRate, newChannels) - && (numChannels == 0 || check (client->GetService (__uuidof (IAudioCaptureClient), (void**) captureClient.resetAndGetPointerAddress()))); + && (numChannels == 0 || check (client->GetService (__uuidof (IAudioCaptureClient), + (void**) captureClient.resetAndGetPointerAddress()))); } void close() @@ -251979,18 +251976,19 @@ public: reservoir.setSize (0); } - void updateFormat (bool isFloat) + template + void updateFormatWithType (SourceType*) { typedef AudioData::Pointer NativeType; + converter = new AudioData::ConverterInstance , NativeType> (actualNumChannels, 1); + } - if (isFloat) - converter = new AudioData::ConverterInstance , NativeType> (actualNumChannels, 1); - else if (bytesPerSample == 4) - converter = new AudioData::ConverterInstance , NativeType> (actualNumChannels, 1); - else if (bytesPerSample == 3) - converter = new AudioData::ConverterInstance , NativeType> (actualNumChannels, 1); - else - converter = new AudioData::ConverterInstance , NativeType> (actualNumChannels, 1); + void updateFormat (bool isFloat) + { + if (isFloat) updateFormatWithType ((AudioData::Float32*) 0); + else if (bytesPerSample == 4) updateFormatWithType ((AudioData::Int32*) 0); + else if (bytesPerSample == 3) updateFormatWithType ((AudioData::Int24*) 0); + else updateFormatWithType ((AudioData::Int16*) 0); } void copyBuffers (float** destBuffers, int numDestBuffers, int bufferSize, Thread& thread) @@ -252011,7 +252009,7 @@ public: bufferSize -= samplesToDo; offset += samplesToDo; - reservoirSize -= samplesToDo; + reservoirSize = 0; } else { @@ -252021,14 +252019,14 @@ public: if (packetLength == 0) { - if (thread.threadShouldExit()) + if (thread.threadShouldExit() + || WaitForSingleObject (clientEvent, 1000) == WAIT_TIMEOUT) break; - Thread::sleep (1); continue; } - uint8* inputData = 0; + uint8* inputData; UINT32 numSamplesAvailable; DWORD flags; @@ -252089,18 +252087,19 @@ public: renderClient = 0; } - void updateFormat (bool isFloat) + template + void updateFormatWithType (DestType*) { typedef AudioData::Pointer NativeType; + converter = new AudioData::ConverterInstance > (1, actualNumChannels); + } - if (isFloat) - converter = new AudioData::ConverterInstance > (1, actualNumChannels); - else if (bytesPerSample == 4) - converter = new AudioData::ConverterInstance > (1, actualNumChannels); - else if (bytesPerSample == 3) - converter = new AudioData::ConverterInstance > (1, actualNumChannels); - else - converter = new AudioData::ConverterInstance > (1, actualNumChannels); + void updateFormat (bool isFloat) + { + if (isFloat) updateFormatWithType ((AudioData::Float32*) 0); + else if (bytesPerSample == 4) updateFormatWithType ((AudioData::Int32*) 0); + else if (bytesPerSample == 3) updateFormatWithType ((AudioData::Int24*) 0); + else updateFormatWithType ((AudioData::Int16*) 0); } void copyBuffers (const float** const srcBuffers, const int numSrcBuffers, int bufferSize, Thread& thread) @@ -252121,10 +252120,10 @@ public: if (samplesToDo <= 0) { - if (thread.threadShouldExit()) + if (thread.threadShouldExit() + || WaitForSingleObject (clientEvent, 1000) == WAIT_TIMEOUT) break; - Thread::sleep (0); continue; } @@ -252288,11 +252287,8 @@ public: return lastError; } - if (inputDevice != 0) - ResetEvent (inputDevice->clientEvent); - - if (outputDevice != 0) - ResetEvent (outputDevice->clientEvent); + if (inputDevice != 0) ResetEvent (inputDevice->clientEvent); + if (outputDevice != 0) ResetEvent (outputDevice->clientEvent); startThread (8); Thread::sleep (5); @@ -252318,20 +252314,15 @@ public: void close() { stop(); + signalThreadShouldExit(); - if (inputDevice != 0) - SetEvent (inputDevice->clientEvent); - - if (outputDevice != 0) - SetEvent (outputDevice->clientEvent); + if (inputDevice != 0) SetEvent (inputDevice->clientEvent); + if (outputDevice != 0) SetEvent (outputDevice->clientEvent); stopThread (5000); - if (inputDevice != 0) - inputDevice->close(); - - if (outputDevice != 0) - outputDevice->close(); + if (inputDevice != 0) inputDevice->close(); + if (outputDevice != 0) outputDevice->close(); isOpen_ = false; } @@ -252377,13 +252368,13 @@ public: void setMMThreadPriority() { DynamicLibraryLoader dll ("avrt.dll"); - DynamicLibraryImport (AvSetMmThreadCharacteristics, avSetMmThreadCharacteristics, HANDLE, dll, (LPCTSTR, LPDWORD)) + DynamicLibraryImport (AvSetMmThreadCharacteristicsW, avSetMmThreadCharacteristics, HANDLE, dll, (LPCWSTR, LPDWORD)) DynamicLibraryImport (AvSetMmThreadPriority, avSetMmThreadPriority, HANDLE, dll, (HANDLE, AVRT_PRIORITY)) if (avSetMmThreadCharacteristics != 0 && avSetMmThreadPriority != 0) { DWORD dummy = 0; - HANDLE h = avSetMmThreadCharacteristics (_T("Pro Audio"), &dummy); + HANDLE h = avSetMmThreadCharacteristics (L"Pro Audio", &dummy); if (h != 0) avSetMmThreadPriority (h, AVRT_PRIORITY_NORMAL); @@ -252396,13 +252387,6 @@ public: const int bufferSize = currentBufferSizeSamples; - HANDLE events[2]; - int numEvents = 0; - if (inputDevice != 0) - events [numEvents++] = inputDevice->clientEvent; - if (outputDevice != 0) - events [numEvents++] = outputDevice->clientEvent; - const int numInputBuffers = getActiveInputChannels().countNumberOfSetBits(); const int numOutputBuffers = getActiveOutputChannels().countNumberOfSetBits(); @@ -252414,44 +252398,28 @@ public: while (! threadShouldExit()) { - const DWORD result = useExclusiveMode ? (inputDevice != 0 ? WaitForSingleObject (inputDevice->clientEvent, 1000) : S_OK) - : WaitForMultipleObjects (numEvents, events, true, 1000); - if (result == WAIT_TIMEOUT) - continue; - - if (threadShouldExit()) - break; - if (inputDevice != 0) + { inputDevice->copyBuffers (inputBuffers, numInputBuffers, bufferSize, *this); - // Make the callback.. + if (threadShouldExit()) + break; + } + + JUCE_TRY { const ScopedLock sl (startStopLock); if (isStarted) - { - JUCE_TRY - { - callback->audioDeviceIOCallback ((const float**) inputBuffers, - numInputBuffers, - outputBuffers, - numOutputBuffers, - bufferSize); - } - JUCE_CATCH_EXCEPTION - } + callback->audioDeviceIOCallback (const_cast (inputBuffers), numInputBuffers, + outputBuffers, numOutputBuffers, bufferSize); else - { outs.clear(); - } } - - if (useExclusiveMode && WaitForSingleObject (outputDevice->clientEvent, 1000) == WAIT_TIMEOUT) - continue; + JUCE_CATCH_EXCEPTION if (outputDevice != 0) - outputDevice->copyBuffers ((const float**) outputBuffers, numOutputBuffers, bufferSize, *this); + outputDevice->copyBuffers (const_cast (outputBuffers), numOutputBuffers, bufferSize, *this); } } diff --git a/juce_amalgamated.h b/juce_amalgamated.h index 55f7c50524..6030ab24f3 100644 --- a/juce_amalgamated.h +++ b/juce_amalgamated.h @@ -64,7 +64,7 @@ */ #define JUCE_MAJOR_VERSION 1 #define JUCE_MINOR_VERSION 52 -#define JUCE_BUILDNUMBER 104 +#define JUCE_BUILDNUMBER 105 /** Current Juce version number. @@ -27535,24 +27535,21 @@ public: float wheelIncrementY); /** Ensures that a non-stop stream of mouse-drag events will be sent during the - next mouse-drag operation. + current mouse-drag operation. - This allows you to make sure that mouseDrag() events sent continuously, even + This allows you to make sure that mouseDrag() events are sent continuously, even when the mouse isn't moving. This can be useful for things like auto-scrolling components when the mouse is near an edge. Call this method during a mouseDown() or mouseDrag() callback, specifying the minimum interval between consecutive mouse drag callbacks. The callbacks will continue until the mouse is released, and then the interval will be reset, - so you need to make sure it's called every time you begin a drag event. If it - is called when the mouse isn't actually being pressed, it will apply to the next - mouse-drag operation that happens. - + so you need to make sure it's called every time you begin a drag event. Passing an interval of 0 or less will cancel the auto-repeat. - @see mouseDrag + @see mouseDrag, Desktop::beginDragAutoRepeat */ - static void beginDragAutoRepeat (int millisecondIntervalBetweenCallbacks); + static void beginDragAutoRepeat (int millisecondsBetweenCallbacks); /** Causes automatic repaints when the mouse enters or exits this component. @@ -29591,6 +29588,23 @@ public: */ MouseInputSource* getDraggingMouseSource (int index) const throw(); + /** Ensures that a non-stop stream of mouse-drag events will be sent during the + current mouse-drag operation. + + This allows you to make sure that mouseDrag() events are sent continuously, even + when the mouse isn't moving. This can be useful for things like auto-scrolling + components when the mouse is near an edge. + + Call this method during a mouseDown() or mouseDrag() callback, specifying the + minimum interval between consecutive mouse drag callbacks. The callbacks + will continue until the mouse is released, and then the interval will be reset, + so you need to make sure it's called every time you begin a drag event. + Passing an interval of 0 or less will cancel the auto-repeat. + + @see mouseDrag + */ + void beginDragAutoRepeat (int millisecondsBetweenCallbacks); + /** In a tablet device which can be turned around, this is used to inidicate the orientation. */ enum DisplayOrientation { @@ -29654,6 +29668,8 @@ private: int mouseClickCounter; void incrementMouseClickCounter() throw(); + ScopedPointer dragRepeater; + Component* kioskModeComponent; Rectangle kioskComponentOriginalBounds; @@ -32425,8 +32441,6 @@ public: /** Destructor. */ ~AudioFormatManager(); - juce_DeclareSingleton (AudioFormatManager, false); - /** Adds a format to the manager's list of available file types. The object passed-in will be deleted by this object, so don't keep a pointer @@ -56680,7 +56694,7 @@ public: /** Returns the component that was last known to be under this pointer. */ Component* getComponentUnderMouse() const; - /** Tells the device to dispatch a mouse-move event. + /** Tells the device to dispatch a mouse-move or mouse-drag event. This is asynchronous - the event will occur on the message thread. */ void triggerFakeMove() const; diff --git a/src/audio/audio_file_formats/juce_AudioFormatManager.cpp b/src/audio/audio_file_formats/juce_AudioFormatManager.cpp index 6fe49da78e..2cc8620e12 100644 --- a/src/audio/audio_file_formats/juce_AudioFormatManager.cpp +++ b/src/audio/audio_file_formats/juce_AudioFormatManager.cpp @@ -44,22 +44,16 @@ AudioFormatManager::AudioFormatManager() AudioFormatManager::~AudioFormatManager() { - clearFormats(); - clearSingletonInstance(); } -juce_ImplementSingleton (AudioFormatManager); - - //============================================================================== -void AudioFormatManager::registerFormat (AudioFormat* newFormat, - const bool makeThisTheDefaultFormat) +void AudioFormatManager::registerFormat (AudioFormat* newFormat, const bool makeThisTheDefaultFormat) { jassert (newFormat != 0); if (newFormat != 0) { -#if JUCE_DEBUG + #if JUCE_DEBUG for (int i = getNumKnownFormats(); --i >= 0;) { if (getKnownFormat (i)->getFormatName() == newFormat->getFormatName()) @@ -67,7 +61,7 @@ void AudioFormatManager::registerFormat (AudioFormat* newFormat, jassertfalse; // trying to add the same format twice! } } -#endif + #endif if (makeThisTheDefaultFormat) defaultFormatIndex = getNumKnownFormats(); @@ -78,21 +72,21 @@ void AudioFormatManager::registerFormat (AudioFormat* newFormat, void AudioFormatManager::registerBasicFormats() { -#if JUCE_MAC + #if JUCE_MAC registerFormat (new AiffAudioFormat(), true); registerFormat (new WavAudioFormat(), false); -#else + #else registerFormat (new WavAudioFormat(), true); registerFormat (new AiffAudioFormat(), false); -#endif + #endif -#if JUCE_USE_FLAC + #if JUCE_USE_FLAC registerFormat (new FlacAudioFormat(), false); -#endif + #endif -#if JUCE_USE_OGGVORBIS + #if JUCE_USE_OGGVORBIS registerFormat (new OggVorbisAudioFormat(), false); -#endif + #endif } void AudioFormatManager::clearFormats() diff --git a/src/audio/audio_file_formats/juce_AudioFormatManager.h b/src/audio/audio_file_formats/juce_AudioFormatManager.h index dfe8a7856b..5717619fa2 100644 --- a/src/audio/audio_file_formats/juce_AudioFormatManager.h +++ b/src/audio/audio_file_formats/juce_AudioFormatManager.h @@ -56,8 +56,6 @@ public: /** Destructor. */ ~AudioFormatManager(); - juce_DeclareSingleton (AudioFormatManager, false); - //============================================================================== /** Adds a format to the manager's list of available file types. diff --git a/src/audio/audio_file_formats/juce_AudioThumbnail.cpp b/src/audio/audio_file_formats/juce_AudioThumbnail.cpp index c16f1f7a07..cf9b6e49ac 100644 --- a/src/audio/audio_file_formats/juce_AudioThumbnail.cpp +++ b/src/audio/audio_file_formats/juce_AudioThumbnail.cpp @@ -370,9 +370,10 @@ public: for (int w = clip.getWidth(); --w >= 0;) { if (cacheData->isNonZero()) - g.drawVerticalLine (x++, jmax (midY - cacheData->maxValue * vscale - 0.3f, topY), - jmin (midY - cacheData->minValue * vscale + 0.3f, bottomY)); + g.drawVerticalLine (x, jmax (midY - cacheData->maxValue * vscale - 0.3f, topY), + jmin (midY - cacheData->minValue * vscale + 0.3f, bottomY)); + ++x; ++cacheData; } } diff --git a/src/core/juce_StandardHeader.h b/src/core/juce_StandardHeader.h index d77d9e401e..a4ef6a2334 100644 --- a/src/core/juce_StandardHeader.h +++ b/src/core/juce_StandardHeader.h @@ -33,7 +33,7 @@ */ #define JUCE_MAJOR_VERSION 1 #define JUCE_MINOR_VERSION 52 -#define JUCE_BUILDNUMBER 104 +#define JUCE_BUILDNUMBER 105 /** Current Juce version number. diff --git a/src/gui/components/juce_Component.cpp b/src/gui/components/juce_Component.cpp index aec29102e9..82c347d736 100644 --- a/src/gui/components/juce_Component.cpp +++ b/src/gui/components/juce_Component.cpp @@ -2296,59 +2296,6 @@ void Component::internalMouseExit (MouseInputSource& source, const Point& r } } -//============================================================================== -class InternalDragRepeater : public Timer -{ -public: - InternalDragRepeater() - {} - - ~InternalDragRepeater() - { - clearSingletonInstance(); - } - - juce_DeclareSingleton_SingleThreaded_Minimal (InternalDragRepeater) - - void timerCallback() - { - Desktop& desktop = Desktop::getInstance(); - int numMiceDown = 0; - - for (int i = desktop.getNumMouseSources(); --i >= 0;) - { - MouseInputSource* const source = desktop.getMouseSource(i); - if (source->isDragging()) - { - source->triggerFakeMove(); - ++numMiceDown; - } - } - - if (numMiceDown == 0) - deleteInstance(); - } - -private: - JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (InternalDragRepeater); -}; - -juce_ImplementSingleton_SingleThreaded (InternalDragRepeater) - - -void Component::beginDragAutoRepeat (const int interval) -{ - if (interval > 0) - { - if (InternalDragRepeater::getInstance()->getTimerInterval() != interval) - InternalDragRepeater::getInstance()->startTimer (interval); - } - else - { - InternalDragRepeater::deleteInstance(); - } -} - //============================================================================== void Component::internalMouseDown (MouseInputSource& source, const Point& relativePos, const Time& time) { @@ -2559,7 +2506,15 @@ void Component::internalMouseWheel (MouseInputSource& source, const Point& void Component::sendFakeMouseMove() const { - Desktop::getInstance().getMainMouseSource().triggerFakeMove(); + MouseInputSource& mainMouse = Desktop::getInstance().getMainMouseSource(); + + if (! mainMouse.isDragging()) + mainMouse.triggerFakeMove(); +} + +void Component::beginDragAutoRepeat (const int interval) +{ + Desktop::getInstance().beginDragAutoRepeat (interval); } void Component::broughtToFront() @@ -2993,10 +2948,10 @@ ComponentPeer* Component::getPeer() const { if (flags.hasHeavyweightPeerFlag) return ComponentPeer::getPeerFor (this); - else if (parentComponent_ != 0) - return parentComponent_->getPeer(); - else + else if (parentComponent_ == 0) return 0; + + return parentComponent_->getPeer(); } //============================================================================== diff --git a/src/gui/components/juce_Component.h b/src/gui/components/juce_Component.h index 4aafeec5bb..4e35ce66c0 100644 --- a/src/gui/components/juce_Component.h +++ b/src/gui/components/juce_Component.h @@ -1514,24 +1514,21 @@ public: //============================================================================== /** Ensures that a non-stop stream of mouse-drag events will be sent during the - next mouse-drag operation. + current mouse-drag operation. - This allows you to make sure that mouseDrag() events sent continuously, even + This allows you to make sure that mouseDrag() events are sent continuously, even when the mouse isn't moving. This can be useful for things like auto-scrolling components when the mouse is near an edge. Call this method during a mouseDown() or mouseDrag() callback, specifying the minimum interval between consecutive mouse drag callbacks. The callbacks will continue until the mouse is released, and then the interval will be reset, - so you need to make sure it's called every time you begin a drag event. If it - is called when the mouse isn't actually being pressed, it will apply to the next - mouse-drag operation that happens. - + so you need to make sure it's called every time you begin a drag event. Passing an interval of 0 or less will cancel the auto-repeat. - @see mouseDrag + @see mouseDrag, Desktop::beginDragAutoRepeat */ - static void beginDragAutoRepeat (int millisecondIntervalBetweenCallbacks); + static void beginDragAutoRepeat (int millisecondsBetweenCallbacks); /** Causes automatic repaints when the mouse enters or exits this component. diff --git a/src/gui/components/juce_Desktop.cpp b/src/gui/components/juce_Desktop.cpp index 1fc1bb49eb..5e8100dccc 100644 --- a/src/gui/components/juce_Desktop.cpp +++ b/src/gui/components/juce_Desktop.cpp @@ -70,11 +70,10 @@ extern void juce_updateMultiMonitorInfo (Array >& monitorCoords, void Desktop::refreshMonitorSizes() { - const Array > oldClipped (monitorCoordsClipped); - const Array > oldUnclipped (monitorCoordsUnclipped); + Array > oldClipped, oldUnclipped; + oldClipped.swapWithArray (monitorCoordsClipped); + oldUnclipped.swapWithArray (monitorCoordsUnclipped); - monitorCoordsClipped.clear(); - monitorCoordsUnclipped.clear(); juce_updateMultiMonitorInfo (monitorCoordsClipped, true); juce_updateMultiMonitorInfo (monitorCoordsUnclipped, false); jassert (monitorCoordsClipped.size() == monitorCoordsUnclipped.size()); @@ -256,6 +255,51 @@ MouseInputSource* Desktop::getDraggingMouseSource (int index) const throw() return 0; } +//============================================================================== +class MouseDragAutoRepeater : public Timer +{ +public: + MouseDragAutoRepeater() {} + + void timerCallback() + { + Desktop& desktop = Desktop::getInstance(); + int numMiceDown = 0; + + for (int i = desktop.getNumMouseSources(); --i >= 0;) + { + MouseInputSource* const source = desktop.getMouseSource(i); + if (source->isDragging()) + { + source->triggerFakeMove(); + ++numMiceDown; + } + } + + if (numMiceDown == 0) + desktop.beginDragAutoRepeat (0); + } + +private: + JUCE_DECLARE_NON_COPYABLE (MouseDragAutoRepeater); +}; + +void Desktop::beginDragAutoRepeat (const int interval) +{ + if (interval > 0) + { + if (dragRepeater == 0) + dragRepeater = new MouseDragAutoRepeater(); + + if (dragRepeater->getTimerInterval() != interval) + dragRepeater->startTimer (interval); + } + else + { + dragRepeater = 0; + } +} + //============================================================================== void Desktop::addFocusChangeListener (FocusChangeListener* const listener) { diff --git a/src/gui/components/juce_Desktop.h b/src/gui/components/juce_Desktop.h index 7d0a02fb78..e067c5bd4e 100644 --- a/src/gui/components/juce_Desktop.h +++ b/src/gui/components/juce_Desktop.h @@ -281,6 +281,22 @@ public: */ MouseInputSource* getDraggingMouseSource (int index) const throw(); + /** Ensures that a non-stop stream of mouse-drag events will be sent during the + current mouse-drag operation. + + This allows you to make sure that mouseDrag() events are sent continuously, even + when the mouse isn't moving. This can be useful for things like auto-scrolling + components when the mouse is near an edge. + + Call this method during a mouseDown() or mouseDrag() callback, specifying the + minimum interval between consecutive mouse drag callbacks. The callbacks + will continue until the mouse is released, and then the interval will be reset, + so you need to make sure it's called every time you begin a drag event. + Passing an interval of 0 or less will cancel the auto-repeat. + + @see mouseDrag + */ + void beginDragAutoRepeat (int millisecondsBetweenCallbacks); //============================================================================== /** In a tablet device which can be turned around, this is used to inidicate the orientation. */ @@ -347,6 +363,8 @@ private: int mouseClickCounter; void incrementMouseClickCounter() throw(); + ScopedPointer dragRepeater; + Component* kioskModeComponent; Rectangle kioskComponentOriginalBounds; diff --git a/src/gui/components/mouse/juce_MouseInputSource.h b/src/gui/components/mouse/juce_MouseInputSource.h index cb3ab4a9c2..cae78745b1 100644 --- a/src/gui/components/mouse/juce_MouseInputSource.h +++ b/src/gui/components/mouse/juce_MouseInputSource.h @@ -109,7 +109,7 @@ public: /** Returns the component that was last known to be under this pointer. */ Component* getComponentUnderMouse() const; - /** Tells the device to dispatch a mouse-move event. + /** Tells the device to dispatch a mouse-move or mouse-drag event. This is asynchronous - the event will occur on the message thread. */ void triggerFakeMove() const; diff --git a/src/native/windows/juce_win32_WASAPI.cpp b/src/native/windows/juce_win32_WASAPI.cpp index f8b8a1467c..df7b926603 100644 --- a/src/native/windows/juce_win32_WASAPI.cpp +++ b/src/native/windows/juce_win32_WASAPI.cpp @@ -28,7 +28,7 @@ #if JUCE_INCLUDED_FILE && JUCE_WASAPI #ifndef WASAPI_ENABLE_LOGGING - #define WASAPI_ENABLE_LOGGING 1 + #define WASAPI_ENABLE_LOGGING 0 #endif //============================================================================== @@ -353,7 +353,8 @@ public: reservoirCapacity = 16384; reservoir.setSize (actualNumChannels * reservoirCapacity * sizeof (float)); return openClient (newSampleRate, newChannels) - && (numChannels == 0 || check (client->GetService (__uuidof (IAudioCaptureClient), (void**) captureClient.resetAndGetPointerAddress()))); + && (numChannels == 0 || check (client->GetService (__uuidof (IAudioCaptureClient), + (void**) captureClient.resetAndGetPointerAddress()))); } void close() @@ -363,18 +364,19 @@ public: reservoir.setSize (0); } - void updateFormat (bool isFloat) + template + void updateFormatWithType (SourceType*) { typedef AudioData::Pointer NativeType; + converter = new AudioData::ConverterInstance , NativeType> (actualNumChannels, 1); + } - if (isFloat) - converter = new AudioData::ConverterInstance , NativeType> (actualNumChannels, 1); - else if (bytesPerSample == 4) - converter = new AudioData::ConverterInstance , NativeType> (actualNumChannels, 1); - else if (bytesPerSample == 3) - converter = new AudioData::ConverterInstance , NativeType> (actualNumChannels, 1); - else - converter = new AudioData::ConverterInstance , NativeType> (actualNumChannels, 1); + void updateFormat (bool isFloat) + { + if (isFloat) updateFormatWithType ((AudioData::Float32*) 0); + else if (bytesPerSample == 4) updateFormatWithType ((AudioData::Int32*) 0); + else if (bytesPerSample == 3) updateFormatWithType ((AudioData::Int24*) 0); + else updateFormatWithType ((AudioData::Int16*) 0); } void copyBuffers (float** destBuffers, int numDestBuffers, int bufferSize, Thread& thread) @@ -395,7 +397,7 @@ public: bufferSize -= samplesToDo; offset += samplesToDo; - reservoirSize -= samplesToDo; + reservoirSize = 0; } else { @@ -405,14 +407,14 @@ public: if (packetLength == 0) { - if (thread.threadShouldExit()) + if (thread.threadShouldExit() + || WaitForSingleObject (clientEvent, 1000) == WAIT_TIMEOUT) break; - Thread::sleep (1); continue; } - uint8* inputData = 0; + uint8* inputData; UINT32 numSamplesAvailable; DWORD flags; @@ -474,18 +476,19 @@ public: renderClient = 0; } - void updateFormat (bool isFloat) + template + void updateFormatWithType (DestType*) { typedef AudioData::Pointer NativeType; + converter = new AudioData::ConverterInstance > (1, actualNumChannels); + } - if (isFloat) - converter = new AudioData::ConverterInstance > (1, actualNumChannels); - else if (bytesPerSample == 4) - converter = new AudioData::ConverterInstance > (1, actualNumChannels); - else if (bytesPerSample == 3) - converter = new AudioData::ConverterInstance > (1, actualNumChannels); - else - converter = new AudioData::ConverterInstance > (1, actualNumChannels); + void updateFormat (bool isFloat) + { + if (isFloat) updateFormatWithType ((AudioData::Float32*) 0); + else if (bytesPerSample == 4) updateFormatWithType ((AudioData::Int32*) 0); + else if (bytesPerSample == 3) updateFormatWithType ((AudioData::Int24*) 0); + else updateFormatWithType ((AudioData::Int16*) 0); } void copyBuffers (const float** const srcBuffers, const int numSrcBuffers, int bufferSize, Thread& thread) @@ -506,10 +509,10 @@ public: if (samplesToDo <= 0) { - if (thread.threadShouldExit()) + if (thread.threadShouldExit() + || WaitForSingleObject (clientEvent, 1000) == WAIT_TIMEOUT) break; - Thread::sleep (0); continue; } @@ -675,11 +678,8 @@ public: return lastError; } - if (inputDevice != 0) - ResetEvent (inputDevice->clientEvent); - - if (outputDevice != 0) - ResetEvent (outputDevice->clientEvent); + if (inputDevice != 0) ResetEvent (inputDevice->clientEvent); + if (outputDevice != 0) ResetEvent (outputDevice->clientEvent); startThread (8); Thread::sleep (5); @@ -705,20 +705,15 @@ public: void close() { stop(); + signalThreadShouldExit(); - if (inputDevice != 0) - SetEvent (inputDevice->clientEvent); - - if (outputDevice != 0) - SetEvent (outputDevice->clientEvent); + if (inputDevice != 0) SetEvent (inputDevice->clientEvent); + if (outputDevice != 0) SetEvent (outputDevice->clientEvent); stopThread (5000); - if (inputDevice != 0) - inputDevice->close(); - - if (outputDevice != 0) - outputDevice->close(); + if (inputDevice != 0) inputDevice->close(); + if (outputDevice != 0) outputDevice->close(); isOpen_ = false; } @@ -764,13 +759,13 @@ public: void setMMThreadPriority() { DynamicLibraryLoader dll ("avrt.dll"); - DynamicLibraryImport (AvSetMmThreadCharacteristics, avSetMmThreadCharacteristics, HANDLE, dll, (LPCTSTR, LPDWORD)) + DynamicLibraryImport (AvSetMmThreadCharacteristicsW, avSetMmThreadCharacteristics, HANDLE, dll, (LPCWSTR, LPDWORD)) DynamicLibraryImport (AvSetMmThreadPriority, avSetMmThreadPriority, HANDLE, dll, (HANDLE, AVRT_PRIORITY)) if (avSetMmThreadCharacteristics != 0 && avSetMmThreadPriority != 0) { DWORD dummy = 0; - HANDLE h = avSetMmThreadCharacteristics (_T("Pro Audio"), &dummy); + HANDLE h = avSetMmThreadCharacteristics (L"Pro Audio", &dummy); if (h != 0) avSetMmThreadPriority (h, AVRT_PRIORITY_NORMAL); @@ -783,13 +778,6 @@ public: const int bufferSize = currentBufferSizeSamples; - HANDLE events[2]; - int numEvents = 0; - if (inputDevice != 0) - events [numEvents++] = inputDevice->clientEvent; - if (outputDevice != 0) - events [numEvents++] = outputDevice->clientEvent; - const int numInputBuffers = getActiveInputChannels().countNumberOfSetBits(); const int numOutputBuffers = getActiveOutputChannels().countNumberOfSetBits(); @@ -801,44 +789,28 @@ public: while (! threadShouldExit()) { - const DWORD result = useExclusiveMode ? (inputDevice != 0 ? WaitForSingleObject (inputDevice->clientEvent, 1000) : S_OK) - : WaitForMultipleObjects (numEvents, events, true, 1000); - if (result == WAIT_TIMEOUT) - continue; - - if (threadShouldExit()) - break; - if (inputDevice != 0) + { inputDevice->copyBuffers (inputBuffers, numInputBuffers, bufferSize, *this); - // Make the callback.. + if (threadShouldExit()) + break; + } + + JUCE_TRY { const ScopedLock sl (startStopLock); if (isStarted) - { - JUCE_TRY - { - callback->audioDeviceIOCallback ((const float**) inputBuffers, - numInputBuffers, - outputBuffers, - numOutputBuffers, - bufferSize); - } - JUCE_CATCH_EXCEPTION - } + callback->audioDeviceIOCallback (const_cast (inputBuffers), numInputBuffers, + outputBuffers, numOutputBuffers, bufferSize); else - { outs.clear(); - } } - - if (useExclusiveMode && WaitForSingleObject (outputDevice->clientEvent, 1000) == WAIT_TIMEOUT) - continue; + JUCE_CATCH_EXCEPTION if (outputDevice != 0) - outputDevice->copyBuffers ((const float**) outputBuffers, numOutputBuffers, bufferSize, *this); + outputDevice->copyBuffers (const_cast (outputBuffers), numOutputBuffers, bufferSize, *this); } }