Browse Source

macOS/iOS: Replace compile-time deployment target checks with runtime checks using the available keyword

v6.1.6
ed 4 years ago
parent
commit
7d1918b385
21 changed files with 1070 additions and 1099 deletions
  1. +13
    -4
      modules/juce_audio_devices/native/juce_ios_Audio.cpp
  2. +2
    -2
      modules/juce_audio_devices/native/juce_mac_CoreMidi.mm
  3. +30
    -27
      modules/juce_audio_plugin_client/AU/juce_AUv3_Wrapper.mm
  4. +4
    -53
      modules/juce_audio_processors/format_types/juce_AudioUnitPluginFormat.mm
  5. +8
    -17
      modules/juce_audio_utils/native/juce_mac_BluetoothMidiDevicePairingDialogue.mm
  6. +1
    -1
      modules/juce_core/native/juce_BasicNativeHeaders.h
  7. +27
    -15
      modules/juce_core/native/juce_mac_Files.mm
  8. +416
    -419
      modules/juce_core/native/juce_mac_Network.mm
  9. +15
    -9
      modules/juce_core/native/juce_mac_SystemStats.mm
  10. +5
    -1
      modules/juce_gui_basics/native/accessibility/juce_ios_Accessibility.mm
  11. +1
    -3
      modules/juce_gui_basics/native/juce_ios_FileChooser.mm
  12. +11
    -8
      modules/juce_gui_basics/native/juce_ios_UIViewComponentPeer.mm
  13. +4
    -1
      modules/juce_gui_basics/native/juce_ios_Windowing.mm
  14. +11
    -8
      modules/juce_gui_basics/native/juce_mac_NSViewComponentPeer.mm
  15. +9
    -6
      modules/juce_gui_extra/native/juce_mac_AppleRemote.mm
  16. +1
    -1
      modules/juce_gui_extra/native/juce_mac_SystemTrayIcon.cpp
  17. +271
    -306
      modules/juce_gui_extra/native/juce_mac_WebBrowserComponent.mm
  18. +12
    -10
      modules/juce_opengl/native/juce_OpenGL_osx.h
  19. +1
    -1
      modules/juce_video/capture/juce_CameraDevice.cpp
  20. +18
    -18
      modules/juce_video/native/juce_ios_CameraDevice.h
  21. +210
    -189
      modules/juce_video/native/juce_mac_CameraDevice.h

+ 13
- 4
modules/juce_audio_devices/native/juce_ios_Audio.cpp View File

@@ -722,11 +722,20 @@ struct iOSAudioIODevice::Pimpl : public AudioPlayHead,
&dataSize); &dataSize);
if (err == noErr) if (err == noErr)
{ {
#if (! defined __IPHONE_10_0) || (__IPHONE_OS_VERSION_MIN_REQUIRED < __IPHONE_10_0)
[[UIApplication sharedApplication] openURL: (NSURL*)hostUrl];
#else
[[UIApplication sharedApplication] openURL: (NSURL*)hostUrl options: @{} completionHandler: nil];
#if defined (__IPHONE_10_0) && __IPHONE_OS_VERSION_MAX_ALLOWED >= __IPHONE_10_0
if (@available (iOS 10.0, *))
{
[[UIApplication sharedApplication] openURL: (NSURL*) hostUrl
options: @{}
completionHandler: nil];
return;
}
#endif #endif
JUCE_BEGIN_IGNORE_WARNINGS_GCC_LIKE ("-Wdeprecated-declarations")
[[UIApplication sharedApplication] openURL: (NSURL*) hostUrl];
JUCE_END_IGNORE_WARNINGS_GCC_LIKE
} }
} }


+ 2
- 2
modules/juce_audio_devices/native/juce_mac_CoreMidi.mm View File

@@ -82,7 +82,7 @@ namespace CoreMidiHelpers
struct Sender; struct Sender;
#if JUCE_HAS_NEW_COREMIDI_API #if JUCE_HAS_NEW_COREMIDI_API
JUCE_BEGIN_IGNORE_WARNINGS_GCC_LIKE ("-Wunguarded-availability-new")
JUCE_BEGIN_IGNORE_WARNINGS_GCC_LIKE ("-Wunguarded-availability", "-Wunguarded-availability-new")
template <> template <>
struct Sender<ImplementationStrategy::onlyNew> : public SenderBase struct Sender<ImplementationStrategy::onlyNew> : public SenderBase
@@ -829,7 +829,7 @@ namespace CoreMidiHelpers
struct CreatorFunctions; struct CreatorFunctions;
#if JUCE_HAS_NEW_COREMIDI_API #if JUCE_HAS_NEW_COREMIDI_API
JUCE_BEGIN_IGNORE_WARNINGS_GCC_LIKE ("-Wunguarded-availability-new")
JUCE_BEGIN_IGNORE_WARNINGS_GCC_LIKE ("-Wunguarded-availability", "-Wunguarded-availability-new")
template <> template <>
struct CreatorFunctions<ImplementationStrategy::onlyNew> struct CreatorFunctions<ImplementationStrategy::onlyNew>


+ 30
- 27
modules/juce_audio_plugin_client/AU/juce_AUv3_Wrapper.mm View File

@@ -28,27 +28,19 @@
#if JucePlugin_Build_AUv3 #if JucePlugin_Build_AUv3
#if JUCE_MAC
#if (! defined MAC_OS_X_VERSION_MIN_REQUIRED) || (! defined MAC_OS_X_VERSION_10_11) || (MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_X_VERSION_10_11)
#error AUv3 needs Deployment Target OS X 10.11 or higher to compile
#endif
#if (defined MAC_OS_X_VERSION_10_13) && (MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_13)
#define JUCE_AUV3_MIDI_OUTPUT_SUPPORTED 1
#define JUCE_AUV3_VIEW_CONFIG_SUPPORTED 1
#endif
#if defined (MAC_OS_VERSION_12_0)
#define JUCE_AUV3_MIDI_EVENT_LIST_SUPPORTED 1
#endif
#if JUCE_MAC && ! (defined (MAC_OS_X_VERSION_10_11) && MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_11)
#error AUv3 needs Deployment Target OS X 10.11 or higher to compile
#endif #endif
#if JUCE_IOS
#if (defined __IPHONE_11_0) && (__IPHONE_OS_VERSION_MIN_REQUIRED >= __IPHONE_11_0)
#define JUCE_AUV3_MIDI_OUTPUT_SUPPORTED 1
#define JUCE_AUV3_VIEW_CONFIG_SUPPORTED 1
#endif
#if (defined __IPHONE_15_0)
#define JUCE_AUV3_MIDI_EVENT_LIST_SUPPORTED 1
#endif
#if (JUCE_IOS && defined (__IPHONE_15_0) && __IPHONE_OS_VERSION_MAX_ALLOWED >= __IPHONE_15_0) \
|| (JUCE_MAC && defined (MAC_OS_VERSION_12_0) && MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_VERSION_12_0)
#define JUCE_AUV3_MIDI_EVENT_LIST_SUPPORTED 1
#endif
#if (JUCE_IOS && defined (__IPHONE_11_0) && __IPHONE_OS_VERSION_MAX_ALLOWED >= __IPHONE_11_0) \
|| (JUCE_MAC && defined (MAC_OS_X_VERSION_10_13) && MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_13)
#define JUCE_AUV3_MIDI_OUTPUT_SUPPORTED 1
#define JUCE_AUV3_VIEW_CONFIG_SUPPORTED 1
#endif #endif
#ifndef __OBJC2__ #ifndef __OBJC2__
@@ -210,8 +202,10 @@ public:
//============================================================================== //==============================================================================
#if JUCE_AUV3_VIEW_CONFIG_SUPPORTED #if JUCE_AUV3_VIEW_CONFIG_SUPPORTED
JUCE_BEGIN_IGNORE_WARNINGS_GCC_LIKE ("-Wunguarded-availability", "-Wunguarded-availability-new")
virtual NSIndexSet* getSupportedViewConfigurations (NSArray<AUAudioUnitViewConfiguration*>*) = 0; virtual NSIndexSet* getSupportedViewConfigurations (NSArray<AUAudioUnitViewConfiguration*>*) = 0;
virtual void selectViewConfiguration (AUAudioUnitViewConfiguration*) = 0;
virtual void selectViewConfiguration (AUAudioUnitViewConfiguration*) = 0;
JUCE_END_IGNORE_WARNINGS_GCC_LIKE
#endif #endif
private: private:
@@ -265,7 +259,8 @@ private:
JUCE_END_IGNORE_WARNINGS_GCC_LIKE JUCE_END_IGNORE_WARNINGS_GCC_LIKE
#if JUCE_AUV3_MIDI_OUTPUT_SUPPORTED #if JUCE_AUV3_MIDI_OUTPUT_SUPPORTED
addMethod (@selector (MIDIOutputNames), getMIDIOutputNames, "@@:");
if (@available (macOS 10.13, iOS 11.0, *))
addMethod (@selector (MIDIOutputNames), getMIDIOutputNames, "@@:");
#endif #endif
//============================================================================== //==============================================================================
@@ -284,8 +279,11 @@ private:
//============================================================================== //==============================================================================
#if JUCE_AUV3_VIEW_CONFIG_SUPPORTED #if JUCE_AUV3_VIEW_CONFIG_SUPPORTED
addMethod (@selector (supportedViewConfigurations:), getSupportedViewConfigurations, "@@:@");
addMethod (@selector (selectViewConfiguration:), selectViewConfiguration, "v@:@");
if (@available (macOS 10.13, iOS 11.0, *))
{
addMethod (@selector (supportedViewConfigurations:), getSupportedViewConfigurations, "@@:@");
addMethod (@selector (selectViewConfiguration:), selectViewConfiguration, "v@:@");
}
#endif #endif
registerClass(); registerClass();
@@ -396,8 +394,10 @@ private:
//============================================================================== //==============================================================================
#if JUCE_AUV3_VIEW_CONFIG_SUPPORTED #if JUCE_AUV3_VIEW_CONFIG_SUPPORTED
JUCE_BEGIN_IGNORE_WARNINGS_GCC_LIKE ("-Wunguarded-availability", "-Wunguarded-availability-new")
static NSIndexSet* getSupportedViewConfigurations (id self, SEL, NSArray<AUAudioUnitViewConfiguration*>* configs) { return _this (self)->getSupportedViewConfigurations (configs); } static NSIndexSet* getSupportedViewConfigurations (id self, SEL, NSArray<AUAudioUnitViewConfiguration*>* configs) { return _this (self)->getSupportedViewConfigurations (configs); }
static void selectViewConfiguration (id self, SEL, AUAudioUnitViewConfiguration* config) { _this (self)->selectViewConfiguration (config); }
static void selectViewConfiguration (id self, SEL, AUAudioUnitViewConfiguration* config) { _this (self)->selectViewConfiguration (config); }
JUCE_END_IGNORE_WARNINGS_GCC_LIKE
#endif #endif
}; };
@@ -896,6 +896,7 @@ public:
//============================================================================== //==============================================================================
#if JUCE_AUV3_VIEW_CONFIG_SUPPORTED #if JUCE_AUV3_VIEW_CONFIG_SUPPORTED
JUCE_BEGIN_IGNORE_WARNINGS_GCC_LIKE ("-Wunguarded-availability", "-Wunguarded-availability-new")
NSIndexSet* getSupportedViewConfigurations (NSArray<AUAudioUnitViewConfiguration*>* configs) override NSIndexSet* getSupportedViewConfigurations (NSArray<AUAudioUnitViewConfiguration*>* configs) override
{ {
auto supportedViewIndecies = [[NSMutableIndexSet alloc] init]; auto supportedViewIndecies = [[NSMutableIndexSet alloc] init];
@@ -932,6 +933,7 @@ public:
{ {
processorHolder->viewConfiguration.reset (new AudioProcessorHolder::ViewConfig { [config width], [config height], [config hostHasController] == YES }); processorHolder->viewConfiguration.reset (new AudioProcessorHolder::ViewConfig { [config width], [config height], [config hostHasController] == YES });
} }
JUCE_END_IGNORE_WARNINGS_GCC_LIKE
#endif #endif
struct ScopedKeyChange struct ScopedKeyChange
@@ -1598,10 +1600,11 @@ private:
// send MIDI // send MIDI
#if JucePlugin_ProducesMidiOutput && JUCE_AUV3_MIDI_OUTPUT_SUPPORTED #if JucePlugin_ProducesMidiOutput && JUCE_AUV3_MIDI_OUTPUT_SUPPORTED
if (auto midiOut = [au MIDIOutputEventBlock])
if (@available (macOS 10.13, iOS 11.0, *))
{ {
for (const auto metadata : midiMessages)
midiOut (metadata.samplePosition, 0, metadata.numBytes, metadata.data);
if (auto midiOut = [au MIDIOutputEventBlock])
for (const auto metadata : midiMessages)
midiOut (metadata.samplePosition, 0, metadata.numBytes, metadata.data);
} }
#endif #endif


+ 4
- 53
modules/juce_audio_processors/format_types/juce_AudioUnitPluginFormat.mm View File

@@ -39,18 +39,7 @@ JUCE_BEGIN_IGNORE_WARNINGS_GCC_LIKE ("-Wdeprecated-declarations")
#include <AudioUnit/AudioUnitCarbonView.h> #include <AudioUnit/AudioUnitCarbonView.h>
#endif #endif
#ifndef JUCE_SUPPORTS_AUv3
#if __OBJC2__ \
&& (JUCE_IOS || (defined (MAC_OS_X_VERSION_10_11) && (MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_11)))
#define JUCE_SUPPORTS_AUv3 1
#else
#define JUCE_SUPPORTS_AUv3 0
#endif
#endif
#if JUCE_SUPPORTS_AUv3
#include <CoreAudioKit/AUViewController.h>
#endif
#include <CoreAudioKit/AUViewController.h>
#include <juce_audio_basics/native/juce_mac_CoreAudioLayouts.h> #include <juce_audio_basics/native/juce_mac_CoreAudioLayouts.h>
#include <juce_audio_basics/midi/juce_MidiDataConcatenator.h> #include <juce_audio_basics/midi/juce_MidiDataConcatenator.h>
@@ -547,9 +536,7 @@ public:
AudioComponentGetDescription (auComponent, &componentDesc); AudioComponentGetDescription (auComponent, &componentDesc);
#if JUCE_SUPPORTS_AUv3
isAUv3 = ((componentDesc.componentFlags & kAudioComponentFlag_IsV3AudioUnit) != 0); isAUv3 = ((componentDesc.componentFlags & kAudioComponentFlag_IsV3AudioUnit) != 0);
#endif
wantsMidiMessages = componentDesc.componentType == kAudioUnitType_MusicDevice wantsMidiMessages = componentDesc.componentType == kAudioUnitType_MusicDevice
|| componentDesc.componentType == kAudioUnitType_MusicEffect || componentDesc.componentType == kAudioUnitType_MusicEffect
@@ -1136,18 +1123,12 @@ public:
bool hasEditor() const override bool hasEditor() const override
{ {
#if JUCE_MAC
return true;
#elif JUCE_SUPPORTS_AUv3
UInt32 dataSize; UInt32 dataSize;
Boolean isWritable; Boolean isWritable;
return (AudioUnitGetPropertyInfo (audioUnit, kAudioUnitProperty_RequestViewController, return (AudioUnitGetPropertyInfo (audioUnit, kAudioUnitProperty_RequestViewController,
kAudioUnitScope_Global, 0, &dataSize, &isWritable) == noErr kAudioUnitScope_Global, 0, &dataSize, &isWritable) == noErr
&& dataSize == sizeof (uintptr_t) && isWritable != 0); && dataSize == sizeof (uintptr_t) && isWritable != 0);
#else
return false;
#endif
} }
AudioProcessorEditor* createEditor() override; AudioProcessorEditor* createEditor() override;
@@ -2261,10 +2242,8 @@ public:
{ {
addAndMakeVisible (wrapper); addAndMakeVisible (wrapper);
#if JUCE_SUPPORTS_AUv3
viewControllerCallback = viewControllerCallback =
CreateObjCBlock (this, &AudioUnitPluginWindowCocoa::requestViewControllerCallback); CreateObjCBlock (this, &AudioUnitPluginWindowCocoa::requestViewControllerCallback);
#endif
setOpaque (true); setOpaque (true);
setVisible (true); setVisible (true);
@@ -2284,7 +2263,6 @@ public:
} }
} }
#if JUCE_SUPPORTS_AUv3
void embedViewController (JUCE_IOS_MAC_VIEW* pluginView, const CGSize& size) void embedViewController (JUCE_IOS_MAC_VIEW* pluginView, const CGSize& size)
{ {
wrapper.setView (pluginView); wrapper.setView (pluginView);
@@ -2299,7 +2277,6 @@ public:
wrapper.setSize (static_cast<int> (size.width), static_cast<int> (size.height)); wrapper.setSize (static_cast<int> (size.width), static_cast<int> (size.height));
#endif #endif
} }
#endif
bool isValid() const { return wrapper.getView() != nil || waitingForViewCallback; } bool isValid() const { return wrapper.getView() != nil || waitingForViewCallback; }
@@ -2323,10 +2300,8 @@ private:
AudioUnitPluginInstance& plugin; AudioUnitPluginInstance& plugin;
AudioUnitFormatHelpers::AutoResizingNSViewComponent wrapper; AudioUnitFormatHelpers::AutoResizingNSViewComponent wrapper;
#if JUCE_SUPPORTS_AUv3
typedef void (^ViewControllerCallbackBlock)(AUViewControllerBase *); typedef void (^ViewControllerCallbackBlock)(AUViewControllerBase *);
ObjCBlock<ViewControllerCallbackBlock> viewControllerCallback; ObjCBlock<ViewControllerCallbackBlock> viewControllerCallback;
#endif
bool waitingForViewCallback = false; bool waitingForViewCallback = false;
@@ -2375,7 +2350,6 @@ private:
dataSize = 0; dataSize = 0;
isWritable = false; isWritable = false;
#if JUCE_SUPPORTS_AUv3
if (AudioUnitGetPropertyInfo (plugin.audioUnit, kAudioUnitProperty_RequestViewController, kAudioUnitScope_Global, if (AudioUnitGetPropertyInfo (plugin.audioUnit, kAudioUnitProperty_RequestViewController, kAudioUnitScope_Global,
0, &dataSize, &isWritable) == noErr 0, &dataSize, &isWritable) == noErr
&& dataSize == sizeof (ViewControllerCallbackBlock)) && dataSize == sizeof (ViewControllerCallbackBlock))
@@ -2391,7 +2365,6 @@ private:
waitingForViewCallback = false; waitingForViewCallback = false;
} }
#endif
#if JUCE_MAC #if JUCE_MAC
if (createGenericViewIfNeeded && (pluginView == nil)) if (createGenericViewIfNeeded && (pluginView == nil))
@@ -2418,7 +2391,6 @@ private:
return pluginView != nil; return pluginView != nil;
} }
#if JUCE_SUPPORTS_AUv3
void requestViewControllerCallback (AUViewControllerBase* controller) void requestViewControllerCallback (AUViewControllerBase* controller)
{ {
const auto viewSize = [&controller] const auto viewSize = [&controller]
@@ -2459,7 +2431,6 @@ private:
embedViewController ([controller view], viewSize); embedViewController ([controller view], viewSize);
} }
} }
#endif
}; };
#if JUCE_SUPPORT_CARBON #if JUCE_SUPPORT_CARBON
@@ -2693,23 +2664,17 @@ void AudioUnitPluginFormat::createPluginInstance (const PluginDescription& desc,
struct AUAsyncInitializationCallback struct AUAsyncInitializationCallback
{ {
#if JUCE_SUPPORTS_AUv3
typedef void (^AUCompletionCallbackBlock)(AudioComponentInstance, OSStatus); typedef void (^AUCompletionCallbackBlock)(AudioComponentInstance, OSStatus);
#endif
AUAsyncInitializationCallback (double inSampleRate, int inFramesPerBuffer, AUAsyncInitializationCallback (double inSampleRate, int inFramesPerBuffer,
PluginCreationCallback inOriginalCallback) PluginCreationCallback inOriginalCallback)
: sampleRate (inSampleRate), framesPerBuffer (inFramesPerBuffer), : sampleRate (inSampleRate), framesPerBuffer (inFramesPerBuffer),
originalCallback (std::move (inOriginalCallback)) originalCallback (std::move (inOriginalCallback))
{ {
#if JUCE_SUPPORTS_AUv3
block = CreateObjCBlock (this, &AUAsyncInitializationCallback::completion); block = CreateObjCBlock (this, &AUAsyncInitializationCallback::completion);
#endif
} }
#if JUCE_SUPPORTS_AUv3
AUCompletionCallbackBlock getBlock() noexcept { return block; }
#endif
AUCompletionCallbackBlock getBlock() noexcept { return block; }
void completion (AudioComponentInstance audioUnit, OSStatus err) void completion (AudioComponentInstance audioUnit, OSStatus err)
{ {
@@ -2734,26 +2699,18 @@ void AudioUnitPluginFormat::createPluginInstance (const PluginDescription& desc,
double sampleRate; double sampleRate;
int framesPerBuffer; int framesPerBuffer;
PluginCreationCallback originalCallback; PluginCreationCallback originalCallback;
#if JUCE_SUPPORTS_AUv3
ObjCBlock<AUCompletionCallbackBlock> block; ObjCBlock<AUCompletionCallbackBlock> block;
#endif
}; };
auto callbackBlock = new AUAsyncInitializationCallback (rate, blockSize, std::move (callback)); auto callbackBlock = new AUAsyncInitializationCallback (rate, blockSize, std::move (callback));
#if JUCE_SUPPORTS_AUv3
//==============================================================================
bool isAUv3 = ((componentDesc.componentFlags & kAudioComponentFlag_IsV3AudioUnit) != 0);
if (isAUv3)
if ((componentDesc.componentFlags & kAudioComponentFlag_IsV3AudioUnit) != 0)
{ {
AudioComponentInstantiate (auComponent, kAudioComponentInstantiation_LoadOutOfProcess, AudioComponentInstantiate (auComponent, kAudioComponentInstantiation_LoadOutOfProcess,
callbackBlock->getBlock()); callbackBlock->getBlock());
return; return;
} }
#endif // JUCE_SUPPORTS_AUv3
AudioComponentInstance audioUnit; AudioComponentInstance audioUnit;
auto err = AudioComponentInstanceNew(auComponent, &audioUnit); auto err = AudioComponentInstanceNew(auComponent, &audioUnit);
@@ -2767,7 +2724,6 @@ void AudioUnitPluginFormat::createPluginInstance (const PluginDescription& desc,
bool AudioUnitPluginFormat::requiresUnblockedMessageThreadDuringCreation (const PluginDescription& desc) const bool AudioUnitPluginFormat::requiresUnblockedMessageThreadDuringCreation (const PluginDescription& desc) const
{ {
#if JUCE_SUPPORTS_AUv3
String pluginName, version, manufacturer; String pluginName, version, manufacturer;
AudioComponentDescription componentDesc; AudioComponentDescription componentDesc;
@@ -2780,9 +2736,6 @@ bool AudioUnitPluginFormat::requiresUnblockedMessageThreadDuringCreation (const
if (AudioComponentGetDescription (auComp, &componentDesc) == noErr) if (AudioComponentGetDescription (auComp, &componentDesc) == noErr)
return ((componentDesc.componentFlags & kAudioComponentFlag_IsV3AudioUnit) != 0); return ((componentDesc.componentFlags & kAudioComponentFlag_IsV3AudioUnit) != 0);
} }
#else
ignoreUnused (desc);
#endif
return false; return false;
} }
@@ -2815,11 +2768,9 @@ StringArray AudioUnitPluginFormat::searchPathsForPlugins (const FileSearchPath&,
{ {
ignoreUnused (allowPluginsWhichRequireAsynchronousInstantiation); ignoreUnused (allowPluginsWhichRequireAsynchronousInstantiation);
#if JUCE_SUPPORTS_AUv3
bool isAUv3 = ((desc.componentFlags & kAudioComponentFlag_IsV3AudioUnit) != 0);
const auto isAUv3 = ((desc.componentFlags & kAudioComponentFlag_IsV3AudioUnit) != 0);
if (allowPluginsWhichRequireAsynchronousInstantiation || ! isAUv3) if (allowPluginsWhichRequireAsynchronousInstantiation || ! isAUv3)
#endif
result.add (AudioUnitFormatHelpers::createPluginIdentifier (desc)); result.add (AudioUnitFormatHelpers::createPluginIdentifier (desc));
} }
} }


+ 8
- 17
modules/juce_audio_utils/native/juce_mac_BluetoothMidiDevicePairingDialogue.mm View File

@@ -26,8 +26,6 @@
namespace juce namespace juce
{ {
#if defined (MAC_OS_X_VERSION_10_11) && MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_11
//============================================================================== //==============================================================================
class BluetoothMidiPairingWindowClass : public ObjCClass<NSObject> class BluetoothMidiPairingWindowClass : public ObjCClass<NSObject>
{ {
@@ -159,20 +157,12 @@ private:
bool BluetoothMidiDevicePairingDialogue::open (ModalComponentManager::Callback* exitCallback, bool BluetoothMidiDevicePairingDialogue::open (ModalComponentManager::Callback* exitCallback,
Rectangle<int>* bounds) Rectangle<int>* bounds)
{ {
new BluetoothMidiSelectorWindowHelper (exitCallback, bounds);
return true;
}
bool BluetoothMidiDevicePairingDialogue::isAvailable()
{
return true;
}
#else
if (@available (macOS 10.11, *))
{
new BluetoothMidiSelectorWindowHelper (exitCallback, bounds);
return true;
}
bool BluetoothMidiDevicePairingDialogue::open (ModalComponentManager::Callback* exitCallback,
Rectangle<int>*)
{
std::unique_ptr<ModalComponentManager::Callback> cb (exitCallback); std::unique_ptr<ModalComponentManager::Callback> cb (exitCallback);
// This functionality is unavailable when targetting OSX < 10.11. Instead, // This functionality is unavailable when targetting OSX < 10.11. Instead,
// you should pair Bluetooth MIDI devices using the "Audio MIDI Setup" app // you should pair Bluetooth MIDI devices using the "Audio MIDI Setup" app
@@ -183,9 +173,10 @@ bool BluetoothMidiDevicePairingDialogue::open (ModalComponentManager::Callback*
bool BluetoothMidiDevicePairingDialogue::isAvailable() bool BluetoothMidiDevicePairingDialogue::isAvailable()
{ {
if (@available (macOS 10.11, *))
return true;
return false; return false;
} }
#endif
} // namespace juce } // namespace juce

+ 1
- 1
modules/juce_core/native/juce_BasicNativeHeaders.h View File

@@ -28,7 +28,7 @@
#if JUCE_MAC || JUCE_IOS #if JUCE_MAC || JUCE_IOS
#if JUCE_IOS #if JUCE_IOS
#if JUCE_MODULE_AVAILABLE_juce_opengl && defined (__IPHONE_12_0) && __IPHONE_OS_VERSION_MIN_REQUIRED >= __IPHONE_12_0
#if JUCE_MODULE_AVAILABLE_juce_opengl && defined (__IPHONE_12_0) && __IPHONE_OS_VERSION_MAX_ALLOWED >= __IPHONE_12_0
#define GLES_SILENCE_DEPRECATION 1 #define GLES_SILENCE_DEPRECATION 1
#endif #endif


+ 27
- 15
modules/juce_core/native/juce_mac_Files.mm View File

@@ -410,12 +410,20 @@ bool JUCE_CALLTYPE Process::openDocument (const String& fileName, const String&
#if JUCE_IOS #if JUCE_IOS
ignoreUnused (parameters); ignoreUnused (parameters);
#if (! defined __IPHONE_OS_VERSION_MIN_REQUIRED) || (! defined __IPHONE_10_0) || (__IPHONE_OS_VERSION_MIN_REQUIRED < __IPHONE_10_0)
return [[UIApplication sharedApplication] openURL: filenameAsURL];
#else
[[UIApplication sharedApplication] openURL: filenameAsURL options: @{} completionHandler: nil];
return true;
#if defined (__IPHONE_10_0) && __IPHONE_OS_VERSION_MAX_ALLOWED >= __IPHONE_10_0
if (@available (iOS 10.0, *))
{
[[UIApplication sharedApplication] openURL: filenameAsURL
options: @{}
completionHandler: nil];
return true;
}
#endif #endif
JUCE_BEGIN_IGNORE_WARNINGS_GCC_LIKE ("-Wdeprecated-declarations")
return [[UIApplication sharedApplication] openURL: filenameAsURL];
JUCE_END_IGNORE_WARNINGS_GCC_LIKE
#else #else
NSWorkspace* workspace = [NSWorkspace sharedWorkspace]; NSWorkspace* workspace = [NSWorkspace sharedWorkspace];
@@ -434,16 +442,21 @@ bool JUCE_CALLTYPE Process::openDocument (const String& fileName, const String&
for (int i = 0; i < params.size(); ++i) for (int i = 0; i < params.size(); ++i)
[paramArray addObject: juceStringToNS (params[i])]; [paramArray addObject: juceStringToNS (params[i])];
#if (defined MAC_OS_X_VERSION_10_15) && MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_15
auto config = [NSWorkspaceOpenConfiguration configuration];
[config setCreatesNewApplicationInstance: YES];
config.arguments = paramArray;
#if defined (MAC_OS_X_VERSION_10_15) && MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_15
if (@available (macOS 10.15, *))
{
auto config = [NSWorkspaceOpenConfiguration configuration];
[config setCreatesNewApplicationInstance: YES];
config.arguments = paramArray;
[workspace openApplicationAtURL: filenameAsURL
configuration: config
completionHandler: nil];
return true;
}
#endif
[workspace openApplicationAtURL: filenameAsURL
configuration: config
completionHandler: nil];
return true;
#else
NSMutableDictionary* dict = [[NSMutableDictionary new] autorelease]; NSMutableDictionary* dict = [[NSMutableDictionary new] autorelease];
[dict setObject: paramArray [dict setObject: paramArray
@@ -453,7 +466,6 @@ bool JUCE_CALLTYPE Process::openDocument (const String& fileName, const String&
options: NSWorkspaceLaunchDefault | NSWorkspaceLaunchNewInstance options: NSWorkspaceLaunchDefault | NSWorkspaceLaunchNewInstance
configuration: dict configuration: dict
error: nil]; error: nil];
#endif
} }
if (file.exists()) if (file.exists())


+ 416
- 419
modules/juce_core/native/juce_mac_Network.mm
File diff suppressed because it is too large
View File


+ 15
- 9
modules/juce_core/native/juce_mac_SystemStats.mm View File

@@ -89,15 +89,21 @@ static String getOSXVersion()
{ {
JUCE_AUTORELEASEPOOL JUCE_AUTORELEASEPOOL
{ {
const String systemVersionPlist ("/System/Library/CoreServices/SystemVersion.plist");
#if (defined (MAC_OS_X_VERSION_10_13) && MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_13)
NSError* error = nullptr;
NSDictionary* dict = [NSDictionary dictionaryWithContentsOfURL: createNSURLFromFile (systemVersionPlist)
error: &error];
#else
NSDictionary* dict = [NSDictionary dictionaryWithContentsOfFile: juceStringToNS (systemVersionPlist)];
#endif
const auto* dict = []
{
const String systemVersionPlist ("/System/Library/CoreServices/SystemVersion.plist");
#if defined (MAC_OS_X_VERSION_10_13) && MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_13
if (@available (macOS 10.13, *))
{
NSError* error = nullptr;
return [NSDictionary dictionaryWithContentsOfURL: createNSURLFromFile (systemVersionPlist)
error: &error];
}
#endif
return [NSDictionary dictionaryWithContentsOfFile: juceStringToNS (systemVersionPlist)];
}();
if (dict != nullptr) if (dict != nullptr)
return nsStringToJuce ([dict objectForKey: nsStringLiteral ("ProductVersion")]); return nsStringToJuce ([dict objectForKey: nsStringLiteral ("ProductVersion")]);


+ 5
- 1
modules/juce_gui_basics/native/accessibility/juce_ios_Accessibility.mm View File

@@ -37,10 +37,12 @@ static void juceFreeAccessibilityPlatformSpecificData (UIAccessibilityElement* e
namespace juce namespace juce
{ {
#if (defined (__IPHONE_11_0) && __IPHONE_OS_VERSION_MIN_REQUIRED >= __IPHONE_11_0)
#if defined (__IPHONE_11_0) && __IPHONE_OS_VERSION_MAX_ALLOWED >= __IPHONE_11_0
#define JUCE_IOS_CONTAINER_API_AVAILABLE 1 #define JUCE_IOS_CONTAINER_API_AVAILABLE 1
#endif #endif
JUCE_BEGIN_IGNORE_WARNINGS_GCC_LIKE ("-Wunguarded-availability", "-Wunguarded-availability-new")
constexpr auto juceUIAccessibilityContainerTypeNone = constexpr auto juceUIAccessibilityContainerTypeNone =
#if JUCE_IOS_CONTAINER_API_AVAILABLE #if JUCE_IOS_CONTAINER_API_AVAILABLE
UIAccessibilityContainerTypeNone; UIAccessibilityContainerTypeNone;
@@ -62,6 +64,8 @@ constexpr auto juceUIAccessibilityContainerTypeList =
2; 2;
#endif #endif
JUCE_END_IGNORE_WARNINGS_GCC_LIKE
#define JUCE_NATIVE_ACCESSIBILITY_INCLUDED 1 #define JUCE_NATIVE_ACCESSIBILITY_INCLUDED 1
//============================================================================== //==============================================================================


+ 1
- 3
modules/juce_gui_basics/native/juce_ios_FileChooser.mm View File

@@ -26,7 +26,7 @@
namespace juce namespace juce
{ {
#if ! (defined (__IPHONE_16_0) && __IPHONE_OS_VERSION_MIN_REQUIRED >= __IPHONE_16_0)
#if ! (defined (__IPHONE_16_0) && __IPHONE_OS_VERSION_MAX_ALLOWED >= __IPHONE_16_0)
JUCE_BEGIN_IGNORE_WARNINGS_GCC_LIKE ("-Wdeprecated-declarations") JUCE_BEGIN_IGNORE_WARNINGS_GCC_LIKE ("-Wdeprecated-declarations")
#define JUCE_DEPRECATION_IGNORED 1 #define JUCE_DEPRECATION_IGNORED 1
#endif #endif
@@ -382,6 +382,4 @@ std::shared_ptr<FileChooser::Pimpl> FileChooser::showPlatformDialog (FileChooser
JUCE_END_IGNORE_WARNINGS_GCC_LIKE JUCE_END_IGNORE_WARNINGS_GCC_LIKE
#endif #endif
#undef JUCE_DEPRECATION_IGNORED
} // namespace juce } // namespace juce

+ 11
- 8
modules/juce_gui_basics/native/juce_ios_UIViewComponentPeer.mm View File

@@ -23,7 +23,7 @@
============================================================================== ==============================================================================
*/ */
#if defined (__IPHONE_13_0)
#if defined (__IPHONE_13_0) && __IPHONE_OS_VERSION_MAX_ALLOWED >= __IPHONE_13_0
#define JUCE_HAS_IOS_POINTER_SUPPORT 1 #define JUCE_HAS_IOS_POINTER_SUPPORT 1
#else #else
#define JUCE_HAS_IOS_POINTER_SUPPORT 0 #define JUCE_HAS_IOS_POINTER_SUPPORT 0
@@ -38,15 +38,18 @@ static UIInterfaceOrientation getWindowOrientation()
{ {
UIApplication* sharedApplication = [UIApplication sharedApplication]; UIApplication* sharedApplication = [UIApplication sharedApplication];
#if (defined (__IPHONE_13_0) && __IPHONE_OS_VERSION_MIN_REQUIRED >= __IPHONE_13_0)
for (UIScene* scene in [sharedApplication connectedScenes])
if ([scene isKindOfClass: [UIWindowScene class]])
return [(UIWindowScene*) scene interfaceOrientation];
#if defined (__IPHONE_13_0) && __IPHONE_OS_VERSION_MAX_ALLOWED >= __IPHONE_13_0
if (@available (iOS 13.0, *))
{
for (UIScene* scene in [sharedApplication connectedScenes])
if ([scene isKindOfClass: [UIWindowScene class]])
return [(UIWindowScene*) scene interfaceOrientation];
}
#endif
return UIInterfaceOrientationPortrait;
#else
JUCE_BEGIN_IGNORE_WARNINGS_GCC_LIKE ("-Wdeprecated-declarations")
return [sharedApplication statusBarOrientation]; return [sharedApplication statusBarOrientation];
#endif
JUCE_END_IGNORE_WARNINGS_GCC_LIKE
} }
namespace Orientations namespace Orientations


+ 4
- 1
modules/juce_gui_basics/native/juce_ios_Windowing.mm View File

@@ -787,7 +787,7 @@ static Rectangle<int> getRecommendedWindowBounds()
static BorderSize<int> getSafeAreaInsets (float masterScale) static BorderSize<int> getSafeAreaInsets (float masterScale)
{ {
#if defined (__IPHONE_11_0)
#if defined (__IPHONE_11_0) && __IPHONE_OS_VERSION_MAX_ALLOWED >= __IPHONE_11_0
if (@available (iOS 11.0, *)) if (@available (iOS 11.0, *))
{ {
UIEdgeInsets safeInsets = TemporaryWindow().window.safeAreaInsets; UIEdgeInsets safeInsets = TemporaryWindow().window.safeAreaInsets;
@@ -799,7 +799,10 @@ static BorderSize<int> getSafeAreaInsets (float masterScale)
} }
#endif #endif
JUCE_BEGIN_IGNORE_WARNINGS_GCC_LIKE ("-Wdeprecated-declarations")
auto statusBarSize = [UIApplication sharedApplication].statusBarFrame.size; auto statusBarSize = [UIApplication sharedApplication].statusBarFrame.size;
JUCE_END_IGNORE_WARNINGS_GCC_LIKE
auto statusBarHeight = jmin (statusBarSize.width, statusBarSize.height); auto statusBarHeight = jmin (statusBarSize.width, statusBarSize.height);
return { roundToInt (statusBarHeight / masterScale), 0, 0, 0 }; return { roundToInt (statusBarHeight / masterScale), 0, 0, 0 };


+ 11
- 8
modules/juce_gui_basics/native/juce_mac_NSViewComponentPeer.mm View File

@@ -1344,14 +1344,17 @@ public:
static NSArray* getSupportedDragTypes() static NSArray* getSupportedDragTypes()
{ {
const auto type =
#if defined (MAC_OS_X_VERSION_10_13) && MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_13
NSPasteboardTypeFileURL;
#else
kUTTypeFileURL;
#endif
return [NSArray arrayWithObjects: (NSString*) type, (NSString*) kPasteboardTypeFileURLPromise, NSPasteboardTypeString, nil];
const auto type = []
{
#if defined (MAC_OS_X_VERSION_10_13) && MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_13
if (@available (macOS 10.13, *))
return NSPasteboardTypeFileURL;
#endif
return (NSString*) kUTTypeFileURL;
}();
return [NSArray arrayWithObjects: type, (NSString*) kPasteboardTypeFileURLPromise, NSPasteboardTypeString, nil];
} }
BOOL sendDragCallback (const int type, id <NSDraggingInfo> sender) BOOL sendDragCallback (const int type, id <NSDraggingInfo> sender)


+ 9
- 6
modules/juce_gui_extra/native/juce_mac_AppleRemote.mm View File

@@ -47,12 +47,15 @@ namespace
io_iterator_t iter = 0; io_iterator_t iter = 0;
io_object_t iod = 0; io_object_t iod = 0;
const auto defaultPort =
#if defined (MAC_OS_VERSION_12_0) && MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_VERSION_12_0
kIOMainPortDefault;
#else
kIOMasterPortDefault;
#endif
const auto defaultPort = []
{
#if defined (MAC_OS_VERSION_12_0) && MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_VERSION_12_0
if (@available (macOS 12.0, *))
return kIOMainPortDefault;
#endif
return kIOMasterPortDefault;
}();
if (IOServiceGetMatchingServices (defaultPort, dict, &iter) == kIOReturnSuccess if (IOServiceGetMatchingServices (defaultPort, dict, &iter) == kIOReturnSuccess
&& iter != 0) && iter != 0)


+ 1
- 1
modules/juce_gui_extra/native/juce_mac_SystemTrayIcon.cpp View File

@@ -26,7 +26,7 @@
namespace juce namespace juce
{ {
JUCE_BEGIN_IGNORE_WARNINGS_GCC_LIKE ("-Wunguarded-availability", "-Wdeprecated-declarations")
JUCE_BEGIN_IGNORE_WARNINGS_GCC_LIKE ("-Wunguarded-availability", "-Wunguarded-availability-new", "-Wdeprecated-declarations")
extern NSMenu* createNSMenu (const PopupMenu&, const String& name, int topLevelMenuId, extern NSMenu* createNSMenu (const PopupMenu&, const String& name, int topLevelMenuId,
int topLevelIndex, bool addDelegate); int topLevelIndex, bool addDelegate);


+ 271
- 306
modules/juce_gui_extra/native/juce_mac_WebBrowserComponent.mm View File

@@ -26,11 +26,7 @@
namespace juce namespace juce
{ {
#if JUCE_IOS || (defined (MAC_OS_X_VERSION_10_10) && MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_10)
#define JUCE_USE_WKWEBVIEW 1
#endif
#if (defined (MAC_OS_X_VERSION_10_12) && MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_12)
#if JUCE_MAC && defined (MAC_OS_X_VERSION_10_12) && MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_12
#define WKWEBVIEW_OPENPANEL_SUPPORTED 1 #define WKWEBVIEW_OPENPANEL_SUPPORTED 1
#endif #endif
@@ -115,41 +111,39 @@ static NSMutableURLRequest* getRequestForURL (const String& url, const StringArr
} }
#if JUCE_MAC #if JUCE_MAC
#if JUCE_USE_WKWEBVIEW
using WebViewBase = ObjCClass<WKWebView>;
#else
using WebViewBase = ObjCClass<WebView>;
#endif
struct WebViewKeyEquivalentResponder : public WebViewBase
template <class WebViewClass>
struct WebViewKeyEquivalentResponder : public ObjCClass<WebViewClass>
{ {
WebViewKeyEquivalentResponder() WebViewKeyEquivalentResponder()
: WebViewBase ("WebViewKeyEquivalentResponder_")
: ObjCClass<WebViewClass> ("WebViewKeyEquivalentResponder_")
{ {
addMethod (@selector (performKeyEquivalent:), performKeyEquivalent, @encode (BOOL), "@:@");
registerClass();
ObjCClass<WebViewClass>::addMethod (@selector (performKeyEquivalent:), performKeyEquivalent, @encode (BOOL), "@:@");
ObjCClass<WebViewClass>::registerClass();
} }
private: private:
static BOOL performKeyEquivalent (id self, SEL selector, NSEvent* event) static BOOL performKeyEquivalent (id self, SEL selector, NSEvent* event)
{ {
NSResponder* first = [[self window] firstResponder];
const auto isCommandDown = [event]
{
const auto modifierFlags = [event modifierFlags];
#if (defined (MAC_OS_X_VERSION_10_12) && MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_12)
constexpr auto mask = NSEventModifierFlagDeviceIndependentFlagsMask;
constexpr auto key = NSEventModifierFlagCommand;
#else
constexpr auto mask = NSDeviceIndependentModifierFlagsMask;
constexpr auto key = NSCommandKeyMask;
#endif
#if defined (MAC_OS_X_VERSION_10_12) && MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_12
if (@available (macOS 10.12, *))
return (modifierFlags & NSEventModifierFlagDeviceIndependentFlagsMask) == NSEventModifierFlagCommand;
#endif
if (([event modifierFlags] & mask) == key)
JUCE_BEGIN_IGNORE_WARNINGS_GCC_LIKE ("-Wdeprecated-declarations")
return (modifierFlags & NSDeviceIndependentModifierFlagsMask) == NSCommandKeyMask;
JUCE_END_IGNORE_WARNINGS_GCC_LIKE
}();
if (isCommandDown)
{ {
auto sendAction = [&] (SEL actionSelector) -> BOOL auto sendAction = [&] (SEL actionSelector) -> BOOL
{ {
return [NSApp sendAction: actionSelector return [NSApp sendAction: actionSelector
to: first
to: [[self window] firstResponder]
from: self]; from: self];
}; };
@@ -159,13 +153,122 @@ private:
if ([[event charactersIgnoringModifiers] isEqualToString: @"a"]) return sendAction (@selector (selectAll:)); if ([[event charactersIgnoringModifiers] isEqualToString: @"a"]) return sendAction (@selector (selectAll:));
} }
return sendSuperclassMessage<BOOL> (self, selector, event);
return ObjCClass<WebViewClass>::template sendSuperclassMessage<BOOL> (self, selector, event);
} }
}; };
#endif
JUCE_BEGIN_IGNORE_WARNINGS_GCC_LIKE ("-Wdeprecated-declarations")
struct DownloadClickDetectorClass : public ObjCClass<NSObject>
{
DownloadClickDetectorClass() : ObjCClass<NSObject> ("JUCEWebClickDetector_")
{
addIvar<WebBrowserComponent*> ("owner");
addMethod (@selector (webView:decidePolicyForNavigationAction:request:frame:decisionListener:),
decidePolicyForNavigationAction, "v@:@@@@@");
addMethod (@selector (webView:decidePolicyForNewWindowAction:request:newFrameName:decisionListener:),
decidePolicyForNewWindowAction, "v@:@@@@@");
addMethod (@selector (webView:didFinishLoadForFrame:), didFinishLoadForFrame, "v@:@@");
addMethod (@selector (webView:didFailLoadWithError:forFrame:), didFailLoadWithError, "v@:@@@");
addMethod (@selector (webView:didFailProvisionalLoadWithError:forFrame:), didFailLoadWithError, "v@:@@@");
addMethod (@selector (webView:willCloseFrame:), willCloseFrame, "v@:@@");
addMethod (@selector (webView:runOpenPanelForFileButtonWithResultListener:allowMultipleFiles:), runOpenPanel, "v@:@@", @encode (BOOL));
registerClass();
}
static void setOwner (id self, WebBrowserComponent* owner) { object_setInstanceVariable (self, "owner", owner); }
static WebBrowserComponent* getOwner (id self) { return getIvar<WebBrowserComponent*> (self, "owner"); }
private:
static String getOriginalURL (NSDictionary* actionInformation)
{
if (NSURL* url = [actionInformation valueForKey: nsStringLiteral ("WebActionOriginalURLKey")])
return nsStringToJuce ([url absoluteString]);
return {};
}
static void decidePolicyForNavigationAction (id self, SEL, WebView*, NSDictionary* actionInformation,
NSURLRequest*, WebFrame*, id<WebPolicyDecisionListener> listener)
{
if (getOwner (self)->pageAboutToLoad (getOriginalURL (actionInformation)))
[listener use];
else
[listener ignore];
}
static void decidePolicyForNewWindowAction (id self, SEL, WebView*, NSDictionary* actionInformation,
NSURLRequest*, NSString*, id<WebPolicyDecisionListener> listener)
{
getOwner (self)->newWindowAttemptingToLoad (getOriginalURL (actionInformation));
[listener ignore];
}
static void didFinishLoadForFrame (id self, SEL, WebView* sender, WebFrame* frame)
{
if ([frame isEqual: [sender mainFrame]])
{
NSURL* url = [[[frame dataSource] request] URL];
getOwner (self)->pageFinishedLoading (nsStringToJuce ([url absoluteString]));
}
}
#if JUCE_USE_WKWEBVIEW
static void didFailLoadWithError (id self, SEL, WebView* sender, NSError* error, WebFrame* frame)
{
if ([frame isEqual: [sender mainFrame]] && error != nullptr && [error code] != NSURLErrorCancelled)
{
auto errorString = nsStringToJuce ([error localizedDescription]);
bool proceedToErrorPage = getOwner (self)->pageLoadHadNetworkError (errorString);
// WebKit doesn't have an internal error page, so make a really simple one ourselves
if (proceedToErrorPage)
getOwner (self)->goToURL ("data:text/plain;charset=UTF-8," + errorString);
}
}
static void willCloseFrame (id self, SEL, WebView*, WebFrame*)
{
getOwner (self)->windowCloseRequest();
}
static void runOpenPanel (id, SEL, WebView*, id<WebOpenPanelResultListener> resultListener, BOOL allowMultipleFiles)
{
struct DeletedFileChooserWrapper : private DeletedAtShutdown
{
DeletedFileChooserWrapper (std::unique_ptr<FileChooser> fc, id<WebOpenPanelResultListener> rl)
: chooser (std::move (fc)), listener (rl)
{
[listener retain];
}
~DeletedFileChooserWrapper()
{
[listener release];
}
std::unique_ptr<FileChooser> chooser;
id<WebOpenPanelResultListener> listener;
};
auto chooser = std::make_unique<FileChooser> (TRANS("Select the file you want to upload..."),
File::getSpecialLocation (File::userHomeDirectory), "*");
auto* wrapper = new DeletedFileChooserWrapper (std::move (chooser), resultListener);
auto flags = FileBrowserComponent::openMode | FileBrowserComponent::canSelectFiles
| (allowMultipleFiles ? FileBrowserComponent::canSelectMultipleItems : 0);
wrapper->chooser->launchAsync (flags, [wrapper] (const FileChooser&)
{
for (auto& f : wrapper->chooser->getResults())
[wrapper->listener chooseFilename: juceStringToNS (f.getFullPathName())];
delete wrapper;
});
}
};
JUCE_END_IGNORE_WARNINGS_GCC_LIKE
#endif
struct WebViewDelegateClass : public ObjCClass<NSObject> struct WebViewDelegateClass : public ObjCClass<NSObject>
{ {
@@ -182,7 +285,8 @@ struct WebViewDelegateClass : public ObjCClass<NSObject>
windowFeatures:), createWebView, "@@:@@@@"); windowFeatures:), createWebView, "@@:@@@@");
#if WKWEBVIEW_OPENPANEL_SUPPORTED #if WKWEBVIEW_OPENPANEL_SUPPORTED
addMethod (@selector (webView:runOpenPanelWithParameters:initiatedByFrame:completionHandler:), runOpenPanel, "v@:@@@@");
if (@available (macOS 10.12, *))
addMethod (@selector (webView:runOpenPanelWithParameters:initiatedByFrame:completionHandler:), runOpenPanel, "v@:@@@@");
#endif #endif
registerClass(); registerClass();
@@ -242,6 +346,7 @@ private:
} }
#if WKWEBVIEW_OPENPANEL_SUPPORTED #if WKWEBVIEW_OPENPANEL_SUPPORTED
JUCE_BEGIN_IGNORE_WARNINGS_GCC_LIKE ("-Wunguarded-availability", "-Wunguarded-availability-new")
static void runOpenPanel (id, SEL, WKWebView*, WKOpenPanelParameters* parameters, WKFrameInfo*, static void runOpenPanel (id, SEL, WKWebView*, WKOpenPanelParameters* parameters, WKFrameInfo*,
void (^completionHandler)(NSArray<NSURL*>*)) void (^completionHandler)(NSArray<NSURL*>*))
{ {
@@ -285,10 +390,13 @@ private:
auto flags = FileBrowserComponent::openMode | FileBrowserComponent::canSelectFiles auto flags = FileBrowserComponent::openMode | FileBrowserComponent::canSelectFiles
| ([parameters allowsMultipleSelection] ? FileBrowserComponent::canSelectMultipleItems : 0); | ([parameters allowsMultipleSelection] ? FileBrowserComponent::canSelectMultipleItems : 0);
#if (defined (MAC_OS_X_VERSION_10_14) && MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_14)
if ([parameters allowsDirectories])
flags |= FileBrowserComponent::canSelectDirectories;
#endif
#if (defined (MAC_OS_X_VERSION_10_14) && MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_14)
if (@available (macOS 10.14, *))
{
if ([parameters allowsDirectories])
flags |= FileBrowserComponent::canSelectDirectories;
}
#endif
wrapper->chooser->launchAsync (flags, [wrapper] (const FileChooser&) wrapper->chooser->launchAsync (flags, [wrapper] (const FileChooser&)
{ {
@@ -302,242 +410,186 @@ private:
delete wrapper; delete wrapper;
}); });
} }
JUCE_END_IGNORE_WARNINGS_GCC_LIKE
#endif #endif
}; };
//============================================================================== //==============================================================================
class WebBrowserComponent::Pimpl
#if JUCE_MAC
: public NSViewComponent
#else
: public UIViewComponent
#endif
struct WebViewBase
{
virtual ~WebViewBase() = default;
virtual void goToURL (const String&, const StringArray*, const MemoryBlock*) = 0;
virtual void goBack() = 0;
virtual void goForward() = 0;
virtual void stop() = 0;
virtual void refresh() = 0;
virtual id getWebView() = 0;
};
#if JUCE_MAC
JUCE_BEGIN_IGNORE_WARNINGS_GCC_LIKE ("-Wdeprecated-declarations")
class WebViewImpl : public WebViewBase
{ {
public: public:
Pimpl (WebBrowserComponent* owner)
WebViewImpl (WebBrowserComponent* owner)
{ {
#if JUCE_MAC
static WebViewKeyEquivalentResponder webviewClass;
webView = (WKWebView*) webviewClass.createInstance();
webView = [webView initWithFrame: NSMakeRect (0, 0, 100.0f, 100.0f)];
#else
webView = [[WKWebView alloc] initWithFrame: CGRectMake (0, 0, 100.0f, 100.0f)];
#endif
static WebViewKeyEquivalentResponder<WebView> webviewClass;
webView = (WebView*) webviewClass.createInstance();
static WebViewDelegateClass cls;
webViewDelegate = [cls.createInstance() init];
WebViewDelegateClass::setOwner (webViewDelegate, owner);
webView = [webView initWithFrame: NSMakeRect (0, 0, 100.0f, 100.0f)
frameName: nsEmptyString()
groupName: nsEmptyString()];
[webView setNavigationDelegate: webViewDelegate];
[webView setUIDelegate: webViewDelegate];
static DownloadClickDetectorClass cls;
clickListener = [cls.createInstance() init];
DownloadClickDetectorClass::setOwner (clickListener, owner);
setView (webView);
[webView setPolicyDelegate: clickListener];
[webView setFrameLoadDelegate: clickListener];
[webView setUIDelegate: clickListener];
} }
~Pimpl()
~WebViewImpl() override
{ {
[webView setNavigationDelegate: nil];
[webView setUIDelegate: nil];
[webViewDelegate release];
[webView setPolicyDelegate: nil];
[webView setFrameLoadDelegate: nil];
[webView setUIDelegate: nil];
setView (nil);
[clickListener release];
} }
void goToURL (const String& url, void goToURL (const String& url,
const StringArray* headers, const StringArray* headers,
const MemoryBlock* postData)
const MemoryBlock* postData) override
{ {
auto trimmed = url.trimStart();
if (trimmed.startsWithIgnoreCase ("javascript:"))
if (url.trimStart().startsWithIgnoreCase ("javascript:"))
{ {
[webView evaluateJavaScript: juceStringToNS (url.fromFirstOccurrenceOf (":", false, false))
completionHandler: nil];
[webView stringByEvaluatingJavaScriptFromString: juceStringToNS (url.fromFirstOccurrenceOf (":", false, false))];
return; return;
} }
stop(); stop();
if (trimmed.startsWithIgnoreCase ("file:"))
auto getRequest = [&]() -> NSMutableURLRequest*
{ {
auto file = URL (url).getLocalFile();
if (url.trimStart().startsWithIgnoreCase ("file:"))
{
auto file = URL (url).getLocalFile();
if (NSURL* nsUrl = [NSURL fileURLWithPath: juceStringToNS (file.getFullPathName())])
[webView loadFileURL: appendParametersToFileURL (url, nsUrl) allowingReadAccessToURL: nsUrl];
}
else if (NSMutableURLRequest* request = getRequestForURL (url, headers, postData))
{
[webView loadRequest: request];
}
}
if (NSURL* nsUrl = [NSURL fileURLWithPath: juceStringToNS (file.getFullPathName())])
return [NSMutableURLRequest requestWithURL: appendParametersToFileURL (url, nsUrl)
cachePolicy: NSURLRequestUseProtocolCachePolicy
timeoutInterval: 30.0];
void goBack() { [webView goBack]; }
void goForward() { [webView goForward]; }
return nullptr;
}
void stop() { [webView stopLoading]; }
void refresh() { [webView reload]; }
return getRequestForURL (url, headers, postData);
};
private:
WKWebView* webView = nil;
id webViewDelegate;
};
if (NSMutableURLRequest* request = getRequest())
[[webView mainFrame] loadRequest: request];
}
#else
void goBack() override { [webView goBack]; }
void goForward() override { [webView goForward]; }
#if JUCE_MAC
void stop() override { [webView stopLoading: nil]; }
void refresh() override { [webView reload: nil]; }
struct DownloadClickDetectorClass : public ObjCClass<NSObject>
{
DownloadClickDetectorClass() : ObjCClass<NSObject> ("JUCEWebClickDetector_")
{
addIvar<WebBrowserComponent*> ("owner");
id getWebView() override { return webView; }
addMethod (@selector (webView:decidePolicyForNavigationAction:request:frame:decisionListener:),
decidePolicyForNavigationAction, "v@:@@@@@");
addMethod (@selector (webView:decidePolicyForNewWindowAction:request:newFrameName:decisionListener:),
decidePolicyForNewWindowAction, "v@:@@@@@");
addMethod (@selector (webView:didFinishLoadForFrame:), didFinishLoadForFrame, "v@:@@");
addMethod (@selector (webView:didFailLoadWithError:forFrame:), didFailLoadWithError, "v@:@@@");
addMethod (@selector (webView:didFailProvisionalLoadWithError:forFrame:), didFailLoadWithError, "v@:@@@");
addMethod (@selector (webView:willCloseFrame:), willCloseFrame, "v@:@@");
addMethod (@selector (webView:runOpenPanelForFileButtonWithResultListener:allowMultipleFiles:), runOpenPanel, "v@:@@", @encode (BOOL));
registerClass();
void mouseMove (const MouseEvent&)
{
JUCE_BEGIN_IGNORE_WARNINGS_GCC_LIKE ("-Wundeclared-selector")
// WebKit doesn't capture mouse-moves itself, so it seems the only way to make
// them work is to push them via this non-public method..
if ([webView respondsToSelector: @selector (_updateMouseoverWithFakeEvent)])
[webView performSelector: @selector (_updateMouseoverWithFakeEvent)];
JUCE_END_IGNORE_WARNINGS_GCC_LIKE
} }
static void setOwner (id self, WebBrowserComponent* owner) { object_setInstanceVariable (self, "owner", owner); }
static WebBrowserComponent* getOwner (id self) { return getIvar<WebBrowserComponent*> (self, "owner"); }
private: private:
static String getOriginalURL (NSDictionary* actionInformation)
{
if (NSURL* url = [actionInformation valueForKey: nsStringLiteral ("WebActionOriginalURLKey")])
return nsStringToJuce ([url absoluteString]);
return {};
}
WebView* webView = nil;
id clickListener;
};
JUCE_END_IGNORE_WARNINGS_GCC_LIKE
#endif
static void decidePolicyForNavigationAction (id self, SEL, WebView*, NSDictionary* actionInformation,
NSURLRequest*, WebFrame*, id<WebPolicyDecisionListener> listener)
class WKWebViewImpl : public WebViewBase
{
public:
WKWebViewImpl (WebBrowserComponent* owner)
{ {
if (getOwner (self)->pageAboutToLoad (getOriginalURL (actionInformation)))
[listener use];
else
[listener ignore];
}
#if JUCE_MAC
static WebViewKeyEquivalentResponder<WKWebView> webviewClass;
webView = (WKWebView*) webviewClass.createInstance();
static void decidePolicyForNewWindowAction (id self, SEL, WebView*, NSDictionary* actionInformation,
NSURLRequest*, NSString*, id<WebPolicyDecisionListener> listener)
{
getOwner (self)->newWindowAttemptingToLoad (getOriginalURL (actionInformation));
[listener ignore];
}
webView = [webView initWithFrame: NSMakeRect (0, 0, 100.0f, 100.0f)];
#else
webView = [[WKWebView alloc] initWithFrame: CGRectMake (0, 0, 100.0f, 100.0f)];
#endif
static void didFinishLoadForFrame (id self, SEL, WebView* sender, WebFrame* frame)
{
if ([frame isEqual: [sender mainFrame]])
{
NSURL* url = [[[frame dataSource] request] URL];
getOwner (self)->pageFinishedLoading (nsStringToJuce ([url absoluteString]));
}
static WebViewDelegateClass cls;
webViewDelegate = [cls.createInstance() init];
WebViewDelegateClass::setOwner (webViewDelegate, owner);
[webView setNavigationDelegate: webViewDelegate];
[webView setUIDelegate: webViewDelegate];
} }
static void didFailLoadWithError (id self, SEL, WebView* sender, NSError* error, WebFrame* frame)
~WKWebViewImpl() override
{ {
if ([frame isEqual: [sender mainFrame]] && error != nullptr && [error code] != NSURLErrorCancelled)
{
auto errorString = nsStringToJuce ([error localizedDescription]);
bool proceedToErrorPage = getOwner (self)->pageLoadHadNetworkError (errorString);
[webView setNavigationDelegate: nil];
[webView setUIDelegate: nil];
// WebKit doesn't have an internal error page, so make a really simple one ourselves
if (proceedToErrorPage)
getOwner (self)->goToURL ("data:text/plain;charset=UTF-8," + errorString);
}
[webViewDelegate release];
} }
static void willCloseFrame (id self, SEL, WebView*, WebFrame*)
void goToURL (const String& url,
const StringArray* headers,
const MemoryBlock* postData) override
{ {
getOwner (self)->windowCloseRequest();
}
auto trimmed = url.trimStart();
static void runOpenPanel (id, SEL, WebView*, id<WebOpenPanelResultListener> resultListener, BOOL allowMultipleFiles)
{
struct DeletedFileChooserWrapper : private DeletedAtShutdown
if (trimmed.startsWithIgnoreCase ("javascript:"))
{ {
DeletedFileChooserWrapper (std::unique_ptr<FileChooser> fc, id<WebOpenPanelResultListener> rl)
: chooser (std::move (fc)), listener (rl)
{
[listener retain];
}
~DeletedFileChooserWrapper()
{
[listener release];
}
std::unique_ptr<FileChooser> chooser;
id<WebOpenPanelResultListener> listener;
};
[webView evaluateJavaScript: juceStringToNS (url.fromFirstOccurrenceOf (":", false, false))
completionHandler: nil];
auto chooser = std::make_unique<FileChooser> (TRANS("Select the file you want to upload..."),
File::getSpecialLocation (File::userHomeDirectory), "*");
auto* wrapper = new DeletedFileChooserWrapper (std::move (chooser), resultListener);
return;
}
auto flags = FileBrowserComponent::openMode | FileBrowserComponent::canSelectFiles
| (allowMultipleFiles ? FileBrowserComponent::canSelectMultipleItems : 0);
stop();
wrapper->chooser->launchAsync (flags, [wrapper] (const FileChooser&)
if (trimmed.startsWithIgnoreCase ("file:"))
{ {
for (auto& f : wrapper->chooser->getResults())
[wrapper->listener chooseFilename: juceStringToNS (f.getFullPathName())];
auto file = URL (url).getLocalFile();
delete wrapper;
});
if (NSURL* nsUrl = [NSURL fileURLWithPath: juceStringToNS (file.getFullPathName())])
[webView loadFileURL: appendParametersToFileURL (url, nsUrl) allowingReadAccessToURL: nsUrl];
}
else if (NSMutableURLRequest* request = getRequestForURL (url, headers, postData))
{
[webView loadRequest: request];
}
} }
};
#else
struct WebViewDelegateClass : public ObjCClass<NSObject>
{
WebViewDelegateClass() : ObjCClass<NSObject> ("JUCEWebViewDelegate_")
{
addIvar<WebBrowserComponent*> ("owner");
void goBack() override { [webView goBack]; }
void goForward() override { [webView goForward]; }
addMethod (@selector (gestureRecognizer:shouldRecognizeSimultaneouslyWithGestureRecognizer:),
shouldRecognizeSimultaneouslyWithGestureRecognizer, "c@:@@");
void stop() override { [webView stopLoading]; }
void refresh() override { [webView reload]; }
addMethod (@selector (webView:shouldStartLoadWithRequest:navigationType:), shouldStartLoadWithRequest, "c@:@@@");
addMethod (@selector (webViewDidFinishLoad:), webViewDidFinishLoad, "v@:@");
registerClass();
}
static void setOwner (id self, WebBrowserComponent* owner) { object_setInstanceVariable (self, "owner", owner); }
static WebBrowserComponent* getOwner (id self) { return getIvar<WebBrowserComponent*> (self, "owner"); }
id getWebView() override { return webView; }
private: private:
static BOOL shouldRecognizeSimultaneouslyWithGestureRecognizer (id, SEL, UIGestureRecognizer*, UIGestureRecognizer*)
{
return YES;
}
static BOOL shouldStartLoadWithRequest (id self, SEL, UIWebView*, NSURLRequest* request, UIWebViewNavigationType)
{
return getOwner (self)->pageAboutToLoad (nsStringToJuce ([[request URL] absoluteString]));
}
static void webViewDidFinishLoad (id self, SEL, UIWebView* webView)
{
getOwner (self)->pageFinishedLoading (nsStringToJuce ([[[webView request] URL] absoluteString]));
}
WKWebView* webView = nil;
id webViewDelegate;
}; };
#endif
//============================================================================== //==============================================================================
class WebBrowserComponent::Pimpl class WebBrowserComponent::Pimpl
#if JUCE_MAC #if JUCE_MAC
@@ -549,47 +601,19 @@ class WebBrowserComponent::Pimpl
public: public:
Pimpl (WebBrowserComponent* owner) Pimpl (WebBrowserComponent* owner)
{ {
if (@available (macOS 10.10, *))
webView = std::make_unique<WKWebViewImpl> (owner);
#if JUCE_MAC #if JUCE_MAC
static WebViewKeyEquivalentResponder webviewClass;
webView = (WebView*) webviewClass.createInstance();
webView = [webView initWithFrame: NSMakeRect (0, 0, 100.0f, 100.0f)
frameName: nsEmptyString()
groupName: nsEmptyString()];
static DownloadClickDetectorClass cls;
clickListener = [cls.createInstance() init];
DownloadClickDetectorClass::setOwner (clickListener, owner);
[webView setPolicyDelegate: clickListener];
[webView setFrameLoadDelegate: clickListener];
[webView setUIDelegate: clickListener];
#else
webView = [[UIWebView alloc] initWithFrame: CGRectMake (0, 0, 1.0f, 1.0f)];
static WebViewDelegateClass cls;
webViewDelegate = [cls.createInstance() init];
WebViewDelegateClass::setOwner (webViewDelegate, owner);
[webView setDelegate: webViewDelegate];
else
webView = std::make_unique<WebViewImpl> (owner);
#endif #endif
setView (webView);
setView (webView->getWebView());
} }
~Pimpl() ~Pimpl()
{ {
#if JUCE_MAC
[webView setPolicyDelegate: nil];
[webView setFrameLoadDelegate: nil];
[webView setUIDelegate: nil];
[clickListener release];
#else
[webView setDelegate: nil];
[webViewDelegate release];
#endif
webView = nullptr;
setView (nil); setView (nil);
} }
@@ -597,78 +621,19 @@ public:
const StringArray* headers, const StringArray* headers,
const MemoryBlock* postData) const MemoryBlock* postData)
{ {
if (url.trimStart().startsWithIgnoreCase ("javascript:"))
{
[webView stringByEvaluatingJavaScriptFromString: juceStringToNS (url.fromFirstOccurrenceOf (":", false, false))];
return;
}
stop();
auto getRequest = [&]() -> NSMutableURLRequest*
{
if (url.trimStart().startsWithIgnoreCase ("file:"))
{
auto file = URL (url).getLocalFile();
if (NSURL* nsUrl = [NSURL fileURLWithPath: juceStringToNS (file.getFullPathName())])
return [NSMutableURLRequest requestWithURL: appendParametersToFileURL (url, nsUrl)
cachePolicy: NSURLRequestUseProtocolCachePolicy
timeoutInterval: 30.0];
return nullptr;
}
return getRequestForURL (url, headers, postData);
};
if (NSMutableURLRequest* request = getRequest())
{
#if JUCE_MAC
[[webView mainFrame] loadRequest: request];
#else
[webView loadRequest: request];
#endif
#if JUCE_IOS
[webView setScalesPageToFit: YES];
#endif
}
webView->goToURL (url, headers, postData);
} }
void goBack() { [webView goBack]; }
void goForward() { [webView goForward]; }
#if JUCE_MAC
void stop() { [webView stopLoading: nil]; }
void refresh() { [webView reload: nil]; }
#else
void stop() { [webView stopLoading]; }
void refresh() { [webView reload]; }
#endif
void goBack() { webView->goBack(); }
void goForward() { webView->goForward(); }
void mouseMove (const MouseEvent&)
{
JUCE_BEGIN_IGNORE_WARNINGS_GCC_LIKE ("-Wundeclared-selector")
// WebKit doesn't capture mouse-moves itself, so it seems the only way to make
// them work is to push them via this non-public method..
if ([webView respondsToSelector: @selector (_updateMouseoverWithFakeEvent)])
[webView performSelector: @selector (_updateMouseoverWithFakeEvent)];
JUCE_END_IGNORE_WARNINGS_GCC_LIKE
}
void stop() { webView->stop(); }
void refresh() { webView->refresh(); }
private: private:
#if JUCE_MAC
WebView* webView = nil;
id clickListener;
#else
UIWebView* webView = nil;
id webViewDelegate;
#endif
std::unique_ptr<WebViewBase> webView;
}; };
#endif
//============================================================================== //==============================================================================
WebBrowserComponent::WebBrowserComponent (bool unloadWhenHidden) WebBrowserComponent::WebBrowserComponent (bool unloadWhenHidden)
: unloadPageWhenHidden (unloadWhenHidden) : unloadPageWhenHidden (unloadWhenHidden)


+ 12
- 10
modules/juce_opengl/native/juce_OpenGL_osx.h View File

@@ -206,11 +206,7 @@ public:
jassert (isPositiveAndBelow (numFramesPerSwap, 2)); jassert (isPositiveAndBelow (numFramesPerSwap, 2));
[renderContext setValues: (const GLint*) &numFramesPerSwap [renderContext setValues: (const GLint*) &numFramesPerSwap
#if defined (MAC_OS_X_VERSION_10_12) && MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_12
forParameter: NSOpenGLContextParameterSwapInterval];
#else
forParameter: NSOpenGLCPSwapInterval];
#endif
forParameter: getSwapIntervalParameter()];
updateMinSwapTime(); updateMinSwapTime();
@@ -221,11 +217,7 @@ public:
{ {
GLint numFrames = 0; GLint numFrames = 0;
[renderContext getValues: &numFrames [renderContext getValues: &numFrames
#if defined (MAC_OS_X_VERSION_10_12) && MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_12
forParameter: NSOpenGLContextParameterSwapInterval];
#else
forParameter: NSOpenGLCPSwapInterval];
#endif
forParameter: getSwapIntervalParameter()];
return numFrames; return numFrames;
} }
@@ -242,6 +234,16 @@ public:
minSwapTimeMs = static_cast<int> (numFramesPerSwap * 1000 * videoRefreshPeriodS); minSwapTimeMs = static_cast<int> (numFramesPerSwap * 1000 * videoRefreshPeriodS);
} }
static NSOpenGLContextParameter getSwapIntervalParameter()
{
#if defined (MAC_OS_X_VERSION_10_12) && MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_12
if (@available (macOS 10.12, *))
return NSOpenGLContextParameterSwapInterval;
#endif
return NSOpenGLCPSwapInterval;
}
NSOpenGLContext* renderContext = nil; NSOpenGLContext* renderContext = nil;
NSOpenGLView* view = nil; NSOpenGLView* view = nil;
ReferenceCountedObjectPtr<ReferenceCountedObject> viewAttachment; ReferenceCountedObjectPtr<ReferenceCountedObject> viewAttachment;


+ 1
- 1
modules/juce_video/capture/juce_CameraDevice.cpp View File

@@ -31,7 +31,7 @@ namespace juce
#elif JUCE_WINDOWS #elif JUCE_WINDOWS
#include "../native/juce_win32_CameraDevice.h" #include "../native/juce_win32_CameraDevice.h"
#elif JUCE_IOS #elif JUCE_IOS
JUCE_BEGIN_IGNORE_WARNINGS_GCC_LIKE ("-Wunguarded-availability-new")
JUCE_BEGIN_IGNORE_WARNINGS_GCC_LIKE ("-Wunguarded-availability", "-Wunguarded-availability-new")
#include "../native/juce_ios_CameraDevice.h" #include "../native/juce_ios_CameraDevice.h"


+ 18
- 18
modules/juce_video/native/juce_ios_CameraDevice.h View File

@@ -23,9 +23,9 @@
============================================================================== ==============================================================================
*/ */
#if (defined (__IPHONE_10_0) && __IPHONE_OS_VERSION_MIN_REQUIRED >= __IPHONE_10_0)
#if (defined (__IPHONE_10_0) && __IPHONE_OS_VERSION_MAX_ALLOWED >= __IPHONE_10_0)
JUCE_BEGIN_IGNORE_WARNINGS_GCC_LIKE ("-Wdeprecated-declarations") JUCE_BEGIN_IGNORE_WARNINGS_GCC_LIKE ("-Wdeprecated-declarations")
#define JUCE_DEPRECATION_IGNORED 1
#define JUCE_USE_NEW_CAMERA_API 1
#endif #endif
struct CameraDevice::Pimpl struct CameraDevice::Pimpl
@@ -141,7 +141,7 @@ struct CameraDevice::Pimpl
private: private:
static NSArray<AVCaptureDevice*>* getDevices() static NSArray<AVCaptureDevice*>* getDevices()
{ {
#if defined (__IPHONE_10_0) && __IPHONE_OS_VERSION_MAX_ALLOWED >= __IPHONE_10_0
#if JUCE_USE_NEW_CAMERA_API
if (@available (iOS 10.0, *)) if (@available (iOS 10.0, *))
{ {
std::unique_ptr<NSMutableArray<AVCaptureDeviceType>, NSObjectDeleter> deviceTypes ([[NSMutableArray alloc] initWithCapacity: 2]); std::unique_ptr<NSMutableArray<AVCaptureDeviceType>, NSObjectDeleter> deviceTypes ([[NSMutableArray alloc] initWithCapacity: 2]);
@@ -207,7 +207,7 @@ private:
JUCE_CAMERA_LOG ("Supports custom exposure: " + String ((int)[device isExposureModeSupported: AVCaptureExposureModeCustom])); JUCE_CAMERA_LOG ("Supports custom exposure: " + String ((int)[device isExposureModeSupported: AVCaptureExposureModeCustom]));
JUCE_CAMERA_LOG ("Supports point of interest exposure: " + String ((int)device.exposurePointOfInterestSupported)); JUCE_CAMERA_LOG ("Supports point of interest exposure: " + String ((int)device.exposurePointOfInterestSupported));
#if defined (__IPHONE_10_0) && __IPHONE_OS_VERSION_MAX_ALLOWED >= __IPHONE_10_0
#if JUCE_USE_NEW_CAMERA_API
if (@available (iOS 10.0, *)) if (@available (iOS 10.0, *))
{ {
JUCE_CAMERA_LOG ("Device type: " + nsStringToJuce (device.deviceType)); JUCE_CAMERA_LOG ("Device type: " + nsStringToJuce (device.deviceType));
@@ -238,7 +238,7 @@ private:
{ {
JUCE_CAMERA_LOG ("Media type: " + nsStringToJuce (format.mediaType)); JUCE_CAMERA_LOG ("Media type: " + nsStringToJuce (format.mediaType));
#if defined (__IPHONE_10_0) && __IPHONE_OS_VERSION_MAX_ALLOWED >= __IPHONE_10_0
#if JUCE_USE_NEW_CAMERA_API
if (@available (iOS 10.0, *)) if (@available (iOS 10.0, *))
{ {
String colourSpaces; String colourSpaces;
@@ -592,12 +592,14 @@ private:
captureOutput (createCaptureOutput()), captureOutput (createCaptureOutput()),
photoOutputDelegate (nullptr) photoOutputDelegate (nullptr)
{ {
#if JUCE_USE_NEW_CAMERA_API
if (@available (iOS 10.0, *)) if (@available (iOS 10.0, *))
{ {
static PhotoOutputDelegateClass cls; static PhotoOutputDelegateClass cls;
photoOutputDelegate.reset ([cls.createInstance() init]); photoOutputDelegate.reset ([cls.createInstance() init]);
PhotoOutputDelegateClass::setOwner (photoOutputDelegate.get(), this); PhotoOutputDelegateClass::setOwner (photoOutputDelegate.get(), this);
} }
#endif
captureSession.addOutputIfPossible (captureOutput); captureSession.addOutputIfPossible (captureOutput);
} }
@@ -617,9 +619,9 @@ private:
if (auto* connection = findVideoConnection (captureOutput)) if (auto* connection = findVideoConnection (captureOutput))
{ {
#if defined (__IPHONE_10_0) && __IPHONE_OS_VERSION_MAX_ALLOWED >= __IPHONE_10_0
#if JUCE_USE_NEW_CAMERA_API
if (@available (iOS 10.0, *)) if (@available (iOS 10.0, *))
{
{
if ([captureOutput isKindOfClass: [AVCapturePhotoOutput class]]) if ([captureOutput isKindOfClass: [AVCapturePhotoOutput class]])
{ {
auto* photoOutput = (AVCapturePhotoOutput*) captureOutput; auto* photoOutput = (AVCapturePhotoOutput*) captureOutput;
@@ -669,7 +671,7 @@ private:
private: private:
static AVCaptureOutput* createCaptureOutput() static AVCaptureOutput* createCaptureOutput()
{ {
#if defined (__IPHONE_10_0) && __IPHONE_OS_VERSION_MAX_ALLOWED >= __IPHONE_10_0
#if JUCE_USE_NEW_CAMERA_API
if (@available (iOS 10.0, *)) if (@available (iOS 10.0, *))
return [AVCapturePhotoOutput new]; return [AVCapturePhotoOutput new];
#endif #endif
@@ -679,7 +681,7 @@ private:
static void printImageOutputDebugInfo (AVCaptureOutput* captureOutput) static void printImageOutputDebugInfo (AVCaptureOutput* captureOutput)
{ {
#if defined (__IPHONE_10_0) && __IPHONE_OS_VERSION_MAX_ALLOWED >= __IPHONE_10_0
#if JUCE_USE_NEW_CAMERA_API
if (@available (iOS 10.0, *)) if (@available (iOS 10.0, *))
{ {
if ([captureOutput isKindOfClass: [AVCapturePhotoOutput class]]) if ([captureOutput isKindOfClass: [AVCapturePhotoOutput class]])
@@ -688,7 +690,7 @@ private:
String typesString; String typesString;
for (AVVideoCodecType type in photoOutput.availablePhotoCodecTypes)
for (id type in photoOutput.availablePhotoCodecTypes)
typesString << nsStringToJuce (type) << " "; typesString << nsStringToJuce (type) << " ";
JUCE_CAMERA_LOG ("Available image codec types: " + typesString); JUCE_CAMERA_LOG ("Available image codec types: " + typesString);
@@ -741,7 +743,7 @@ private:
String typesString; String typesString;
for (AVVideoCodecType type in stillImageOutput.availableImageDataCodecTypes)
for (id type in stillImageOutput.availableImageDataCodecTypes)
typesString << nsStringToJuce (type) << " "; typesString << nsStringToJuce (type) << " ";
JUCE_CAMERA_LOG ("Available image codec types: " + typesString); JUCE_CAMERA_LOG ("Available image codec types: " + typesString);
@@ -763,8 +765,7 @@ private:
} }
//============================================================================== //==============================================================================
JUCE_BEGIN_IGNORE_WARNINGS_GCC_LIKE ("-Wunguarded-availability", "-Wunguarded-availability-new")
#if JUCE_USE_NEW_CAMERA_API
class PhotoOutputDelegateClass : public ObjCClass<NSObject> class PhotoOutputDelegateClass : public ObjCClass<NSObject>
{ {
public: public:
@@ -974,8 +975,7 @@ private:
} }
} }
}; };
JUCE_END_IGNORE_WARNINGS_GCC_LIKE
#endif
//============================================================================== //==============================================================================
void callListeners (const Image& image) void callListeners (const Image& image)
@@ -1026,7 +1026,7 @@ private:
void startRecording (const File& file, AVCaptureVideoOrientation orientationToUse) void startRecording (const File& file, AVCaptureVideoOrientation orientationToUse)
{ {
#if defined (__IPHONE_10_0) && __IPHONE_OS_VERSION_MAX_ALLOWED >= __IPHONE_10_0
#if JUCE_USE_NEW_CAMERA_API
if (@available (iOS 10.0, *)) if (@available (iOS 10.0, *))
printVideoOutputDebugInfo (movieFileOutput); printVideoOutputDebugInfo (movieFileOutput);
#endif #endif
@@ -1058,7 +1058,7 @@ private:
JUCE_CAMERA_LOG ("Available video codec types:"); JUCE_CAMERA_LOG ("Available video codec types:");
#if JUCE_CAMERA_LOG_ENABLED #if JUCE_CAMERA_LOG_ENABLED
for (AVVideoCodecType type in output.availableVideoCodecTypes)
for (id type in output.availableVideoCodecTypes)
JUCE_CAMERA_LOG (nsStringToJuce (type)); JUCE_CAMERA_LOG (nsStringToJuce (type));
#endif #endif
@@ -1335,6 +1335,6 @@ String CameraDevice::getFileExtension()
return ".mov"; return ".mov";
} }
#if JUCE_DEPRECATION_IGNORED
#if JUCE_USE_NEW_CAMERA_API
JUCE_END_IGNORE_WARNINGS_GCC_LIKE JUCE_END_IGNORE_WARNINGS_GCC_LIKE
#endif #endif

+ 210
- 189
modules/juce_video/native/juce_mac_CameraDevice.h View File

@@ -23,180 +23,12 @@
============================================================================== ==============================================================================
*/ */
#if defined (MAC_OS_X_VERSION_10_15) && MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_15
#define JUCE_USE_NEW_CAMERA_API 1
#endif
struct CameraDevice::Pimpl struct CameraDevice::Pimpl
{ {
#if defined (MAC_OS_X_VERSION_10_15) && MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_15
#define JUCE_USE_NEW_APPLE_CAMERA_API 1
#else
#define JUCE_USE_NEW_APPLE_CAMERA_API 0
#endif
#if JUCE_USE_NEW_APPLE_CAMERA_API
class PostCatalinaPhotoOutput
{
public:
PostCatalinaPhotoOutput()
{
static PhotoOutputDelegateClass cls;
delegate.reset ([cls.createInstance() init]);
}
void addImageCapture (AVCaptureSession* s)
{
if (imageOutput != nil)
return;
imageOutput = [[AVCapturePhotoOutput alloc] init];
[s addOutput: imageOutput];
}
void removeImageCapture (AVCaptureSession* s)
{
if (imageOutput == nil)
return;
[s removeOutput: imageOutput];
[imageOutput release];
imageOutput = nil;
}
NSArray<AVCaptureConnection*>* getConnections() const
{
if (imageOutput != nil)
return imageOutput.connections;
return nil;
}
void triggerImageCapture (Pimpl& p)
{
if (imageOutput == nil)
return;
PhotoOutputDelegateClass::setOwner (delegate.get(), &p);
[imageOutput capturePhotoWithSettings: [AVCapturePhotoSettings photoSettings]
delegate: id<AVCapturePhotoCaptureDelegate> (delegate.get())];
}
static NSArray* getAvailableDevices()
{
auto* discovery = [AVCaptureDeviceDiscoverySession discoverySessionWithDeviceTypes: @[AVCaptureDeviceTypeBuiltInWideAngleCamera,
AVCaptureDeviceTypeExternalUnknown]
mediaType: AVMediaTypeVideo
position: AVCaptureDevicePositionUnspecified];
return [discovery devices];
}
private:
class PhotoOutputDelegateClass : public ObjCClass<NSObject>
{
public:
PhotoOutputDelegateClass() : ObjCClass<NSObject> ("PhotoOutputDelegateClass_")
{
addMethod (@selector (captureOutput:didFinishProcessingPhoto:error:), didFinishProcessingPhoto, "v@:@@@");
addIvar<Pimpl*> ("owner");
registerClass();
}
static void didFinishProcessingPhoto (id self, SEL, AVCapturePhotoOutput*, AVCapturePhoto* photo, NSError* error)
{
if (error != nil)
{
String errorString = error != nil ? nsStringToJuce (error.localizedDescription) : String();
ignoreUnused (errorString);
JUCE_CAMERA_LOG ("Still picture capture failed, error: " + errorString);
jassertfalse;
return;
}
auto* imageData = [photo fileDataRepresentation];
auto image = ImageFileFormat::loadFrom (imageData.bytes, (size_t) imageData.length);
getOwner (self).imageCaptureFinished (image);
}
static Pimpl& getOwner (id self) { return *getIvar<Pimpl*> (self, "owner"); }
static void setOwner (id self, Pimpl* t) { object_setInstanceVariable (self, "owner", t); }
};
AVCapturePhotoOutput* imageOutput = nil;
std::unique_ptr<NSObject, NSObjectDeleter> delegate;
};
#else
struct PreCatalinaStillImageOutput
{
public:
void addImageCapture (AVCaptureSession* s)
{
if (imageOutput != nil)
return;
const auto codecType =
#if defined (MAC_OS_X_VERSION_10_13) && MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_13
AVVideoCodecTypeJPEG;
#else
AVVideoCodecJPEG;
#endif
imageOutput = [[AVCaptureStillImageOutput alloc] init];
auto imageSettings = [[NSDictionary alloc] initWithObjectsAndKeys: codecType, AVVideoCodecKey, nil];
[imageOutput setOutputSettings: imageSettings];
[imageSettings release];
[s addOutput: imageOutput];
}
void removeImageCapture (AVCaptureSession* s)
{
if (imageOutput == nil)
return;
[s removeOutput: imageOutput];
[imageOutput release];
imageOutput = nil;
}
NSArray<AVCaptureConnection*>* getConnections() const
{
if (imageOutput != nil)
return imageOutput.connections;
return nil;
}
void triggerImageCapture (Pimpl& p)
{
if (auto* videoConnection = p.getVideoConnection())
{
[imageOutput captureStillImageAsynchronouslyFromConnection: videoConnection
completionHandler: ^(CMSampleBufferRef sampleBuffer, NSError* error)
{
if (error != nil)
{
JUCE_CAMERA_LOG ("Still picture capture failed, error: " + nsStringToJuce (error.localizedDescription));
jassertfalse;
return;
}
auto* imageData = [AVCaptureStillImageOutput jpegStillImageNSDataRepresentation: sampleBuffer];
auto image = ImageFileFormat::loadFrom (imageData.bytes, (size_t) imageData.length);
p.imageCaptureFinished (image);
}];
}
}
static NSArray* getAvailableDevices()
{
return [AVCaptureDevice devicesWithMediaType: AVMediaTypeVideo];
}
private:
AVCaptureStillImageOutput* imageOutput = nil;
};
#endif
Pimpl (CameraDevice& ownerToUse, const String& deviceNameToUse, int /*index*/, Pimpl (CameraDevice& ownerToUse, const String& deviceNameToUse, int /*index*/,
int /*minWidth*/, int /*minHeight*/, int /*minWidth*/, int /*minHeight*/,
int /*maxWidth*/, int /*maxHeight*/, int /*maxWidth*/, int /*maxHeight*/,
@@ -204,6 +36,16 @@ struct CameraDevice::Pimpl
: owner (ownerToUse), : owner (ownerToUse),
deviceName (deviceNameToUse) deviceName (deviceNameToUse)
{ {
imageOutput = []() -> std::unique_ptr<ImageOutputBase>
{
#if JUCE_USE_NEW_CAMERA_API
if (@available (macOS 10.15, *))
return std::make_unique<PostCatalinaPhotoOutput>();
#endif
return std::make_unique<PreCatalinaStillImageOutput>();
}();
session = [[AVCaptureSession alloc] init]; session = [[AVCaptureSession alloc] init];
session.sessionPreset = useHighQuality ? AVCaptureSessionPresetHigh session.sessionPreset = useHighQuality ? AVCaptureSessionPresetHigh
@@ -299,13 +141,30 @@ struct CameraDevice::Pimpl
listeners.remove (listenerToRemove); listeners.remove (listenerToRemove);
} }
static StringArray getAvailableDevices()
static NSArray* getCaptureDevices()
{ {
auto* devices = decltype (imageOutput)::getAvailableDevices();
#if JUCE_USE_NEW_CAMERA_API
if (@available (macOS 10.15, *))
{
auto* discovery = [AVCaptureDeviceDiscoverySession discoverySessionWithDeviceTypes: @[AVCaptureDeviceTypeBuiltInWideAngleCamera,
AVCaptureDeviceTypeExternalUnknown]
mediaType: AVMediaTypeVideo
position: AVCaptureDevicePositionUnspecified];
return [discovery devices];
}
#endif
JUCE_BEGIN_IGNORE_WARNINGS_GCC_LIKE ("-Wdeprecated-declarations")
return [AVCaptureDevice devicesWithMediaType: AVMediaTypeVideo];
JUCE_END_IGNORE_WARNINGS_GCC_LIKE
}
static StringArray getAvailableDevices()
{
StringArray results; StringArray results;
for (AVCaptureDevice* device : devices)
for (AVCaptureDevice* device : getCaptureDevices())
results.add (nsStringToJuce ([device localizedName])); results.add (nsStringToJuce ([device localizedName]));
return results; return results;
@@ -373,10 +232,180 @@ private:
} }
}; };
//==============================================================================
struct ImageOutputBase
{
virtual ~ImageOutputBase() = default;
virtual void addImageCapture (AVCaptureSession*) = 0;
virtual void removeImageCapture (AVCaptureSession*) = 0;
virtual NSArray<AVCaptureConnection*>* getConnections() const = 0;
virtual void triggerImageCapture (Pimpl& p) = 0;
};
#if JUCE_USE_NEW_CAMERA_API
JUCE_BEGIN_IGNORE_WARNINGS_GCC_LIKE ("-Wunguarded-availability", "-Wunguarded-availability-new")
class PostCatalinaPhotoOutput : public ImageOutputBase
{
public:
PostCatalinaPhotoOutput()
{
static PhotoOutputDelegateClass cls;
delegate.reset ([cls.createInstance() init]);
}
void addImageCapture (AVCaptureSession* s) override
{
if (imageOutput != nil)
return;
imageOutput = [[AVCapturePhotoOutput alloc] init];
[s addOutput: imageOutput];
}
void removeImageCapture (AVCaptureSession* s) override
{
if (imageOutput == nil)
return;
[s removeOutput: imageOutput];
[imageOutput release];
imageOutput = nil;
}
NSArray<AVCaptureConnection*>* getConnections() const override
{
if (imageOutput != nil)
return imageOutput.connections;
return nil;
}
void triggerImageCapture (Pimpl& p) override
{
if (imageOutput == nil)
return;
PhotoOutputDelegateClass::setOwner (delegate.get(), &p);
[imageOutput capturePhotoWithSettings: [AVCapturePhotoSettings photoSettings]
delegate: id<AVCapturePhotoCaptureDelegate> (delegate.get())];
}
private:
class PhotoOutputDelegateClass : public ObjCClass<NSObject>
{
public:
PhotoOutputDelegateClass() : ObjCClass<NSObject> ("PhotoOutputDelegateClass_")
{
addMethod (@selector (captureOutput:didFinishProcessingPhoto:error:), didFinishProcessingPhoto, "v@:@@@");
addIvar<Pimpl*> ("owner");
registerClass();
}
static void didFinishProcessingPhoto (id self, SEL, AVCapturePhotoOutput*, AVCapturePhoto* photo, NSError* error)
{
if (error != nil)
{
String errorString = error != nil ? nsStringToJuce (error.localizedDescription) : String();
ignoreUnused (errorString);
JUCE_CAMERA_LOG ("Still picture capture failed, error: " + errorString);
jassertfalse;
return;
}
auto* imageData = [photo fileDataRepresentation];
auto image = ImageFileFormat::loadFrom (imageData.bytes, (size_t) imageData.length);
getOwner (self).imageCaptureFinished (image);
}
static Pimpl& getOwner (id self) { return *getIvar<Pimpl*> (self, "owner"); }
static void setOwner (id self, Pimpl* t) { object_setInstanceVariable (self, "owner", t); }
};
AVCapturePhotoOutput* imageOutput = nil;
std::unique_ptr<NSObject, NSObjectDeleter> delegate;
};
JUCE_END_IGNORE_WARNINGS_GCC_LIKE
#endif
JUCE_BEGIN_IGNORE_WARNINGS_GCC_LIKE ("-Wdeprecated-declarations")
class PreCatalinaStillImageOutput : public ImageOutputBase
{
public:
void addImageCapture (AVCaptureSession* s) override
{
if (imageOutput != nil)
return;
const auto codecType = []
{
#if defined (MAC_OS_X_VERSION_10_13) && MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_13
if (@available (macOS 10.13, *))
return AVVideoCodecTypeJPEG;
#endif
return AVVideoCodecJPEG;
}();
imageOutput = [[AVCaptureStillImageOutput alloc] init];
auto imageSettings = [[NSDictionary alloc] initWithObjectsAndKeys: codecType, AVVideoCodecKey, nil];
[imageOutput setOutputSettings: imageSettings];
[imageSettings release];
[s addOutput: imageOutput];
}
void removeImageCapture (AVCaptureSession* s) override
{
if (imageOutput == nil)
return;
[s removeOutput: imageOutput];
[imageOutput release];
imageOutput = nil;
}
NSArray<AVCaptureConnection*>* getConnections() const override
{
if (imageOutput != nil)
return imageOutput.connections;
return nil;
}
void triggerImageCapture (Pimpl& p) override
{
if (auto* videoConnection = p.getVideoConnection())
{
[imageOutput captureStillImageAsynchronouslyFromConnection: videoConnection
completionHandler: ^(CMSampleBufferRef sampleBuffer, NSError* error)
{
if (error != nil)
{
JUCE_CAMERA_LOG ("Still picture capture failed, error: " + nsStringToJuce (error.localizedDescription));
jassertfalse;
return;
}
auto* imageData = [AVCaptureStillImageOutput jpegStillImageNSDataRepresentation: sampleBuffer];
auto image = ImageFileFormat::loadFrom (imageData.bytes, (size_t) imageData.length);
p.imageCaptureFinished (image);
}];
}
}
private:
AVCaptureStillImageOutput* imageOutput = nil;
};
JUCE_END_IGNORE_WARNINGS_GCC_LIKE
//============================================================================== //==============================================================================
void addImageCapture() void addImageCapture()
{ {
imageOutput.addImageCapture (session);
imageOutput->addImageCapture (session);
} }
void addMovieCapture() void addMovieCapture()
@@ -390,7 +419,7 @@ private:
void removeImageCapture() void removeImageCapture()
{ {
imageOutput.removeImageCapture (session);
imageOutput->removeImageCapture (session);
} }
void removeMovieCapture() void removeMovieCapture()
@@ -419,9 +448,7 @@ private:
{ {
if (currentInput == nil) if (currentInput == nil)
{ {
auto* availableDevices = decltype (imageOutput)::getAvailableDevices();
for (AVCaptureDevice* device : availableDevices)
for (AVCaptureDevice* device : getCaptureDevices())
{ {
if (deviceName == nsStringToJuce ([device localizedName])) if (deviceName == nsStringToJuce ([device localizedName]))
{ {
@@ -480,7 +507,7 @@ private:
AVCaptureConnection* getVideoConnection() const AVCaptureConnection* getVideoConnection() const
{ {
auto* connections = imageOutput.getConnections();
auto* connections = imageOutput->getConnections();
if (connections != nil) if (connections != nil)
for (AVCaptureConnection* connection in connections) for (AVCaptureConnection* connection in connections)
@@ -519,7 +546,7 @@ private:
startSession(); startSession();
if (auto* videoConnection = getVideoConnection()) if (auto* videoConnection = getVideoConnection())
imageOutput.triggerImageCapture (*this);
imageOutput->triggerImageCapture (*this);
} }
void cameraSessionRuntimeError (const String& error) void cameraSessionRuntimeError (const String& error)
@@ -536,11 +563,7 @@ private:
AVCaptureSession* session = nil; AVCaptureSession* session = nil;
AVCaptureMovieFileOutput* fileOutput = nil; AVCaptureMovieFileOutput* fileOutput = nil;
#if JUCE_USE_NEW_APPLE_CAMERA_API
PostCatalinaPhotoOutput imageOutput;
#else
PreCatalinaStillImageOutput imageOutput;
#endif
std::unique_ptr<ImageOutputBase> imageOutput;
AVCaptureDeviceInput* currentInput = nil; AVCaptureDeviceInput* currentInput = nil;
id<AVCaptureFileOutputRecordingDelegate> callbackDelegate = nil; id<AVCaptureFileOutputRecordingDelegate> callbackDelegate = nil;
@@ -578,5 +601,3 @@ String CameraDevice::getFileExtension()
{ {
return ".mov"; return ".mov";
} }
#undef JUCE_USE_NEW_APPLE_CAMERA_API

Loading…
Cancel
Save