| @@ -210,17 +210,15 @@ static SleepEvent sleepEvent; | |||||
| void JUCE_CALLTYPE Thread::sleep (const int millisecs) | void JUCE_CALLTYPE Thread::sleep (const int millisecs) | ||||
| { | { | ||||
| jassert (millisecs >= 0); | |||||
| if (millisecs >= 10 || sleepEvent.handle == 0) | if (millisecs >= 10 || sleepEvent.handle == 0) | ||||
| { | |||||
| Sleep ((DWORD) millisecs); | Sleep ((DWORD) millisecs); | ||||
| } | |||||
| else | else | ||||
| { | |||||
| // unlike Sleep() this is guaranteed to return to the current thread after | // unlike Sleep() this is guaranteed to return to the current thread after | ||||
| // the time expires, so we'll use this for short waits, which are more likely | // the time expires, so we'll use this for short waits, which are more likely | ||||
| // to need to be accurate | // to need to be accurate | ||||
| WaitForSingleObject (sleepEvent.handle, (DWORD) millisecs); | WaitForSingleObject (sleepEvent.handle, (DWORD) millisecs); | ||||
| } | |||||
| } | } | ||||
| void Thread::yield() | void Thread::yield() | ||||
| @@ -231,7 +229,7 @@ void Thread::yield() | |||||
| //============================================================================== | //============================================================================== | ||||
| static int lastProcessPriority = -1; | static int lastProcessPriority = -1; | ||||
| // called by WindowDriver because Windows does weird things to process priority | |||||
| // called when the app gains focus because Windows does weird things to process priority | |||||
| // when you swap apps, and this forces an update when the app is brought to the front. | // when you swap apps, and this forces an update when the app is brought to the front. | ||||
| void juce_repeatLastProcessPriority() | void juce_repeatLastProcessPriority() | ||||
| { | { | ||||
| @@ -59,18 +59,15 @@ public: | |||||
| ReadWriteLock() noexcept; | ReadWriteLock() noexcept; | ||||
| /** Destructor. | /** Destructor. | ||||
| If the object is deleted whilst locked, any subsequent behaviour | |||||
| is unpredictable. | |||||
| If the object is deleted whilst locked, any subsequent behaviour is undefined. | |||||
| */ | */ | ||||
| ~ReadWriteLock() noexcept; | ~ReadWriteLock() noexcept; | ||||
| //============================================================================== | //============================================================================== | ||||
| /** Locks this object for reading. | /** Locks this object for reading. | ||||
| Multiple threads can simulaneously lock the object for reading, but if another | |||||
| thread has it locked for writing, then this will block until it releases the | |||||
| lock. | |||||
| Multiple threads can simultaneously lock the object for reading, but if another | |||||
| thread has it locked for writing, then this will block until it releases the lock. | |||||
| @see exitRead, ScopedReadLock | @see exitRead, ScopedReadLock | ||||
| */ | */ | ||||
| @@ -78,7 +75,7 @@ public: | |||||
| /** Tries to lock this object for reading. | /** Tries to lock this object for reading. | ||||
| Multiple threads can simulaneously lock the object for reading, but if another | |||||
| Multiple threads can simultaneously lock the object for reading, but if another | |||||
| thread has it locked for writing, then this will fail and return false. | thread has it locked for writing, then this will fail and return false. | ||||
| @returns true if the lock is successfully gained. | @returns true if the lock is successfully gained. | ||||
| @@ -177,7 +177,7 @@ public: | |||||
| ModifierKeys withFlags (int rawFlagsToSet) const noexcept { return ModifierKeys (flags | rawFlagsToSet); } | ModifierKeys withFlags (int rawFlagsToSet) const noexcept { return ModifierKeys (flags | rawFlagsToSet); } | ||||
| /** Tests a combination of flags and returns true if any of them are set. */ | /** Tests a combination of flags and returns true if any of them are set. */ | ||||
| bool testFlags (const int flagsToTest) const noexcept { return (flags & flagsToTest) != 0; } | |||||
| bool testFlags (int flagsToTest) const noexcept { return (flags & flagsToTest) != 0; } | |||||
| /** Returns the total number of mouse buttons that are down. */ | /** Returns the total number of mouse buttons that are down. */ | ||||
| int getNumMouseButtonsDown() const noexcept; | int getNumMouseButtonsDown() const noexcept; | ||||
| @@ -49,7 +49,7 @@ void ComponentDragger::dragComponent (Component* const componentToDrag, const Mo | |||||
| // so their coordinates become wrong after the first one moves the window, so in that case, we'll use | // so their coordinates become wrong after the first one moves the window, so in that case, we'll use | ||||
| // the current mouse position instead of the one that the event contains... | // the current mouse position instead of the one that the event contains... | ||||
| if (componentToDrag->isOnDesktop()) | if (componentToDrag->isOnDesktop()) | ||||
| bounds += componentToDrag->getMouseXYRelative() - mouseDownWithinTarget; | |||||
| bounds += componentToDrag->getLocalPoint (nullptr, e.source.getScreenPosition()) - mouseDownWithinTarget; | |||||
| else | else | ||||
| bounds += e.getEventRelativeTo (componentToDrag).getPosition() - mouseDownWithinTarget; | bounds += e.getEventRelativeTo (componentToDrag).getPosition() - mouseDownWithinTarget; | ||||
| @@ -27,8 +27,9 @@ class MouseInputSourceInternal : private AsyncUpdater | |||||
| public: | public: | ||||
| //============================================================================== | //============================================================================== | ||||
| MouseInputSourceInternal (const int i, const bool isMouse) | MouseInputSourceInternal (const int i, const bool isMouse) | ||||
| : index (i), isMouseDevice (isMouse), lastPeer (nullptr), | |||||
| isUnboundedMouseModeOn (false), isCursorVisibleUntilOffscreen (false), currentCursorHandle (nullptr), | |||||
| : index (i), isMouseDevice (isMouse), | |||||
| isUnboundedMouseModeOn (false), isCursorVisibleUntilOffscreen (false), | |||||
| lastPeer (nullptr), currentCursorHandle (nullptr), | |||||
| mouseEventCounter (0), mouseMovedSignificantlySincePressed (false) | mouseEventCounter (0), mouseMovedSignificantlySincePressed (false) | ||||
| { | { | ||||
| } | } | ||||
| @@ -463,12 +464,13 @@ public: | |||||
| Point<int> lastScreenPos; | Point<int> lastScreenPos; | ||||
| ModifierKeys buttonState; | ModifierKeys buttonState; | ||||
| Point<int> unboundedMouseOffset; | |||||
| bool isUnboundedMouseModeOn, isCursorVisibleUntilOffscreen; | |||||
| private: | private: | ||||
| WeakReference<Component> componentUnderMouse; | WeakReference<Component> componentUnderMouse; | ||||
| ComponentPeer* lastPeer; | ComponentPeer* lastPeer; | ||||
| Point<int> unboundedMouseOffset; | |||||
| bool isUnboundedMouseModeOn, isCursorVisibleUntilOffscreen; | |||||
| void* currentCursorHandle; | void* currentCursorHandle; | ||||
| int mouseEventCounter; | int mouseEventCounter; | ||||
| @@ -550,6 +552,7 @@ bool MouseInputSource::hasMouseMovedSignificantlySincePressed() const noexcept | |||||
| bool MouseInputSource::canDoUnboundedMovement() const noexcept { return isMouse(); } | bool MouseInputSource::canDoUnboundedMovement() const noexcept { return isMouse(); } | ||||
| void MouseInputSource::enableUnboundedMouseMovement (bool isEnabled, bool keepCursorVisibleUntilOffscreen) const | void MouseInputSource::enableUnboundedMouseMovement (bool isEnabled, bool keepCursorVisibleUntilOffscreen) const | ||||
| { pimpl->enableUnboundedMouseMovement (isEnabled, keepCursorVisibleUntilOffscreen); } | { pimpl->enableUnboundedMouseMovement (isEnabled, keepCursorVisibleUntilOffscreen); } | ||||
| bool MouseInputSource::isUnboundedMouseMovementEnabled() const { return pimpl->isUnboundedMouseModeOn; } | |||||
| bool MouseInputSource::hasMouseCursor() const noexcept { return isMouse(); } | bool MouseInputSource::hasMouseCursor() const noexcept { return isMouse(); } | ||||
| void MouseInputSource::showMouseCursor (const MouseCursor& cursor) { pimpl->showMouseCursor (cursor, false); } | void MouseInputSource::showMouseCursor (const MouseCursor& cursor) { pimpl->showMouseCursor (cursor, false); } | ||||
| void MouseInputSource::hideCursor() { pimpl->hideCursor(); } | void MouseInputSource::hideCursor() { pimpl->hideCursor(); } | ||||
| @@ -158,6 +158,9 @@ public: | |||||
| */ | */ | ||||
| void enableUnboundedMouseMovement (bool isEnabled, bool keepCursorVisibleUntilOffscreen = false) const; | void enableUnboundedMouseMovement (bool isEnabled, bool keepCursorVisibleUntilOffscreen = false) const; | ||||
| /** Returns true if this source is currently in "unbounded" mode. */ | |||||
| bool isUnboundedMouseMovementEnabled() const; | |||||
| /** Attempts to set this mouse pointer's screen position. */ | /** Attempts to set this mouse pointer's screen position. */ | ||||
| void setScreenPosition (Point<int> newPosition); | void setScreenPosition (Point<int> newPosition); | ||||
| @@ -818,13 +818,11 @@ public: | |||||
| valueWhenLastDragged = owner.proportionOfLengthToValue (jlimit (0.0, 1.0, currentPos + speed)); | valueWhenLastDragged = owner.proportionOfLengthToValue (jlimit (0.0, 1.0, currentPos + speed)); | ||||
| e.source.enableUnboundedMouseMovement (true, false); | e.source.enableUnboundedMouseMovement (true, false); | ||||
| mouseWasHidden = true; | |||||
| } | } | ||||
| } | } | ||||
| void mouseDown (const MouseEvent& e) | void mouseDown (const MouseEvent& e) | ||||
| { | { | ||||
| mouseWasHidden = false; | |||||
| incDecDragged = false; | incDecDragged = false; | ||||
| useDragEvents = false; | useDragEvents = false; | ||||
| mouseDragStartPos = mousePosWhenLastDragged = e.getPosition(); | mouseDragStartPos = mousePosWhenLastDragged = e.getPosition(); | ||||
| @@ -880,9 +878,9 @@ public: | |||||
| void mouseDrag (const MouseEvent& e) | void mouseDrag (const MouseEvent& e) | ||||
| { | { | ||||
| if (useDragEvents | |||||
| && maximum > minimum | |||||
| && ! ((style == LinearBar || style == LinearBarVertical) && e.mouseWasClicked() && valueBox != nullptr && valueBox->isEditable())) | |||||
| if (useDragEvents && maximum > minimum | |||||
| && ! ((style == LinearBar || style == LinearBarVertical) | |||||
| && e.mouseWasClicked() && valueBox != nullptr && valueBox->isEditable())) | |||||
| { | { | ||||
| if (style == Rotary) | if (style == Rotary) | ||||
| { | { | ||||
| @@ -899,10 +897,7 @@ public: | |||||
| mouseDragStartPos = e.getPosition(); | mouseDragStartPos = e.getPosition(); | ||||
| } | } | ||||
| if (isVelocityBased == (userKeyOverridesVelocity && e.mods.testFlags (ModifierKeys::ctrlModifier | |||||
| | ModifierKeys::commandModifier | |||||
| | ModifierKeys::altModifier)) | |||||
| || (maximum - minimum) / sliderRegionSize < interval) | |||||
| if (isAbsoluteDragMode (e.mods) || (maximum - minimum) / sliderRegionSize < interval) | |||||
| handleAbsoluteDrag (e); | handleAbsoluteDrag (e); | ||||
| else | else | ||||
| handleVelocityDrag (e); | handleVelocityDrag (e); | ||||
| @@ -1019,50 +1014,54 @@ public: | |||||
| void modifierKeysChanged (const ModifierKeys& modifiers) | void modifierKeysChanged (const ModifierKeys& modifiers) | ||||
| { | { | ||||
| if (style != IncDecButtons | |||||
| && style != Rotary | |||||
| && isVelocityBased == modifiers.isAnyModifierKeyDown()) | |||||
| { | |||||
| if (style != IncDecButtons && style != Rotary && isAbsoluteDragMode (modifiers)) | |||||
| restoreMouseIfHidden(); | restoreMouseIfHidden(); | ||||
| } | |||||
| } | |||||
| bool isAbsoluteDragMode (ModifierKeys mods) const | |||||
| { | |||||
| return isVelocityBased == (userKeyOverridesVelocity | |||||
| && mods.testFlags (ModifierKeys::ctrlAltCommandModifiers)); | |||||
| } | } | ||||
| void restoreMouseIfHidden() | void restoreMouseIfHidden() | ||||
| { | { | ||||
| if (mouseWasHidden) | |||||
| const Array<MouseInputSource>& mouseSources = Desktop::getInstance().getMouseSources(); | |||||
| for (MouseInputSource* mi = mouseSources.begin(), * const e = mouseSources.end(); mi != e; ++mi) | |||||
| { | { | ||||
| mouseWasHidden = false; | |||||
| if (mi->isUnboundedMouseMovementEnabled()) | |||||
| { | |||||
| mi->enableUnboundedMouseMovement (false); | |||||
| const Array<MouseInputSource>& mouseSources = Desktop::getInstance().getMouseSources(); | |||||
| const double pos = sliderBeingDragged == 2 ? getMaxValue() | |||||
| : (sliderBeingDragged == 1 ? getMinValue() | |||||
| : (double) currentValue.getValue()); | |||||
| Point<int> mousePos; | |||||
| for (MouseInputSource* mi = mouseSources.begin(), * const e = mouseSources.end(); mi != e; ++mi) | |||||
| mi->enableUnboundedMouseMovement (false); | |||||
| if (isRotary()) | |||||
| { | |||||
| mousePos = mi->getLastMouseDownPosition(); | |||||
| const double pos = sliderBeingDragged == 2 ? getMaxValue() | |||||
| : (sliderBeingDragged == 1 ? getMinValue() | |||||
| : (double) currentValue.getValue()); | |||||
| Point<int> mousePos; | |||||
| const int delta = roundToInt (pixelsForFullDragExtent * (owner.valueToProportionOfLength (valueOnMouseDown) | |||||
| - owner.valueToProportionOfLength (pos))); | |||||
| if (isRotary()) | |||||
| { | |||||
| mousePos = Desktop::getLastMouseDownPosition(); | |||||
| if (style == RotaryHorizontalDrag) mousePos += Point<int> (-delta, 0); | |||||
| else if (style == RotaryVerticalDrag) mousePos += Point<int> (0, delta); | |||||
| else mousePos += Point<int> (delta / -2, delta / 2); | |||||
| const int delta = roundToInt (pixelsForFullDragExtent * (owner.valueToProportionOfLength (valueOnMouseDown) | |||||
| - owner.valueToProportionOfLength (pos))); | |||||
| mousePos = owner.getScreenBounds().getConstrainedPoint (mousePos); | |||||
| } | |||||
| else | |||||
| { | |||||
| const int pixelPos = (int) getLinearSliderPos (pos); | |||||
| if (style == RotaryHorizontalDrag) mousePos += Point<int> (-delta, 0); | |||||
| else if (style == RotaryVerticalDrag) mousePos += Point<int> (0, delta); | |||||
| else mousePos += Point<int> (delta / -2, delta / 2); | |||||
| } | |||||
| else | |||||
| { | |||||
| const int pixelPos = (int) getLinearSliderPos (pos); | |||||
| mousePos = owner.localPointToGlobal (Point<int> (isHorizontal() ? pixelPos : (owner.getWidth() / 2), | |||||
| isVertical() ? pixelPos : (owner.getHeight() / 2))); | |||||
| } | |||||
| mousePos = owner.localPointToGlobal (Point<int> (isHorizontal() ? pixelPos : (owner.getWidth() / 2), | |||||
| isVertical() ? pixelPos : (owner.getHeight() / 2))); | |||||
| mi->setScreenPosition (mousePos); | |||||
| } | } | ||||
| Desktop::setMousePosition (mousePos); | |||||
| } | } | ||||
| } | } | ||||
| @@ -1254,7 +1253,6 @@ public: | |||||
| bool popupDisplayEnabled; | bool popupDisplayEnabled; | ||||
| bool menuEnabled; | bool menuEnabled; | ||||
| bool useDragEvents; | bool useDragEvents; | ||||
| bool mouseWasHidden; | |||||
| bool incDecDragged; | bool incDecDragged; | ||||
| bool scrollWheelEnabled; | bool scrollWheelEnabled; | ||||
| bool snapsToMousePos; | bool snapsToMousePos; | ||||