Browse Source

Update juce, add all vital juce changes too

Signed-off-by: falkTX <falktx@falktx.com>
tags/2021-03-15
falkTX 4 years ago
parent
commit
ab81f77779
Signed by: falkTX <falktx@falktx.com> GPG Key ID: CDBAA37ABC74FBA0
55 changed files with 889 additions and 761 deletions
  1. +8
    -8
      libs/juce-current/patches/22_mingw-filechooser-no-vista.patch
  2. +28
    -28
      libs/juce-current/patches/24_vital-needed-changes.patch
  3. +2
    -2
      libs/juce-current/source/modules/juce_audio_basics/midi/juce_MidiKeyboardState.cpp
  4. +1
    -1
      libs/juce-current/source/modules/juce_audio_basics/midi/juce_MidiRPN.cpp
  5. +1
    -1
      libs/juce-current/source/modules/juce_audio_basics/mpe/juce_MPEUtils.cpp
  6. +24
    -1
      libs/juce-current/source/modules/juce_audio_formats/codecs/juce_WavAudioFormat.cpp
  7. +43
    -21
      libs/juce-current/source/modules/juce_audio_plugin_client/AU/juce_AU_Wrapper.mm
  8. +0
    -5
      libs/juce-current/source/modules/juce_audio_plugin_client/VST/juce_VST_Wrapper.cpp
  9. +6
    -0
      libs/juce-current/source/modules/juce_audio_plugin_client/VST3/juce_VST3_Wrapper.cpp
  10. +14
    -20
      libs/juce-current/source/modules/juce_audio_processors/format_types/juce_VSTPluginFormat.cpp
  11. +1
    -0
      libs/juce-current/source/modules/juce_audio_processors/juce_audio_processors.cpp
  12. +24
    -47
      libs/juce-current/source/modules/juce_audio_processors/processors/juce_AudioProcessorEditor.cpp
  13. +31
    -19
      libs/juce-current/source/modules/juce_audio_processors/processors/juce_AudioProcessorEditor.h
  14. +3
    -0
      libs/juce-current/source/modules/juce_audio_utils/gui/juce_AudioDeviceSelectorComponent.cpp
  15. +3
    -0
      libs/juce-current/source/modules/juce_core/native/juce_curl_Network.cpp
  16. +1
    -1
      libs/juce-current/source/modules/juce_core/native/juce_linux_Files.cpp
  17. +9
    -1
      libs/juce-current/source/modules/juce_core/system/juce_PlatformDefs.h
  18. +2
    -0
      libs/juce-current/source/modules/juce_dsp/native/juce_sse_SIMDNativeOps.h
  19. +223
    -220
      libs/juce-current/source/modules/juce_events/native/juce_mac_MessageManager.mm
  20. +1
    -4
      libs/juce-current/source/modules/juce_gui_basics/buttons/juce_Button.cpp
  21. +0
    -3
      libs/juce-current/source/modules/juce_gui_basics/buttons/juce_ShapeButton.cpp
  22. +3
    -2
      libs/juce-current/source/modules/juce_gui_basics/buttons/juce_ShapeButton.h
  23. +2
    -1
      libs/juce-current/source/modules/juce_gui_basics/components/juce_Component.cpp
  24. +9
    -1
      libs/juce-current/source/modules/juce_gui_basics/components/juce_Component.cpp.orig
  25. +2
    -5
      libs/juce-current/source/modules/juce_gui_basics/components/juce_Component.h
  26. +5
    -7
      libs/juce-current/source/modules/juce_gui_basics/filebrowser/juce_FileChooser.cpp
  27. +3
    -4
      libs/juce-current/source/modules/juce_gui_basics/filebrowser/juce_FileChooser.h
  28. +1
    -0
      libs/juce-current/source/modules/juce_gui_basics/juce_gui_basics.cpp
  29. +4
    -0
      libs/juce-current/source/modules/juce_gui_basics/juce_gui_basics.h
  30. +0
    -5
      libs/juce-current/source/modules/juce_gui_basics/keyboard/juce_CaretComponent.cpp
  31. +1
    -3
      libs/juce-current/source/modules/juce_gui_basics/keyboard/juce_CaretComponent.h
  32. +0
    -17
      libs/juce-current/source/modules/juce_gui_basics/layout/juce_ComponentBoundsConstrainer.cpp
  33. +2
    -4
      libs/juce-current/source/modules/juce_gui_basics/lookandfeel/juce_LookAndFeel_V1.cpp
  34. +0
    -2
      libs/juce-current/source/modules/juce_gui_basics/lookandfeel/juce_LookAndFeel_V1.h
  35. +0
    -2
      libs/juce-current/source/modules/juce_gui_basics/lookandfeel/juce_LookAndFeel_V4.cpp
  36. +0
    -3
      libs/juce-current/source/modules/juce_gui_basics/misc/juce_BubbleComponent.cpp
  37. +0
    -1
      libs/juce-current/source/modules/juce_gui_basics/misc/juce_BubbleComponent.h
  38. +2
    -2
      libs/juce-current/source/modules/juce_gui_basics/native/juce_linux_FileChooser.cpp
  39. +11
    -11
      libs/juce-current/source/modules/juce_gui_basics/native/juce_linux_Windowing.cpp
  40. +3
    -3
      libs/juce-current/source/modules/juce_gui_basics/native/juce_mac_FileChooser.mm
  41. +86
    -67
      libs/juce-current/source/modules/juce_gui_basics/native/juce_win32_FileChooser.cpp
  42. +245
    -207
      libs/juce-current/source/modules/juce_gui_basics/native/juce_win32_Windowing.cpp
  43. +3
    -3
      libs/juce-current/source/modules/juce_gui_basics/native/x11/juce_linux_XWindowSystem.cpp
  44. +1
    -1
      libs/juce-current/source/modules/juce_gui_basics/native/x11/juce_linux_XWindowSystem.h
  45. +3
    -2
      libs/juce-current/source/modules/juce_gui_basics/widgets/juce_Slider.cpp
  46. +11
    -0
      libs/juce-current/source/modules/juce_gui_basics/widgets/juce_TextEditor.cpp
  47. +0
    -3
      libs/juce-current/source/modules/juce_gui_extra/embedding/juce_ScopedDPIAwarenessDisabler.h
  48. +7
    -0
      libs/juce-current/source/modules/juce_gui_extra/juce_gui_extra.cpp
  49. +3
    -5
      libs/juce-current/source/modules/juce_gui_extra/native/juce_win32_HWNDComponent.cpp
  50. +1
    -0
      libs/juce-current/source/modules/juce_opengl/juce_opengl.cpp
  51. +1
    -1
      libs/juce-current/source/modules/juce_opengl/juce_opengl.h
  52. +8
    -0
      libs/juce-current/source/modules/juce_opengl/native/juce_MissingGLDefinitions.h
  53. +28
    -5
      libs/juce-current/source/modules/juce_opengl/native/juce_OpenGL_linux_X11.h
  54. +17
    -10
      libs/juce-current/source/modules/juce_opengl/native/juce_OpenGL_win32.h
  55. +2
    -2
      libs/juce-current/source/modules/juce_opengl/opengl/juce_OpenGLHelpers.cpp

+ 8
- 8
libs/juce-current/patches/22_mingw-filechooser-no-vista.patch View File

@@ -1,16 +1,16 @@
diff --git a/modules/juce_gui_basics/native/juce_win32_FileChooser.cpp b/modules/juce_gui_basics/native/juce_win32_FileChooser.cpp
index 0c1138a2b..a5b42b8ef 100644
--- a/modules/juce_gui_basics/native/juce_win32_FileChooser.cpp
+++ b/modules/juce_gui_basics/native/juce_win32_FileChooser.cpp
@@ -172,6 +172,7 @@ private:
diff --git a/modules/juce_gui_basics/native/juce_win32_FileChooser.cpp b/modules/juce_gui_basics/native/juce_win32_FileChooser.cpp
index 0c1138a2b..a5b42b8ef 100644
--- a/modules/juce_gui_basics/native/juce_win32_FileChooser.cpp
+++ b/modules/juce_gui_basics/native/juce_win32_FileChooser.cpp
@@ -172,6 +172,7 @@ private:
void operator() (LPWSTR ptr) const noexcept { CoTaskMemFree (ptr); } void operator() (LPWSTR ptr) const noexcept { CoTaskMemFree (ptr); }
}; };
+ #if JUCE_MSVC + #if JUCE_MSVC
bool showDialog (IFileDialog& dialog, bool async) const
bool showDialog (IFileDialog& dialog, bool async)
{ {
FILEOPENDIALOGOPTIONS flags = {}; FILEOPENDIALOGOPTIONS flags = {};
@@ -327,6 +328,7 @@ private:
@@ -327,6 +328,7 @@ private:
return result; return result;
} }
@@ -18,7 +18,7 @@ index 0c1138a2b..a5b42b8ef 100644
Array<URL> openDialogPreVista (bool async) Array<URL> openDialogPreVista (bool async)
{ {
@@ -436,11 +438,13 @@ private:
@@ -436,11 +438,13 @@ private:
const Remover remover (*this); const Remover remover (*this);


+ 28
- 28
libs/juce-current/patches/24_vital-needed-changes.patch View File

@@ -1,8 +1,8 @@
diff --git a/modules/juce_gui_basics/components/juce_Component.cpp b/modules/juce_gui_basics/components/juce_Component.cpp
index c4404c637..fa8d3ccf5 100644
--- a/modules/juce_gui_basics/components/juce_Component.cpp
+++ b/modules/juce_gui_basics/components/juce_Component.cpp
@@ -387,6 +387,10 @@ struct Component::ComponentHelpers
diff --git a/modules/juce_gui_basics/components/juce_Component.cpp b/modules/juce_gui_basics/components/juce_Component.cpp
index c4404c637..fa8d3ccf5 100644
--- a/modules/juce_gui_basics/components/juce_Component.cpp
+++ b/modules/juce_gui_basics/components/juce_Component.cpp
@@ -387,6 +387,10 @@ struct Component::ComponentHelpers
template <typename PointOrRect> template <typename PointOrRect>
static PointOrRect convertCoordinate (const Component* target, const Component* source, PointOrRect p) static PointOrRect convertCoordinate (const Component* target, const Component* source, PointOrRect p)
{ {
@@ -13,7 +13,7 @@ index c4404c637..fa8d3ccf5 100644
while (source != nullptr) while (source != nullptr)
{ {
if (source == target) if (source == target)
@@ -395,6 +399,9 @@ struct Component::ComponentHelpers
@@ -395,6 +399,9 @@ struct Component::ComponentHelpers
if (source->isParentOf (target)) if (source->isParentOf (target))
return convertFromDistantParentSpace (source, *target, p); return convertFromDistantParentSpace (source, *target, p);
@@ -23,7 +23,7 @@ index c4404c637..fa8d3ccf5 100644
p = convertToParentSpace (*source, p); p = convertToParentSpace (*source, p);
source = source->getParentComponent(); source = source->getParentComponent();
} }
@@ -1390,13 +1397,14 @@ bool Component::reallyContains (Point<int> point, bool returnTrueIfWithinAChild)
@@ -1390,13 +1397,14 @@ bool Component::reallyContains (Point<int> point, bool returnTrueIfWithinAChild)
Component* Component::getComponentAt (Point<int> position) Component* Component::getComponentAt (Point<int> position)
{ {
@@ -39,11 +39,11 @@ index c4404c637..fa8d3ccf5 100644
if (child != nullptr) if (child != nullptr)
return child; return child;
diff --git a/modules/juce_gui_basics/components/juce_Component.h b/modules/juce_gui_basics/components/juce_Component.h
index 6b2b0072b..ccb2681fa 100644
--- a/modules/juce_gui_basics/components/juce_Component.h
+++ b/modules/juce_gui_basics/components/juce_Component.h
@@ -2284,6 +2284,17 @@ public:
diff --git a/modules/juce_gui_basics/components/juce_Component.h b/modules/juce_gui_basics/components/juce_Component.h
index 6b2b0072b..ccb2681fa 100644
--- a/modules/juce_gui_basics/components/juce_Component.h
+++ b/modules/juce_gui_basics/components/juce_Component.h
@@ -2284,6 +2284,17 @@ public:
*/ */
bool getViewportIgnoreDragFlag() const noexcept { return flags.viewportIgnoreDragFlag; } bool getViewportIgnoreDragFlag() const noexcept { return flags.viewportIgnoreDragFlag; }
@@ -61,11 +61,11 @@ index 6b2b0072b..ccb2681fa 100644
private: private:
//============================================================================== //==============================================================================
friend class ComponentPeer; friend class ComponentPeer;
diff --git a/modules/juce_gui_basics/mouse/juce_MouseInputSource.cpp b/modules/juce_gui_basics/mouse/juce_MouseInputSource.cpp
index a8c2c283a..ddb15b88d 100644
--- a/modules/juce_gui_basics/mouse/juce_MouseInputSource.cpp
+++ b/modules/juce_gui_basics/mouse/juce_MouseInputSource.cpp
@@ -61,7 +61,7 @@ public:
diff --git a/modules/juce_gui_basics/mouse/juce_MouseInputSource.cpp b/modules/juce_gui_basics/mouse/juce_MouseInputSource.cpp
index a8c2c283a..ddb15b88d 100644
--- a/modules/juce_gui_basics/mouse/juce_MouseInputSource.cpp
+++ b/modules/juce_gui_basics/mouse/juce_MouseInputSource.cpp
@@ -61,7 +61,7 @@ public:
{ {
if (auto* peer = comp.getPeer()) if (auto* peer = comp.getPeer())
{ {
@@ -74,11 +74,11 @@ index a8c2c283a..ddb15b88d 100644
auto& peerComp = peer->getComponent(); auto& peerComp = peer->getComponent();
return comp.getLocalPoint (&peerComp, ScalingHelpers::unscaledScreenPosToScaled (peerComp, pos)); return comp.getLocalPoint (&peerComp, ScalingHelpers::unscaledScreenPosToScaled (peerComp, pos));
} }
diff --git a/modules/juce_gui_basics/windows/juce_ComponentPeer.cpp b/modules/juce_gui_basics/windows/juce_ComponentPeer.cpp
index 8d7febd4b..7ec8fbb00 100644
--- a/modules/juce_gui_basics/windows/juce_ComponentPeer.cpp
+++ b/modules/juce_gui_basics/windows/juce_ComponentPeer.cpp
@@ -474,7 +474,7 @@ bool ComponentPeer::handleDragMove (const ComponentPeer::DragInfo& info)
diff --git a/modules/juce_gui_basics/windows/juce_ComponentPeer.cpp b/modules/juce_gui_basics/windows/juce_ComponentPeer.cpp
index 8d7febd4b..7ec8fbb00 100644
--- a/modules/juce_gui_basics/windows/juce_ComponentPeer.cpp
+++ b/modules/juce_gui_basics/windows/juce_ComponentPeer.cpp
@@ -474,7 +474,7 @@ bool ComponentPeer::handleDragMove (const ComponentPeer::DragInfo& info)
if (DragHelpers::isSuitableTarget (info, newTarget)) if (DragHelpers::isSuitableTarget (info, newTarget))
{ {
dragAndDropTargetComponent = newTarget; dragAndDropTargetComponent = newTarget;
@@ -87,7 +87,7 @@ index 8d7febd4b..7ec8fbb00 100644
if (DragHelpers::isFileDrag (info)) if (DragHelpers::isFileDrag (info))
dynamic_cast<FileDragAndDropTarget*> (newTarget)->fileDragEnter (info.files, pos.x, pos.y); dynamic_cast<FileDragAndDropTarget*> (newTarget)->fileDragEnter (info.files, pos.x, pos.y);
@@ -491,7 +491,7 @@ bool ComponentPeer::handleDragMove (const ComponentPeer::DragInfo& info)
@@ -491,7 +491,7 @@ bool ComponentPeer::handleDragMove (const ComponentPeer::DragInfo& info)
if (! DragHelpers::isSuitableTarget (info, newTarget)) if (! DragHelpers::isSuitableTarget (info, newTarget))
return false; return false;
@@ -96,11 +96,11 @@ index 8d7febd4b..7ec8fbb00 100644
if (DragHelpers::isFileDrag (info)) if (DragHelpers::isFileDrag (info))
dynamic_cast<FileDragAndDropTarget*> (newTarget)->fileDragMove (info.files, pos.x, pos.y); dynamic_cast<FileDragAndDropTarget*> (newTarget)->fileDragMove (info.files, pos.x, pos.y);
diff --git a/modules/juce_opengl/native/juce_OpenGLExtensions.h b/modules/juce_opengl/native/juce_OpenGLExtensions.h
index e7eab9dbf..d7039b144 100644
--- a/modules/juce_opengl/native/juce_OpenGLExtensions.h
+++ b/modules/juce_opengl/native/juce_OpenGLExtensions.h
@@ -83,7 +83,13 @@ namespace juce
diff --git a/modules/juce_opengl/native/juce_OpenGLExtensions.h b/modules/juce_opengl/native/juce_OpenGLExtensions.h
index e7eab9dbf..d7039b144 100644
--- a/modules/juce_opengl/native/juce_OpenGLExtensions.h
+++ b/modules/juce_opengl/native/juce_OpenGLExtensions.h
@@ -83,7 +83,13 @@ namespace juce
USE_FUNCTION (glCheckFramebufferStatus, GLenum, (GLenum p1), (p1))\ USE_FUNCTION (glCheckFramebufferStatus, GLenum, (GLenum p1), (p1))\
USE_FUNCTION (glFramebufferTexture2D, void, (GLenum p1, GLenum p2, GLenum p3, GLuint p4, GLint p5), (p1, p2, p3, p4, p5))\ USE_FUNCTION (glFramebufferTexture2D, void, (GLenum p1, GLenum p2, GLenum p3, GLuint p4, GLint p5), (p1, p2, p3, p4, p5))\
USE_FUNCTION (glFramebufferRenderbuffer, void, (GLenum p1, GLenum p2, GLenum p3, GLuint p4), (p1, p2, p3, p4))\ USE_FUNCTION (glFramebufferRenderbuffer, void, (GLenum p1, GLenum p2, GLenum p3, GLuint p4), (p1, p2, p3, p4))\


+ 2
- 2
libs/juce-current/source/modules/juce_audio_basics/midi/juce_MidiKeyboardState.cpp View File

@@ -42,7 +42,7 @@ void MidiKeyboardState::reset()
bool MidiKeyboardState::isNoteOn (const int midiChannel, const int n) const noexcept bool MidiKeyboardState::isNoteOn (const int midiChannel, const int n) const noexcept
{ {
jassert (midiChannel >= 0 && midiChannel <= 16);
jassert (midiChannel > 0 && midiChannel <= 16);
return isPositiveAndBelow (n, 128) return isPositiveAndBelow (n, 128)
&& (noteStates[n] & (1 << (midiChannel - 1))) != 0; && (noteStates[n] & (1 << (midiChannel - 1))) != 0;
@@ -56,7 +56,7 @@ bool MidiKeyboardState::isNoteOnForChannels (const int midiChannelMask, const in
void MidiKeyboardState::noteOn (const int midiChannel, const int midiNoteNumber, const float velocity) void MidiKeyboardState::noteOn (const int midiChannel, const int midiNoteNumber, const float velocity)
{ {
jassert (midiChannel >= 0 && midiChannel <= 16);
jassert (midiChannel > 0 && midiChannel <= 16);
jassert (isPositiveAndBelow (midiNoteNumber, 128)); jassert (isPositiveAndBelow (midiNoteNumber, 128));
const ScopedLock sl (lock); const ScopedLock sl (lock);


+ 1
- 1
libs/juce-current/source/modules/juce_audio_basics/midi/juce_MidiRPN.cpp View File

@@ -36,7 +36,7 @@ bool MidiRPNDetector::parseControllerMessage (int midiChannel,
int controllerValue, int controllerValue,
MidiRPNMessage& result) noexcept MidiRPNMessage& result) noexcept
{ {
jassert (midiChannel >= 1 && midiChannel <= 16);
jassert (midiChannel > 0 && midiChannel <= 16);
jassert (controllerNumber >= 0 && controllerNumber < 128); jassert (controllerNumber >= 0 && controllerNumber < 128);
jassert (controllerValue >= 0 && controllerValue < 128); jassert (controllerValue >= 0 && controllerValue < 128);


+ 1
- 1
libs/juce-current/source/modules/juce_audio_basics/mpe/juce_MPEUtils.cpp View File

@@ -97,7 +97,7 @@ void MPEChannelAssigner::noteOff (int noteNumber, int midiChannel)
return false; return false;
}; };
if (midiChannel >= 0 && midiChannel < 17)
if (midiChannel >= 0 && midiChannel <= 16)
{ {
removeNote (midiChannels[midiChannel], noteNumber); removeNote (midiChannels[midiChannel], noteNumber);
return; return;


+ 24
- 1
libs/juce-current/source/modules/juce_audio_formats/codecs/juce_WavAudioFormat.cpp View File

@@ -842,6 +842,26 @@ namespace WavFileHelpers
return out.getMemoryBlock(); return out.getMemoryBlock();
} }
}; };
//==============================================================================
struct Clm_Chunk
{
static MemoryBlock createFrom (const StringPairArray& values)
{
MemoryOutputStream out;
auto s = values["clm "];
if (s.isNotEmpty())
{
out.writeString (s);
if ((out.getDataSize() & 1) != 0)
out.writeByte(0);
}
return out.getMemoryBlock();
}
};
//============================================================================== //==============================================================================
namespace AXMLChunk namespace AXMLChunk
@@ -1321,6 +1341,7 @@ public:
listInfoChunk = ListInfoChunk::createFrom (metadataValues); listInfoChunk = ListInfoChunk::createFrom (metadataValues);
acidChunk = AcidChunk::createFrom (metadataValues); acidChunk = AcidChunk::createFrom (metadataValues);
trckChunk = TracktionChunk::createFrom (metadataValues); trckChunk = TracktionChunk::createFrom (metadataValues);
clm_Chunk = Clm_Chunk::createFrom (metadataValues);
} }
headerPosition = out->getPosition(); headerPosition = out->getPosition();
@@ -1383,7 +1404,7 @@ public:
} }
private: private:
MemoryBlock tempBlock, bwavChunk, axmlChunk, smplChunk, instChunk, cueChunk, listChunk, listInfoChunk, acidChunk, trckChunk;
MemoryBlock tempBlock, bwavChunk, axmlChunk, smplChunk, instChunk, cueChunk, listChunk, listInfoChunk, acidChunk, trckChunk, clm_Chunk;
uint64 lengthInSamples = 0, bytesWritten = 0; uint64 lengthInSamples = 0, bytesWritten = 0;
int64 headerPosition = 0; int64 headerPosition = 0;
bool writeFailed = false; bool writeFailed = false;
@@ -1421,6 +1442,7 @@ private:
+ chunkSize (listInfoChunk) + chunkSize (listInfoChunk)
+ chunkSize (acidChunk) + chunkSize (acidChunk)
+ chunkSize (trckChunk) + chunkSize (trckChunk)
+ chunkSize (clm_Chunk)
+ (8 + 28)); // (ds64 chunk) + (8 + 28)); // (ds64 chunk)
riffChunkSize += (riffChunkSize & 1); riffChunkSize += (riffChunkSize & 1);
@@ -1503,6 +1525,7 @@ private:
writeChunk (listInfoChunk, chunkName ("LIST")); writeChunk (listInfoChunk, chunkName ("LIST"));
writeChunk (acidChunk, chunkName ("acid")); writeChunk (acidChunk, chunkName ("acid"));
writeChunk (trckChunk, chunkName ("Trkn")); writeChunk (trckChunk, chunkName ("Trkn"));
writeChunk (clm_Chunk, chunkName ("clm "));
writeChunkHeader (chunkName ("data"), isRF64 ? -1 : (int) (lengthInSamples * bytesPerFrame)); writeChunkHeader (chunkName ("data"), isRF64 ? -1 : (int) (lengthInSamples * bytesPerFrame));


+ 43
- 21
libs/juce-current/source/modules/juce_audio_plugin_client/AU/juce_AU_Wrapper.mm View File

@@ -1755,6 +1755,9 @@ private:
Array<const AudioProcessorParameterGroup*> parameterGroups; Array<const AudioProcessorParameterGroup*> parameterGroups;
//============================================================================== //==============================================================================
// According to the docs, this is the maximum size of a MIDIPacketList.
static constexpr UInt32 packetListBytes = 65536;
AudioUnitEvent auEvent; AudioUnitEvent auEvent;
mutable Array<AUPreset> presetsArray; mutable Array<AUPreset> presetsArray;
CriticalSection incomingMidiLock; CriticalSection incomingMidiLock;
@@ -1762,6 +1765,7 @@ private:
AudioTimeStamp lastTimeStamp; AudioTimeStamp lastTimeStamp;
int totalInChannels, totalOutChannels; int totalInChannels, totalOutChannels;
HeapBlock<bool> pulledSucceeded; HeapBlock<bool> pulledSucceeded;
HeapBlock<MIDIPacketList> packetList { packetListBytes, 1 };
ThreadLocalValue<bool> inParameterChangedCallback; ThreadLocalValue<bool> inParameterChangedCallback;
@@ -1858,37 +1862,55 @@ private:
void pushMidiOutput (UInt32 nFrames) noexcept void pushMidiOutput (UInt32 nFrames) noexcept
{ {
UInt32 numPackets = 0;
size_t dataSize = 0;
MIDIPacket* end = nullptr;
for (const auto metadata : midiEvents)
const auto init = [&]
{ {
jassert (isPositiveAndBelow (metadata.samplePosition, nFrames));
ignoreUnused (nFrames);
end = MIDIPacketListInit (packetList);
};
dataSize += (size_t) metadata.numBytes;
++numPackets;
}
MIDIPacket* p;
const size_t packetMembersSize = sizeof (MIDIPacket) - sizeof (p->data); // NB: GCC chokes on "sizeof (MidiMessage::data)"
const size_t packetListMembersSize = sizeof (MIDIPacketList) - sizeof (p->data);
const auto send = [&]
{
midiCallback.midiOutputCallback (midiCallback.userData, &lastTimeStamp, 0, packetList);
};
HeapBlock<MIDIPacketList> packetList;
packetList.malloc (packetListMembersSize + packetMembersSize * numPackets + dataSize, 1);
packetList->numPackets = numPackets;
const auto add = [&] (const MidiMessageMetadata& metadata)
{
end = MIDIPacketListAdd (packetList,
packetListBytes,
end,
static_cast<MIDITimeStamp> (metadata.samplePosition),
static_cast<ByteCount> (metadata.numBytes),
metadata.data);
};
p = packetList->packet;
init();
for (const auto metadata : midiEvents) for (const auto metadata : midiEvents)
{ {
p->timeStamp = (MIDITimeStamp) metadata.samplePosition;
p->length = (UInt16) metadata.numBytes;
memcpy (p->data, metadata.data, (size_t) metadata.numBytes);
p = MIDIPacketNext (p);
jassert (isPositiveAndBelow (metadata.samplePosition, nFrames));
ignoreUnused (nFrames);
add (metadata);
if (end == nullptr)
{
send();
init();
add (metadata);
if (end == nullptr)
{
// If this is hit, the size of this midi packet exceeds the maximum size of
// a MIDIPacketList. Large SysEx messages should be broken up into smaller
// chunks.
jassertfalse;
init();
}
}
} }
midiCallback.midiOutputCallback (midiCallback.userData, &lastTimeStamp, 0, packetList);
send();
} }
void GetAudioBufferList (bool isInput, int busIdx, AudioBufferList*& bufferList, bool& interleaved, int& numChannels) void GetAudioBufferList (bool isInput, int busIdx, AudioBufferList*& bufferList, bool& interleaved, int& numChannels)


+ 0
- 5
libs/juce-current/source/modules/juce_audio_plugin_client/VST/juce_VST_Wrapper.cpp View File

@@ -1158,11 +1158,6 @@ public:
{ {
auto editorBounds = getSizeToContainChild(); auto editorBounds = getSizeToContainChild();
#if JUCE_MAC
if (wrapper.useNSView)
setTopLeftPosition (0, getHeight() - editorBounds.getHeight());
#endif
resizeHostWindow (editorBounds.getWidth(), editorBounds.getHeight()); resizeHostWindow (editorBounds.getWidth(), editorBounds.getHeight());
{ {


+ 6
- 0
libs/juce-current/source/modules/juce_audio_plugin_client/VST3/juce_VST3_Wrapper.cpp View File

@@ -28,6 +28,9 @@
//============================================================================== //==============================================================================
#if JucePlugin_Build_VST3 && (JUCE_MAC || JUCE_WINDOWS || JUCE_LINUX) #if JucePlugin_Build_VST3 && (JUCE_MAC || JUCE_WINDOWS || JUCE_LINUX)
#if JUCE_LINUX^M
#include <arpa/inet.h>^M
#endif^M
#if JUCE_PLUGINHOST_VST3 #if JUCE_PLUGINHOST_VST3
#if JUCE_MAC #if JUCE_MAC
@@ -2618,6 +2621,9 @@ public:
//============================================================================== //==============================================================================
void processParameterChanges (Vst::IParameterChanges& paramChanges) void processParameterChanges (Vst::IParameterChanges& paramChanges)
{ {
if (juceVST3EditController == nullptr)
return;
jassert (pluginInstance != nullptr); jassert (pluginInstance != nullptr);
auto numParamsChanged = paramChanges.getParameterCount(); auto numParamsChanged = paramChanges.getParameterCount();


+ 14
- 20
libs/juce-current/source/modules/juce_audio_processors/format_types/juce_VSTPluginFormat.cpp View File

@@ -78,9 +78,6 @@ JUCE_BEGIN_IGNORE_WARNINGS_MSVC (4355)
//============================================================================== //==============================================================================
namespace juce namespace juce
{ {
#if JUCE_WINDOWS
extern void setThreadDPIAwarenessForWindow (HWND);
#endif
//============================================================================== //==============================================================================
namespace namespace
@@ -2848,38 +2845,30 @@ public:
if (recursiveResize) if (recursiveResize)
return; return;
auto* topComp = getTopLevelComponent();
if (topComp->getPeer() != nullptr)
if (auto* peer = getTopLevelComponent()->getPeer())
{ {
auto pos = (topComp->getLocalPoint (this, Point<int>()) * nativeScaleFactor).roundToInt();
const ScopedValueSetter<bool> recursiveResizeSetter (recursiveResize, true);
recursiveResize = true;
auto pos = (peer->getAreaCoveredBy (*this).toFloat() * nativeScaleFactor).toNearestInt();
#if JUCE_WINDOWS #if JUCE_WINDOWS
if (pluginHWND != 0) if (pluginHWND != 0)
{ {
setThreadDPIAwarenessForWindow (pluginHWND);
MoveWindow (pluginHWND, pos.getX(), pos.getY(),
roundToInt (getWidth() * nativeScaleFactor),
roundToInt (getHeight() * nativeScaleFactor),
TRUE);
ScopedThreadDPIAwarenessSetter threadDpiAwarenessSetter { pluginHWND };
MoveWindow (pluginHWND, pos.getX(), pos.getY(), pos.getWidth(), pos.getHeight(), TRUE);
} }
#elif JUCE_LINUX #elif JUCE_LINUX
if (pluginWindow != 0) if (pluginWindow != 0)
{ {
X11Symbols::getInstance()->xMoveResizeWindow (display, pluginWindow, X11Symbols::getInstance()->xMoveResizeWindow (display, pluginWindow,
pos.getX(), pos.getY(), pos.getX(), pos.getY(),
static_cast<unsigned int> (roundToInt ((float) getWidth() * nativeScaleFactor)),
static_cast<unsigned int> (roundToInt ((float) getHeight() * nativeScaleFactor)));
(unsigned int) pos.getWidth(),
(unsigned int) pos.getHeight());
X11Symbols::getInstance()->xMapRaised (display, pluginWindow); X11Symbols::getInstance()->xMapRaised (display, pluginWindow);
X11Symbols::getInstance()->xFlush (display); X11Symbols::getInstance()->xFlush (display);
} }
#endif #endif
recursiveResize = false;
} }
} }
@@ -3107,7 +3096,12 @@ private:
JUCE_END_IGNORE_WARNINGS_MSVC JUCE_END_IGNORE_WARNINGS_MSVC
RECT r; RECT r;
GetWindowRect (pluginHWND, &r);
{
ScopedThreadDPIAwarenessSetter threadDpiAwarenessSetter { pluginHWND };
GetWindowRect (pluginHWND, &r);
}
auto w = (int) (r.right - r.left); auto w = (int) (r.right - r.left);
auto h = (int) (r.bottom - r.top); auto h = (int) (r.bottom - r.top);
@@ -3122,7 +3116,7 @@ private:
// very dodgy logic to decide which size is right. // very dodgy logic to decide which size is right.
if (std::abs (rw - w) > 350 || std::abs (rh - h) > 350) if (std::abs (rw - w) > 350 || std::abs (rh - h) > 350)
{ {
setThreadDPIAwarenessForWindow (pluginHWND);
ScopedThreadDPIAwarenessSetter threadDpiAwarenessSetter { pluginHWND };
SetWindowPos (pluginHWND, 0, SetWindowPos (pluginHWND, 0,
0, 0, roundToInt (rw * nativeScaleFactor), roundToInt (rh * nativeScaleFactor), 0, 0, roundToInt (rw * nativeScaleFactor), roundToInt (rh * nativeScaleFactor),


+ 1
- 0
libs/juce-current/source/modules/juce_audio_processors/juce_audio_processors.cpp View File

@@ -35,6 +35,7 @@
#define JUCE_CORE_INCLUDE_NATIVE_HEADERS 1 #define JUCE_CORE_INCLUDE_NATIVE_HEADERS 1
#define JUCE_CORE_INCLUDE_OBJC_HELPERS 1 #define JUCE_CORE_INCLUDE_OBJC_HELPERS 1
#define JUCE_GUI_BASICS_INCLUDE_XHEADERS 1 #define JUCE_GUI_BASICS_INCLUDE_XHEADERS 1
#define JUCE_GUI_BASICS_INCLUDE_SCOPED_THREAD_DPI_AWARENESS_SETTER 1
#include "juce_audio_processors.h" #include "juce_audio_processors.h"
#include <juce_gui_extra/juce_gui_extra.h> #include <juce_gui_extra/juce_gui_extra.h>


+ 24
- 47
libs/juce-current/source/modules/juce_audio_processors/processors/juce_AudioProcessorEditor.cpp View File

@@ -54,38 +54,24 @@ void AudioProcessorEditor::hostMIDIControllerIsAvailable (bool) {
void AudioProcessorEditor::initialise() void AudioProcessorEditor::initialise()
{ {
resizable = false;
attachConstrainer (&defaultConstrainer);
setConstrainer (&defaultConstrainer);
resizeListener.reset (new AudioProcessorEditorListener (*this)); resizeListener.reset (new AudioProcessorEditorListener (*this));
addComponentListener (resizeListener.get()); addComponentListener (resizeListener.get());
} }
//============================================================================== //==============================================================================
void AudioProcessorEditor::setResizable (const bool shouldBeResizable, const bool useBottomRightCornerResizer)
void AudioProcessorEditor::setResizable (bool allowHostToResize, bool useBottomRightCornerResizer)
{ {
if (shouldBeResizable != resizable)
{
resizable = shouldBeResizable;
if (! resizable && constrainer == &defaultConstrainer)
{
auto width = getWidth();
auto height = getHeight();
if (width > 0 && height > 0)
defaultConstrainer.setSizeLimits (width, height, width, height);
}
}
resizableByHost = allowHostToResize;
bool shouldHaveCornerResizer = (useBottomRightCornerResizer && shouldBeResizable);
const auto hasResizableCorner = (resizableCorner.get() != nullptr);
if (shouldHaveCornerResizer != (resizableCorner != nullptr))
if (useBottomRightCornerResizer != hasResizableCorner)
{ {
if (shouldHaveCornerResizer)
if (useBottomRightCornerResizer)
attachResizableCornerComponent(); attachResizableCornerComponent();
else else
resizableCorner.reset();
resizableCorner = nullptr;
} }
} }
@@ -94,19 +80,23 @@ void AudioProcessorEditor::setResizeLimits (int newMinimumWidth,
int newMaximumWidth, int newMaximumWidth,
int newMaximumHeight) noexcept int newMaximumHeight) noexcept
{ {
// if you've set up a custom constrainer then these settings won't have any effect..
jassert (constrainer == &defaultConstrainer || constrainer == nullptr);
if (constrainer != nullptr && constrainer != &defaultConstrainer)
{
// if you've set up a custom constrainer then these settings won't have any effect..
jassertfalse;
return;
}
const bool shouldEnableResize = (newMinimumWidth != newMaximumWidth || newMinimumHeight != newMaximumHeight);
const bool shouldHaveCornerResizer = (shouldEnableResize != resizable || resizableCorner != nullptr);
resizableByHost = (newMinimumWidth != newMaximumWidth || newMinimumHeight != newMaximumHeight);
setResizable (shouldEnableResize, shouldHaveCornerResizer);
defaultConstrainer.setSizeLimits (newMinimumWidth, newMinimumHeight,
newMaximumWidth, newMaximumHeight);
if (constrainer == nullptr) if (constrainer == nullptr)
setConstrainer (&defaultConstrainer); setConstrainer (&defaultConstrainer);
defaultConstrainer.setSizeLimits (newMinimumWidth, newMinimumHeight,
newMaximumWidth, newMaximumHeight);
if (resizableCorner != nullptr)
attachResizableCornerComponent();
setBoundsConstrained (getBounds()); setBoundsConstrained (getBounds());
} }
@@ -115,29 +105,21 @@ void AudioProcessorEditor::setConstrainer (ComponentBoundsConstrainer* newConstr
{ {
if (constrainer != newConstrainer) if (constrainer != newConstrainer)
{ {
if (newConstrainer != nullptr)
resizable = (newConstrainer->getMinimumWidth() != newConstrainer->getMaximumWidth()
|| newConstrainer->getMinimumHeight() != newConstrainer->getMaximumHeight());
constrainer = newConstrainer;
updatePeer();
attachConstrainer (newConstrainer);
if (constrainer != nullptr)
resizableByHost = (newConstrainer->getMinimumWidth() != newConstrainer->getMaximumWidth()
|| newConstrainer->getMinimumHeight() != newConstrainer->getMaximumHeight());
if (resizableCorner != nullptr) if (resizableCorner != nullptr)
attachResizableCornerComponent(); attachResizableCornerComponent();
} }
} }
void AudioProcessorEditor::attachConstrainer (ComponentBoundsConstrainer* newConstrainer)
{
if (constrainer != newConstrainer)
{
constrainer = newConstrainer;
updatePeer();
}
}
void AudioProcessorEditor::attachResizableCornerComponent() void AudioProcessorEditor::attachResizableCornerComponent()
{ {
resizableCorner.reset (new ResizableCornerComponent (this, constrainer));
resizableCorner = std::make_unique<ResizableCornerComponent> (this, constrainer);
Component::addChildComponent (resizableCorner.get()); Component::addChildComponent (resizableCorner.get());
resizableCorner->setAlwaysOnTop (true); resizableCorner->setAlwaysOnTop (true);
editorResized (true); editorResized (true);
@@ -175,11 +157,6 @@ void AudioProcessorEditor::editorResized (bool wasResized)
getHeight() - resizerSize, getHeight() - resizerSize,
resizerSize, resizerSize); resizerSize, resizerSize);
} }
if (! resizable)
if (auto w = getWidth())
if (auto h = getHeight())
defaultConstrainer.setSizeLimits (w, h, w, h);
} }
} }


+ 31
- 19
libs/juce-current/source/modules/juce_audio_processors/processors/juce_AudioProcessorEditor.h View File

@@ -54,12 +54,12 @@ public:
/** Destructor. */ /** Destructor. */
~AudioProcessorEditor() override; ~AudioProcessorEditor() override;
//============================================================================== //==============================================================================
/** The AudioProcessor that this editor represents. */ /** The AudioProcessor that this editor represents. */
AudioProcessor& processor; AudioProcessor& processor;
/** Returns a pointer to the processor that this editor represents. /** Returns a pointer to the processor that this editor represents.
This method is here to support legacy code, but it's easier to just use the This method is here to support legacy code, but it's easier to just use the
AudioProcessorEditor::processor member variable directly to get this object. AudioProcessorEditor::processor member variable directly to get this object.
*/ */
@@ -76,6 +76,7 @@ public:
/** Some types of plugin can call this to suggest that the control for a particular /** Some types of plugin can call this to suggest that the control for a particular
parameter should be highlighted. parameter should be highlighted.
Currently only AAX plugins will call this, and implementing it is optional. Currently only AAX plugins will call this, and implementing it is optional.
*/ */
virtual void setControlHighlight (ParameterControlHighlightInfo); virtual void setControlHighlight (ParameterControlHighlightInfo);
@@ -117,36 +118,45 @@ public:
virtual void setScaleFactor (float newScale); virtual void setScaleFactor (float newScale);
//============================================================================== //==============================================================================
/** Marks the host's editor window as resizable
@param allowHostToResize whether the editor's parent window can be resized
by the user or the host. Even if this is false, you
can still resize your window yourself by calling
setBounds (for example, when a user clicks on a button
in your editor to drop out a panel) which will bypass any
resizable/constraints checks. If you are using
your own corner resizer than this will also bypass
any checks.
@param useBottomRightCornerResizer
/** Sets whether the editor is resizable by the host and/or user.
@param allowHostToResize whether the editor's parent window can be resized
by the host. Even if this is false, you can still
resize your window yourself by calling setBounds
(for example, when a user clicks on a button in
your editor to drop out a panel) which will bypass
any resizable/constraints checks.
@param useBottomRightCornerResizer if this is true, a ResizableCornerComponent will be
added to the editor's bottom-right to allow the user
to resize the editor regardless of the value of
`allowHostToResize`.
@see setResizeLimits, isResizable @see setResizeLimits, isResizable
*/ */
void setResizable (bool allowHostToResize, bool useBottomRightCornerResizer); void setResizable (bool allowHostToResize, bool useBottomRightCornerResizer);
/** Returns true if the host is allowed to resize editor's parent window
/** Returns true if the host is allowed to resize the editor's parent window.
@see setResizable @see setResizable
*/ */
bool isResizable() const noexcept { return resizable; }
bool isResizable() const noexcept { return resizableByHost; }
/** This sets the maximum and minimum sizes for the window. /** This sets the maximum and minimum sizes for the window.
If the window's current size is outside these limits, it will be resized to If the window's current size is outside these limits, it will be resized to
make sure it's within them. make sure it's within them.
If you pass in a different minimum and maximum size, this will mark the editor
as resizable by the host.
A direct call to setBounds() will bypass any constraint checks, but when the A direct call to setBounds() will bypass any constraint checks, but when the
window is dragged by the user or resized by other indirect means, the constrainer window is dragged by the user or resized by other indirect means, the constrainer
will limit the numbers involved. will limit the numbers involved.
Note that if you have set a custom constrainer for this editor then this will have
no effect, and if you have removed the constrainer with `setConstrainer (nullptr);`
then this will re-add the default constrainer with the new limits.
@see setResizable @see setResizable
*/ */
void setResizeLimits (int newMinimumWidth, void setResizeLimits (int newMinimumWidth,
@@ -154,8 +164,8 @@ public:
int newMaximumWidth, int newMaximumWidth,
int newMaximumHeight) noexcept; int newMaximumHeight) noexcept;
/** Returns the bounds constrainer object that this window is using. /** Returns the bounds constrainer object that this window is using.
You can access this to change its properties. You can access this to change its properties.
*/ */
ComponentBoundsConstrainer* getConstrainer() noexcept { return constrainer; } ComponentBoundsConstrainer* getConstrainer() noexcept { return constrainer; }
@@ -176,11 +186,14 @@ public:
*/ */
void setBoundsConstrained (Rectangle<int> newBounds); void setBoundsConstrained (Rectangle<int> newBounds);
/** The ResizableCornerComponent which is currently being used by this editor,
or nullptr if it does not have one.
*/
std::unique_ptr<ResizableCornerComponent> resizableCorner; std::unique_ptr<ResizableCornerComponent> resizableCorner;
private: private:
//============================================================================== //==============================================================================
struct AudioProcessorEditorListener : ComponentListener
struct AudioProcessorEditorListener : public ComponentListener
{ {
AudioProcessorEditorListener (AudioProcessorEditor& e) : ed (e) {} AudioProcessorEditorListener (AudioProcessorEditor& e) : ed (e) {}
@@ -198,14 +211,13 @@ private:
void initialise(); void initialise();
void editorResized (bool wasResized); void editorResized (bool wasResized);
void updatePeer(); void updatePeer();
void attachConstrainer (ComponentBoundsConstrainer*);
void attachResizableCornerComponent(); void attachResizableCornerComponent();
//============================================================================== //==============================================================================
std::unique_ptr<AudioProcessorEditorListener> resizeListener; std::unique_ptr<AudioProcessorEditorListener> resizeListener;
bool resizable;
bool resizableByHost = false;
ComponentBoundsConstrainer defaultConstrainer; ComponentBoundsConstrainer defaultConstrainer;
ComponentBoundsConstrainer* constrainer = {};
ComponentBoundsConstrainer* constrainer = nullptr;
AffineTransform hostScaleTransform; AffineTransform hostScaleTransform;
JUCE_DECLARE_NON_COPYABLE (AudioProcessorEditor) JUCE_DECLARE_NON_COPYABLE (AudioProcessorEditor)


+ 3
- 0
libs/juce-current/source/modules/juce_audio_utils/gui/juce_AudioDeviceSelectorComponent.cpp View File

@@ -393,6 +393,7 @@ public:
AlertWindow::showMessageBoxAsync (AlertWindow::WarningIcon, AlertWindow::showMessageBoxAsync (AlertWindow::WarningIcon,
TRANS("Error when trying to open audio device!"), TRANS("Error when trying to open audio device!"),
error); error);
resized();
} }
bool showDeviceControlPanel() bool showDeviceControlPanel()
@@ -1120,6 +1121,8 @@ void AudioDeviceSelectorComponent::updateMidiOutput()
deviceManager.setDefaultMidiOutputDevice ({}); deviceManager.setDefaultMidiOutputDevice ({});
else else
deviceManager.setDefaultMidiOutputDevice (currentMidiOutputs[selectedId - 1].identifier); deviceManager.setDefaultMidiOutputDevice (currentMidiOutputs[selectedId - 1].identifier);
resized();
} }
void AudioDeviceSelectorComponent::changeListenerCallback (ChangeBroadcaster*) void AudioDeviceSelectorComponent::changeListenerCallback (ChangeBroadcaster*)


+ 3
- 0
libs/juce-current/source/modules/juce_core/native/juce_curl_Network.cpp View File

@@ -332,6 +332,9 @@ public:
// or 3) data is in the in buffer // or 3) data is in the in buffer
while ((! finished) && curlBuffer.getSize() == 0) while ((! finished) && curlBuffer.getSize() == 0)
{ {
if (Thread::currentThreadShouldExit())
return false;
{ {
const ScopedLock lock (cleanupLock); const ScopedLock lock (cleanupLock);


+ 1
- 1
libs/juce-current/source/modules/juce_core/native/juce_linux_Files.cpp View File

@@ -203,7 +203,7 @@ bool Process::openDocument (const String& fileName, const String& parameters)
for (auto browserName : { "xdg-open", "/etc/alternatives/x-www-browser", "firefox", "mozilla", for (auto browserName : { "xdg-open", "/etc/alternatives/x-www-browser", "firefox", "mozilla",
"google-chrome", "chromium-browser", "opera", "konqueror" }) "google-chrome", "chromium-browser", "opera", "konqueror" })
{ {
cmdLines.add (String (browserName) + " " + cmdString.trim());
cmdLines.add (String (browserName) + " " + cmdString.trim().quoted());
} }
cmdString = cmdLines.joinIntoString (" || "); cmdString = cmdLines.joinIntoString (" || ");


+ 9
- 1
libs/juce-current/source/modules/juce_core/system/juce_PlatformDefs.h View File

@@ -186,7 +186,8 @@ namespace juce
#define JUCE_STRINGIFY(item) JUCE_STRINGIFY_MACRO_HELPER (item) #define JUCE_STRINGIFY(item) JUCE_STRINGIFY_MACRO_HELPER (item)
//============================================================================== //==============================================================================
/** This is a shorthand macro for declaring stubs for a class's copy constructor and operator=.
/** This is a shorthand macro for deleting a class's copy constructor and
copy assignment operator.
For example, instead of For example, instead of
@code @code
@@ -214,6 +215,13 @@ namespace juce
className (const className&) = delete;\ className (const className&) = delete;\
className& operator= (const className&) = delete; className& operator= (const className&) = delete;
/** This is a shorthand macro for deleting a class's move constructor and
move assignment operator.
*/
#define JUCE_DECLARE_NON_MOVEABLE(className) \
className (className&&) = delete;\
className& operator= (className&&) = delete;
/** This is a shorthand way of writing both a JUCE_DECLARE_NON_COPYABLE and /** This is a shorthand way of writing both a JUCE_DECLARE_NON_COPYABLE and
JUCE_LEAK_DETECTOR macro for a class. JUCE_LEAK_DETECTOR macro for a class.
*/ */


+ 2
- 0
libs/juce-current/source/modules/juce_dsp/native/juce_sse_SIMDNativeOps.h View File

@@ -74,6 +74,7 @@ struct SIMDNativeOps<float>
static forcedinline __m128 JUCE_VECTOR_CALLTYPE add (__m128 a, __m128 b) noexcept { return _mm_add_ps (a, b); } static forcedinline __m128 JUCE_VECTOR_CALLTYPE add (__m128 a, __m128 b) noexcept { return _mm_add_ps (a, b); }
static forcedinline __m128 JUCE_VECTOR_CALLTYPE sub (__m128 a, __m128 b) noexcept { return _mm_sub_ps (a, b); } static forcedinline __m128 JUCE_VECTOR_CALLTYPE sub (__m128 a, __m128 b) noexcept { return _mm_sub_ps (a, b); }
static forcedinline __m128 JUCE_VECTOR_CALLTYPE mul (__m128 a, __m128 b) noexcept { return _mm_mul_ps (a, b); } static forcedinline __m128 JUCE_VECTOR_CALLTYPE mul (__m128 a, __m128 b) noexcept { return _mm_mul_ps (a, b); }
static forcedinline __m128 JUCE_VECTOR_CALLTYPE div (__m128 a, __m128 b) noexcept { return _mm_div_ps (a, b); }
static forcedinline __m128 JUCE_VECTOR_CALLTYPE bit_and (__m128 a, __m128 b) noexcept { return _mm_and_ps (a, b); } static forcedinline __m128 JUCE_VECTOR_CALLTYPE bit_and (__m128 a, __m128 b) noexcept { return _mm_and_ps (a, b); }
static forcedinline __m128 JUCE_VECTOR_CALLTYPE bit_or (__m128 a, __m128 b) noexcept { return _mm_or_ps (a, b); } static forcedinline __m128 JUCE_VECTOR_CALLTYPE bit_or (__m128 a, __m128 b) noexcept { return _mm_or_ps (a, b); }
static forcedinline __m128 JUCE_VECTOR_CALLTYPE bit_xor (__m128 a, __m128 b) noexcept { return _mm_xor_ps (a, b); } static forcedinline __m128 JUCE_VECTOR_CALLTYPE bit_xor (__m128 a, __m128 b) noexcept { return _mm_xor_ps (a, b); }
@@ -142,6 +143,7 @@ struct SIMDNativeOps<double>
static forcedinline __m128d JUCE_VECTOR_CALLTYPE add (__m128d a, __m128d b) noexcept { return _mm_add_pd (a, b); } static forcedinline __m128d JUCE_VECTOR_CALLTYPE add (__m128d a, __m128d b) noexcept { return _mm_add_pd (a, b); }
static forcedinline __m128d JUCE_VECTOR_CALLTYPE sub (__m128d a, __m128d b) noexcept { return _mm_sub_pd (a, b); } static forcedinline __m128d JUCE_VECTOR_CALLTYPE sub (__m128d a, __m128d b) noexcept { return _mm_sub_pd (a, b); }
static forcedinline __m128d JUCE_VECTOR_CALLTYPE mul (__m128d a, __m128d b) noexcept { return _mm_mul_pd (a, b); } static forcedinline __m128d JUCE_VECTOR_CALLTYPE mul (__m128d a, __m128d b) noexcept { return _mm_mul_pd (a, b); }
static forcedinline __m128d JUCE_VECTOR_CALLTYPE div (__m128d a, __m128d b) noexcept { return _mm_div_pd (a, b); }
static forcedinline __m128d JUCE_VECTOR_CALLTYPE bit_and (__m128d a, __m128d b) noexcept { return _mm_and_pd (a, b); } static forcedinline __m128d JUCE_VECTOR_CALLTYPE bit_and (__m128d a, __m128d b) noexcept { return _mm_and_pd (a, b); }
static forcedinline __m128d JUCE_VECTOR_CALLTYPE bit_or (__m128d a, __m128d b) noexcept { return _mm_or_pd (a, b); } static forcedinline __m128d JUCE_VECTOR_CALLTYPE bit_or (__m128d a, __m128d b) noexcept { return _mm_or_pd (a, b); }
static forcedinline __m128d JUCE_VECTOR_CALLTYPE bit_xor (__m128d a, __m128d b) noexcept { return _mm_xor_pd (a, b); } static forcedinline __m128d JUCE_VECTOR_CALLTYPE bit_xor (__m128d a, __m128d b) noexcept { return _mm_xor_pd (a, b); }


+ 223
- 220
libs/juce-current/source/modules/juce_events/native/juce_mac_MessageManager.mm View File

@@ -33,300 +33,302 @@ using MenuTrackingChangedCallback = void (*)(bool);
MenuTrackingChangedCallback menuTrackingChangedCallback = nullptr; MenuTrackingChangedCallback menuTrackingChangedCallback = nullptr;
//============================================================================== //==============================================================================
struct AppDelegate
struct AppDelegateClass : public ObjCClass<NSObject>
{ {
public:
AppDelegate()
AppDelegateClass() : ObjCClass<NSObject> ("JUCEAppDelegate_")
{ {
static AppDelegateClass cls;
delegate = [cls.createInstance() init];
addMethod (@selector (applicationWillFinishLaunching:), applicationWillFinishLaunching, "v@:@");
addMethod (@selector (applicationShouldTerminate:), applicationShouldTerminate, "I@:@");
addMethod (@selector (applicationWillTerminate:), applicationWillTerminate, "v@:@");
addMethod (@selector (application:openFile:), application_openFile, "c@:@@");
addMethod (@selector (application:openFiles:), application_openFiles, "v@:@@");
addMethod (@selector (applicationDidBecomeActive:), applicationDidBecomeActive, "v@:@");
addMethod (@selector (applicationDidResignActive:), applicationDidResignActive, "v@:@");
addMethod (@selector (applicationWillUnhide:), applicationWillUnhide, "v@:@");
NSNotificationCenter* center = [NSNotificationCenter defaultCenter];
JUCE_BEGIN_IGNORE_WARNINGS_GCC_LIKE ("-Wundeclared-selector")
addMethod (@selector (getUrl:withReplyEvent:), getUrl_withReplyEvent, "v@:@@");
addMethod (@selector (broadcastMessageCallback:), broadcastMessageCallback, "v@:@");
addMethod (@selector (mainMenuTrackingBegan:), mainMenuTrackingBegan, "v@:@");
addMethod (@selector (mainMenuTrackingEnded:), mainMenuTrackingEnded, "v@:@");
addMethod (@selector (dummyMethod), dummyMethod, "v@:");
JUCE_END_IGNORE_WARNINGS_GCC_LIKE
#if JUCE_PUSH_NOTIFICATIONS
//==============================================================================
addIvar<NSObject<NSApplicationDelegate, NSUserNotificationCenterDelegate>*> ("pushNotificationsDelegate");
addMethod (@selector (applicationDidFinishLaunching:), applicationDidFinishLaunching, "v@:@");
JUCE_BEGIN_IGNORE_WARNINGS_GCC_LIKE ("-Wundeclared-selector") JUCE_BEGIN_IGNORE_WARNINGS_GCC_LIKE ("-Wundeclared-selector")
[center addObserver: delegate selector: @selector (mainMenuTrackingBegan:)
name: NSMenuDidBeginTrackingNotification object: nil];
[center addObserver: delegate selector: @selector (mainMenuTrackingEnded:)
name: NSMenuDidEndTrackingNotification object: nil];
addMethod (@selector (setPushNotificationsDelegate:), setPushNotificationsDelegate, "v@:@");
JUCE_END_IGNORE_WARNINGS_GCC_LIKE JUCE_END_IGNORE_WARNINGS_GCC_LIKE
if (JUCEApplicationBase::isStandaloneApp())
{
[NSApp setDelegate: delegate];
addMethod (@selector (application:didRegisterForRemoteNotificationsWithDeviceToken:), registeredForRemoteNotifications, "v@:@@");
addMethod (@selector (application:didFailToRegisterForRemoteNotificationsWithError:), failedToRegisterForRemoteNotifications, "v@:@@");
addMethod (@selector (application:didReceiveRemoteNotification:), didReceiveRemoteNotification, "v@:@@");
#endif
JUCE_BEGIN_IGNORE_WARNINGS_GCC_LIKE ("-Wundeclared-selector")
[[NSDistributedNotificationCenter defaultCenter] addObserver: delegate
selector: @selector (broadcastMessageCallback:)
name: getBroadcastEventName()
object: nil
suspensionBehavior: NSNotificationSuspensionBehaviorDeliverImmediately];
JUCE_END_IGNORE_WARNINGS_GCC_LIKE
}
else
{
[center addObserver: delegate selector: @selector (applicationDidResignActive:)
name: NSApplicationDidResignActiveNotification object: NSApp];
registerClass();
}
[center addObserver: delegate selector: @selector (applicationDidBecomeActive:)
name: NSApplicationDidBecomeActiveNotification object: NSApp];
private:
static void applicationWillFinishLaunching (id self, SEL, NSNotification*)
{
JUCE_BEGIN_IGNORE_WARNINGS_GCC_LIKE ("-Wundeclared-selector")
[[NSAppleEventManager sharedAppleEventManager] setEventHandler: self
andSelector: @selector (getUrl:withReplyEvent:)
forEventClass: kInternetEventClass
andEventID: kAEGetURL];
JUCE_END_IGNORE_WARNINGS_GCC_LIKE
}
[center addObserver: delegate selector: @selector (applicationWillUnhide:)
name: NSApplicationWillUnhideNotification object: NSApp];
#if JUCE_PUSH_NOTIFICATIONS
static void applicationDidFinishLaunching (id self, SEL, NSNotification* notification)
{
if (notification.userInfo != nil)
{
JUCE_BEGIN_IGNORE_WARNINGS_GCC_LIKE ("-Wdeprecated-declarations")
// NSUserNotification is deprecated from macOS 11, but there doesn't seem to be a
// replacement for NSApplicationLaunchUserNotificationKey returning a non-deprecated type
NSUserNotification* userNotification = notification.userInfo[NSApplicationLaunchUserNotificationKey];
JUCE_END_IGNORE_WARNINGS_GCC_LIKE
if (userNotification != nil && userNotification.userInfo != nil)
didReceiveRemoteNotification (self, nil, [NSApplication sharedApplication], userNotification.userInfo);
} }
} }
#endif
~AppDelegate()
static NSApplicationTerminateReply applicationShouldTerminate (id /*self*/, SEL, NSApplication*)
{ {
[[NSRunLoop currentRunLoop] cancelPerformSelectorsWithTarget: delegate];
[[NSNotificationCenter defaultCenter] removeObserver: delegate];
if (JUCEApplicationBase::isStandaloneApp())
if (auto* app = JUCEApplicationBase::getInstance())
{ {
[NSApp setDelegate: nil];
app->systemRequestedQuit();
[[NSDistributedNotificationCenter defaultCenter] removeObserver: delegate
name: getBroadcastEventName()
object: nil];
if (! MessageManager::getInstance()->hasStopMessageBeenSent())
return NSTerminateCancel;
} }
[delegate release];
return NSTerminateNow;
} }
static NSString* getBroadcastEventName()
static void applicationWillTerminate (id /*self*/, SEL, NSNotification*)
{ {
return juceStringToNS ("juce_" + String::toHexString (File::getSpecialLocation (File::currentExecutableFile).hashCode64()));
JUCEApplicationBase::appWillTerminateByForce();
} }
MessageQueue messageQueue;
id delegate;
private:
//==============================================================================
struct AppDelegateClass : public ObjCClass<NSObject>
static BOOL application_openFile (id /*self*/, SEL, NSApplication*, NSString* filename)
{ {
AppDelegateClass() : ObjCClass<NSObject> ("JUCEAppDelegate_")
if (auto* app = JUCEApplicationBase::getInstance())
{ {
addMethod (@selector (applicationWillFinishLaunching:), applicationWillFinishLaunching, "v@:@");
addMethod (@selector (applicationShouldTerminate:), applicationShouldTerminate, "I@:@");
addMethod (@selector (applicationWillTerminate:), applicationWillTerminate, "v@:@");
addMethod (@selector (application:openFile:), application_openFile, "c@:@@");
addMethod (@selector (application:openFiles:), application_openFiles, "v@:@@");
addMethod (@selector (applicationDidBecomeActive:), applicationDidBecomeActive, "v@:@");
addMethod (@selector (applicationDidResignActive:), applicationDidResignActive, "v@:@");
addMethod (@selector (applicationWillUnhide:), applicationWillUnhide, "v@:@");
app->anotherInstanceStarted (quotedIfContainsSpaces (filename));
return YES;
}
JUCE_BEGIN_IGNORE_WARNINGS_GCC_LIKE ("-Wundeclared-selector")
addMethod (@selector (getUrl:withReplyEvent:), getUrl_withReplyEvent, "v@:@@");
addMethod (@selector (broadcastMessageCallback:), broadcastMessageCallback, "v@:@");
addMethod (@selector (mainMenuTrackingBegan:), mainMenuTrackingBegan, "v@:@");
addMethod (@selector (mainMenuTrackingEnded:), mainMenuTrackingEnded, "v@:@");
addMethod (@selector (dummyMethod), dummyMethod, "v@:");
JUCE_END_IGNORE_WARNINGS_GCC_LIKE
return NO;
}
#if JUCE_PUSH_NOTIFICATIONS
//==============================================================================
addIvar<NSObject<NSApplicationDelegate, NSUserNotificationCenterDelegate>*> ("pushNotificationsDelegate");
static void application_openFiles (id /*self*/, SEL, NSApplication*, NSArray* filenames)
{
if (auto* app = JUCEApplicationBase::getInstance())
{
StringArray files;
addMethod (@selector (applicationDidFinishLaunching:), applicationDidFinishLaunching, "v@:@");
for (NSString* f in filenames)
files.add (quotedIfContainsSpaces (f));
JUCE_BEGIN_IGNORE_WARNINGS_GCC_LIKE ("-Wundeclared-selector")
addMethod (@selector (setPushNotificationsDelegate:), setPushNotificationsDelegate, "v@:@");
JUCE_END_IGNORE_WARNINGS_GCC_LIKE
if (files.size() > 0)
app->anotherInstanceStarted (files.joinIntoString (" "));
}
}
addMethod (@selector (application:didRegisterForRemoteNotificationsWithDeviceToken:), registeredForRemoteNotifications, "v@:@@");
addMethod (@selector (application:didFailToRegisterForRemoteNotificationsWithError:), failedToRegisterForRemoteNotifications, "v@:@@");
addMethod (@selector (application:didReceiveRemoteNotification:), didReceiveRemoteNotification, "v@:@@");
#endif
static void applicationDidBecomeActive (id /*self*/, SEL, NSNotification*) { focusChanged(); }
static void applicationDidResignActive (id /*self*/, SEL, NSNotification*) { focusChanged(); }
static void applicationWillUnhide (id /*self*/, SEL, NSNotification*) { focusChanged(); }
registerClass();
}
static void broadcastMessageCallback (id /*self*/, SEL, NSNotification* n)
{
NSDictionary* dict = (NSDictionary*) [n userInfo];
auto messageString = nsStringToJuce ((NSString*) [dict valueForKey: nsStringLiteral ("message")]);
MessageManager::getInstance()->deliverBroadcastMessage (messageString);
}
private:
static void applicationWillFinishLaunching (id self, SEL, NSNotification*)
{
JUCE_BEGIN_IGNORE_WARNINGS_GCC_LIKE ("-Wundeclared-selector")
[[NSAppleEventManager sharedAppleEventManager] setEventHandler: self
andSelector: @selector (getUrl:withReplyEvent:)
forEventClass: kInternetEventClass
andEventID: kAEGetURL];
JUCE_END_IGNORE_WARNINGS_GCC_LIKE
}
static void mainMenuTrackingBegan (id /*self*/, SEL, NSNotification*)
{
if (menuTrackingChangedCallback != nullptr)
(*menuTrackingChangedCallback) (true);
}
#if JUCE_PUSH_NOTIFICATIONS
static void applicationDidFinishLaunching (id self, SEL, NSNotification* notification)
{
if (notification.userInfo != nil)
{
JUCE_BEGIN_IGNORE_WARNINGS_GCC_LIKE ("-Wdeprecated-declarations")
// NSUserNotification is deprecated from macOS 11, but there doesn't seem to be a
// replacement for NSApplicationLaunchUserNotificationKey returning a non-deprecated type
NSUserNotification* userNotification = notification.userInfo[NSApplicationLaunchUserNotificationKey];
JUCE_END_IGNORE_WARNINGS_GCC_LIKE
if (userNotification != nil && userNotification.userInfo != nil)
didReceiveRemoteNotification (self, nil, [NSApplication sharedApplication], userNotification.userInfo);
}
}
#endif
static void mainMenuTrackingEnded (id /*self*/, SEL, NSNotification*)
{
if (menuTrackingChangedCallback != nullptr)
(*menuTrackingChangedCallback) (false);
}
static NSApplicationTerminateReply applicationShouldTerminate (id /*self*/, SEL, NSApplication*)
{
if (auto* app = JUCEApplicationBase::getInstance())
{
app->systemRequestedQuit();
static void dummyMethod (id /*self*/, SEL) {} // (used as a way of running a dummy thread)
if (! MessageManager::getInstance()->hasStopMessageBeenSent())
return NSTerminateCancel;
}
static void focusChanged()
{
if (appFocusChangeCallback != nullptr)
(*appFocusChangeCallback)();
}
return NSTerminateNow;
}
static void getUrl_withReplyEvent (id /*self*/, SEL, NSAppleEventDescriptor* event, NSAppleEventDescriptor*)
{
if (auto* app = JUCEApplicationBase::getInstance())
app->anotherInstanceStarted (quotedIfContainsSpaces ([[event paramDescriptorForKeyword: keyDirectObject] stringValue]));
}
static void applicationWillTerminate (id /*self*/, SEL, NSNotification*)
{
JUCEApplicationBase::appWillTerminateByForce();
}
static String quotedIfContainsSpaces (NSString* file)
{
String s (nsStringToJuce (file));
s = s.unquoted().replace ("\"", "\\\"");
static BOOL application_openFile (id /*self*/, SEL, NSApplication*, NSString* filename)
{
if (auto* app = JUCEApplicationBase::getInstance())
{
app->anotherInstanceStarted (quotedIfContainsSpaces (filename));
return YES;
}
if (s.containsChar (' '))
s = s.quoted();
return NO;
}
return s;
}
static void application_openFiles (id /*self*/, SEL, NSApplication*, NSArray* filenames)
{
if (auto* app = JUCEApplicationBase::getInstance())
{
StringArray files;
#if JUCE_PUSH_NOTIFICATIONS
//==============================================================================
static void setPushNotificationsDelegate (id self, SEL, NSObject<NSApplicationDelegate, NSUserNotificationCenterDelegate>* delegate)
{
object_setInstanceVariable (self, "pushNotificationsDelegate", delegate);
}
for (NSString* f in filenames)
files.add (quotedIfContainsSpaces (f));
static NSObject<NSApplicationDelegate, NSUserNotificationCenterDelegate>* getPushNotificationsDelegate (id self)
{
return getIvar<NSObject<NSApplicationDelegate, NSUserNotificationCenterDelegate>*> (self, "pushNotificationsDelegate");
}
if (files.size() > 0)
app->anotherInstanceStarted (files.joinIntoString (" "));
}
}
static void registeredForRemoteNotifications (id self, SEL, NSApplication* application, NSData* deviceToken)
{
auto* delegate = getPushNotificationsDelegate (self);
static void applicationDidBecomeActive (id /*self*/, SEL, NSNotification*) { focusChanged(); }
static void applicationDidResignActive (id /*self*/, SEL, NSNotification*) { focusChanged(); }
static void applicationWillUnhide (id /*self*/, SEL, NSNotification*) { focusChanged(); }
SEL selector = @selector (application:didRegisterForRemoteNotificationsWithDeviceToken:);
static void broadcastMessageCallback (id /*self*/, SEL, NSNotification* n)
if (delegate != nil && [delegate respondsToSelector: selector])
{ {
NSDictionary* dict = (NSDictionary*) [n userInfo];
auto messageString = nsStringToJuce ((NSString*) [dict valueForKey: nsStringLiteral ("message")]);
MessageManager::getInstance()->deliverBroadcastMessage (messageString);
}
NSInvocation* invocation = [NSInvocation invocationWithMethodSignature: [delegate methodSignatureForSelector: selector]];
[invocation setSelector: selector];
[invocation setTarget: delegate];
[invocation setArgument: &application atIndex:2];
[invocation setArgument: &deviceToken atIndex:3];
static void mainMenuTrackingBegan (id /*self*/, SEL, NSNotification*)
{
if (menuTrackingChangedCallback != nullptr)
(*menuTrackingChangedCallback) (true);
[invocation invoke];
} }
}
static void mainMenuTrackingEnded (id /*self*/, SEL, NSNotification*)
{
if (menuTrackingChangedCallback != nullptr)
(*menuTrackingChangedCallback) (false);
}
static void failedToRegisterForRemoteNotifications (id self, SEL, NSApplication* application, NSError* error)
{
auto* delegate = getPushNotificationsDelegate (self);
static void dummyMethod (id /*self*/, SEL) {} // (used as a way of running a dummy thread)
SEL selector = @selector (application:didFailToRegisterForRemoteNotificationsWithError:);
static void focusChanged()
if (delegate != nil && [delegate respondsToSelector: selector])
{ {
if (appFocusChangeCallback != nullptr)
(*appFocusChangeCallback)();
}
NSInvocation* invocation = [NSInvocation invocationWithMethodSignature: [delegate methodSignatureForSelector: selector]];
[invocation setSelector: selector];
[invocation setTarget: delegate];
[invocation setArgument: &application atIndex:2];
[invocation setArgument: &error atIndex:3];
static void getUrl_withReplyEvent (id /*self*/, SEL, NSAppleEventDescriptor* event, NSAppleEventDescriptor*)
{
if (auto* app = JUCEApplicationBase::getInstance())
app->anotherInstanceStarted (quotedIfContainsSpaces ([[event paramDescriptorForKeyword: keyDirectObject] stringValue]));
[invocation invoke];
} }
}
static String quotedIfContainsSpaces (NSString* file)
{
String s (nsStringToJuce (file));
s = s.unquoted().replace ("\"", "\\\"");
static void didReceiveRemoteNotification (id self, SEL, NSApplication* application, NSDictionary* userInfo)
{
auto* delegate = getPushNotificationsDelegate (self);
if (s.containsChar (' '))
s = s.quoted();
SEL selector = @selector (application:didReceiveRemoteNotification:);
return s;
}
#if JUCE_PUSH_NOTIFICATIONS
//==============================================================================
static void setPushNotificationsDelegate (id self, SEL, NSObject<NSApplicationDelegate, NSUserNotificationCenterDelegate>* delegate)
if (delegate != nil && [delegate respondsToSelector: selector])
{ {
object_setInstanceVariable (self, "pushNotificationsDelegate", delegate);
}
NSInvocation* invocation = [NSInvocation invocationWithMethodSignature: [delegate methodSignatureForSelector: selector]];
[invocation setSelector: selector];
[invocation setTarget: delegate];
[invocation setArgument: &application atIndex:2];
[invocation setArgument: &userInfo atIndex:3];
static NSObject<NSApplicationDelegate, NSUserNotificationCenterDelegate>* getPushNotificationsDelegate (id self)
{
return getIvar<NSObject<NSApplicationDelegate, NSUserNotificationCenterDelegate>*> (self, "pushNotificationsDelegate");
[invocation invoke];
} }
}
#endif
};
static void registeredForRemoteNotifications (id self, SEL, NSApplication* application, NSData* deviceToken)
{
auto* delegate = getPushNotificationsDelegate (self);
// This is declared at file scope, so that it's guaranteed to be
// constructed before and destructed after `appDelegate` (below)
static AppDelegateClass appDelegateClass;
SEL selector = @selector (application:didRegisterForRemoteNotificationsWithDeviceToken:);
//==============================================================================
struct AppDelegate
{
public:
AppDelegate()
{
delegate = [appDelegateClass.createInstance() init];
if (delegate != nil && [delegate respondsToSelector: selector])
{
NSInvocation* invocation = [NSInvocation invocationWithMethodSignature: [delegate methodSignatureForSelector: selector]];
[invocation setSelector: selector];
[invocation setTarget: delegate];
[invocation setArgument: &application atIndex:2];
[invocation setArgument: &deviceToken atIndex:3];
NSNotificationCenter* center = [NSNotificationCenter defaultCenter];
[invocation invoke];
}
}
JUCE_BEGIN_IGNORE_WARNINGS_GCC_LIKE ("-Wundeclared-selector")
[center addObserver: delegate selector: @selector (mainMenuTrackingBegan:)
name: NSMenuDidBeginTrackingNotification object: nil];
[center addObserver: delegate selector: @selector (mainMenuTrackingEnded:)
name: NSMenuDidEndTrackingNotification object: nil];
JUCE_END_IGNORE_WARNINGS_GCC_LIKE
static void failedToRegisterForRemoteNotifications (id self, SEL, NSApplication* application, NSError* error)
if (JUCEApplicationBase::isStandaloneApp())
{ {
auto* delegate = getPushNotificationsDelegate (self);
[NSApp setDelegate: delegate];
SEL selector = @selector (application:didFailToRegisterForRemoteNotificationsWithError:);
JUCE_BEGIN_IGNORE_WARNINGS_GCC_LIKE ("-Wundeclared-selector")
[[NSDistributedNotificationCenter defaultCenter] addObserver: delegate
selector: @selector (broadcastMessageCallback:)
name: getBroadcastEventName()
object: nil
suspensionBehavior: NSNotificationSuspensionBehaviorDeliverImmediately];
JUCE_END_IGNORE_WARNINGS_GCC_LIKE
}
else
{
[center addObserver: delegate selector: @selector (applicationDidResignActive:)
name: NSApplicationDidResignActiveNotification object: NSApp];
if (delegate != nil && [delegate respondsToSelector: selector])
{
NSInvocation* invocation = [NSInvocation invocationWithMethodSignature: [delegate methodSignatureForSelector: selector]];
[invocation setSelector: selector];
[invocation setTarget: delegate];
[invocation setArgument: &application atIndex:2];
[invocation setArgument: &error atIndex:3];
[center addObserver: delegate selector: @selector (applicationDidBecomeActive:)
name: NSApplicationDidBecomeActiveNotification object: NSApp];
[invocation invoke];
}
[center addObserver: delegate selector: @selector (applicationWillUnhide:)
name: NSApplicationWillUnhideNotification object: NSApp];
} }
}
static void didReceiveRemoteNotification (id self, SEL, NSApplication* application, NSDictionary* userInfo)
~AppDelegate()
{
[[NSRunLoop currentRunLoop] cancelPerformSelectorsWithTarget: delegate];
[[NSNotificationCenter defaultCenter] removeObserver: delegate];
if (JUCEApplicationBase::isStandaloneApp())
{ {
auto* delegate = getPushNotificationsDelegate (self);
[NSApp setDelegate: nil];
SEL selector = @selector (application:didReceiveRemoteNotification:);
[[NSDistributedNotificationCenter defaultCenter] removeObserver: delegate
name: getBroadcastEventName()
object: nil];
}
if (delegate != nil && [delegate respondsToSelector: selector])
{
NSInvocation* invocation = [NSInvocation invocationWithMethodSignature: [delegate methodSignatureForSelector: selector]];
[invocation setSelector: selector];
[invocation setTarget: delegate];
[invocation setArgument: &application atIndex:2];
[invocation setArgument: &userInfo atIndex:3];
[delegate release];
}
[invocation invoke];
}
}
#endif
};
static NSString* getBroadcastEventName()
{
return juceStringToNS ("juce_" + String::toHexString (File::getSpecialLocation (File::currentExecutableFile).hashCode64()));
}
MessageQueue messageQueue;
id delegate;
}; };
//============================================================================== //==============================================================================
@@ -367,6 +369,7 @@ void MessageManager::runDispatchLoop()
static void shutdownNSApp() static void shutdownNSApp()
{ {
[NSApp stop: nil]; [NSApp stop: nil];
[NSEvent stopPeriodicEvents];
[NSEvent startPeriodicEventsAfterDelay: 0 withPeriod: 0.1]; [NSEvent startPeriodicEventsAfterDelay: 0 withPeriod: 0.1];
} }


+ 1
- 4
libs/juce-current/source/modules/juce_gui_basics/buttons/juce_Button.cpp View File

@@ -482,10 +482,7 @@ void Button::mouseDrag (const MouseEvent& e)
bool Button::isMouseSourceOver (const MouseEvent& e) bool Button::isMouseSourceOver (const MouseEvent& e)
{ {
if (e.source.isTouch() || e.source.isPen())
return getLocalBounds().toFloat().contains (e.position);
return isMouseOver();
return getLocalBounds().toFloat().contains (e.position);
} }
void Button::focusGained (FocusChangeType) void Button::focusGained (FocusChangeType)


+ 0
- 3
libs/juce-current/source/modules/juce_gui_basics/buttons/juce_ShapeButton.cpp View File

@@ -76,9 +76,6 @@ void ShapeButton::setShape (const Path& newShape,
shape = newShape; shape = newShape;
maintainShapeProportions = maintainShapeProportions_; maintainShapeProportions = maintainShapeProportions_;
shadow.setShadowProperties (DropShadow (Colours::black.withAlpha (0.5f), 3, Point<int>()));
setComponentEffect (hasShadow ? &shadow : nullptr);
if (resizeNowToFitThisShape) if (resizeNowToFitThisShape)
{ {
auto newBounds = shape.getBounds(); auto newBounds = shape.getBounds();


+ 3
- 2
libs/juce-current/source/modules/juce_gui_basics/buttons/juce_ShapeButton.h View File

@@ -88,6 +88,8 @@ public:
Colour overColourOn, Colour overColourOn,
Colour downColourOn); Colour downColourOn);
void setShadowColour (Colour shadow) { shadowColour = shadow; }
/** Set whether the button should use the 'on' set of colours when its toggle state is 'on'. /** Set whether the button should use the 'on' set of colours when its toggle state is 'on'.
By default these will be the same as the normal colours but the setOnColours method can be By default these will be the same as the normal colours but the setOnColours method can be
used to provide a different set of colours. used to provide a different set of colours.
@@ -112,9 +114,8 @@ public:
private: private:
//============================================================================== //==============================================================================
Colour normalColour, overColour, downColour, Colour normalColour, overColour, downColour,
normalColourOn, overColourOn, downColourOn, outlineColour;
normalColourOn, overColourOn, downColourOn, outlineColour, shadowColour;
bool useOnColours; bool useOnColours;
DropShadowEffect shadow;
Path shape; Path shape;
BorderSize<int> border; BorderSize<int> border;
bool maintainShapeProportions; bool maintainShapeProportions;


+ 2
- 1
libs/juce-current/source/modules/juce_gui_basics/components/juce_Component.cpp View File

@@ -3021,7 +3021,8 @@ void Component::modifierKeysChanged (const ModifierKeys& modifiers)
void Component::internalModifierKeysChanged() void Component::internalModifierKeysChanged()
{ {
sendFakeMouseMove();
auto mainMouse = Desktop::getInstance().getMainMouseSource();
mainMouse.triggerFakeMove();
modifierKeysChanged (ModifierKeys::currentModifiers); modifierKeysChanged (ModifierKeys::currentModifiers);
} }


+ 9
- 1
libs/juce-current/source/modules/juce_gui_basics/components/juce_Component.cpp.orig View File

@@ -387,6 +387,10 @@ struct Component::ComponentHelpers
template <typename PointOrRect> template <typename PointOrRect>
static PointOrRect convertCoordinate (const Component* target, const Component* source, PointOrRect p) static PointOrRect convertCoordinate (const Component* target, const Component* source, PointOrRect p)
{ {
float total_scaling = source->getTotalPixelScaling();
Component* top = nullptr;
if (source)
top = source->getTopLevelComponent();
while (source != nullptr) while (source != nullptr)
{ {
if (source == target) if (source == target)
@@ -395,6 +399,9 @@ struct Component::ComponentHelpers
if (source->isParentOf (target)) if (source->isParentOf (target))
return convertFromDistantParentSpace (source, *target, p); return convertFromDistantParentSpace (source, *target, p);
if (source == top)
p /= total_scaling;
p = convertToParentSpace (*source, p); p = convertToParentSpace (*source, p);
source = source->getParentComponent(); source = source->getParentComponent();
} }
@@ -1390,13 +1397,14 @@ bool Component::reallyContains (Point<int> point, bool returnTrueIfWithinAChild)
Component* Component::getComponentAt (Point<int> position) Component* Component::getComponentAt (Point<int> position)
{ {
Point<int> scale = (position.toFloat() * getPixelScaling()).roundToInt();
if (flags.visibleFlag && ComponentHelpers::hitTest (*this, position)) if (flags.visibleFlag && ComponentHelpers::hitTest (*this, position))
{ {
for (int i = childComponentList.size(); --i >= 0;) for (int i = childComponentList.size(); --i >= 0;)
{ {
auto* child = childComponentList.getUnchecked(i); auto* child = childComponentList.getUnchecked(i);
child = child->getComponentAt (ComponentHelpers::convertFromParentSpace (*child, position));
child = child->getComponentAt (ComponentHelpers::convertFromParentSpace (*child, scale));
if (child != nullptr) if (child != nullptr)
return child; return child;


+ 2
- 5
libs/juce-current/source/modules/juce_gui_basics/components/juce_Component.h View File

@@ -439,7 +439,7 @@ public:
@see setBounds, ComponentListener::componentMovedOrResized @see setBounds, ComponentListener::componentMovedOrResized
*/ */
void setTopLeftPosition (Point<int> newTopLeftPosition);
virtual void setTopLeftPosition (Point<int> newTopLeftPosition);
/** Moves the component to a new position. /** Moves the component to a new position.
@@ -2179,10 +2179,7 @@ public:
operator ComponentType*() const noexcept { return getComponent(); } operator ComponentType*() const noexcept { return getComponent(); }
/** Returns the component that this pointer refers to, or null if the component no longer exists. */ /** Returns the component that this pointer refers to, or null if the component no longer exists. */
ComponentType* operator->() noexcept { return getComponent(); }
/** Returns the component that this pointer refers to, or null if the component no longer exists. */
const ComponentType* operator->() const noexcept { return getComponent(); }
ComponentType* operator->() const noexcept { return getComponent(); }
/** If the component is valid, this deletes it and sets this pointer to null. */ /** If the component is valid, this deletes it and sets this pointer to null. */
void deleteAndZero() { delete getComponent(); } void deleteAndZero() { delete getComponent(); }


+ 5
- 7
libs/juce-current/source/modules/juce_gui_basics/filebrowser/juce_FileChooser.cpp View File

@@ -158,7 +158,7 @@ bool FileChooser::showDialog (const int flags, FilePreviewComponent* const previ
{ {
FocusRestorer focusRestorer; FocusRestorer focusRestorer;
pimpl.reset (createPimpl (flags, previewComp));
pimpl = createPimpl (flags, previewComp);
pimpl->runModally(); pimpl->runModally();
// ensure that the finished function was invoked // ensure that the finished function was invoked
@@ -179,12 +179,12 @@ void FileChooser::launchAsync (int flags, std::function<void (const FileChooser&
asyncCallback = std::move (callback); asyncCallback = std::move (callback);
pimpl.reset (createPimpl (flags, previewComp));
pimpl = createPimpl (flags, previewComp);
pimpl->launch(); pimpl->launch();
} }
FileChooser::Pimpl* FileChooser::createPimpl (int flags, FilePreviewComponent* previewComp)
std::shared_ptr<FileChooser::Pimpl> FileChooser::createPimpl (int flags, FilePreviewComponent* previewComp)
{ {
results.clear(); results.clear();
@@ -214,10 +214,8 @@ FileChooser::Pimpl* FileChooser::createPimpl (int flags, FilePreviewComponent* p
{ {
return showPlatformDialog (*this, flags, previewComp); return showPlatformDialog (*this, flags, previewComp);
} }
else
{
return new NonNative (*this, flags, previewComp);
}
return std::make_unique<NonNative> (*this, flags, previewComp);
} }
Array<File> FileChooser::getResults() const noexcept Array<File> FileChooser::getResults() const noexcept


+ 3
- 4
libs/juce-current/source/modules/juce_gui_basics/filebrowser/juce_FileChooser.h View File

@@ -325,12 +325,11 @@ private:
virtual void runModally() = 0; virtual void runModally() = 0;
}; };
std::unique_ptr<Pimpl> pimpl;
std::shared_ptr<Pimpl> pimpl;
//============================================================================== //==============================================================================
Pimpl* createPimpl (int, FilePreviewComponent*);
static Pimpl* showPlatformDialog (FileChooser&, int,
FilePreviewComponent*);
std::shared_ptr<Pimpl> createPimpl (int, FilePreviewComponent*);
static std::shared_ptr<Pimpl> showPlatformDialog (FileChooser&, int, FilePreviewComponent*);
class NonNative; class NonNative;
friend class NonNative; friend class NonNative;


+ 1
- 0
libs/juce-current/source/modules/juce_gui_basics/juce_gui_basics.cpp View File

@@ -41,6 +41,7 @@
#define JUCE_EVENTS_INCLUDE_WIN32_MESSAGE_WINDOW 1 #define JUCE_EVENTS_INCLUDE_WIN32_MESSAGE_WINDOW 1
#define JUCE_GRAPHICS_INCLUDE_COREGRAPHICS_HELPERS 1 #define JUCE_GRAPHICS_INCLUDE_COREGRAPHICS_HELPERS 1
#define JUCE_GUI_BASICS_INCLUDE_XHEADERS 1 #define JUCE_GUI_BASICS_INCLUDE_XHEADERS 1
#define JUCE_GUI_BASICS_INCLUDE_SCOPED_THREAD_DPI_AWARENESS_SETTER 1
#include "juce_gui_basics.h" #include "juce_gui_basics.h"


+ 4
- 0
libs/juce-current/source/modules/juce_gui_basics/juce_gui_basics.h View File

@@ -341,6 +341,10 @@ namespace juce
#endif #endif
#endif #endif
#if JUCE_GUI_BASICS_INCLUDE_SCOPED_THREAD_DPI_AWARENESS_SETTER && JUCE_WINDOWS
#include "native/juce_win32_ScopedThreadDPIAwarenessSetter.h"
#endif
#include "layout/juce_FlexItem.h" #include "layout/juce_FlexItem.h"
#include "layout/juce_FlexBox.h" #include "layout/juce_FlexBox.h"


+ 0
- 5
libs/juce-current/source/modules/juce_gui_basics/keyboard/juce_CaretComponent.cpp View File

@@ -43,14 +43,9 @@ void CaretComponent::paint (Graphics& g)
g.fillRect (getLocalBounds()); g.fillRect (getLocalBounds());
} }
void CaretComponent::timerCallback()
{
setVisible (shouldBeShown() && ! isVisible());
}
void CaretComponent::setCaretPosition (const Rectangle<int>& characterArea) void CaretComponent::setCaretPosition (const Rectangle<int>& characterArea)
{ {
startTimer (380);
setVisible (shouldBeShown()); setVisible (shouldBeShown());
setBounds (characterArea.withWidth (2)); setBounds (characterArea.withWidth (2));
} }


+ 1
- 3
libs/juce-current/source/modules/juce_gui_basics/keyboard/juce_CaretComponent.h View File

@@ -31,8 +31,7 @@ namespace juce
@tags{GUI} @tags{GUI}
*/ */
class JUCE_API CaretComponent : public Component,
private Timer
class JUCE_API CaretComponent : public Component
{ {
public: public:
//============================================================================== //==============================================================================
@@ -73,7 +72,6 @@ private:
Component* owner; Component* owner;
bool shouldBeShown() const; bool shouldBeShown() const;
void timerCallback() override;
JUCE_DECLARE_NON_COPYABLE (CaretComponent) JUCE_DECLARE_NON_COPYABLE (CaretComponent)
}; };


+ 0
- 17
libs/juce-current/source/modules/juce_gui_basics/layout/juce_ComponentBoundsConstrainer.cpp View File

@@ -271,23 +271,6 @@ void ComponentBoundsConstrainer::checkBounds (Rectangle<int>& bounds,
bounds.setWidth (roundToInt (bounds.getHeight() * aspectRatio)); bounds.setWidth (roundToInt (bounds.getHeight() * aspectRatio));
} }
} }
if ((isStretchingTop || isStretchingBottom) && ! (isStretchingLeft || isStretchingRight))
{
bounds.setX (old.getX() + (old.getWidth() - bounds.getWidth()) / 2);
}
else if ((isStretchingLeft || isStretchingRight) && ! (isStretchingTop || isStretchingBottom))
{
bounds.setY (old.getY() + (old.getHeight() - bounds.getHeight()) / 2);
}
else
{
if (isStretchingLeft)
bounds.setX (old.getRight() - bounds.getWidth());
if (isStretchingTop)
bounds.setY (old.getBottom() - bounds.getHeight());
}
} }
jassert (! bounds.isEmpty()); jassert (! bounds.isEmpty());


+ 2
- 4
libs/juce-current/source/modules/juce_gui_basics/lookandfeel/juce_LookAndFeel_V1.cpp View File

@@ -41,8 +41,6 @@ LookAndFeel_V1::LookAndFeel_V1()
setColour (PopupMenu::highlightedBackgroundColourId, Colour (0xbfa4c2ce)); setColour (PopupMenu::highlightedBackgroundColourId, Colour (0xbfa4c2ce));
setColour (PopupMenu::highlightedTextColourId, Colours::black); setColour (PopupMenu::highlightedTextColourId, Colours::black);
setColour (TextEditor::focusedOutlineColourId, findColour (TextButton::buttonColourId)); setColour (TextEditor::focusedOutlineColourId, findColour (TextButton::buttonColourId));
scrollbarShadow.setShadowProperties (DropShadow (Colours::black.withAlpha (0.5f), 2, Point<int>()));
} }
LookAndFeel_V1::~LookAndFeel_V1() LookAndFeel_V1::~LookAndFeel_V1()
@@ -291,7 +289,7 @@ void LookAndFeel_V1::drawScrollbar (Graphics& g, ScrollBar& bar,
ImageEffectFilter* LookAndFeel_V1::getScrollbarEffect() ImageEffectFilter* LookAndFeel_V1::getScrollbarEffect()
{ {
return &scrollbarShadow;
return nullptr;
} }
@@ -477,7 +475,7 @@ Button* LookAndFeel_V1::createSliderButton (Slider&, const bool isIncrement)
ImageEffectFilter* LookAndFeel_V1::getSliderEffect (Slider&) ImageEffectFilter* LookAndFeel_V1::getSliderEffect (Slider&)
{ {
return &scrollbarShadow;
return nullptr;
} }
int LookAndFeel_V1::getSliderThumbRadius (Slider&) int LookAndFeel_V1::getSliderThumbRadius (Slider&)


+ 0
- 2
libs/juce-current/source/modules/juce_gui_basics/lookandfeel/juce_LookAndFeel_V1.h View File

@@ -97,8 +97,6 @@ public:
bool positionTitleBarButtonsOnLeft) override; bool positionTitleBarButtonsOnLeft) override;
private: private:
DropShadowEffect scrollbarShadow;
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (LookAndFeel_V1) JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (LookAndFeel_V1)
}; };


+ 0
- 2
libs/juce-current/source/modules/juce_gui_basics/lookandfeel/juce_LookAndFeel_V4.cpp View File

@@ -1292,8 +1292,6 @@ void LookAndFeel_V4::drawCallOutBoxBackground (CallOutBox& box, Graphics& g,
{ {
cachedImage = { Image::ARGB, box.getWidth(), box.getHeight(), true }; cachedImage = { Image::ARGB, box.getWidth(), box.getHeight(), true };
Graphics g2 (cachedImage); Graphics g2 (cachedImage);
DropShadow (Colours::black.withAlpha (0.7f), 8, { 0, 2 }).drawForPath (g2, path);
} }
g.setColour (Colours::black); g.setColour (Colours::black);


+ 0
- 3
libs/juce-current/source/modules/juce_gui_basics/misc/juce_BubbleComponent.cpp View File

@@ -30,9 +30,6 @@ BubbleComponent::BubbleComponent()
: allowablePlacements (above | below | left | right) : allowablePlacements (above | below | left | right)
{ {
setInterceptsMouseClicks (false, false); setInterceptsMouseClicks (false, false);
shadow.setShadowProperties (DropShadow (Colours::black.withAlpha (0.35f), 5, Point<int>()));
setComponentEffect (&shadow);
} }
BubbleComponent::~BubbleComponent() {} BubbleComponent::~BubbleComponent() {}


+ 0
- 1
libs/juce-current/source/modules/juce_gui_basics/misc/juce_BubbleComponent.h View File

@@ -178,7 +178,6 @@ private:
Rectangle<int> content; Rectangle<int> content;
Point<int> arrowTip; Point<int> arrowTip;
int allowablePlacements; int allowablePlacements;
DropShadowEffect shadow;
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (BubbleComponent) JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (BubbleComponent)
}; };


+ 2
- 2
libs/juce-current/source/modules/juce_gui_basics/native/juce_linux_FileChooser.cpp View File

@@ -258,10 +258,10 @@ bool FileChooser::isPlatformDialogAvailable()
#endif #endif
} }
FileChooser::Pimpl* FileChooser::showPlatformDialog (FileChooser& owner, int flags, FilePreviewComponent*)
std::shared_ptr<FileChooser::Pimpl> FileChooser::showPlatformDialog (FileChooser& owner, int flags, FilePreviewComponent*)
{ {
#if JUCE_MODAL_LOOPS_PERMITTED #if JUCE_MODAL_LOOPS_PERMITTED
return new Native (owner, flags);
return std::make_shared<Native> (owner, flags);
#else #else
return nullptr; return nullptr;
#endif #endif


+ 11
- 11
libs/juce-current/source/modules/juce_gui_basics/native/juce_linux_Windowing.cpp View File

@@ -85,8 +85,8 @@ public:
updateScaleFactorFromNewBounds (bounds, false); updateScaleFactorFromNewBounds (bounds, false);
auto physicalBounds = (parentWindow == 0 ? Desktop::getInstance().getDisplays().logicalToPhysical (bounds)
: bounds * currentScaleFactor);
auto physicalBounds = parentWindow == 0 ? Desktop::getInstance().getDisplays().logicalToPhysical (bounds)
: bounds * currentScaleFactor;
WeakReference<Component> deletionChecker (&component); WeakReference<Component> deletionChecker (&component);
@@ -103,13 +103,16 @@ public:
Point<int> getScreenPosition (bool physical) const Point<int> getScreenPosition (bool physical) const
{ {
auto parentPosition = XWindowSystem::getInstance()->getParentScreenPosition();
auto physicalParentPosition = XWindowSystem::getInstance()->getPhysicalParentScreenPosition();
auto parentPosition = parentWindow == 0 ? Desktop::getInstance().getDisplays().physicalToLogical (physicalParentPosition)
: physicalParentPosition / currentScaleFactor;
auto screenBounds = (parentWindow == 0 ? bounds
: bounds.translated (parentPosition.x, parentPosition.y));
auto screenBounds = parentWindow == 0 ? bounds
: bounds.translated (parentPosition.x, parentPosition.y);
if (physical) if (physical)
return Desktop::getInstance().getDisplays().logicalToPhysical (screenBounds.getTopLeft());
return parentWindow == 0 ? Desktop::getInstance().getDisplays().logicalToPhysical (screenBounds.getTopLeft())
: screenBounds.getTopLeft() * currentScaleFactor;
return screenBounds.getTopLeft(); return screenBounds.getTopLeft();
} }
@@ -314,8 +317,8 @@ public:
updateScaleFactorFromNewBounds (physicalBounds, true); updateScaleFactorFromNewBounds (physicalBounds, true);
bounds = (parentWindow == 0 ? Desktop::getInstance().getDisplays().physicalToLogical (physicalBounds)
: physicalBounds / currentScaleFactor);
bounds = parentWindow == 0 ? Desktop::getInstance().getDisplays().physicalToLogical (physicalBounds)
: physicalBounds / currentScaleFactor;
} }
} }
@@ -433,9 +436,6 @@ private:
//============================================================================== //==============================================================================
void updateScaleFactorFromNewBounds (const Rectangle<int>& newBounds, bool isPhysical) void updateScaleFactorFromNewBounds (const Rectangle<int>& newBounds, bool isPhysical)
{ {
if (! JUCEApplicationBase::isStandaloneApp())
return;
Point<int> translation = (parentWindow != 0 ? getScreenPosition (isPhysical) : Point<int>()); Point<int> translation = (parentWindow != 0 ? getScreenPosition (isPhysical) : Point<int>());
const auto& desktop = Desktop::getInstance(); const auto& desktop = Desktop::getInstance();


+ 3
- 3
libs/juce-current/source/modules/juce_gui_basics/native/juce_mac_FileChooser.mm View File

@@ -377,10 +377,10 @@ private:
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (Native) JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (Native)
}; };
FileChooser::Pimpl* FileChooser::showPlatformDialog (FileChooser& owner, int flags,
FilePreviewComponent* preview)
std::shared_ptr<FileChooser::Pimpl> FileChooser::showPlatformDialog (FileChooser& owner, int flags,
FilePreviewComponent* preview)
{ {
return new FileChooser::Native (owner, flags, preview);
return std::make_shared<FileChooser::Native> (owner, flags, preview);
} }
bool FileChooser::isPlatformDialogAvailable() bool FileChooser::isPlatformDialogAvailable()


+ 86
- 67
libs/juce-current/source/modules/juce_gui_basics/native/juce_win32_FileChooser.cpp View File

@@ -26,32 +26,23 @@
namespace juce namespace juce
{ {
// Win32NativeFileChooser needs to be a reference counted object as there
// is no way for the parent to know when the dialog HWND has actually been
// created without pumping the message thread (which is forbidden when modal
// loops are disabled). However, the HWND pointer is the only way to cancel
// the dialog box. This means that the actual native FileChooser HWND may
// not have been created yet when the user deletes JUCE's FileChooser class. If this
// occurs the Win32NativeFileChooser will still have a reference count of 1 and will
// simply delete itself immediately once the HWND will have been created a while later.
class Win32NativeFileChooser : public ReferenceCountedObject,
class Win32NativeFileChooser : public std::enable_shared_from_this<Win32NativeFileChooser>,
private Thread private Thread
{ {
public: public:
using Ptr = ReferenceCountedObjectPtr<Win32NativeFileChooser>;
enum { charsAvailableForResult = 32768 }; enum { charsAvailableForResult = 32768 };
Win32NativeFileChooser (Component* parent, int flags, FilePreviewComponent* previewComp, Win32NativeFileChooser (Component* parent, int flags, FilePreviewComponent* previewComp,
const File& startingFile, const String& titleToUse, const File& startingFile, const String& titleToUse,
const String& filtersToUse) const String& filtersToUse)
: Thread ("Native Win32 FileChooser"), : Thread ("Native Win32 FileChooser"),
owner (parent), title (titleToUse), filtersString (filtersToUse.replaceCharacter (',', ';')),
owner (parent),
title (titleToUse),
filtersString (filtersToUse.replaceCharacter (',', ';')),
selectsDirectories ((flags & FileBrowserComponent::canSelectDirectories) != 0), selectsDirectories ((flags & FileBrowserComponent::canSelectDirectories) != 0),
isSave ((flags & FileBrowserComponent::saveMode) != 0), isSave ((flags & FileBrowserComponent::saveMode) != 0),
warnAboutOverwrite ((flags & FileBrowserComponent::warnAboutOverwriting) != 0), warnAboutOverwrite ((flags & FileBrowserComponent::warnAboutOverwriting) != 0),
selectMultiple ((flags & FileBrowserComponent::canSelectMultipleItems) != 0),
nativeDialogRef (nullptr), shouldCancel (0)
selectMultiple ((flags & FileBrowserComponent::canSelectMultipleItems) != 0)
{ {
auto parentDirectory = startingFile.getParentDirectory(); auto parentDirectory = startingFile.getParentDirectory();
@@ -91,14 +82,13 @@ public:
// the thread should not be running // the thread should not be running
nativeDialogRef.set (nullptr); nativeDialogRef.set (nullptr);
weakThis = shared_from_this();
if (async) if (async)
{ {
jassert (! isThreadRunning()); jassert (! isThreadRunning());
threadHasReference.reset();
startThread(); startThread();
threadHasReference.wait (-1);
} }
else else
{ {
@@ -112,7 +102,7 @@ public:
ScopedLock lock (deletingDialog); ScopedLock lock (deletingDialog);
customComponent = nullptr; customComponent = nullptr;
shouldCancel.set (1);
shouldCancel = true;
if (auto hwnd = nativeDialogRef.get()) if (auto hwnd = nativeDialogRef.get())
EndDialog (hwnd, 0); EndDialog (hwnd, 0);
@@ -151,12 +141,12 @@ private:
}; };
//============================================================================== //==============================================================================
Component::SafePointer<Component> owner;
const Component::SafePointer<Component> owner;
std::weak_ptr<Win32NativeFileChooser> weakThis;
String title, filtersString; String title, filtersString;
std::unique_ptr<CustomComponentHolder> customComponent; std::unique_ptr<CustomComponentHolder> customComponent;
String initialPath, returnedString; String initialPath, returnedString;
WaitableEvent threadHasReference;
CriticalSection deletingDialog; CriticalSection deletingDialog;
bool selectsDirectories, isSave, warnAboutOverwrite, selectMultiple; bool selectsDirectories, isSave, warnAboutOverwrite, selectMultiple;
@@ -164,8 +154,8 @@ private:
HeapBlock<WCHAR> files; HeapBlock<WCHAR> files;
HeapBlock<WCHAR> filters; HeapBlock<WCHAR> filters;
Atomic<HWND> nativeDialogRef;
Atomic<int> shouldCancel;
Atomic<HWND> nativeDialogRef { nullptr };
bool shouldCancel = false;
struct FreeLPWSTR struct FreeLPWSTR
{ {
@@ -173,7 +163,7 @@ private:
}; };
#if JUCE_MSVC #if JUCE_MSVC
bool showDialog (IFileDialog& dialog, bool async) const
bool showDialog (IFileDialog& dialog, bool async)
{ {
FILEOPENDIALOGOPTIONS flags = {}; FILEOPENDIALOGOPTIONS flags = {};
@@ -236,7 +226,49 @@ private:
if (! selectsDirectories && FAILED (dialog.SetFileTypes (numElementsInArray (spec), spec))) if (! selectsDirectories && FAILED (dialog.SetFileTypes (numElementsInArray (spec), spec)))
return false; return false;
return dialog.Show (static_cast<HWND> (async ? nullptr : owner->getWindowHandle())) == S_OK;
struct Events : public ComBaseClassHelper<IFileDialogEvents>
{
explicit Events (Win32NativeFileChooser& o) : owner (o) {}
JUCE_COMRESULT OnTypeChange (IFileDialog* d) override
{
HWND hwnd = nullptr;
IUnknown_GetWindow (d, &hwnd);
ScopedLock lock (owner.deletingDialog);
if (hwnd != nullptr)
owner.nativeDialogRef = hwnd;
return owner.shouldCancel ? S_FALSE : S_OK;
}
JUCE_COMRESULT OnFolderChanging (IFileDialog*, IShellItem*) override { return S_OK; }
JUCE_COMRESULT OnFileOk (IFileDialog*) override { return S_OK; }
JUCE_COMRESULT OnFolderChange (IFileDialog*) override { return S_OK; }
JUCE_COMRESULT OnSelectionChange (IFileDialog*) override { return S_OK; }
JUCE_COMRESULT OnShareViolation (IFileDialog*, IShellItem*, FDE_SHAREVIOLATION_RESPONSE*) override { return S_OK; }
JUCE_COMRESULT OnOverwrite (IFileDialog*, IShellItem*, FDE_OVERWRITE_RESPONSE*) override { return S_OK; }
Win32NativeFileChooser& owner;
};
DWORD cookie = 0;
dialog.Advise (new Events { *this }, &cookie);
{
ScopedLock lock (deletingDialog);
if (shouldCancel)
return false;
}
const auto result = dialog.Show (async ? nullptr : static_cast<HWND> (owner->getWindowHandle())) == S_OK;
ScopedLock lock (deletingDialog);
nativeDialogRef = nullptr;
return result;
} }
//============================================================================== //==============================================================================
@@ -451,33 +483,21 @@ private:
void run() override void run() override
{ {
// We use a functor rather than a lambda here because
// we want to move ownership of the Ptr into the function
// object, and C++11 doesn't support general lambda capture
struct AsyncCallback
{
AsyncCallback (Ptr p, Array<URL> r)
: ptr (std::move (p)),
results (std::move (r)) {}
void operator()()
{
ptr->results = std::move (results);
if (ptr->owner != nullptr)
ptr->owner->exitModalState (ptr->results.size() > 0 ? 1 : 0);
}
// IUnknown_GetWindow will only succeed when instantiated in a single-thread apartment
CoInitializeEx (nullptr, COINIT_APARTMENTTHREADED);
Ptr ptr;
Array<URL> results;
};
auto resultsCopy = openDialog (true);
auto safeOwner = owner;
auto weakThisCopy = weakThis;
// as long as the thread is running, don't delete this class
Ptr safeThis (this);
threadHasReference.signal();
MessageManager::callAsync ([resultsCopy, safeOwner, weakThisCopy]
{
if (auto locked = weakThisCopy.lock())
locked->results = resultsCopy;
auto r = openDialog (true);
MessageManager::callAsync (AsyncCallback (std::move (safeThis), std::move (r)));
if (safeOwner != nullptr)
safeOwner->exitModalState (resultsCopy.size() > 0 ? 1 : 0);
});
} }
static HashMap<HWND, Win32NativeFileChooser*>& getNativeDialogList() static HashMap<HWND, Win32NativeFileChooser*>& getNativeDialogList()
@@ -486,9 +506,9 @@ private:
return dialogs; return dialogs;
} }
static Win32NativeFileChooser* getNativePointerForDialog (HWND hWnd)
static Win32NativeFileChooser* getNativePointerForDialog (HWND hwnd)
{ {
return getNativeDialogList()[hWnd];
return getNativeDialogList()[hwnd];
} }
//============================================================================== //==============================================================================
@@ -556,7 +576,7 @@ private:
ScopedLock lock (deletingDialog); ScopedLock lock (deletingDialog);
getNativeDialogList().set (hdlg, this); getNativeDialogList().set (hdlg, this);
if (shouldCancel.get() != 0)
if (shouldCancel)
{ {
EndDialog (hdlg, 0); EndDialog (hdlg, 0);
} }
@@ -621,7 +641,7 @@ private:
{ {
ScopedLock lock (deletingDialog); ScopedLock lock (deletingDialog);
if (customComponent != nullptr && shouldCancel.get() == 0)
if (customComponent != nullptr && ! shouldCancel)
{ {
if (FilePreviewComponent* comp = dynamic_cast<FilePreviewComponent*> (customComponent->getChildComponent (0))) if (FilePreviewComponent* comp = dynamic_cast<FilePreviewComponent*> (customComponent->getChildComponent (0)))
{ {
@@ -719,14 +739,15 @@ private:
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (Win32NativeFileChooser) JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (Win32NativeFileChooser)
}; };
class FileChooser::Native : public Component,
class FileChooser::Native : public std::enable_shared_from_this<Native>,
public Component,
public FileChooser::Pimpl public FileChooser::Pimpl
{ {
public: public:
Native (FileChooser& fileChooser, int flags, FilePreviewComponent* previewComp) Native (FileChooser& fileChooser, int flags, FilePreviewComponent* previewComp)
: owner (fileChooser), : owner (fileChooser),
nativeFileChooser (new Win32NativeFileChooser (this, flags, previewComp, fileChooser.startingFile,
fileChooser.title, fileChooser.filters))
nativeFileChooser (std::make_shared<Win32NativeFileChooser> (this, flags, previewComp, fileChooser.startingFile,
fileChooser.title, fileChooser.filters))
{ {
auto mainMon = Desktop::getInstance().getDisplays().getPrimaryDisplay()->userArea; auto mainMon = Desktop::getInstance().getDisplays().getPrimaryDisplay()->userArea;
@@ -743,19 +764,17 @@ public:
{ {
exitModalState (0); exitModalState (0);
nativeFileChooser->cancel(); nativeFileChooser->cancel();
nativeFileChooser = nullptr;
} }
void launch() override void launch() override
{ {
SafePointer<Native> safeThis (this);
std::weak_ptr<Native> safeThis = shared_from_this();
enterModalState (true, ModalCallbackFunction::create (
[safeThis] (int)
{
if (safeThis != nullptr)
safeThis->owner.finished (safeThis->nativeFileChooser->results);
}));
enterModalState (true, ModalCallbackFunction::create ([safeThis] (int)
{
if (auto locked = safeThis.lock())
locked->owner.finished (locked->nativeFileChooser->results);
}));
nativeFileChooser->open (true); nativeFileChooser->open (true);
} }
@@ -787,7 +806,7 @@ public:
private: private:
FileChooser& owner; FileChooser& owner;
Win32NativeFileChooser::Ptr nativeFileChooser;
std::shared_ptr<Win32NativeFileChooser> nativeFileChooser;
}; };
//============================================================================== //==============================================================================
@@ -800,10 +819,10 @@ bool FileChooser::isPlatformDialogAvailable()
#endif #endif
} }
FileChooser::Pimpl* FileChooser::showPlatformDialog (FileChooser& owner, int flags,
FilePreviewComponent* preview)
std::shared_ptr<FileChooser::Pimpl> FileChooser::showPlatformDialog (FileChooser& owner, int flags,
FilePreviewComponent* preview)
{ {
return new FileChooser::Native (owner, flags, preview);
return std::make_shared<FileChooser::Native> (owner, flags, preview);
} }
} // namespace juce } // namespace juce

+ 245
- 207
libs/juce-current/source/modules/juce_gui_basics/native/juce_win32_Windowing.cpp View File

@@ -27,7 +27,7 @@
#include <juce_audio_plugin_client/AAX/juce_AAX_Modifier_Injector.h> #include <juce_audio_plugin_client/AAX/juce_AAX_Modifier_Injector.h>
#endif #endif
#if JUCE_WIN_PER_MONITOR_DPI_AWARE && JUCE_MODULE_AVAILABLE_juce_gui_extra
#if JUCE_MODULE_AVAILABLE_juce_gui_extra
#include <juce_gui_extra/embedding/juce_ScopedDPIAwarenessDisabler.h> #include <juce_gui_extra/embedding/juce_ScopedDPIAwarenessDisabler.h>
#endif #endif
@@ -63,6 +63,31 @@ static bool shouldDeactivateTitleBar = true;
void* getUser32Function (const char*); void* getUser32Function (const char*);
#if JUCE_DEBUG
int numActiveScopedDpiAwarenessDisablers = 0;
bool isInScopedDPIAwarenessDisabler() { return numActiveScopedDpiAwarenessDisablers > 0; }
extern HWND juce_messageWindowHandle;
#endif
struct ScopedDeviceContext
{
explicit ScopedDeviceContext (HWND h)
: hwnd (h), dc (GetDC (hwnd))
{
}
~ScopedDeviceContext()
{
ReleaseDC (hwnd, dc);
}
HWND hwnd;
HDC dc;
JUCE_DECLARE_NON_COPYABLE (ScopedDeviceContext)
JUCE_DECLARE_NON_MOVEABLE (ScopedDeviceContext)
};
//============================================================================== //==============================================================================
#ifndef WM_TOUCH #ifndef WM_TOUCH
enum enum
@@ -408,7 +433,9 @@ static void setDPIAwareness()
static bool isPerMonitorDPIAwareProcess() static bool isPerMonitorDPIAwareProcess()
{ {
#if JUCE_WIN_PER_MONITOR_DPI_AWARE
#if ! JUCE_WIN_PER_MONITOR_DPI_AWARE
return false;
#else
static bool dpiAware = []() -> bool static bool dpiAware = []() -> bool
{ {
setDPIAwareness(); setDPIAwareness();
@@ -423,39 +450,43 @@ static bool isPerMonitorDPIAwareProcess()
}(); }();
return dpiAware; return dpiAware;
#else
return false;
#endif #endif
} }
static bool isPerMonitorDPIAwareWindow (HWND h)
static bool isPerMonitorDPIAwareWindow (HWND nativeWindow)
{ {
#if JUCE_WIN_PER_MONITOR_DPI_AWARE
jassert (h != nullptr);
#if ! JUCE_WIN_PER_MONITOR_DPI_AWARE
ignoreUnused (nativeWindow);
return false;
#else
setDPIAwareness(); setDPIAwareness();
if (getWindowDPIAwarenessContext != nullptr && getAwarenessFromDPIAwarenessContext != nullptr)
return getAwarenessFromDPIAwarenessContext (getWindowDPIAwarenessContext (h)) == DPI_Awareness::DPI_Awareness_Per_Monitor_Aware;
if (getWindowDPIAwarenessContext != nullptr
&& getAwarenessFromDPIAwarenessContext != nullptr)
{
return (getAwarenessFromDPIAwarenessContext (getWindowDPIAwarenessContext (nativeWindow))
== DPI_Awareness::DPI_Awareness_Per_Monitor_Aware);
}
return isPerMonitorDPIAwareProcess(); return isPerMonitorDPIAwareProcess();
#else
ignoreUnused (h);
return false;
#endif #endif
} }
static bool isPerMonitorDPIAwareThread() static bool isPerMonitorDPIAwareThread()
{ {
#if JUCE_WIN_PER_MONITOR_DPI_AWARE
#if ! JUCE_WIN_PER_MONITOR_DPI_AWARE
return false;
#else
setDPIAwareness(); setDPIAwareness();
if (getThreadDPIAwarenessContext != nullptr && getAwarenessFromDPIAwarenessContext != nullptr)
return getAwarenessFromDPIAwarenessContext (getThreadDPIAwarenessContext()) == DPI_Awareness::DPI_Awareness_Per_Monitor_Aware;
if (getThreadDPIAwarenessContext != nullptr
&& getAwarenessFromDPIAwarenessContext != nullptr)
{
return (getAwarenessFromDPIAwarenessContext (getThreadDPIAwarenessContext())
== DPI_Awareness::DPI_Awareness_Per_Monitor_Aware);
}
return isPerMonitorDPIAwareProcess(); return isPerMonitorDPIAwareProcess();
#else
return false;
#endif #endif
} }
@@ -463,27 +494,114 @@ static double getGlobalDPI()
{ {
setDPIAwareness(); setDPIAwareness();
HDC dc = GetDC (nullptr);
auto dpi = (GetDeviceCaps (dc, LOGPIXELSX) + GetDeviceCaps (dc, LOGPIXELSY)) / 2.0;
ReleaseDC (nullptr, dc);
return dpi;
ScopedDeviceContext deviceContext { nullptr };
return (GetDeviceCaps (deviceContext.dc, LOGPIXELSX) + GetDeviceCaps (deviceContext.dc, LOGPIXELSY)) / 2.0;
} }
//============================================================================== //==============================================================================
#if JUCE_WIN_PER_MONITOR_DPI_AWARE && JUCE_MODULE_AVAILABLE_juce_gui_extra
class ScopedThreadDPIAwarenessSetter::NativeImpl
{
public:
explicit NativeImpl (HWND nativeWindow)
{
ignoreUnused (nativeWindow);
#if JUCE_WIN_PER_MONITOR_DPI_AWARE
if (auto* functionSingleton = FunctionSingleton::getInstance())
{
if (! functionSingleton->isLoaded())
return;
auto dpiAwareWindow = (functionSingleton->getAwarenessFromContext (functionSingleton->getWindowAwareness (nativeWindow))
== DPI_Awareness::DPI_Awareness_Per_Monitor_Aware);
auto dpiAwareThread = (functionSingleton->getAwarenessFromContext (functionSingleton->getThreadAwareness())
== DPI_Awareness::DPI_Awareness_Per_Monitor_Aware);
if (dpiAwareWindow && ! dpiAwareThread)
oldContext = functionSingleton->setThreadAwareness (DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE);
else if (! dpiAwareWindow && dpiAwareThread)
oldContext = functionSingleton->setThreadAwareness (DPI_AWARENESS_CONTEXT_UNAWARE);
}
#endif
}
~NativeImpl()
{
if (oldContext != nullptr)
if (auto* functionSingleton = FunctionSingleton::getInstance())
functionSingleton->setThreadAwareness (oldContext);
}
private:
struct FunctionSingleton : public DeletedAtShutdown
{
FunctionSingleton() = default;
~FunctionSingleton() override { clearSingletonInstance(); }
SetThreadDPIAwarenessContextFunc setThreadAwareness = (SetThreadDPIAwarenessContextFunc) getUser32Function ("SetThreadDpiAwarenessContext");
GetWindowDPIAwarenessContextFunc getWindowAwareness = (GetWindowDPIAwarenessContextFunc) getUser32Function ("GetWindowDpiAwarenessContext");
GetThreadDPIAwarenessContextFunc getThreadAwareness = (GetThreadDPIAwarenessContextFunc) getUser32Function ("GetThreadDpiAwarenessContext");
GetAwarenessFromDpiAwarenessContextFunc getAwarenessFromContext = (GetAwarenessFromDpiAwarenessContextFunc) getUser32Function ("GetAwarenessFromDpiAwarenessContext");
bool isLoaded() const noexcept
{
return setThreadAwareness != nullptr
&& getWindowAwareness != nullptr
&& getThreadAwareness != nullptr
&& getAwarenessFromContext != nullptr;
}
JUCE_DECLARE_SINGLETON_SINGLETHREADED_MINIMAL (FunctionSingleton)
JUCE_DECLARE_NON_COPYABLE (FunctionSingleton)
JUCE_DECLARE_NON_MOVEABLE (FunctionSingleton)
};
DPI_AWARENESS_CONTEXT oldContext = nullptr;
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (NativeImpl)
JUCE_DECLARE_NON_MOVEABLE (NativeImpl)
};
JUCE_IMPLEMENT_SINGLETON (ScopedThreadDPIAwarenessSetter::NativeImpl::FunctionSingleton)
ScopedThreadDPIAwarenessSetter::ScopedThreadDPIAwarenessSetter (void* nativeWindow)
{
pimpl = std::make_unique<NativeImpl> ((HWND) nativeWindow);
}
ScopedThreadDPIAwarenessSetter::~ScopedThreadDPIAwarenessSetter()
{
}
#if JUCE_MODULE_AVAILABLE_juce_gui_extra
ScopedDPIAwarenessDisabler::ScopedDPIAwarenessDisabler() ScopedDPIAwarenessDisabler::ScopedDPIAwarenessDisabler()
{ {
if (! isPerMonitorDPIAwareThread()) if (! isPerMonitorDPIAwareThread())
return; return;
if (setThreadDPIAwarenessContext != nullptr) if (setThreadDPIAwarenessContext != nullptr)
{
previousContext = setThreadDPIAwarenessContext (DPI_AWARENESS_CONTEXT_UNAWARE); previousContext = setThreadDPIAwarenessContext (DPI_AWARENESS_CONTEXT_UNAWARE);
#if JUCE_DEBUG
++numActiveScopedDpiAwarenessDisablers;
#endif
}
} }
ScopedDPIAwarenessDisabler::~ScopedDPIAwarenessDisabler() ScopedDPIAwarenessDisabler::~ScopedDPIAwarenessDisabler()
{ {
if (previousContext != nullptr) if (previousContext != nullptr)
{
setThreadDPIAwarenessContext ((DPI_AWARENESS_CONTEXT) previousContext); setThreadDPIAwarenessContext ((DPI_AWARENESS_CONTEXT) previousContext);
#if JUCE_DEBUG
--numActiveScopedDpiAwarenessDisablers;
#endif
}
} }
#endif #endif
@@ -527,6 +645,14 @@ static Point<int> convertPhysicalScreenPointToLogical (Point<int> p, HWND h) noe
return p; return p;
} }
static Point<int> convertLogicalScreenPointToPhysical (Point<int> p, HWND h) noexcept
{
if (isPerMonitorDPIAwareWindow (h))
return Desktop::getInstance().getDisplays().logicalToPhysical (p, getCurrentDisplayFromScaleFactor (h));
return p;
}
JUCE_API double getScaleFactorForWindow (HWND h) JUCE_API double getScaleFactorForWindow (HWND h)
{ {
// NB. Using a local function here because we need to call this method from the plug-in wrappers // NB. Using a local function here because we need to call this method from the plug-in wrappers
@@ -549,50 +675,11 @@ JUCE_API double getScaleFactorForWindow (HWND h)
return 1.0; return 1.0;
} }
JUCE_API void setThreadDPIAwarenessForWindow (HWND nativeWindow)
{
#if JUCE_WIN_PER_MONITOR_DPI_AWARE
// NB. Using local functions here because we need to call this method from the plug-in wrappers
// which don't load the DPI-awareness functions on startup
static SetThreadDPIAwarenessContextFunc localSetThreadDPIAwarenessContext = nullptr;
static GetWindowDPIAwarenessContextFunc localGetWindowDPIAwarenessContext = nullptr;
static GetThreadDPIAwarenessContextFunc localGetThreadDPIAwarenessContext = nullptr;
static GetAwarenessFromDpiAwarenessContextFunc localGetAwarenessFromDPIAwarenessContext = nullptr;
static bool hasChecked = false;
static bool loadedOK = false;
if (! hasChecked)
{
hasChecked = true;
localSetThreadDPIAwarenessContext = (SetThreadDPIAwarenessContextFunc) getUser32Function ("SetThreadDpiAwarenessContext");
localGetWindowDPIAwarenessContext = (GetWindowDPIAwarenessContextFunc) getUser32Function ("GetWindowDpiAwarenessContext");
localGetThreadDPIAwarenessContext = (GetThreadDPIAwarenessContextFunc) getUser32Function ("GetThreadDpiAwarenessContext");
localGetAwarenessFromDPIAwarenessContext = (GetAwarenessFromDpiAwarenessContextFunc) getUser32Function ("GetAwarenessFromDpiAwarenessContext");
loadedOK = (localSetThreadDPIAwarenessContext != nullptr && localGetWindowDPIAwarenessContext != nullptr
&& localGetThreadDPIAwarenessContext != nullptr && localGetAwarenessFromDPIAwarenessContext != nullptr);
}
if (loadedOK)
{
auto dpiAwareWindow = localGetAwarenessFromDPIAwarenessContext (localGetWindowDPIAwarenessContext (nativeWindow)) == DPI_Awareness::DPI_Awareness_Per_Monitor_Aware;
auto dpiAwareThread = localGetAwarenessFromDPIAwarenessContext (localGetThreadDPIAwarenessContext()) == DPI_Awareness::DPI_Awareness_Per_Monitor_Aware;
if (dpiAwareWindow && ! dpiAwareThread)
localSetThreadDPIAwarenessContext (DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE);
else if (! dpiAwareWindow && dpiAwareThread)
localSetThreadDPIAwarenessContext (DPI_AWARENESS_CONTEXT_UNAWARE);
}
#else
ignoreUnused (nativeWindow);
#endif
}
//============================================================================== //==============================================================================
static void setWindowPos (HWND hwnd, Rectangle<int> bounds, UINT flags, bool adjustTopLeft = false) static void setWindowPos (HWND hwnd, Rectangle<int> bounds, UINT flags, bool adjustTopLeft = false)
{ {
ScopedThreadDPIAwarenessSetter setter { hwnd };
if (isPerMonitorDPIAwareWindow (hwnd)) if (isPerMonitorDPIAwareWindow (hwnd))
{ {
if (adjustTopLeft) if (adjustTopLeft)
@@ -607,9 +694,7 @@ static void setWindowPos (HWND hwnd, Rectangle<int> bounds, UINT flags, bool adj
static RECT getWindowScreenRect (HWND hwnd) static RECT getWindowScreenRect (HWND hwnd)
{ {
#if JUCE_WIN_PER_MONITOR_DPI_AWARE
setThreadDPIAwarenessForWindow (hwnd);
#endif
ScopedThreadDPIAwarenessSetter setter { hwnd };
RECT rect; RECT rect;
GetWindowRect (hwnd, &rect); GetWindowRect (hwnd, &rect);
@@ -621,7 +706,10 @@ static RECT getWindowClientRect (HWND hwnd)
auto rect = getWindowScreenRect (hwnd); auto rect = getWindowScreenRect (hwnd);
if (auto parentH = GetParent (hwnd)) if (auto parentH = GetParent (hwnd))
{
ScopedThreadDPIAwarenessSetter setter { hwnd };
MapWindowPoints (HWND_DESKTOP, parentH, (LPPOINT) &rect, 2); MapWindowPoints (HWND_DESKTOP, parentH, (LPPOINT) &rect, 2);
}
return rect; return rect;
} }
@@ -634,14 +722,8 @@ static void setWindowZOrder (HWND hwnd, HWND insertAfter)
//============================================================================== //==============================================================================
double Desktop::getDefaultMasterScale() double Desktop::getDefaultMasterScale()
{ {
if (! JUCEApplicationBase::isStandaloneApp()
#if JUCE_WIN_PER_MONITOR_DPI_AWARE
|| isPerMonitorDPIAwareProcess()
#endif
)
{
if (! JUCEApplicationBase::isStandaloneApp() || isPerMonitorDPIAwareProcess())
return 1.0; return 1.0;
}
return getGlobalDPI() / USER_DEFAULT_SCREEN_DPI; return getGlobalDPI() / USER_DEFAULT_SCREEN_DPI;
} }
@@ -782,9 +864,10 @@ public:
bitmapInfo.bV4V4Compression = BI_RGB; bitmapInfo.bV4V4Compression = BI_RGB;
} }
HDC dc = GetDC (nullptr);
hdc = CreateCompatibleDC (dc);
ReleaseDC (nullptr, dc);
{
ScopedDeviceContext deviceContext { nullptr };
hdc = CreateCompatibleDC (deviceContext.dc);
}
SetMapMode (hdc, MM_TEXT); SetMapMode (hdc, MM_TEXT);
@@ -877,10 +960,8 @@ public:
private: private:
static bool isGraphicsCard32Bit() static bool isGraphicsCard32Bit()
{ {
auto dc = GetDC (nullptr);
auto bitsPerPixel = GetDeviceCaps (dc, BITSPIXEL);
ReleaseDC (nullptr, dc);
return bitsPerPixel > 24;
ScopedDeviceContext deviceContext { nullptr };
return GetDeviceCaps (deviceContext.dc, BITSPIXEL) > 24;
} }
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (WindowsBitmapImage) JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (WindowsBitmapImage)
@@ -893,13 +974,13 @@ Image createSnapshotOfNativeWindow (void* nativeWindowHandle)
auto hwnd = (HWND) nativeWindowHandle; auto hwnd = (HWND) nativeWindowHandle;
auto r = convertPhysicalScreenRectangleToLogical (rectangleFromRECT (getWindowScreenRect (hwnd)), hwnd); auto r = convertPhysicalScreenRectangleToLogical (rectangleFromRECT (getWindowScreenRect (hwnd)), hwnd);
const int w = r.getWidth();
const int h = r.getHeight();
const auto w = r.getWidth();
const auto h = r.getHeight();
auto nativeBitmap = new WindowsBitmapImage (Image::RGB, w, h, true); auto nativeBitmap = new WindowsBitmapImage (Image::RGB, w, h, true);
Image bitmap (nativeBitmap); Image bitmap (nativeBitmap);
HDC dc = GetDC (hwnd);
ScopedDeviceContext deviceContext { hwnd };
if (isPerMonitorDPIAwareProcess()) if (isPerMonitorDPIAwareProcess())
{ {
@@ -908,18 +989,16 @@ Image createSnapshotOfNativeWindow (void* nativeWindowHandle)
SetBrushOrgEx (nativeBitmap->hdc, 0, 0, NULL); SetBrushOrgEx (nativeBitmap->hdc, 0, 0, NULL);
StretchBlt (nativeBitmap->hdc, 0, 0, w, h, StretchBlt (nativeBitmap->hdc, 0, 0, w, h,
dc, 0, 0, roundToInt (w * scale), roundToInt (h * scale),
deviceContext.dc, 0, 0, roundToInt (w * scale), roundToInt (h * scale),
SRCCOPY); SRCCOPY);
SetStretchBltMode (nativeBitmap->hdc, prevStretchMode); SetStretchBltMode (nativeBitmap->hdc, prevStretchMode);
} }
else else
{ {
BitBlt (nativeBitmap->hdc, 0, 0, w, h, dc, 0, 0, SRCCOPY);
BitBlt (nativeBitmap->hdc, 0, 0, w, h, deviceContext.dc, 0, 0, SRCCOPY);
} }
ReleaseDC (hwnd, dc);
return SoftwareImageType().convert (bitmap); return SoftwareImageType().convert (bitmap);
} }
@@ -960,79 +1039,75 @@ namespace IconConverters
&& bm.bmWidth > 0 && bm.bmHeight > 0)) && bm.bmWidth > 0 && bm.bmHeight > 0))
return {}; return {};
if (auto* tempDC = ::GetDC (nullptr))
ScopedDeviceContext deviceContext { nullptr };
if (auto* dc = ::CreateCompatibleDC (deviceContext.dc))
{ {
if (auto* dc = ::CreateCompatibleDC (tempDC))
BITMAPV5HEADER header = {};
header.bV5Size = sizeof (BITMAPV5HEADER);
header.bV5Width = bm.bmWidth;
header.bV5Height = -bm.bmHeight;
header.bV5Planes = 1;
header.bV5Compression = BI_RGB;
header.bV5BitCount = 32;
header.bV5RedMask = 0x00FF0000;
header.bV5GreenMask = 0x0000FF00;
header.bV5BlueMask = 0x000000FF;
header.bV5AlphaMask = 0xFF000000;
header.bV5CSType = LCS_WINDOWS_COLOR_SPACE;
header.bV5Intent = LCS_GM_IMAGES;
uint32* bitmapImageData = nullptr;
if (auto* dib = ::CreateDIBSection (deviceContext.dc, (BITMAPINFO*) &header, DIB_RGB_COLORS,
(void**) &bitmapImageData, nullptr, 0))
{ {
BITMAPV5HEADER header = {};
header.bV5Size = sizeof (BITMAPV5HEADER);
header.bV5Width = bm.bmWidth;
header.bV5Height = -bm.bmHeight;
header.bV5Planes = 1;
header.bV5Compression = BI_RGB;
header.bV5BitCount = 32;
header.bV5RedMask = 0x00FF0000;
header.bV5GreenMask = 0x0000FF00;
header.bV5BlueMask = 0x000000FF;
header.bV5AlphaMask = 0xFF000000;
header.bV5CSType = LCS_WINDOWS_COLOR_SPACE;
header.bV5Intent = LCS_GM_IMAGES;
uint32* bitmapImageData = nullptr;
if (auto* dib = ::CreateDIBSection (tempDC, (BITMAPINFO*) &header, DIB_RGB_COLORS,
(void**) &bitmapImageData, nullptr, 0))
{
auto oldObject = ::SelectObject (dc, dib);
auto oldObject = ::SelectObject (dc, dib);
auto numPixels = bm.bmWidth * bm.bmHeight;
auto numColourComponents = (size_t) numPixels * 4;
auto numPixels = bm.bmWidth * bm.bmHeight;
auto numColourComponents = (size_t) numPixels * 4;
// Windows icon data comes as two layers, an XOR mask which contains the bulk
// of the image data and an AND mask which provides the transparency. Annoyingly
// the XOR mask can also contain an alpha channel, in which case the transparency
// mask should not be applied, but there's no way to find out a priori if the XOR
// mask contains an alpha channel.
// Windows icon data comes as two layers, an XOR mask which contains the bulk
// of the image data and an AND mask which provides the transparency. Annoyingly
// the XOR mask can also contain an alpha channel, in which case the transparency
// mask should not be applied, but there's no way to find out a priori if the XOR
// mask contains an alpha channel.
HeapBlock<bool> opacityMask (numPixels);
memset (bitmapImageData, 0, numColourComponents);
::DrawIconEx (dc, 0, 0, icon, bm.bmWidth, bm.bmHeight, 0, nullptr, DI_MASK);
HeapBlock<bool> opacityMask (numPixels);
memset (bitmapImageData, 0, numColourComponents);
::DrawIconEx (dc, 0, 0, icon, bm.bmWidth, bm.bmHeight, 0, nullptr, DI_MASK);
for (int i = 0; i < numPixels; ++i)
opacityMask[i] = (bitmapImageData[i] == 0);
Image result = Image (Image::ARGB, bm.bmWidth, bm.bmHeight, true);
Image::BitmapData imageData (result, Image::BitmapData::readWrite);
for (int i = 0; i < numPixels; ++i)
opacityMask[i] = (bitmapImageData[i] == 0);
memset (bitmapImageData, 0, numColourComponents);
::DrawIconEx (dc, 0, 0, icon, bm.bmWidth, bm.bmHeight, 0, nullptr, DI_NORMAL);
memcpy (imageData.data, bitmapImageData, numColourComponents);
Image result = Image (Image::ARGB, bm.bmWidth, bm.bmHeight, true);
Image::BitmapData imageData (result, Image::BitmapData::readWrite);
auto imageHasAlphaChannel = [&imageData, numPixels]()
{
for (int i = 0; i < numPixels; ++i)
if (imageData.data[i * 4] != 0)
return true;
return false;
};
memset (bitmapImageData, 0, numColourComponents);
::DrawIconEx (dc, 0, 0, icon, bm.bmWidth, bm.bmHeight, 0, nullptr, DI_NORMAL);
memcpy (imageData.data, bitmapImageData, numColourComponents);
if (! imageHasAlphaChannel())
for (int i = 0; i < numPixels; ++i)
imageData.data[i * 4] = opacityMask[i] ? 0xff : 0x00;
auto imageHasAlphaChannel = [&imageData, numPixels]()
{
for (int i = 0; i < numPixels; ++i)
if (imageData.data[i * 4] != 0)
return true;
::SelectObject (dc, oldObject);
::DeleteObject(dib);
::DeleteDC (dc);
::ReleaseDC (nullptr, tempDC);
return false;
};
return result;
}
if (! imageHasAlphaChannel())
for (int i = 0; i < numPixels; ++i)
imageData.data[i * 4] = opacityMask[i] ? 0xff : 0x00;
::SelectObject (dc, oldObject);
::DeleteObject (dib);
::DeleteDC (dc); ::DeleteDC (dc);
return result;
} }
::ReleaseDC (nullptr, tempDC);
::DeleteDC (dc);
} }
return {}; return {};
@@ -1433,10 +1508,8 @@ public:
auto localBounds = rectangleFromRECT (getWindowClientRect (hwnd)); auto localBounds = rectangleFromRECT (getWindowClientRect (hwnd));
#if JUCE_WIN_PER_MONITOR_DPI_AWARE
if (isPerMonitorDPIAwareWindow (hwnd)) if (isPerMonitorDPIAwareWindow (hwnd))
return (localBounds.toDouble() / getPlatformScaleFactor()).toNearestInt(); return (localBounds.toDouble() / getPlatformScaleFactor()).toNearestInt();
#endif
return localBounds; return localBounds;
}(); }();
@@ -1554,16 +1627,10 @@ public:
if (! r.withZeroOrigin().contains (localPos)) if (! r.withZeroOrigin().contains (localPos))
return false; return false;
auto globalPos = localPos + getScreenPosition();
#if JUCE_WIN_PER_MONITOR_DPI_AWARE
if (isPerMonitorDPIAwareThread() || isPerMonitorDPIAwareWindow (hwnd))
globalPos = Desktop::getInstance().getDisplays().logicalToPhysical (globalPos);
#endif
auto w = WindowFromPoint (POINTFromPoint (globalPos));
auto w = WindowFromPoint (POINTFromPoint (convertLogicalScreenPointToPhysical (localPos + getScreenPosition(),
hwnd)));
return w == hwnd || (trueIfInAChildWindow && (IsChild (hwnd, w) != 0));
return w == hwnd || (trueIfInAChildWindow && (IsChild (hwnd, w) != 0));
} }
BorderSize<int> getFrameSize() const override BorderSize<int> getFrameSize() const override
@@ -1663,18 +1730,7 @@ public:
void repaint (const Rectangle<int>& area) override void repaint (const Rectangle<int>& area) override
{ {
auto scale = getPlatformScaleFactor();
#if JUCE_WIN_PER_MONITOR_DPI_AWARE
// if the calling thread is DPI-aware but we are invalidating a non-DPI aware window RECT, we actually have to
// divide the bounds by the scale factor as it will get multiplied for the virtualised paint callback...
if (isPerMonitorDPIAwareThread() && ! isPerMonitorDPIAwareWindow (hwnd))
scale = 1.0 / Desktop::getInstance().getDisplays().getPrimaryDisplay()->scale;
#endif
auto scaled = area.toDouble() * scale;
auto r = RECTFromRectangle (scaled.getSmallestIntegerContainer());
auto r = RECTFromRectangle ((area.toDouble() * getPlatformScaleFactor()).getSmallestIntegerContainer());
InvalidateRect (hwnd, &r, FALSE); InvalidateRect (hwnd, &r, FALSE);
} }
@@ -1760,7 +1816,7 @@ public:
if (peerIsDeleted) if (peerIsDeleted)
return S_FALSE; return S_FALSE;
peer.handleDragExit (dragInfo);
peer.handleDragDrop (dragInfo);
return S_OK; return S_OK;
} }
@@ -1795,19 +1851,8 @@ public:
private: private:
Point<float> getMousePos (POINTL mousePos) const Point<float> getMousePos (POINTL mousePos) const
{ {
auto screenPos = pointFromPOINT ({ mousePos.x, mousePos.y }).toFloat();
#if JUCE_WIN_PER_MONITOR_DPI_AWARE
auto h = (HWND) peer.getNativeHandle();
if (isPerMonitorDPIAwareWindow (h))
screenPos = convertPhysicalScreenPointToLogical (screenPos.roundToInt(), h).toFloat();
#else
if (JUCEApplication::isStandaloneApp())
screenPos /= static_cast<float> (getGlobalDPI() / USER_DEFAULT_SCREEN_DPI);
#endif
return peer.getComponent().getLocalPoint (nullptr, screenPos);
return peer.getComponent().getLocalPoint (nullptr, convertPhysicalScreenPointToLogical (pointFromPOINT ({ mousePos.x, mousePos.y }),
(HWND) peer.getNativeHandle()).toFloat());
} }
struct DroppedData struct DroppedData
@@ -1902,7 +1947,9 @@ public:
double getPlatformScaleFactor() const noexcept override double getPlatformScaleFactor() const noexcept override
{ {
#if JUCE_WIN_PER_MONITOR_DPI_AWARE
#if ! JUCE_WIN_PER_MONITOR_DPI_AWARE
return 1.0;
#else
if (! isPerMonitorDPIAwareWindow (hwnd)) if (! isPerMonitorDPIAwareWindow (hwnd))
return 1.0; return 1.0;
@@ -1916,8 +1963,6 @@ public:
} }
return scaleFactor; return scaleFactor;
#else
return 1.0;
#endif #endif
} }
@@ -2153,6 +2198,14 @@ private:
L"", type, 0, 0, 0, 0, parentToAddTo, nullptr, L"", type, 0, 0, 0, 0, parentToAddTo, nullptr,
(HINSTANCE) Process::getCurrentModuleInstanceHandle(), nullptr); (HINSTANCE) Process::getCurrentModuleInstanceHandle(), nullptr);
#if JUCE_DEBUG
// The DPI-awareness context of this window and JUCE's hidden message window are different.
// You normally want these to match otherwise timer events and async messages will happen
// in a different context to normal HWND messages which can cause issues with UI scaling.
jassert (isPerMonitorDPIAwareWindow (hwnd) == isPerMonitorDPIAwareWindow (juce_messageWindowHandle)
|| isInScopedDPIAwarenessDisabler());
#endif
if (hwnd != nullptr) if (hwnd != nullptr)
{ {
SetWindowLongPtr (hwnd, 0, 0); SetWindowLongPtr (hwnd, 0, 0);
@@ -2179,19 +2232,8 @@ private:
setDPIAwareness(); setDPIAwareness();
#if JUCE_WIN_PER_MONITOR_DPI_AWARE
if (isPerMonitorDPIAwareThread()) if (isPerMonitorDPIAwareThread())
{
auto bounds = component.getBounds();
if (bounds.isEmpty())
scaleFactor = Desktop::getInstance().getDisplays().getPrimaryDisplay()->scale;
else
scaleFactor = Desktop::getInstance().getDisplays().getDisplayForRect (bounds)->scale;
scaleFactor /= Desktop::getInstance().getGlobalScaleFactor();
}
#endif
scaleFactor = getScaleFactorForWindow (hwnd);
setMessageFilter(); setMessageFilter();
updateBorderSize(); updateBorderSize();
@@ -3508,20 +3550,18 @@ private:
Point<float> getPointFromLocalLParam (LPARAM lParam) noexcept Point<float> getPointFromLocalLParam (LPARAM lParam) noexcept
{ {
#if JUCE_WIN_PER_MONITOR_DPI_AWARE
auto p = pointFromPOINT (getPOINTFromLParam (lParam));
if (isPerMonitorDPIAwareWindow (hwnd)) if (isPerMonitorDPIAwareWindow (hwnd))
{ {
// LPARAM is relative to this window's top-left but may be on a different monitor so we need to calculate the // LPARAM is relative to this window's top-left but may be on a different monitor so we need to calculate the
// physical screen position and then convert this to local logical coordinates // physical screen position and then convert this to local logical coordinates
auto localPos = getPOINTFromLParam (lParam);
auto r = getWindowScreenRect (hwnd); auto r = getWindowScreenRect (hwnd);
return globalToLocal (Desktop::getInstance().getDisplays().physicalToLogical (pointFromPOINT ({ r.left + localPos.x + roundToInt (windowBorder.getLeft() * scaleFactor),
r.top + localPos.y + roundToInt (windowBorder.getTop() * scaleFactor) })).toFloat());
return globalToLocal (Desktop::getInstance().getDisplays().physicalToLogical (pointFromPOINT ({ r.left + p.x + roundToInt (windowBorder.getLeft() * scaleFactor),
r.top + p.y + roundToInt (windowBorder.getTop() * scaleFactor) })).toFloat());
} }
#endif
return { static_cast<float> (GET_X_LPARAM (lParam)), static_cast<float> (GET_Y_LPARAM (lParam)) };
return p.toFloat();
} }
Point<float> getCurrentMousePos() noexcept Point<float> getCurrentMousePos() noexcept
@@ -4431,10 +4471,8 @@ Point<float> MouseInputSource::getCurrentRawMousePosition()
auto p = pointFromPOINT (mousePos); auto p = pointFromPOINT (mousePos);
#if JUCE_WIN_PER_MONITOR_DPI_AWARE
if (isPerMonitorDPIAwareThread()) if (isPerMonitorDPIAwareThread())
p = Desktop::getInstance().getDisplays().physicalToLogical (p); p = Desktop::getInstance().getDisplays().physicalToLogical (p);
#endif
return p.toFloat(); return p.toFloat();
} }


+ 3
- 3
libs/juce-current/source/modules/juce_gui_basics/native/x11/juce_linux_XWindowSystem.cpp View File

@@ -1849,14 +1849,14 @@ Rectangle<int> XWindowSystem::getWindowBounds (::Window windowH, ::Window parent
} }
else else
{ {
parentScreenPosition = Desktop::getInstance().getDisplays().physicalToLogical (Point<int> (rootX, rootY));
parentScreenPosition = Point<int> (rootX, rootY);
} }
} }
return { wx, wy, (int) ww, (int) wh }; return { wx, wy, (int) ww, (int) wh };
} }
Point<int> XWindowSystem::getParentScreenPosition() const
Point<int> XWindowSystem::getPhysicalParentScreenPosition() const
{ {
return parentScreenPosition; return parentScreenPosition;
} }
@@ -2474,7 +2474,7 @@ Array<Displays::Display> XWindowSystem::findDisplays (float masterScale) const
+ ((static_cast<double> (crtc->height) * 25.4 * 0.5) / static_cast<double> (output->mm_height)); + ((static_cast<double> (crtc->height) * 25.4 * 0.5) / static_cast<double> (output->mm_height));
auto scale = DisplayHelpers::getDisplayScale (output->name, d.dpi); auto scale = DisplayHelpers::getDisplayScale (output->name, d.dpi);
scale = (scale <= 0.1 ? 1.0 : scale);
scale = (scale <= 0.1 || ! JUCEApplicationBase::isStandaloneApp()) ? 1.0 : scale;
d.scale = masterScale * scale; d.scale = masterScale * scale;


+ 1
- 1
libs/juce-current/source/modules/juce_gui_basics/native/x11/juce_linux_XWindowSystem.h View File

@@ -109,7 +109,7 @@ public:
BorderSize<int> getBorderSize (::Window) const; BorderSize<int> getBorderSize (::Window) const;
Rectangle<int> getWindowBounds (::Window, ::Window parentWindow); Rectangle<int> getWindowBounds (::Window, ::Window parentWindow);
Point<int> getParentScreenPosition() const;
Point<int> getPhysicalParentScreenPosition() const;
bool contains (::Window, Point<int> localPos) const; bool contains (::Window, Point<int> localPos) const;


+ 3
- 2
libs/juce-current/source/modules/juce_gui_basics/widgets/juce_Slider.cpp View File

@@ -749,7 +749,7 @@ public:
? e.position.x - mouseDragStartPos.x ? e.position.x - mouseDragStartPos.x
: mouseDragStartPos.y - e.position.y; : mouseDragStartPos.y - e.position.y;
newPos = owner.valueToProportionOfLength (valueOnMouseDown)
newPos = owner.valueToProportionOfLength (valueWhenLastDragged)
+ mouseDiff * (1.0 / pixelsForFullDragExtent); + mouseDiff * (1.0 / pixelsForFullDragExtent);
if (style == IncDecButtons) if (style == IncDecButtons)
@@ -763,7 +763,7 @@ public:
auto mouseDiff = (e.position.x - mouseDragStartPos.x) auto mouseDiff = (e.position.x - mouseDragStartPos.x)
+ (mouseDragStartPos.y - e.position.y); + (mouseDragStartPos.y - e.position.y);
newPos = owner.valueToProportionOfLength (valueOnMouseDown)
newPos = owner.valueToProportionOfLength (valueWhenLastDragged)
+ mouseDiff * (1.0 / pixelsForFullDragExtent); + mouseDiff * (1.0 / pixelsForFullDragExtent);
} }
else else
@@ -774,6 +774,7 @@ public:
newPos = 1.0 - newPos; newPos = 1.0 - newPos;
} }
mouseDragStartPos = e.position;
newPos = (isRotary() && ! rotaryParams.stopAtEnd) ? newPos - std::floor (newPos) newPos = (isRotary() && ! rotaryParams.stopAtEnd) ? newPos - std::floor (newPos)
: jlimit (0.0, 1.0, newPos); : jlimit (0.0, 1.0, newPos);
valueWhenLastDragged = owner.proportionOfLengthToValue (newPos); valueWhenLastDragged = owner.proportionOfLengthToValue (newPos);


+ 11
- 0
libs/juce-current/source/modules/juce_gui_basics/widgets/juce_TextEditor.cpp View File

@@ -833,6 +833,11 @@ struct TextEditor::TextHolderComponent : public Component,
{ {
owner.drawContent (g); owner.drawContent (g);
} }
void setTopLeftPosition(Point<int> new_position) override {
Component::setTopLeftPosition(new_position);
owner.textChanged();
}
void restartTimer() void restartTimer()
{ {
@@ -1558,6 +1563,9 @@ void TextEditor::moveCaretTo (const int newPosition, const bool isSelecting)
moveCaret (newPosition); moveCaret (newPosition);
selection = Range<int>::emptyRange (getCaretPosition()); selection = Range<int>::emptyRange (getCaretPosition());
} }
if (listeners.size() != 0 || onTextChange != nullptr)
postCommandMessage (TextEditorDefs::textChangeMessageId);
} }
int TextEditor::getTextIndexAt (const int x, const int y) int TextEditor::getTextIndexAt (const int x, const int y)
@@ -2141,6 +2149,9 @@ void TextEditor::focusGained (FocusChangeType cause)
repaint(); repaint();
updateCaretPosition(); updateCaretPosition();
if (listeners.size() != 0 || onTextChange != nullptr)
postCommandMessage (TextEditorDefs::textChangeMessageId);
} }
void TextEditor::focusLost (FocusChangeType) void TextEditor::focusLost (FocusChangeType)


+ 0
- 3
libs/juce-current/source/modules/juce_gui_extra/embedding/juce_ScopedDPIAwarenessDisabler.h View File

@@ -26,8 +26,6 @@
namespace juce namespace juce
{ {
#if (JUCE_WINDOWS && JUCE_WIN_PER_MONITOR_DPI_AWARE) || DOXYGEN
//============================================================================== //==============================================================================
/** /**
A Windows-specific class that temporarily sets the DPI awareness context of A Windows-specific class that temporarily sets the DPI awareness context of
@@ -52,6 +50,5 @@ public:
private: private:
void* previousContext = nullptr; void* previousContext = nullptr;
}; };
#endif
} // namespace juce } // namespace juce

+ 7
- 0
libs/juce-current/source/modules/juce_gui_extra/juce_gui_extra.cpp View File

@@ -39,6 +39,7 @@
#define JUCE_EVENTS_INCLUDE_WIN32_MESSAGE_WINDOW 1 #define JUCE_EVENTS_INCLUDE_WIN32_MESSAGE_WINDOW 1
#define JUCE_GRAPHICS_INCLUDE_COREGRAPHICS_HELPERS 1 #define JUCE_GRAPHICS_INCLUDE_COREGRAPHICS_HELPERS 1
#define JUCE_GUI_BASICS_INCLUDE_XHEADERS 1 #define JUCE_GUI_BASICS_INCLUDE_XHEADERS 1
#define JUCE_GUI_BASICS_INCLUDE_SCOPED_THREAD_DPI_AWARENESS_SETTER 1
#ifndef JUCE_PUSH_NOTIFICATIONS #ifndef JUCE_PUSH_NOTIFICATIONS
#define JUCE_PUSH_NOTIFICATIONS 0 #define JUCE_PUSH_NOTIFICATIONS 0
@@ -192,3 +193,9 @@
#include "native/juce_android_WebBrowserComponent.cpp" #include "native/juce_android_WebBrowserComponent.cpp"
#endif #endif
#endif #endif
//==============================================================================
#if ! JUCE_WINDOWS
juce::ScopedDPIAwarenessDisabler::ScopedDPIAwarenessDisabler() { ignoreUnused (previousContext); }
juce::ScopedDPIAwarenessDisabler::~ScopedDPIAwarenessDisabler() {}
#endif

+ 3
- 5
libs/juce-current/source/modules/juce_gui_extra/native/juce_win32_HWNDComponent.cpp View File

@@ -26,8 +26,6 @@
namespace juce namespace juce
{ {
void setThreadDPIAwarenessForWindow (HWND);
class HWNDComponent::Pimpl : public ComponentMovementWatcher class HWNDComponent::Pimpl : public ComponentMovementWatcher
{ {
public: public:
@@ -52,13 +50,13 @@ public:
{ {
auto area = (peer->getAreaCoveredBy (owner).toFloat() * peer->getPlatformScaleFactor()).getSmallestIntegerContainer(); auto area = (peer->getAreaCoveredBy (owner).toFloat() * peer->getPlatformScaleFactor()).getSmallestIntegerContainer();
setThreadDPIAwarenessForWindow (hwnd);
UINT flagsToSend = SWP_NOACTIVATE | SWP_NOZORDER | SWP_NOOWNERZORDER; UINT flagsToSend = SWP_NOACTIVATE | SWP_NOZORDER | SWP_NOOWNERZORDER;
if (! wasMoved) flagsToSend |= SWP_NOMOVE; if (! wasMoved) flagsToSend |= SWP_NOMOVE;
if (! wasResized) flagsToSend |= SWP_NOSIZE; if (! wasResized) flagsToSend |= SWP_NOSIZE;
ScopedThreadDPIAwarenessSetter threadDpiAwarenessSetter { hwnd };
SetWindowPos (hwnd, nullptr, area.getX(), area.getY(), area.getWidth(), area.getHeight(), flagsToSend); SetWindowPos (hwnd, nullptr, area.getX(), area.getY(), area.getWidth(), area.getHeight(), flagsToSend);
} }
} }
@@ -101,7 +99,7 @@ public:
{ {
if (auto* peer = owner.getPeer()) if (auto* peer = owner.getPeer())
{ {
setThreadDPIAwarenessForWindow (hwnd);
ScopedThreadDPIAwarenessSetter threadDpiAwarenessSetter { hwnd };
RECT r; RECT r;
GetWindowRect (hwnd, &r); GetWindowRect (hwnd, &r);


+ 1
- 0
libs/juce-current/source/modules/juce_opengl/juce_opengl.cpp View File

@@ -37,6 +37,7 @@
#define JUCE_CORE_INCLUDE_NATIVE_HEADERS 1 #define JUCE_CORE_INCLUDE_NATIVE_HEADERS 1
#define JUCE_GRAPHICS_INCLUDE_COREGRAPHICS_HELPERS 1 #define JUCE_GRAPHICS_INCLUDE_COREGRAPHICS_HELPERS 1
#define JUCE_GUI_BASICS_INCLUDE_XHEADERS 1 #define JUCE_GUI_BASICS_INCLUDE_XHEADERS 1
#define JUCE_GUI_BASICS_INCLUDE_SCOPED_THREAD_DPI_AWARENESS_SETTER 1
#include "juce_opengl.h" #include "juce_opengl.h"


+ 1
- 1
libs/juce-current/source/modules/juce_opengl/juce_opengl.h View File

@@ -124,7 +124,7 @@
It's mandatory in OpenGL 3.0 to specify the GLSL version. It's mandatory in OpenGL 3.0 to specify the GLSL version.
*/ */
#if JUCE_OPENGL3 #if JUCE_OPENGL3
#if JUCE_OPENGL_ES
#if JUCE_OPENGL_ES || OPENGL_ES
#define JUCE_GLSL_VERSION "#version 300 es" #define JUCE_GLSL_VERSION "#version 300 es"
#else #else
#define JUCE_GLSL_VERSION "#version 150" #define JUCE_GLSL_VERSION "#version 150"


+ 8
- 0
libs/juce-current/source/modules/juce_opengl/native/juce_MissingGLDefinitions.h View File

@@ -126,6 +126,14 @@ enum MissingOpenGLDefinitions
GL_DYNAMIC_DRAW = 0x88E8, GL_DYNAMIC_DRAW = 0x88E8,
GL_STREAM_DRAW = 0x88E0, GL_STREAM_DRAW = 0x88E0,
GL_GEOMETRY_SHADER = 0x8DD9,
GL_LINE_STRIP_ADJACENCY = 0x000B,
GL_INTERLEAVED_ATTRIBS = 0x8C8C,
GL_STATIC_READ = 0x88E5,
GL_TRANSFORM_FEEDBACK_BUFFER = 0x8C8E,
GL_RASTERIZER_DISCARD = 0x8C89,
GL_MAP_READ_BIT = 0x0001,
WGL_NUMBER_PIXEL_FORMATS_ARB = 0x2000, WGL_NUMBER_PIXEL_FORMATS_ARB = 0x2000,
WGL_DRAW_TO_WINDOW_ARB = 0x2001, WGL_DRAW_TO_WINDOW_ARB = 0x2001,
WGL_ACCELERATION_ARB = 0x2003, WGL_ACCELERATION_ARB = 0x2003,


+ 28
- 5
libs/juce-current/source/modules/juce_opengl/native/juce_OpenGL_linux_X11.h View File

@@ -69,8 +69,8 @@ public:
GLint attribs[] = GLint attribs[] =
{ {
GLX_RGBA,
GLX_DOUBLEBUFFER,
GLX_RENDER_TYPE, GLX_RGBA_BIT,
GLX_DOUBLEBUFFER, True,
GLX_RED_SIZE, cPixelFormat.redBits, GLX_RED_SIZE, cPixelFormat.redBits,
GLX_GREEN_SIZE, cPixelFormat.greenBits, GLX_GREEN_SIZE, cPixelFormat.greenBits,
GLX_BLUE_SIZE, cPixelFormat.blueBits, GLX_BLUE_SIZE, cPixelFormat.blueBits,
@@ -81,13 +81,21 @@ public:
GLX_ACCUM_GREEN_SIZE, cPixelFormat.accumulationBufferGreenBits, GLX_ACCUM_GREEN_SIZE, cPixelFormat.accumulationBufferGreenBits,
GLX_ACCUM_BLUE_SIZE, cPixelFormat.accumulationBufferBlueBits, GLX_ACCUM_BLUE_SIZE, cPixelFormat.accumulationBufferBlueBits,
GLX_ACCUM_ALPHA_SIZE, cPixelFormat.accumulationBufferAlphaBits, GLX_ACCUM_ALPHA_SIZE, cPixelFormat.accumulationBufferAlphaBits,
GLX_X_RENDERABLE, True,
None None
}; };
bestVisual = glXChooseVisual (display, X11Symbols::getInstance()->xDefaultScreen (display), attribs);
if (bestVisual == nullptr)
int countFbConfigs;
fbConfig = glXChooseFBConfig (display, DefaultScreen (display), attribs, &countFbConfigs);
if (fbConfig == nullptr)
return; return;
bestVisual = glXGetVisualFromFBConfig (display, *fbConfig);
if (bestVisual == nullptr) {
X11Symbols::getInstance()->xFree (fbConfig);
return;
}
auto* peer = component.getPeer(); auto* peer = component.getPeer();
jassert (peer != nullptr); jassert (peer != nullptr);
@@ -139,6 +147,9 @@ public:
} }
} }
if (fbConfig != nullptr)
X11Symbols::getInstance()->xFree (fbConfig);
if (bestVisual != nullptr) if (bestVisual != nullptr)
X11Symbols::getInstance()->xFree (bestVisual); X11Symbols::getInstance()->xFree (bestVisual);
} }
@@ -146,7 +157,18 @@ public:
bool initialiseOnRenderThread (OpenGLContext& c) bool initialiseOnRenderThread (OpenGLContext& c)
{ {
XWindowSystemUtilities::ScopedXLock xLock; XWindowSystemUtilities::ScopedXLock xLock;
renderContext = glXCreateContext (display, bestVisual, (GLXContext) contextToShareWith, GL_TRUE);
PFNGLXCREATECONTEXTATTRIBSARBPROC createContextAttribs;
int attribs[] = {
GLX_CONTEXT_MAJOR_VERSION_ARB, 3,
GLX_CONTEXT_MINOR_VERSION_ARB, 2,
GLX_CONTEXT_PROFILE_MASK_ARB, GLX_CONTEXT_CORE_PROFILE_BIT_ARB,
0
};
createContextAttribs = (PFNGLXCREATECONTEXTATTRIBSARBPROC)
OpenGLHelpers::getExtensionFunction("glXCreateContextAttribsARB");
renderContext = createContextAttribs (display, *fbConfig, (GLXContext) contextToShareWith, GL_TRUE, attribs);
c.makeActive(); c.makeActive();
context = &c; context = &c;
@@ -240,6 +262,7 @@ private:
int swapFrames = 1; int swapFrames = 1;
Rectangle<int> bounds; Rectangle<int> bounds;
XVisualInfo* bestVisual = nullptr; XVisualInfo* bestVisual = nullptr;
GLXFBConfig* fbConfig = nullptr;
void* contextToShareWith; void* contextToShareWith;
OpenGLContext* context = nullptr; OpenGLContext* context = nullptr;


+ 17
- 10
libs/juce-current/source/modules/juce_opengl/native/juce_OpenGL_win32.h View File

@@ -28,10 +28,6 @@ namespace juce
extern ComponentPeer* createNonRepaintingEmbeddedWindowsPeer (Component&, void* parent); extern ComponentPeer* createNonRepaintingEmbeddedWindowsPeer (Component&, void* parent);
#if JUCE_WIN_PER_MONITOR_DPI_AWARE
extern void setThreadDPIAwarenessForWindow (HWND);
#endif
//============================================================================== //==============================================================================
class OpenGLContext::NativeContext class OpenGLContext::NativeContext
#if JUCE_WIN_PER_MONITOR_DPI_AWARE #if JUCE_WIN_PER_MONITOR_DPI_AWARE
@@ -97,15 +93,17 @@ public:
bool initialiseOnRenderThread (OpenGLContext& c) bool initialiseOnRenderThread (OpenGLContext& c)
{ {
#if JUCE_WIN_PER_MONITOR_DPI_AWARE
setThreadDPIAwarenessForWindow ((HWND) nativeWindow->getNativeHandle());
#endif
threadAwarenessSetter = std::make_unique<ScopedThreadDPIAwarenessSetter> (nativeWindow->getNativeHandle());
context = &c; context = &c;
return true; return true;
} }
void shutdownOnRenderThread() { deactivateCurrentContext(); context = nullptr; }
void shutdownOnRenderThread()
{
deactivateCurrentContext();
context = nullptr;
threadAwarenessSetter = nullptr;
}
static void deactivateCurrentContext() { wglMakeCurrent (nullptr, nullptr); } static void deactivateCurrentContext() { wglMakeCurrent (nullptr, nullptr); }
bool makeActive() const noexcept { return isActive() || wglMakeCurrent (dc, renderContext) != FALSE; } bool makeActive() const noexcept { return isActive() || wglMakeCurrent (dc, renderContext) != FALSE; }
@@ -170,6 +168,7 @@ private:
std::unique_ptr<DummyComponent> dummyComponent; std::unique_ptr<DummyComponent> dummyComponent;
std::unique_ptr<ComponentPeer> nativeWindow; std::unique_ptr<ComponentPeer> nativeWindow;
std::unique_ptr<ScopedThreadDPIAwarenessSetter> threadAwarenessSetter;
HGLRC renderContext; HGLRC renderContext;
HDC dc; HDC dc;
OpenGLContext* context = {}; OpenGLContext* context = {};
@@ -219,7 +218,13 @@ private:
void createNativeWindow (Component& component) void createNativeWindow (Component& component)
{ {
auto* topComp = component.getTopLevelComponent(); auto* topComp = component.getTopLevelComponent();
nativeWindow.reset (createNonRepaintingEmbeddedWindowsPeer (*dummyComponent, topComp->getWindowHandle()));
{
auto* parentHWND = topComp->getWindowHandle();
ScopedThreadDPIAwarenessSetter setter { parentHWND };
nativeWindow.reset (createNonRepaintingEmbeddedWindowsPeer (*dummyComponent, parentHWND));
}
if (auto* peer = topComp->getPeer()) if (auto* peer = topComp->getPeer())
{ {
@@ -285,6 +290,8 @@ private:
atts[n++] = WGL_DRAW_TO_WINDOW_ARB; atts[n++] = GL_TRUE; atts[n++] = WGL_DRAW_TO_WINDOW_ARB; atts[n++] = GL_TRUE;
atts[n++] = WGL_SUPPORT_OPENGL_ARB; atts[n++] = GL_TRUE; atts[n++] = WGL_SUPPORT_OPENGL_ARB; atts[n++] = GL_TRUE;
atts[n++] = WGL_CONTEXT_MAJOR_VERSION_ARB; atts[n++] = 3;
atts[n++] = WGL_CONTEXT_MINOR_VERSION_ARB; atts[n++] = 2;
atts[n++] = WGL_DOUBLE_BUFFER_ARB; atts[n++] = GL_TRUE; atts[n++] = WGL_DOUBLE_BUFFER_ARB; atts[n++] = GL_TRUE;
atts[n++] = WGL_PIXEL_TYPE_ARB; atts[n++] = WGL_TYPE_RGBA_ARB; atts[n++] = WGL_PIXEL_TYPE_ARB; atts[n++] = WGL_TYPE_RGBA_ARB;
atts[n++] = WGL_ACCELERATION_ARB; atts[n++] = WGL_ACCELERATION_ARB;


+ 2
- 2
libs/juce-current/source/modules/juce_opengl/opengl/juce_OpenGLHelpers.cpp View File

@@ -83,7 +83,7 @@ void OpenGLHelpers::enableScissorTest (Rectangle<int> clip)
String OpenGLHelpers::translateVertexShaderToV3 (const String& code) String OpenGLHelpers::translateVertexShaderToV3 (const String& code)
{ {
#if JUCE_OPENGL3
#if JUCE_OPENGL3 || OPENGL_ES
if (OpenGLShaderProgram::getLanguageVersion() > 1.2) if (OpenGLShaderProgram::getLanguageVersion() > 1.2)
{ {
String output; String output;
@@ -119,7 +119,7 @@ String OpenGLHelpers::translateVertexShaderToV3 (const String& code)
String OpenGLHelpers::translateFragmentShaderToV3 (const String& code) String OpenGLHelpers::translateFragmentShaderToV3 (const String& code)
{ {
#if JUCE_OPENGL3
#if JUCE_OPENGL3 || OPENGL_ES
if (OpenGLShaderProgram::getLanguageVersion() > 1.2) if (OpenGLShaderProgram::getLanguageVersion() > 1.2)
return JUCE_GLSL_VERSION "\n" return JUCE_GLSL_VERSION "\n"
"out " JUCE_MEDIUMP " vec4 fragColor;\n" "out " JUCE_MEDIUMP " vec4 fragColor;\n"


Loading…
Cancel
Save