Browse Source

Rewrote all internal OSX obj-C classes as dynamically-created classes. A side-effect of this is that plugins will no longer suffer from obj-C name-collision problems, and the old JUCE_ObjCExtraSuffix value is no longer needed.

tags/2021-05-28
jules 13 years ago
parent
commit
ac1d6955e7
24 changed files with 2334 additions and 2563 deletions
  1. +0
    -16
      extras/Introjucer/Source/Project Saving/jucer_ProjectExport_XCode.h
  2. +0
    -1
      modules/juce_audio_devices/juce_audio_devices.cpp
  3. +204
    -263
      modules/juce_audio_devices/native/juce_mac_AudioCDBurner.mm
  4. +128
    -137
      modules/juce_audio_plugin_client/AU/juce_AU_Wrapper.mm
  5. +0
    -4
      modules/juce_audio_plugin_client/utility/juce_CheckSettingMacros.h
  6. +3
    -0
      modules/juce_audio_plugin_client/utility/juce_IncludeSystemHeaders.h
  7. +0
    -1
      modules/juce_core/juce_core.cpp
  8. +188
    -198
      modules/juce_core/native/juce_mac_Network.mm
  9. +0
    -52
      modules/juce_core/native/juce_mac_ObjCSuffix.h
  10. +53
    -11
      modules/juce_core/native/juce_osx_ObjCHelpers.h
  11. +0
    -1
      modules/juce_events/juce_events.cpp
  12. +23
    -30
      modules/juce_events/native/juce_mac_MessageManager.mm
  13. +0
    -1
      modules/juce_graphics/juce_graphics.cpp
  14. +0
    -1
      modules/juce_gui_basics/juce_gui_basics.cpp
  15. +63
    -62
      modules/juce_gui_basics/native/juce_mac_FileChooser.mm
  16. +100
    -97
      modules/juce_gui_basics/native/juce_mac_MainMenu.mm
  17. +1348
    -1413
      modules/juce_gui_basics/native/juce_mac_NSViewComponentPeer.mm
  18. +0
    -1
      modules/juce_gui_extra/juce_gui_extra.cpp
  19. +43
    -50
      modules/juce_gui_extra/native/juce_mac_WebBrowserComponent.mm
  20. +0
    -1
      modules/juce_opengl/juce_opengl.cpp
  21. +65
    -71
      modules/juce_opengl/native/juce_OpenGL_osx.h
  22. +0
    -1
      modules/juce_video/juce_video.cpp
  23. +93
    -112
      modules/juce_video/native/juce_mac_CameraDevice.mm
  24. +23
    -39
      modules/juce_video/native/juce_mac_QuickTimeMovieComponent.mm

+ 0
- 16
extras/Introjucer/Source/Project Saving/jucer_ProjectExport_XCode.h View File

@@ -61,8 +61,6 @@ public:
if (getTargetLocationString().isEmpty())
getTargetLocationValue() = getDefaultBuildsRootFolder() + (iOS ? "iOS" : "MacOSX");
setValueIfVoid (getObjCSuffixValue(), createAlphaNumericUID());
}
static XCodeProjectExporter* createForSettings (Project& project, const ValueTree& settings)
@@ -76,9 +74,6 @@ public:
}
//==============================================================================
Value getObjCSuffixValue() { return getSetting ("objCExtraSuffix"); }
String getObjCSuffixString() const { return settings ["objCExtraSuffix"]; }
Value getPListToMergeValue() { return getSetting ("customPList"); }
String getPListToMergeString() const { return settings ["customPList"]; }
@@ -113,11 +108,6 @@ public:
{
ProjectExporter::createPropertyEditors (props);
props.add (new TextPropertyComponent (getObjCSuffixValue(), "Objective-C class name suffix", 64, false),
"Because objective-C linkage is done by string-matching, you can get horrible linkage mix-ups when different modules containing the "
"same class-names are loaded simultaneously. This setting lets you provide a unique string that will be used in naming "
"the obj-C classes in your executable to avoid this.");
if (projectType.isGUIApplication() && ! iOS)
{
props.add (new TextPropertyComponent (getSetting ("documentExtensions"), "Document file extensions", 128, false),
@@ -746,12 +736,6 @@ private:
s.add ("GCC_SYMBOLS_PRIVATE_EXTERN = YES");
}
{
const String objCSuffix (getObjCSuffixString().trim());
if (objCSuffix.isNotEmpty())
defines.set ("JUCE_ObjCExtraSuffix", replacePreprocessorTokens (config, objCSuffix));
}
{
defines = mergePreprocessorDefs (defines, getAllPreprocessorDefs (config));


+ 0
- 1
modules/juce_audio_devices/juce_audio_devices.cpp View File

@@ -163,7 +163,6 @@ namespace juce
//==============================================================================
#if JUCE_MAC
#include "../juce_core/native/juce_osx_ObjCHelpers.h"
#include "../juce_core/native/juce_mac_ObjCSuffix.h"
#include "native/juce_mac_CoreAudio.cpp"
#include "native/juce_mac_CoreMidi.cpp"


+ 204
- 263
modules/juce_audio_devices/native/juce_mac_AudioCDBurner.mm View File

@@ -25,305 +25,256 @@
const int kilobytesPerSecond1x = 176;
} // (juce namespace)
#define OpenDiskDevice MakeObjCClassName(OpenDiskDevice)
@interface OpenDiskDevice : NSObject
struct AudioTrackProducerClass : public ObjCClass <NSObject>
{
@public
DRDevice* device;
NSMutableArray* tracks;
bool underrunProtection;
}
- (OpenDiskDevice*) initWithDRDevice: (DRDevice*) device;
- (void) dealloc;
- (void) addSourceTrack: (juce::AudioSource*) source numSamples: (int) numSamples_;
- (void) burn: (juce::AudioCDBurner::BurnProgressListener*) listener errorString: (juce::String*) error
ejectAfterwards: (bool) shouldEject isFake: (bool) peformFakeBurnForTesting speed: (int) burnSpeed;
@end
//==============================================================================
#define AudioTrackProducer MakeObjCClassName(AudioTrackProducer)
@interface AudioTrackProducer : NSObject
{
juce::AudioSource* source;
int readPosition, lengthInFrames;
}
- (AudioTrackProducer*) init: (int) lengthInFrames;
- (AudioTrackProducer*) initWithAudioSource: (juce::AudioSource*) source numSamples: (int) lengthInSamples;
- (void) dealloc;
- (void) setupTrackProperties: (DRTrack*) track;
- (void) cleanupTrackAfterBurn: (DRTrack*) track;
- (BOOL) cleanupTrackAfterVerification:(DRTrack*)track;
- (uint64_t) estimateLengthOfTrack:(DRTrack*)track;
- (BOOL) prepareTrack:(DRTrack*)track forBurn:(DRBurn*)burn
toMedia:(NSDictionary*)mediaInfo;
- (BOOL) prepareTrackForVerification:(DRTrack*)track;
- (uint32_t) produceDataForTrack:(DRTrack*)track intoBuffer:(char*)buffer
length:(uint32_t)bufferLength atAddress:(uint64_t)address
blockSize:(uint32_t)blockSize ioFlags:(uint32_t*)flags;
- (uint32_t) producePreGapForTrack:(DRTrack*)track
intoBuffer:(char*)buffer length:(uint32_t)bufferLength
atAddress:(uint64_t)address blockSize:(uint32_t)blockSize
ioFlags:(uint32_t*)flags;
- (BOOL) verifyDataForTrack:(DRTrack*)track inBuffer:(const char*)buffer
length:(uint32_t)bufferLength atAddress:(uint64_t)address
blockSize:(uint32_t)blockSize ioFlags:(uint32_t*)flags;
- (uint32_t) producePreGapForTrack:(DRTrack*)track
intoBuffer:(char*)buffer length:(uint32_t)bufferLength
atAddress:(uint64_t)address blockSize:(uint32_t)blockSize
ioFlags:(uint32_t*)flags;
@end
//==============================================================================
@implementation OpenDiskDevice
AudioTrackProducerClass() : ObjCClass ("JUCEAudioTrackProducer_")
{
addIvar<AudioSourceHolder*> ("source");
addMethod (@selector (initWithAudioSourceHolder:), initWithAudioSourceHolder, "@@:^v");
addMethod (@selector (cleanupTrackAfterBurn:), cleanupTrackAfterBurn, "v@:@");
addMethod (@selector (cleanupTrackAfterVerification:), cleanupTrackAfterVerification, "c@:@");
addMethod (@selector (estimateLengthOfTrack:), estimateLengthOfTrack, "Q@:@");
addMethod (@selector (prepareTrack:forBurn:toMedia:), prepareTrack, "c@:@@@");
addMethod (@selector (prepareTrackForVerification:), prepareTrackForVerification, "c@:@");
addMethod (@selector (produceDataForTrack:intoBuffer:length:atAddress:blockSize:ioFlags:),
produceDataForTrack, "I@:@^cIQI^I");
addMethod (@selector (producePreGapForTrack:intoBuffer:length:atAddress:blockSize:ioFlags:),
produceDataForTrack, "I@:@^cIQI^I");
addMethod (@selector (verifyDataForTrack:intoBuffer:length:atAddress:blockSize:ioFlags:),
produceDataForTrack, "I@:@^cIQI^I");
registerClass();
}
- (OpenDiskDevice*) initWithDRDevice: (DRDevice*) device_
{
[super init];
struct AudioSourceHolder
{
AudioSourceHolder (AudioSource* source_, int numFrames)
: source (source_), readPosition (0), lengthInFrames (numFrames)
{
}
device = device_;
tracks = [[NSMutableArray alloc] init];
underrunProtection = true;
return self;
}
~AudioSourceHolder()
{
if (source != nullptr)
source->releaseResources();
}
- (void) dealloc
{
[tracks release];
[super dealloc];
}
ScopedPointer<AudioSource> source;
int readPosition, lengthInFrames;
};
- (void) addSourceTrack: (juce::AudioSource*) source_ numSamples: (int) numSamples_
{
AudioTrackProducer* p = [[AudioTrackProducer alloc] initWithAudioSource: source_ numSamples: numSamples_];
DRTrack* t = [[DRTrack alloc] initWithProducer: p];
[p setupTrackProperties: t];
private:
static id initWithAudioSourceHolder (id self, SEL, AudioSourceHolder* source)
{
self = sendSuperclassMessage (self, @selector (init));
object_setInstanceVariable (self, "source", source);
return self;
}
[tracks addObject: t];
static AudioSourceHolder* getSource (id self)
{
return getIvar<AudioSourceHolder*> (self, "source");
}
[t release];
[p release];
}
static void dealloc (id self, SEL)
{
delete getSource (self);
sendSuperclassMessage (self, @selector (dealloc));
}
- (void) burn: (juce::AudioCDBurner::BurnProgressListener*) listener errorString: (juce::String*) error
ejectAfterwards: (bool) shouldEject isFake: (bool) peformFakeBurnForTesting speed: (int) burnSpeed
{
DRBurn* burn = [DRBurn burnForDevice: device];
static void cleanupTrackAfterBurn (id self, SEL, DRTrack*) {}
static BOOL cleanupTrackAfterVerification (id self, SEL, DRTrack*) { return true; }
if (! [device acquireExclusiveAccess])
static uint64_t estimateLengthOfTrack (id self, SEL, DRTrack*)
{
*error = "Couldn't open or write to the CD device";
return;
return getSource (self)->lengthInFrames;
}
[device acquireMediaReservation];
static BOOL prepareTrack (id self, SEL, DRTrack*, DRBurn*, NSDictionary*)
{
AudioSourceHolder* const source = getSource (self);
NSMutableDictionary* d = [[burn properties] mutableCopy];
[d autorelease];
[d setObject: [NSNumber numberWithBool: peformFakeBurnForTesting] forKey: DRBurnTestingKey];
[d setObject: [NSNumber numberWithBool: false] forKey: DRBurnVerifyDiscKey];
[d setObject: (shouldEject ? DRBurnCompletionActionEject : DRBurnCompletionActionMount) forKey: DRBurnCompletionActionKey];
if (source != nullptr)
{
source->source->prepareToPlay (44100 / 75, 44100);
source->readPosition = 0;
}
if (burnSpeed > 0)
[d setObject: [NSNumber numberWithFloat: burnSpeed * juce::kilobytesPerSecond1x] forKey: DRBurnRequestedSpeedKey];
return true;
}
if (! underrunProtection)
[d setObject: [NSNumber numberWithBool: false] forKey: DRBurnUnderrunProtectionKey];
static BOOL prepareTrackForVerification (id self, SEL, DRTrack*)
{
AudioSourceHolder* const source = getSource (self);
[burn setProperties: d];
if (source != nullptr)
source->source->prepareToPlay (44100 / 75, 44100);
[burn writeLayout: tracks];
return true;
}
for (;;)
static uint32_t produceDataForTrack (id self, SEL, DRTrack*, char* buffer,
uint32_t bufferLength, uint64_t /*address*/,
uint32_t /*blockSize*/, uint32_t* /*flags*/)
{
juce::Thread::sleep (300);
float progress = [[[burn status] objectForKey: DRStatusPercentCompleteKey] floatValue];
AudioSourceHolder* const source = getSource (self);
if (listener != nullptr && listener->audioCDBurnProgress (progress))
if (source != nullptr)
{
[burn abort];
*error = "User cancelled the write operation";
break;
}
const int numSamples = jmin ((int) bufferLength / 4,
(source->lengthInFrames * (44100 / 75)) - source->readPosition);
if ([[[burn status] objectForKey: DRStatusStateKey] isEqualTo: DRStatusStateFailed])
{
*error = "Write operation failed";
break;
}
else if ([[[burn status] objectForKey: DRStatusStateKey] isEqualTo: DRStatusStateDone])
{
break;
}
NSString* err = (NSString*) [[[burn status] objectForKey: DRErrorStatusKey]
objectForKey: DRErrorStatusErrorStringKey];
if (numSamples > 0)
{
AudioSampleBuffer tempBuffer (2, numSamples);
AudioSourceChannelInfo info (tempBuffer);
source->source->getNextAudioBlock (info);
typedef AudioData::Pointer <AudioData::Int16,
AudioData::LittleEndian,
AudioData::Interleaved,
AudioData::NonConst> CDSampleFormat;
typedef AudioData::Pointer <AudioData::Float32,
AudioData::NativeEndian,
AudioData::NonInterleaved,
AudioData::Const> SourceSampleFormat;
CDSampleFormat left (buffer, 2);
left.convertSamples (SourceSampleFormat (tempBuffer.getSampleData (0)), numSamples);
CDSampleFormat right (buffer + 2, 2);
right.convertSamples (SourceSampleFormat (tempBuffer.getSampleData (1)), numSamples);
source->readPosition += numSamples;
}
if ([err length] > 0)
{
*error = juce::CharPointer_UTF8 ([err UTF8String]);
break;
return numSamples * 4;
}
return 0;
}
[device releaseMediaReservation];
[device releaseExclusiveAccess];
}
@end
static uint32_t producePreGapForTrack (id self, SEL, DRTrack*, char* buffer,
uint32_t bufferLength, uint64_t /*address*/,
uint32_t /*blockSize*/, uint32_t* /*flags*/)
{
zeromem (buffer, bufferLength);
return bufferLength;
}
//==============================================================================
@implementation AudioTrackProducer
static BOOL verifyDataForTrack (id self, SEL, DRTrack*, const char*,
uint32_t /*bufferLength*/, uint64_t /*address*/,
uint32_t /*blockSize*/, uint32_t* /*flags*/)
{
return true;
}
};
- (AudioTrackProducer*) init: (int) lengthInFrames_
struct OpenDiskDevice
{
lengthInFrames = lengthInFrames_;
readPosition = 0;
return self;
}
OpenDiskDevice (DRDevice* device_)
: device (device_),
tracks ([[NSMutableArray alloc] init]),
underrunProtection (true)
{
}
- (void) setupTrackProperties: (DRTrack*) track
{
NSMutableDictionary* p = [[track properties] mutableCopy];
[p setObject:[DRMSF msfWithFrames: lengthInFrames] forKey: DRTrackLengthKey];
[p setObject:[NSNumber numberWithUnsignedShort:2352] forKey: DRBlockSizeKey];
[p setObject:[NSNumber numberWithInt:0] forKey: DRDataFormKey];
[p setObject:[NSNumber numberWithInt:0] forKey: DRBlockTypeKey];
[p setObject:[NSNumber numberWithInt:0] forKey: DRTrackModeKey];
[p setObject:[NSNumber numberWithInt:0] forKey: DRSessionFormatKey];
~OpenDiskDevice()
{
[tracks release];
}
void addSourceTrack (AudioSource* source, int numSamples)
{
if (source != nullptr)
{
const int numFrames = (numSamples + 587) / 588;
[track setProperties: p];
[p release];
}
static AudioTrackProducerClass cls;
- (AudioTrackProducer*) initWithAudioSource: (juce::AudioSource*) source_ numSamples: (int) lengthInSamples
{
AudioTrackProducer* s = [self init: (lengthInSamples + 587) / 588];
NSObject* producer = [cls.createInstance() performSelector: @selector (initWithAudioSourceHolder:)
withObject: (id) new AudioTrackProducerClass::AudioSourceHolder (source, numFrames)];
DRTrack* track = [[DRTrack alloc] initWithProducer: producer];
if (s != nil)
s->source = source_;
{
NSMutableDictionary* p = [[track properties] mutableCopy];
[p setObject: [DRMSF msfWithFrames: numFrames] forKey: DRTrackLengthKey];
[p setObject: [NSNumber numberWithUnsignedShort: 2352] forKey: DRBlockSizeKey];
[p setObject: [NSNumber numberWithInt: 0] forKey: DRDataFormKey];
[p setObject: [NSNumber numberWithInt: 0] forKey: DRBlockTypeKey];
[p setObject: [NSNumber numberWithInt: 0] forKey: DRTrackModeKey];
[p setObject: [NSNumber numberWithInt: 0] forKey: DRSessionFormatKey];
[track setProperties: p];
[p release];
}
return s;
}
[tracks addObject: track];
- (void) dealloc
{
if (source != nullptr)
{
source->releaseResources();
delete source;
[track release];
[producer release];
}
}
[super dealloc];
}
- (void) cleanupTrackAfterBurn: (DRTrack*) track
{
(void) track;
}
- (BOOL) cleanupTrackAfterVerification: (DRTrack*) track
{
(void) track;
return true;
}
- (uint64_t) estimateLengthOfTrack: (DRTrack*) track
{
(void) track;
return lengthInFrames;
}
String burn (AudioCDBurner::BurnProgressListener* listener,
bool shouldEject, bool peformFakeBurnForTesting, int burnSpeed)
{
DRBurn* burn = [DRBurn burnForDevice: device];
- (BOOL) prepareTrack: (DRTrack*) track forBurn: (DRBurn*) burn
toMedia: (NSDictionary*) mediaInfo
{
(void) track; (void) burn; (void) mediaInfo;
if (! [device acquireExclusiveAccess])
return "Couldn't open or write to the CD device";
if (source != nullptr)
source->prepareToPlay (44100 / 75, 44100);
[device acquireMediaReservation];
readPosition = 0;
return true;
}
NSMutableDictionary* d = [[burn properties] mutableCopy];
[d autorelease];
[d setObject: [NSNumber numberWithBool: peformFakeBurnForTesting] forKey: DRBurnTestingKey];
[d setObject: [NSNumber numberWithBool: false] forKey: DRBurnVerifyDiscKey];
[d setObject: (shouldEject ? DRBurnCompletionActionEject : DRBurnCompletionActionMount) forKey: DRBurnCompletionActionKey];
- (BOOL) prepareTrackForVerification: (DRTrack*) track
{
(void) track;
if (source != nullptr)
source->prepareToPlay (44100 / 75, 44100);
if (burnSpeed > 0)
[d setObject: [NSNumber numberWithFloat: burnSpeed * kilobytesPerSecond1x] forKey: DRBurnRequestedSpeedKey];
return true;
}
if (! underrunProtection)
[d setObject: [NSNumber numberWithBool: false] forKey: DRBurnUnderrunProtectionKey];
- (uint32_t) produceDataForTrack: (DRTrack*) track intoBuffer: (char*) buffer
length: (uint32_t) bufferLength atAddress: (uint64_t) address
blockSize: (uint32_t) blockSize ioFlags: (uint32_t*) flags
{
(void) track; (void) address; (void) blockSize; (void) flags;
[burn setProperties: d];
if (source != nullptr)
{
const int numSamples = juce::jmin ((int) bufferLength / 4, (lengthInFrames * (44100 / 75)) - readPosition);
[burn writeLayout: tracks];
if (numSamples > 0)
for (;;)
{
juce::AudioSampleBuffer tempBuffer (2, numSamples);
juce::AudioSourceChannelInfo info (tempBuffer);
source->getNextAudioBlock (info);
typedef juce::AudioData::Pointer <juce::AudioData::Int16,
juce::AudioData::LittleEndian,
juce::AudioData::Interleaved,
juce::AudioData::NonConst> CDSampleFormat;
typedef juce::AudioData::Pointer <juce::AudioData::Float32,
juce::AudioData::NativeEndian,
juce::AudioData::NonInterleaved,
juce::AudioData::Const> SourceSampleFormat;
CDSampleFormat left (buffer, 2);
left.convertSamples (SourceSampleFormat (tempBuffer.getSampleData (0)), numSamples);
CDSampleFormat right (buffer + 2, 2);
right.convertSamples (SourceSampleFormat (tempBuffer.getSampleData (1)), numSamples);
readPosition += numSamples;
}
Thread::sleep (300);
float progress = [[[burn status] objectForKey: DRStatusPercentCompleteKey] floatValue];
return numSamples * 4;
}
if (listener != nullptr && listener->audioCDBurnProgress (progress))
{
[burn abort];
return "User cancelled the write operation";
}
return 0;
}
if ([[[burn status] objectForKey: DRStatusStateKey] isEqualTo: DRStatusStateFailed])
return "Write operation failed";
- (uint32_t) producePreGapForTrack: (DRTrack*) track
intoBuffer: (char*) buffer length: (uint32_t) bufferLength
atAddress: (uint64_t) address blockSize: (uint32_t) blockSize
ioFlags: (uint32_t*) flags
{
(void) track; (void) address; (void) blockSize; (void) flags;
zeromem (buffer, bufferLength);
return bufferLength;
}
if ([[[burn status] objectForKey: DRStatusStateKey] isEqualTo: DRStatusStateDone])
break;
- (BOOL) verifyDataForTrack: (DRTrack*) track inBuffer: (const char*) buffer
length: (uint32_t) bufferLength atAddress: (uint64_t) address
blockSize: (uint32_t) blockSize ioFlags: (uint32_t*) flags
{
(void) track; (void) buffer; (void) bufferLength; (void) address; (void) blockSize; (void) flags;
return true;
}
NSString* err = (NSString*) [[[burn status] objectForKey: DRErrorStatusKey]
objectForKey: DRErrorStatusErrorStringKey];
@end
if ([err length] > 0)
return CharPointer_UTF8 ([err UTF8String]);
}
[device releaseMediaReservation];
[device releaseExclusiveAccess];
return String::empty;
}
namespace juce
{
DRDevice* device;
NSMutableArray* tracks;
bool underrunProtection;
};
//==============================================================================
class AudioCDBurner::Pimpl : public Timer
@@ -333,9 +284,10 @@ public:
: device (0), owner (owner_)
{
DRDevice* dev = [[DRDevice devices] objectAtIndex: deviceIndex];
if (dev != nil)
{
device = [[OpenDiskDevice alloc] initWithDRDevice: dev];
device = new OpenDiskDevice (dev);
lastState = getDiskState();
startTimer (1000);
}
@@ -344,7 +296,6 @@ public:
~Pimpl()
{
stopTimer();
[device release];
}
void timerCallback()
@@ -386,7 +337,7 @@ public:
return unknown;
}
bool openTray() { return [device->device isValid] && [device->device ejectMedia]; }
bool openTray() { return [device->device isValid] && [device->device ejectMedia]; }
Array<int> getAvailableWriteSpeeds() const
{
@@ -422,7 +373,7 @@ public:
objectForKey: DRDeviceMediaBlocksFreeKey] intValue];
}
OpenDiskDevice* device;
ScopedPointer<OpenDiskDevice> device;
private:
DiskState lastState;
@@ -528,30 +479,20 @@ bool AudioCDBurner::addAudioTrack (AudioSource* source, int numSamps)
{
if ([pimpl->device->device isValid])
{
[pimpl->device addSourceTrack: source numSamples: numSamps];
pimpl->device->addSourceTrack (source, numSamps);
return true;
}
return false;
}
String AudioCDBurner::burn (juce::AudioCDBurner::BurnProgressListener* listener,
String AudioCDBurner::burn (AudioCDBurner::BurnProgressListener* listener,
bool ejectDiscAfterwards,
bool performFakeBurnForTesting,
int writeSpeed)
{
String error ("Couldn't open or write to the CD device");
if ([pimpl->device->device isValid])
{
error = String::empty;
[pimpl->device burn: listener
errorString: &error
ejectAfterwards: ejectDiscAfterwards
isFake: performFakeBurnForTesting
speed: writeSpeed];
}
return pimpl->device->burn (listener, ejectDiscAfterwards, performFakeBurnForTesting, writeSpeed);
return error;
return "Couldn't open or write to the CD device";
}

+ 128
- 137
modules/juce_audio_plugin_client/AU/juce_AU_Wrapper.mm View File

@@ -77,8 +77,11 @@
#include "../utility/juce_FakeMouseMoveGenerator.h"
#include "../utility/juce_CarbonVisibility.h"
#include "../utility/juce_PluginHostType.h"
#include "../../juce_core/native/juce_osx_ObjCHelpers.h"
//==============================================================================
#define JuceUICreationClass JucePlugin_AUCocoaViewClassName
#define juceFilterObjectPropertyID 0x1a45ffe9
static Array<void*> activePlugins, activeUIs;
@@ -97,52 +100,6 @@ static const int numChannelConfigs = sizeof (channelConfigs) / sizeof (*channelC
*/
extern AudioProcessor* JUCE_CALLTYPE createPluginFilter();
//==============================================================================
#define appendMacro1(a, b, c, d) a ## _ ## b ## _ ## c ## _ ## d
#define appendMacro2(a, b, c, d) appendMacro1(a, b, c, d)
#define MakeObjCClassName(rootName) appendMacro2 (rootName, JUCE_MAJOR_VERSION, JUCE_MINOR_VERSION, JucePlugin_AUExportPrefix)
#define JuceUICreationClass JucePlugin_AUCocoaViewClassName
#define JuceUIViewClass MakeObjCClassName(JuceUIViewClass)
class JuceAU;
class EditorCompHolder;
//==============================================================================
@interface JuceUICreationClass : NSObject <AUCocoaUIBase>
{
}
- (JuceUICreationClass*) init;
- (void) dealloc;
- (unsigned) interfaceVersion;
- (NSString*) description;
- (NSView*) uiViewForAudioUnit: (AudioUnit) inAudioUnit
withSize: (NSSize) inPreferredSize;
@end
//==============================================================================
@interface JuceUIViewClass : NSView
{
AudioProcessor* filter;
JuceAU* au;
EditorCompHolder* editorComp;
}
- (JuceUIViewClass*) initWithFilter: (AudioProcessor*) filter
withAU: (JuceAU*) au
withComponent: (AudioProcessorEditor*) editorComp;
- (void) dealloc;
- (void) shutdown;
- (void) applicationWillTerminate: (NSNotification*) aNotification;
- (void) viewDidMoveToWindow;
- (BOOL) mouseDownCanMoveWindow;
- (void) filterBeingDeleted: (JuceAU*) au_;
- (void) deleteEditor;
@end
//==============================================================================
class JuceAU : public JuceAUBaseClass,
public AudioProcessorListener,
@@ -187,9 +144,7 @@ public:
~JuceAU()
{
for (int i = activeUIs.size(); --i >= 0;)
[((JuceUIViewClass*) activeUIs.getUnchecked(i)) filterBeingDeleted: this];
deleteActiveEditors();
juceFilter = nullptr;
jassert (activePlugins.contains (this));
@@ -199,6 +154,8 @@ public:
shutdownJuce_GUI();
}
void deleteActiveEditors();
//==============================================================================
ComponentResult GetPropertyInfo (AudioUnitPropertyID inID,
AudioUnitScope inScope,
@@ -281,7 +238,7 @@ public:
NSString* bundlePath = [NSString stringWithUTF8String: (const char*) bundleFile.getFullPathName().toUTF8()];
NSBundle* b = [NSBundle bundleWithPath: bundlePath];
info->mCocoaAUViewClass[0] = (CFStringRef) [NSStringFromClass ([JuceUICreationClass class]) retain];
info->mCocoaAUViewClass[0] = (CFStringRef) [nsStringLiteral (JUCE_STRINGIFY (JuceUICreationClass)) retain];
info->mCocoaAUViewBundleLocation = (CFURLRef) [[NSURL fileURLWithPath: [b bundlePath]] retain];
return noErr;
@@ -974,6 +931,32 @@ public:
// have been transferred to another parent which takes over ownership.
}
static NSView* createViewFor (AudioProcessor* filter, JuceAU* au, AudioProcessorEditor* const editor)
{
EditorCompHolder* editorCompHolder = new EditorCompHolder (editor);
NSRect r = NSMakeRect (0, 0, editorCompHolder->getWidth(), editorCompHolder->getHeight());
static JuceUIViewClass cls;
NSView* view = [[cls.createInstance() initWithFrame: r] autorelease];
JuceUIViewClass::setFilter (view, filter);
JuceUIViewClass::setAU (view, au);
JuceUIViewClass::setEditor (view, editorCompHolder);
[view setHidden: NO];
[view setPostsFrameChangedNotifications: YES];
[[NSNotificationCenter defaultCenter] addObserver: view
selector: @selector (applicationWillTerminate:)
name: NSApplicationWillTerminateNotification
object: nil];
activeUIs.add (view);
editorCompHolder->addToDesktop (0, (void*) view);
editorCompHolder->setVisible (view);
return view;
}
void childBoundsChanged (Component*)
{
Component* editor = getChildComponent(0);
@@ -996,117 +979,128 @@ public:
}
}
private:
JUCE_DECLARE_NON_COPYABLE (EditorCompHolder);
};
//==============================================================================
struct JuceUIViewClass : public ObjCClass <NSView>
{
JuceUIViewClass() : ObjCClass ("JUCEAUView_")
{
addIvar<AudioProcessor*> ("filter");
addIvar<JuceAU*> ("au");
addIvar<EditorCompHolder*> ("editor");
addMethod (@selector (dealloc), dealloc, "v@:");
addMethod (@selector (applicationWillTerminate:), applicationWillTerminate, "v@:@");
addMethod (@selector (viewDidMoveToWindow), viewDidMoveToWindow, "v@:");
addMethod (@selector (mouseDownCanMoveWindow), mouseDownCanMoveWindow, "c@:");
registerClass();
}
//==============================================================================
@implementation JuceUIViewClass
static void deleteEditor (id self)
{
ScopedPointer<EditorCompHolder> editorComp (getEditor (self));
- (JuceUIViewClass*) initWithFilter: (AudioProcessor*) filter_
withAU: (JuceAU*) au_
withComponent: (AudioProcessorEditor*) editorComp_
{
filter = filter_;
au = au_;
editorComp = new EditorCompHolder (editorComp_);
if (editorComp != nullptr)
{
JuceAU* const au = getAU (self);
[super initWithFrame: NSMakeRect (0, 0, editorComp_->getWidth(), editorComp_->getHeight())];
[self setHidden: NO];
[self setPostsFrameChangedNotifications: YES];
if (editorComp->getChildComponent(0) != nullptr)
{
if (activePlugins.contains (au)) // plugin may have been deleted before the UI
{
AudioProcessor* const filter = getIvar<AudioProcessor*> (self, "filter");
filter->editorBeingDeleted ((AudioProcessorEditor*) editorComp->getChildComponent(0));
}
}
[[NSNotificationCenter defaultCenter] addObserver: self
selector: @selector (applicationWillTerminate:)
name: NSApplicationWillTerminateNotification
object: nil];
activeUIs.add (self);
editorComp = nullptr;
setEditor (self, nullptr);
}
}
editorComp->addToDesktop (0, (void*) self);
editorComp->setVisible (true);
static JuceAU* getAU (id self) { return getIvar<JuceAU*> (self, "au"); }
static EditorCompHolder* getEditor (id self) { return getIvar<EditorCompHolder*> (self, "editor"); }
return self;
}
static void setFilter (id self, AudioProcessor* filter) { object_setInstanceVariable (self, "filter", filter); }
static void setAU (id self, JuceAU* au) { object_setInstanceVariable (self, "au", au); }
static void setEditor (id self, EditorCompHolder* e) { object_setInstanceVariable (self, "editor", e); }
- (void) dealloc
{
if (activeUIs.contains (self))
[self shutdown];
private:
static void dealloc (id self, SEL)
{
if (activeUIs.contains (self))
shutdown (self);
[super dealloc];
}
sendSuperclassMessage (self, @selector (dealloc));
}
- (void) applicationWillTerminate: (NSNotification*) aNotification
{
(void) aNotification;
[self shutdown];
}
static void applicationWillTerminate (id self, SEL, NSNotification*)
{
shutdown (self);
}
- (void) shutdown
{
// there's some kind of component currently modal, but the host
// is trying to delete our plugin..
jassert (Component::getCurrentlyModalComponent() == nullptr);
static void shutdown (id self)
{
// there's some kind of component currently modal, but the host
// is trying to delete our plugin..
jassert (Component::getCurrentlyModalComponent() == nullptr);
[[NSNotificationCenter defaultCenter] removeObserver: self];
[self deleteEditor];
[[NSNotificationCenter defaultCenter] removeObserver: self];
deleteEditor (self);
jassert (activeUIs.contains (self));
activeUIs.removeValue (self);
if (activePlugins.size() + activeUIs.size() == 0)
shutdownJuce_GUI();
}
jassert (activeUIs.contains (self));
activeUIs.removeValue (self);
if (activePlugins.size() + activeUIs.size() == 0)
shutdownJuce_GUI();
}
- (void) viewDidMoveToWindow
{
if ([self window] != nil)
{
[[self window] setAcceptsMouseMovedEvents: YES];
static void viewDidMoveToWindow (id self, SEL)
{
NSWindow* w = [(NSView*) self window];
if (editorComp != nullptr)
[[self window] makeFirstResponder: (NSView*) editorComp->getWindowHandle()];
}
}
if (w != nil)
{
[w setAcceptsMouseMovedEvents: YES];
- (BOOL) mouseDownCanMoveWindow
{
return NO;
}
EditorCompHolder* const editorComp = getEditor (self);
if (editorComp != nullptr)
[w makeFirstResponder: (NSView*) editorComp->getWindowHandle()];
}
}
static BOOL mouseDownCanMoveWindow (id self, SEL)
{
return NO;
}
};
private:
JUCE_DECLARE_NON_COPYABLE (EditorCompHolder);
};
- (void) deleteEditor
void JuceAU::deleteActiveEditors()
{
if (editorComp != nullptr)
for (int i = activeUIs.size(); --i >= 0;)
{
if (editorComp->getChildComponent(0) != nullptr)
if (activePlugins.contains ((void*) au)) // plugin may have been deleted before the UI
filter->editorBeingDeleted ((AudioProcessorEditor*) editorComp->getChildComponent(0));
id ui = (id) activeUIs.getUnchecked(i);
deleteAndZero (editorComp);
if (EditorCompHolder::JuceUIViewClass::getAU (ui) == this)
EditorCompHolder::JuceUIViewClass::deleteEditor (ui);
}
editorComp = nullptr;
}
- (void) filterBeingDeleted: (JuceAU*) au_
//==============================================================================
@interface JuceUICreationClass : NSObject <AUCocoaUIBase>
{
if (au_ == au)
[self deleteEditor];
}
- (unsigned) interfaceVersion;
- (NSString*) description;
- (NSView*) uiViewForAudioUnit: (AudioUnit) inAudioUnit
withSize: (NSSize) inPreferredSize;
@end
//==============================================================================
@implementation JuceUICreationClass
- (JuceUICreationClass*) init
{
return [super init];
}
- (void) dealloc
{
[super dealloc];
}
- (unsigned) interfaceVersion
{
return 0;
@@ -1114,7 +1108,7 @@ private:
- (NSString*) description
{
return [NSString stringWithString: @JucePlugin_Name];
return [NSString stringWithString: nsStringLiteral (JucePlugin_Name)];
}
- (NSView*) uiViewForAudioUnit: (AudioUnit) inAudioUnit
@@ -1138,13 +1132,10 @@ private:
return nil;
AudioProcessorEditor* editorComp = filter->createEditorIfNeeded();
if (editorComp == nullptr)
return nil;
return [[[JuceUIViewClass alloc] initWithFilter: filter
withAU: au
withComponent: editorComp] autorelease];
return EditorCompHolder::createViewFor (filter, au, editorComp);
}
@end


+ 0
- 4
modules/juce_audio_plugin_client/utility/juce_CheckSettingMacros.h View File

@@ -97,10 +97,6 @@
#error "You need to define the JucePlugin_AUCocoaViewClassName value!"
#endif
#if (defined(__APPLE_CPP__) || defined(__APPLE_CC__)) && ! defined (JUCE_ObjCExtraSuffix)
#error "To avoid objective-C name clashes with other plugins, you need to define the JUCE_ObjCExtraSuffix value as a global definition for your project!"
#endif
#if JucePlugin_Build_LV2 && ! defined (JucePlugin_LV2URI)
#error "You need to define the JucePlugin_LV2URI value!"
#endif


+ 3
- 0
modules/juce_audio_plugin_client/utility/juce_IncludeSystemHeaders.h View File

@@ -61,4 +61,7 @@
#else
#include <Cocoa/Cocoa.h>
#endif
#include <objc/runtime.h>
#include <objc/objc.h>
#include <objc/message.h>
#endif

+ 0
- 1
modules/juce_core/juce_core.cpp View File

@@ -152,7 +152,6 @@ namespace juce
//==============================================================================
#if JUCE_MAC || JUCE_IOS
#include "native/juce_osx_ObjCHelpers.h"
#include "native/juce_mac_ObjCSuffix.h"
#endif
#if JUCE_ANDROID


+ 188
- 198
modules/juce_core/native/juce_mac_Network.mm View File

@@ -98,236 +98,213 @@ bool Process::openEmailWithAttachments (const String& targetEmailAddress,
}
//==============================================================================
} // (juce namespace)
using namespace juce;
//==============================================================================
#define JuceURLConnection MakeObjCClassName(JuceURLConnection)
@interface JuceURLConnection : NSObject
{
@public
NSURLRequest* request;
NSURLConnection* connection;
NSMutableData* data;
Thread* runLoopThread;
bool initialised, hasFailed, hasFinished;
int position;
int64 contentLength;
NSDictionary* headers;
NSLock* dataLock;
}
- (JuceURLConnection*) initWithRequest: (NSURLRequest*) req withCallback: (URL::OpenStreamProgressCallback*) callback withContext: (void*) context;
- (void) dealloc;
- (void) connection: (NSURLConnection*) connection didReceiveResponse: (NSURLResponse*) response;
- (void) connection: (NSURLConnection*) connection didFailWithError: (NSError*) error;
- (void) connection: (NSURLConnection*) connection didReceiveData: (NSData*) data;
- (void) connectionDidFinishLoading: (NSURLConnection*) connection;
- (BOOL) isOpen;
- (int) read: (char*) dest numBytes: (int) num;
- (int) readPosition;
- (void) stop;
- (void) createConnection;
@end
class JuceURLConnectionMessageThread : public Thread
class URLConnectionState : public Thread
{
public:
JuceURLConnectionMessageThread (JuceURLConnection* owner_)
URLConnectionState (NSObject* owner_, NSURLRequest* req)
: Thread ("http connection"),
owner (owner_)
contentLength (-1),
owner (owner_),
request ([req retain]),
connection (nil),
data ([[NSMutableData data] retain]),
headers (nil),
initialised (false),
hasFailed (false),
hasFinished (false)
{
}
~JuceURLConnectionMessageThread()
~URLConnectionState()
{
stopThread (10000);
[connection release];
[data release];
[request release];
[headers release];
}
void run()
bool start (URL::OpenStreamProgressCallback* callback, void* context)
{
[owner createConnection];
startThread();
while (! threadShouldExit())
while (isThreadRunning() && ! initialised)
{
JUCE_AUTORELEASEPOOL
[[NSRunLoop currentRunLoop] runUntilDate: [NSDate dateWithTimeIntervalSinceNow: 0.01]];
if (callback != nullptr)
callback (context, -1, (int) [[request HTTPBody] length]);
Thread::sleep (1);
}
return connection != nil && ! hasFailed;
}
private:
JuceURLConnection* owner;
};
void stop()
{
[connection cancel];
stopThread (10000);
}
int read (char* dest, int numBytes)
{
int numDone = 0;
@implementation JuceURLConnection
while (numBytes > 0)
{
const int available = jmin (numBytes, (int) [data length]);
- (JuceURLConnection*) initWithRequest: (NSURLRequest*) req
withCallback: (URL::OpenStreamProgressCallback*) callback
withContext: (void*) context;
{
[super init];
request = req;
[request retain];
data = [[NSMutableData data] retain];
dataLock = [[NSLock alloc] init];
connection = nil;
initialised = false;
hasFailed = false;
hasFinished = false;
contentLength = -1;
headers = nil;
runLoopThread = new JuceURLConnectionMessageThread (self);
runLoopThread->startThread();
while (runLoopThread->isThreadRunning() && ! initialised)
{
if (callback != nullptr)
callback (context, -1, (int) [[request HTTPBody] length]);
if (available > 0)
{
const ScopedLock sl (dataLock);
[data getBytes: dest length: available];
[data replaceBytesInRange: NSMakeRange (0, available) withBytes: nil length: 0];
numDone += available;
numBytes -= available;
dest += available;
}
else
{
if (hasFailed || hasFinished)
break;
Thread::sleep (1);
}
}
Thread::sleep (1);
return numDone;
}
return self;
}
void didReceiveResponse (NSURLResponse* response)
{
{
const ScopedLock sl (dataLock);
[data setLength: 0];
}
- (void) dealloc
{
[self stop];
deleteAndZero (runLoopThread);
[connection release];
[data release];
[dataLock release];
[request release];
[headers release];
[super dealloc];
}
initialised = true;
contentLength = [response expectedContentLength];
- (void) createConnection
{
NSUInteger oldRetainCount = [self retainCount];
connection = [[NSURLConnection alloc] initWithRequest: request
delegate: self];
[headers release];
headers = nil;
if (oldRetainCount == [self retainCount])
[self retain]; // newer SDK should already retain this, but there were problems in older versions..
if ([response isKindOfClass: [NSHTTPURLResponse class]])
headers = [[((NSHTTPURLResponse*) response) allHeaderFields] retain];
}
if (connection == nil)
runLoopThread->signalThreadShouldExit();
}
void didFailWithError (NSError* error)
{
DBG (nsStringToJuce ([error description])); (void) error;
hasFailed = true;
initialised = true;
signalThreadShouldExit();
}
- (void) connection: (NSURLConnection*) conn didReceiveResponse: (NSURLResponse*) response
{
(void) conn;
[dataLock lock];
[data setLength: 0];
[dataLock unlock];
initialised = true;
contentLength = [response expectedContentLength];
[headers release];
headers = nil;
if ([response isKindOfClass: [NSHTTPURLResponse class]])
headers = [[((NSHTTPURLResponse*) response) allHeaderFields] retain];
}
void didReceiveData (NSData* newData)
{
const ScopedLock sl (dataLock);
[data appendData: newData];
initialised = true;
}
- (void) connection: (NSURLConnection*) conn didFailWithError: (NSError*) error
{
(void) conn;
DBG (nsStringToJuce ([error description]));
hasFailed = true;
initialised = true;
void finishedLoading()
{
hasFinished = true;
initialised = true;
signalThreadShouldExit();
}
if (runLoopThread != nullptr)
runLoopThread->signalThreadShouldExit();
}
void run()
{
NSUInteger oldRetainCount = [owner retainCount];
connection = [[NSURLConnection alloc] initWithRequest: request
delegate: owner];
- (void) connection: (NSURLConnection*) conn didReceiveData: (NSData*) newData
{
(void) conn;
[dataLock lock];
[data appendData: newData];
[dataLock unlock];
initialised = true;
}
if (oldRetainCount == [owner retainCount])
[owner retain]; // newer SDK should already retain this, but there were problems in older versions..
- (void) connectionDidFinishLoading: (NSURLConnection*) conn
{
(void) conn;
hasFinished = true;
initialised = true;
if (connection != nil)
{
while (! threadShouldExit())
{
JUCE_AUTORELEASEPOOL
[[NSRunLoop currentRunLoop] runUntilDate: [NSDate dateWithTimeIntervalSinceNow: 0.01]];
}
}
}
if (runLoopThread != nullptr)
runLoopThread->signalThreadShouldExit();
}
int64 contentLength;
CriticalSection dataLock;
NSObject* owner;
NSURLRequest* request;
NSURLConnection* connection;
NSMutableData* data;
NSDictionary* headers;
bool initialised, hasFailed, hasFinished;
- (BOOL) isOpen
{
return connection != nil && ! hasFailed;
}
private:
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (URLConnectionState);
};
- (int) readPosition
//==============================================================================
struct URLConnectionDelegateClass : public ObjCClass<NSObject>
{
return position;
}
URLConnectionDelegateClass() : ObjCClass ("JUCEAppDelegate_")
{
addIvar <URLConnectionState*> ("state");
- (int) read: (char*) dest numBytes: (int) numNeeded
{
int numDone = 0;
addMethod (@selector (dealloc), dealloc, "v@:");
addMethod (@selector (connection:didReceiveResponse:), didReceiveResponse, "v@:@@");
addMethod (@selector (connection:didFailWithError:), didFailWithError, "v@:@@");
addMethod (@selector (connection:didReceiveData:), didReceiveData, "v@:@@");
addMethod (@selector (connectionDidFinishLoading:), connectionDidFinishLoading, "v@:@");
while (numNeeded > 0)
{
int available = jmin (numNeeded, (int) [data length]);
registerClass();
}
if (available > 0)
{
[dataLock lock];
[data getBytes: dest length: available];
[data replaceBytesInRange: NSMakeRange (0, available) withBytes: nil length: 0];
[dataLock unlock];
numDone += available;
numNeeded -= available;
dest += available;
}
else
{
if (hasFailed || hasFinished)
break;
static void setState (id self, URLConnectionState* state)
{
object_setInstanceVariable (self, "state", state);
}
Thread::sleep (1);
}
static URLConnectionState* getState (id self)
{
return getIvar<URLConnectionState*> (self, "state");
}
position += numDone;
return numDone;
}
private:
static void dealloc (id self, SEL sel)
{
getState (self)->stop();
delete getState (self);
sendSuperclassMessage (self, @selector (dealloc));
}
- (void) stop
{
[connection cancel];
static void didReceiveResponse (id self, SEL, NSURLConnection*, NSURLResponse* response)
{
getState (self)->didReceiveResponse (response);
}
if (runLoopThread != nullptr)
runLoopThread->stopThread (10000);
}
static void didFailWithError (id self, SEL, NSURLConnection*, NSError* error)
{
getState (self)->didFailWithError (error);
}
@end
static void didReceiveData (id self, SEL, NSURLConnection*, NSData* newData)
{
getState (self)->didReceiveData (newData);
}
namespace juce
{
static void connectionDidFinishLoading (id self, SEL, NSURLConnection*)
{
getState (self)->finishedLoading();
}
};
//==============================================================================
class WebInputStream : public InputStream
{
public:
//==============================================================================
WebInputStream (const String& address_, bool isPost_, const MemoryBlock& postData_,
URL::OpenStreamProgressCallback* progressCallback, void* progressCallbackContext,
const String& headers_, int timeOutMs_, StringPairArray* responseHeaders)
@@ -338,14 +315,19 @@ public:
JUCE_AUTORELEASEPOOL
connection = createConnection (progressCallback, progressCallbackContext);
if (responseHeaders != nullptr && connection != nil && connection->headers != nil)
if (responseHeaders != nullptr && connection != nil)
{
NSEnumerator* enumerator = [connection->headers keyEnumerator];
NSString* key;
URLConnectionState* const state = URLConnectionDelegateClass::getState (connection);
if (state->headers != nil)
{
NSEnumerator* enumerator = [state->headers keyEnumerator];
NSString* key;
while ((key = [enumerator nextObject]) != nil)
responseHeaders->set (nsStringToJuce (key),
nsStringToJuce ((NSString*) [connection->headers objectForKey: key]));
while ((key = [enumerator nextObject]) != nil)
responseHeaders->set (nsStringToJuce (key),
nsStringToJuce ((NSString*) [state->headers objectForKey: key]));
}
}
}
@@ -356,7 +338,7 @@ public:
//==============================================================================
bool isError() const { return connection == nil; }
int64 getTotalLength() { return connection == nil ? -1 : connection->contentLength; }
int64 getTotalLength() { return connection == nil ? -1 : URLConnectionDelegateClass::getState (connection)->contentLength; }
bool isExhausted() { return finished; }
int64 getPosition() { return position; }
@@ -371,7 +353,10 @@ public:
else
{
JUCE_AUTORELEASEPOOL
const int bytesRead = [connection read: static_cast <char*> (buffer) numBytes: bytesToRead];
URLConnectionState* const state = URLConnectionDelegateClass::getState (connection);
const int bytesRead = state->read (static_cast <char*> (buffer), bytesToRead);
position += bytesRead;
if (bytesRead == 0)
@@ -402,7 +387,7 @@ public:
//==============================================================================
private:
JuceURLConnection* connection;
NSObject* connection;
String address, headers;
MemoryBlock postData;
int64 position;
@@ -412,13 +397,16 @@ private:
void close()
{
[connection stop];
[connection release];
connection = nil;
if (connection != nil)
{
URLConnectionDelegateClass::getState (connection)->stop();
[connection release];
connection = nil;
}
}
JuceURLConnection* createConnection (URL::OpenStreamProgressCallback* progressCallback,
void* progressCallbackContext)
NSObject* createConnection (URL::OpenStreamProgressCallback* progressCallback,
void* progressCallbackContext)
{
NSMutableURLRequest* req = [NSMutableURLRequest requestWithURL: [NSURL URLWithString: juceStringToNS (address)]
cachePolicy: NSURLRequestReloadIgnoringLocalCacheData
@@ -447,11 +435,13 @@ private:
[req setHTTPBody: [NSData dataWithBytes: postData.getData()
length: postData.getSize()]];
JuceURLConnection* const s = [[JuceURLConnection alloc] initWithRequest: req
withCallback: progressCallback
withContext: progressCallbackContext];
static URLConnectionDelegateClass cls;
NSObject* const s = [cls.createInstance() init];
URLConnectionState* state = new URLConnectionState (s, req);
URLConnectionDelegateClass::setState (s, state);
if ([s isOpen])
if (state->start (progressCallback, progressCallbackContext))
return s;
[s release];


+ 0
- 52
modules/juce_core/native/juce_mac_ObjCSuffix.h View File

@@ -1,52 +0,0 @@
/*
==============================================================================
This file is part of the JUCE library - "Jules' Utility Class Extensions"
Copyright 2004-11 by Raw Material Software Ltd.
------------------------------------------------------------------------------
JUCE can be redistributed and/or modified under the terms of the GNU General
Public License (Version 2), as published by the Free Software Foundation.
A copy of the license is included in the JUCE distribution, or can be found
online at www.gnu.org/licenses.
JUCE is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
A PARTICULAR PURPOSE. See the GNU General Public License for more details.
------------------------------------------------------------------------------
To release a closed-source product which uses JUCE, commercial licenses are
available: visit www.rawmaterialsoftware.com/juce for more information.
==============================================================================
*/
#ifndef __JUCE_MAC_OBJCSUFFIX_JUCEHEADER__
#define __JUCE_MAC_OBJCSUFFIX_JUCEHEADER__
/** This suffix is used for naming all Obj-C classes that are used inside juce.
Because of the flat naming structure used by Obj-C, you can get horrible situations where
two DLLs are loaded into a host, each of which uses classes with the same names, and these get
cross-linked so that when you make a call to a class that you thought was private, it ends up
actually calling into a similarly named class in the other module's address space.
By changing this macro to a unique value, you ensure that all the obj-C classes in your app
have unique names, and should avoid this problem.
If you're using the amalgamated version, you can just set this macro to something unique before
you include juce_amalgamated.cpp.
*/
#ifndef JUCE_ObjCExtraSuffix
#define JUCE_ObjCExtraSuffix 3
#endif
#ifndef DOXYGEN
#define appendMacro1(a, b, c, d, e) a ## _ ## b ## _ ## c ## _ ## d ## _ ## e
#define appendMacro2(a, b, c, d, e) appendMacro1(a, b, c, d, e)
#define MakeObjCClassName(rootName) appendMacro2 (rootName, JUCE_MAJOR_VERSION, JUCE_MINOR_VERSION, JUCE_BUILDNUMBER, JUCE_ObjCExtraSuffix)
#endif
#endif // __JUCE_MAC_OBJCSUFFIX_JUCEHEADER__

+ 53
- 11
modules/juce_core/native/juce_osx_ObjCHelpers.h View File

@@ -55,18 +55,27 @@ namespace
}
//==============================================================================
class ObjCClassBuilder
template <typename SuperclassType>
struct ObjCClass
{
public:
ObjCClassBuilder (Class superClass, const String& name)
: cls (objc_allocateClassPair (superClass, name.toUTF8(), 0))
ObjCClass (const char* nameRoot)
: cls (objc_allocateClassPair ([SuperclassType class], getRandomisedName (nameRoot).toUTF8(), 0))
{
}
Class getClass()
~ObjCClass()
{
objc_disposeClassPair (cls);
}
void registerClass()
{
objc_registerClassPair (cls);
return cls;
}
SuperclassType* createInstance() const
{
return class_createInstance (cls, 0);
}
template <typename Type>
@@ -83,21 +92,54 @@ public:
jassert (b); (void) b;
}
template <typename FunctionType>
void addMethod (SEL selector, FunctionType callbackFn, const char* sig1, const char* sig2)
{
addMethod (selector, callbackFn, (String (sig1) + sig2).toUTF8());
}
template <typename FunctionType>
void addMethod (SEL selector, FunctionType callbackFn, const char* sig1, const char* sig2, const char* sig3)
{
addMethod (selector, callbackFn, (String (sig1) + sig2 + sig3).toUTF8());
}
template <typename FunctionType>
void addMethod (SEL selector, FunctionType callbackFn, const char* sig1, const char* sig2, const char* sig3, const char* sig4)
{
addMethod (selector, callbackFn, (String (sig1) + sig2 + sig3 + sig4).toUTF8());
}
void addProtocol (Protocol* protocol)
{
BOOL b = class_addProtocol (cls, protocol);
jassert (b); (void) b;
}
Class cls;
static id sendSuperclassMessage (id self, SEL selector)
{
objc_super s = { self, [NSObject class] };
objc_super s = { self, [SuperclassType class] };
return objc_msgSendSuper (&s, selector);
}
static String getRandomisedName (const char* root)
template <typename Type>
static Type getIvar (id self, const char* name)
{
return root + String::toHexString (Random::getSystemRandom().nextInt64());
Type v = Type();
object_getInstanceVariable (self, name, (void**) &v);
return v;
}
private:
Class cls;
static String getRandomisedName (const char* root)
{
return root + String::toHexString (Random::getSystemRandom().nextInt64());
}
JUCE_DECLARE_NON_COPYABLE (ObjCClassBuilder);
JUCE_DECLARE_NON_COPYABLE (ObjCClass);
};
#endif // __JUCE_OSX_OBJCHELPERS_JUCEHEADER__

+ 0
- 1
modules/juce_events/juce_events.cpp View File

@@ -81,7 +81,6 @@ namespace juce
//==============================================================================
#if JUCE_MAC
#include "../juce_core/native/juce_osx_ObjCHelpers.h"
#include "../juce_core/native/juce_mac_ObjCSuffix.h"
#include "native/juce_osx_MessageQueue.h"
#include "native/juce_mac_MessageManager.mm"


+ 23
- 30
modules/juce_events/native/juce_mac_MessageManager.mm View File

@@ -30,33 +30,24 @@ typedef bool (*CheckEventBlockedByModalComps) (NSEvent*);
CheckEventBlockedByModalComps isEventBlockedByModalComps = nullptr;
//==============================================================================
struct AppDelegateClass
struct AppDelegateClass : public ObjCClass <NSObject>
{
static Class createClass()
AppDelegateClass() : ObjCClass ("JUCEAppDelegate_")
{
ObjCClassBuilder c ([NSObject class], ObjCClassBuilder::getRandomisedName ("JUCEAppDelegate_"));
c.addMethod (@selector (init), init, "@@:");
c.addMethod (@selector (dealloc), dealloc, "v@:");
c.addMethod (@selector (unregisterObservers), unregisterObservers, "v@:");
c.addMethod (@selector (applicationShouldTerminate:), applicationShouldTerminate, "I@:@");
c.addMethod (@selector (applicationWillTerminate:), applicationWillTerminate, "v@:@");
c.addMethod (@selector (application:openFile:), application_openFile, "c@:@@");
c.addMethod (@selector (application:openFiles:), application_openFiles, "v@:@@");
c.addMethod (@selector (applicationDidBecomeActive:), applicationDidBecomeActive, "v@:@");
c.addMethod (@selector (applicationDidResignActive:), applicationDidResignActive, "v@:@");
c.addMethod (@selector (applicationWillUnhide:), applicationWillUnhide, "v@:@");
c.addMethod (@selector (broadcastMessageCallback:), broadcastMessageCallback, "v@:@");
c.addMethod (@selector (dummyMethod), dummyMethod, "v@:");
return c.getClass();
}
static NSObject* createInstance()
{
static Class c = createClass();
jassert (c != nullptr);
return class_createInstance (c, 0);
addMethod (@selector (init), init, "@@:");
addMethod (@selector (dealloc), dealloc, "v@:");
addMethod (@selector (unregisterObservers), unregisterObservers, "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@:@");
addMethod (@selector (broadcastMessageCallback:), broadcastMessageCallback, "v@:@");
addMethod (@selector (dummyMethod), dummyMethod, "v@:");
registerClass();
}
static NSString* getBroacastEventName()
@@ -64,10 +55,10 @@ struct AppDelegateClass
return juceStringToNS ("juce_" + String::toHexString (File::getSpecialLocation (File::currentExecutableFile).hashCode64()));
}
//==============================================================================
private:
static id init (id self, SEL)
{
self = ObjCClassBuilder::sendSuperclassMessage (self, @selector (init));
self = sendSuperclassMessage (self, @selector (init));
if (JUCEApplicationBase::isStandaloneApp())
{
@@ -97,7 +88,7 @@ struct AppDelegateClass
static void dealloc (id self, SEL)
{
ObjCClassBuilder::sendSuperclassMessage (self, @selector (dealloc));
sendSuperclassMessage (self, @selector (dealloc));
}
static void unregisterObservers (id self, SEL)
@@ -265,8 +256,10 @@ struct AppDelegateHolder
{
public:
AppDelegateHolder()
: delegate ([AppDelegateClass::createInstance() init])
{}
{
static AppDelegateClass cls;
delegate = [cls.createInstance() init];
}
~AppDelegateHolder()
{


+ 0
- 1
modules/juce_graphics/juce_graphics.cpp View File

@@ -111,7 +111,6 @@ namespace juce
//==============================================================================
#if JUCE_MAC || JUCE_IOS
#include "../juce_core/native/juce_osx_ObjCHelpers.h"
#include "../juce_core/native/juce_mac_ObjCSuffix.h"
#include "native/juce_mac_CoreGraphicsHelpers.h"
#include "native/juce_mac_Fonts.mm"
#include "native/juce_mac_CoreGraphicsContext.mm"


+ 0
- 1
modules/juce_gui_basics/juce_gui_basics.cpp View File

@@ -256,7 +256,6 @@ namespace juce
#if JUCE_MAC || JUCE_IOS
#include "../juce_core/native/juce_osx_ObjCHelpers.h"
#include "../juce_core/native/juce_mac_ObjCSuffix.h"
#include "../juce_graphics/native/juce_mac_CoreGraphicsHelpers.h"
#include "../juce_graphics/native/juce_mac_CoreGraphicsContext.h"


+ 63
- 62
modules/juce_gui_basics/native/juce_mac_FileChooser.mm View File

@@ -25,81 +25,69 @@
#if JUCE_MAC
} // (juce namespace)
using namespace juce;
#define JuceFileChooserDelegate MakeObjCClassName(JuceFileChooserDelegate)
#if defined (MAC_OS_X_VERSION_10_6) && MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_6
@interface JuceFileChooserDelegate : NSObject <NSOpenSavePanelDelegate>
#else
@interface JuceFileChooserDelegate : NSObject
#endif
struct FileChooserDelegateClass : public ObjCClass <NSObject>
{
StringArray* filters;
}
FileChooserDelegateClass() : ObjCClass ("JUCEFileChooser_")
{
addIvar<StringArray*> ("filters");
- (JuceFileChooserDelegate*) initWithFilters: (StringArray*) filters_;
- (void) dealloc;
- (BOOL) panel: (id) sender shouldShowFilename: (NSString*) filename;
addMethod (@selector (initWithFilters:), initWithFilters, "@@:^v");
addMethod (@selector (dealloc), dealloc, "v@:");
addMethod (@selector (panel:shouldShowFilename:), shouldShowFilename, "c@:@@");
@end
#if defined (MAC_OS_X_VERSION_10_6) && MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_6
addProtocol (@protocol (NSOpenSavePanelDelegate));
#endif
@implementation JuceFileChooserDelegate
- (JuceFileChooserDelegate*) initWithFilters: (StringArray*) filters_
{
[super init];
filters = filters_;
return self;
}
registerClass();
}
- (void) dealloc
{
delete filters;
[super dealloc];
}
private:
static id initWithFilters (id self, SEL, StringArray* filters)
{
self = sendSuperclassMessage (self, @selector (init));
object_setInstanceVariable (self, "filters", filters);
return self;
}
- (BOOL) panel: (id) sender shouldShowFilename: (NSString*) filename
{
(void) sender;
const File f (nsStringToJuce (filename));
static void dealloc (id self, SEL)
{
delete getIvar<StringArray*> (self, "filters");
sendSuperclassMessage (self, @selector (dealloc));
}
for (int i = filters->size(); --i >= 0;)
if (f.getFileName().matchesWildcard ((*filters)[i], true))
return true;
static BOOL shouldShowFilename (id self, SEL, id /*sender*/, NSString* filename)
{
StringArray* const filters = getIvar<StringArray*> (self, "filters");
#if (! defined (MAC_OS_X_VERSION_10_7)) || MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_X_VERSION_10_7
NSError* error;
NSString* name = [[NSWorkspace sharedWorkspace] typeOfFile: filename error: &error];
const File f (nsStringToJuce (filename));
if ([name isEqualToString: nsStringLiteral ("com.apple.alias-file")])
{
FSRef ref;
FSPathMakeRef ((const UInt8*) [filename fileSystemRepresentation], &ref, nullptr);
for (int i = filters->size(); --i >= 0;)
if (f.getFileName().matchesWildcard ((*filters)[i], true))
return true;
Boolean targetIsFolder = false, wasAliased = false;
FSResolveAliasFileWithMountFlags (&ref, true, &targetIsFolder, &wasAliased, 0);
#if (! defined (MAC_OS_X_VERSION_10_7)) || MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_X_VERSION_10_7
NSError* error;
NSString* name = [[NSWorkspace sharedWorkspace] typeOfFile: filename error: &error];
return wasAliased && targetIsFolder;
}
#endif
if ([name isEqualToString: nsStringLiteral ("com.apple.alias-file")])
{
FSRef ref;
FSPathMakeRef ((const UInt8*) [filename fileSystemRepresentation], &ref, nullptr);
return f.isDirectory()
&& ! [[NSWorkspace sharedWorkspace] isFilePackageAtPath: filename];
}
@end
Boolean targetIsFolder = false, wasAliased = false;
FSResolveAliasFileWithMountFlags (&ref, true, &targetIsFolder, &wasAliased, 0);
return wasAliased && targetIsFolder;
}
#endif
namespace juce
{
return f.isDirectory()
&& ! [[NSWorkspace sharedWorkspace] isFilePackageAtPath: filename];
}
};
//==============================================================================
bool FileChooser::isPlatformDialogAvailable()
{
return true;
}
class TemporaryMainMenuWithStandardCommands
{
public:
@@ -127,7 +115,7 @@ public:
[item release];
item = [[NSApp mainMenu] addItemWithTitle: NSLocalizedString (nsStringLiteral ("Edit"), nil)
action: nil keyEquivalent: nsEmptyString()];
action: nil keyEquivalent: nsEmptyString()];
[[NSApp mainMenu] setSubmenu: menu forItem: item];
[menu release];
}
@@ -141,6 +129,7 @@ private:
MenuBarModel* oldMenu;
};
//==============================================================================
void FileChooser::showPlatformDialog (Array<File>& results,
const String& title,
const File& currentFileOrDirectory,
@@ -161,8 +150,15 @@ void FileChooser::showPlatformDialog (Array<File>& results,
filters->trim();
filters->removeEmptyStrings();
JuceFileChooserDelegate* delegate = [[JuceFileChooserDelegate alloc] initWithFilters: filters];
[delegate autorelease];
#if defined (MAC_OS_X_VERSION_10_6) && MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_6
typedef NSObject<NSOpenSavePanelDelegate> DelegateType;
#else
typedef NSObject DelegateType;
#endif
static FileChooserDelegateClass cls;
DelegateType* delegate = [[cls.createInstance() performSelector: @selector (initWithFilters:)
withObject: (id) filters] autorelease];
NSSavePanel* panel = isSaveDialogue ? [NSSavePanel savePanel]
: [NSOpenPanel openPanel];
@@ -222,6 +218,11 @@ void FileChooser::showPlatformDialog (Array<File>& results,
[panel setDelegate: nil];
}
bool FileChooser::isPlatformDialogAvailable()
{
return true;
}
#else
//==============================================================================


+ 100
- 97
modules/juce_gui_basics/native/juce_mac_MainMenu.mm View File

@@ -23,43 +23,17 @@
==============================================================================
*/
class JuceMainMenuHandler;
} // (juce namespace)
using namespace juce;
#define JuceMenuCallback MakeObjCClassName(JuceMenuCallback)
#if defined (MAC_OS_X_VERSION_10_6) && MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_6
@interface JuceMenuCallback : NSObject <NSMenuDelegate>
#else
@interface JuceMenuCallback : NSObject
#endif
{
JuceMainMenuHandler* owner;
}
- (JuceMenuCallback*) initWithOwner: (JuceMainMenuHandler*) owner_;
- (void) dealloc;
- (void) menuItemInvoked: (id) menu;
- (void) menuNeedsUpdate: (NSMenu*) menu;
@end
namespace juce
{
//==============================================================================
class JuceMainMenuHandler : private MenuBarModel::Listener,
private DeletedAtShutdown
{
public:
//==============================================================================
JuceMainMenuHandler()
: currentModel (nullptr),
lastUpdateTime (0)
{
callback = [[JuceMenuCallback alloc] initWithOwner: this];
static JuceMenuCallbackClass cls;
callback = [cls.createInstance() performSelector: @selector (initWithOwner:)
withObject: (id) this];
}
~JuceMainMenuHandler()
@@ -234,17 +208,38 @@ public:
}
else if (iter.subMenu != nullptr)
{
NSMenuItem* item = [menuToAddTo addItemWithTitle: text
action: nil
keyEquivalent: nsEmptyString()];
if (iter.itemName.containsIgnoreCase ("recent"))
{
NSMenuItem* item = [menuToAddTo addItemWithTitle: NSLocalizedString (@"Open Recent", nil)
action: nil
keyEquivalent: @""];
[item setTag: iter.itemId];
[item setEnabled: iter.isEnabled];
NSMenu* openRecentMenu = [[[NSMenu alloc] initWithTitle: @"Open Recent"] autorelease];
[openRecentMenu performSelector: @selector(_setMenuName:)
withObject: @"NSRecentDocumentsMenu"];
[menuToAddTo setSubmenu: openRecentMenu forItem: item];
item = [openRecentMenu addItemWithTitle: NSLocalizedString(@"Clear Menu", nil)
action: @selector(clearRecentDocuments:)
keyEquivalent: @""];
[openRecentMenu update];
}
else
{
NSMenuItem* item = [menuToAddTo addItemWithTitle: text
action: nil
keyEquivalent: nsEmptyString()];
NSMenu* sub = createMenu (*iter.subMenu, iter.itemName, topLevelMenuId, topLevelIndex);
[sub setDelegate: nil];
[menuToAddTo setSubmenu: sub forItem: item];
[sub release];
[item setTag: iter.itemId];
[item setEnabled: iter.isEnabled];
NSMenu* sub = createMenu (*iter.subMenu, iter.itemName, topLevelMenuId, topLevelIndex);
[sub setDelegate: nil];
[menuToAddTo setSubmenu: sub forItem: item];
[sub release];
}
}
else
{
@@ -289,7 +284,7 @@ public:
MenuBarModel* currentModel;
uint32 lastUpdateTime;
JuceMenuCallback* callback;
NSObject* callback;
private:
//==============================================================================
@@ -301,7 +296,7 @@ private:
NSMenu* m = [[NSMenu alloc] initWithTitle: juceStringToNS (menuName)];
[m setAutoenablesItems: false];
[m setDelegate: callback];
[m setDelegate: (id<NSMenuDelegate>) callback];
for (PopupMenu::MenuItemIterator iter (menu); iter.next();)
addMenuItem (iter, m, topLevelMenuId, topLevelIndex);
@@ -385,8 +380,8 @@ private:
void messageCallback()
{
if (JuceMainMenuHandler::instance != nullptr)
JuceMainMenuHandler::instance->menuBarItemsChanged (nullptr);
if (instance != nullptr)
instance->menuBarItemsChanged (nullptr);
}
private:
@@ -402,8 +397,8 @@ private:
void messageCallback()
{
if (JuceMainMenuHandler::instance != nullptr)
JuceMainMenuHandler::instance->invokeDirectly (commandId, topLevelIndex);
if (instance != nullptr)
instance->invokeDirectly (commandId, topLevelIndex);
}
private:
@@ -411,74 +406,82 @@ private:
JUCE_DECLARE_NON_COPYABLE (AsyncCommandInvoker);
};
};
JuceMainMenuHandler* JuceMainMenuHandler::instance = nullptr;
} // (juce namespace)
//==============================================================================
struct JuceMenuCallbackClass : public ObjCClass <NSObject>
{
JuceMenuCallbackClass()
: ObjCClass ("JUCEMainMenu_")
{
addIvar<JuceMainMenuHandler*> ("owner");
//==============================================================================
@implementation JuceMenuCallback
addMethod (@selector (initWithOwner:), initWithOwner, "@@:^v");
addMethod (@selector (menuItemInvoked:), menuItemInvoked, "v@:@");
addMethod (@selector (menuNeedsUpdate:), menuNeedsUpdate, "v@:@");
- (JuceMenuCallback*) initWithOwner: (JuceMainMenuHandler*) owner_
{
[super init];
owner = owner_;
return self;
}
#if defined (MAC_OS_X_VERSION_10_6) && MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_6
addProtocol (@protocol (NSMenuDelegate));
#endif
- (void) dealloc
{
[super dealloc];
}
registerClass();
}
- (void) menuItemInvoked: (id) menu
{
NSMenuItem* item = (NSMenuItem*) menu;
private:
static id initWithOwner (id self, SEL, JuceMainMenuHandler* owner)
{
self = sendSuperclassMessage (self, @selector (init));
object_setInstanceVariable (self, "owner", owner);
return self;
}
if ([[item representedObject] isKindOfClass: [NSArray class]])
{
// If the menu is being triggered by a keypress, the OS will have picked it up before we had a chance to offer it to
// our own components, which may have wanted to intercept it. So, rather than dispatching directly, we'll feed it back
// into the focused component and let it trigger the menu item indirectly.
NSEvent* e = [NSApp currentEvent];
if ([e type] == NSKeyDown || [e type] == NSKeyUp)
static void menuItemInvoked (id self, SEL, id menu)
{
if (juce::Component::getCurrentlyFocusedComponent() != nullptr)
{
juce::NSViewComponentPeer* peer = dynamic_cast <juce::NSViewComponentPeer*> (juce::Component::getCurrentlyFocusedComponent()->getPeer());
JuceMainMenuHandler* const owner = getIvar<JuceMainMenuHandler*> (self, "owner");
if (peer != nullptr)
NSMenuItem* item = (NSMenuItem*) menu;
if ([[item representedObject] isKindOfClass: [NSArray class]])
{
// If the menu is being triggered by a keypress, the OS will have picked it up before we had a chance to offer it to
// our own components, which may have wanted to intercept it. So, rather than dispatching directly, we'll feed it back
// into the focused component and let it trigger the menu item indirectly.
NSEvent* e = [NSApp currentEvent];
if ([e type] == NSKeyDown || [e type] == NSKeyUp)
{
if ([e type] == NSKeyDown)
peer->redirectKeyDown (e);
else
peer->redirectKeyUp (e);
if (juce::Component::getCurrentlyFocusedComponent() != nullptr)
{
juce::NSViewComponentPeer* peer = dynamic_cast <juce::NSViewComponentPeer*> (juce::Component::getCurrentlyFocusedComponent()->getPeer());
return;
}
}
}
if (peer != nullptr)
{
if ([e type] == NSKeyDown)
peer->redirectKeyDown (e);
else
peer->redirectKeyUp (e);
NSArray* info = (NSArray*) [item representedObject];
return;
}
}
}
owner->invoke ((int) [item tag],
(ApplicationCommandManager*) (pointer_sized_int)
[((NSNumber*) [info objectAtIndex: 0]) unsignedLongLongValue],
(int) [((NSNumber*) [info objectAtIndex: 1]) intValue]);
}
}
NSArray* info = (NSArray*) [item representedObject];
- (void) menuNeedsUpdate: (NSMenu*) menu;
{
if (JuceMainMenuHandler::instance != nullptr)
JuceMainMenuHandler::instance->updateMenus (menu);
}
owner->invoke ((int) [item tag],
(ApplicationCommandManager*) (pointer_sized_int)
[((NSNumber*) [info objectAtIndex: 0]) unsignedLongLongValue],
(int) [((NSNumber*) [info objectAtIndex: 1]) intValue]);
}
}
@end
static void menuNeedsUpdate (id self, SEL, NSMenu* menu)
{
if (instance != nullptr)
instance->updateMenus (menu);
}
};
};
namespace juce
{
JuceMainMenuHandler* JuceMainMenuHandler::instance = nullptr;
//==============================================================================
namespace MainMenuHelpers


+ 1348
- 1413
modules/juce_gui_basics/native/juce_mac_NSViewComponentPeer.mm
File diff suppressed because it is too large
View File


+ 0
- 1
modules/juce_gui_extra/juce_gui_extra.cpp View File

@@ -106,7 +106,6 @@ namespace juce
//==============================================================================
#if JUCE_MAC || JUCE_IOS
#include "../juce_core/native/juce_osx_ObjCHelpers.h"
#include "../juce_core/native/juce_mac_ObjCSuffix.h"
#include "../juce_graphics/native/juce_mac_CoreGraphicsHelpers.h"
#if JUCE_MAC


+ 43
- 50
modules/juce_gui_extra/native/juce_mac_WebBrowserComponent.mm View File

@@ -23,66 +23,57 @@
==============================================================================
*/
} // (juce namespace)
class WebBrowserComponentInternal;
#if JUCE_MAC
#define DownloadClickDetector MakeObjCClassName(DownloadClickDetector)
@interface DownloadClickDetector : NSObject
struct DownloadClickDetectorClass : public ObjCClass <NSObject>
{
juce::WebBrowserComponent* ownerComponent;
}
- (DownloadClickDetector*) initWithWebBrowserOwner: (juce::WebBrowserComponent*) ownerComponent;
- (void) webView: (WebView*) webView decidePolicyForNavigationAction: (NSDictionary*) actionInformation
request: (NSURLRequest*) request
frame: (WebFrame*) frame
decisionListener: (id <WebPolicyDecisionListener>) listener;
- (void) webView: (WebView*) webView didFinishLoadForFrame: (WebFrame*) frame;
DownloadClickDetectorClass() : ObjCClass ("JUCEWebClickDetector_")
{
addIvar <WebBrowserComponent*> ("owner");
@end
addMethod (@selector (webView:decidePolicyForNavigationAction:request:frame:decisionListener:),
decidePolicyForNavigationAction, "v@:@@@@@");
addMethod (@selector (webView:didFinishLoadForFrame:), didFinishLoadForFrame, "v@:@@");
@implementation DownloadClickDetector
registerClass();
}
- (DownloadClickDetector*) initWithWebBrowserOwner: (juce::WebBrowserComponent*) ownerComponent_
{
[super init];
ownerComponent = ownerComponent_;
return self;
}
static void setOwner (id self, WebBrowserComponent* owner)
{
object_setInstanceVariable (self, "owner", owner);
}
- (void) webView: (WebView*) sender decidePolicyForNavigationAction: (NSDictionary*) actionInformation
request: (NSURLRequest*) request
frame: (WebFrame*) frame
decisionListener: (id <WebPolicyDecisionListener>) listener
{
(void) sender; (void) request; (void) frame;
private:
static WebBrowserComponent* getOwner (id self)
{
return getIvar<WebBrowserComponent*> (self, "owner");
}
NSURL* url = [actionInformation valueForKey: nsStringLiteral ("WebActionOriginalURLKey")];
static void decidePolicyForNavigationAction (id self, SEL, WebView*, NSDictionary* actionInformation,
NSURLRequest*, WebFrame*, id <WebPolicyDecisionListener> listener)
{
NSURL* url = [actionInformation valueForKey: nsStringLiteral ("WebActionOriginalURLKey")];
if (ownerComponent->pageAboutToLoad (nsStringToJuce ([url absoluteString])))
[listener use];
else
[listener ignore];
}
if (getOwner (self)->pageAboutToLoad (nsStringToJuce ([url absoluteString])))
[listener use];
else
[listener ignore];
}
- (void) webView: (WebView*) sender didFinishLoadForFrame: (WebFrame*) frame
{
if ([frame isEqual: [sender mainFrame]])
static void didFinishLoadForFrame (id self, SEL, WebView* sender, WebFrame* frame)
{
NSURL* url = [[[frame dataSource] request] URL];
ownerComponent->pageFinishedLoading (nsStringToJuce ([url absoluteString]));
if ([frame isEqual: [sender mainFrame]])
{
NSURL* url = [[[frame dataSource] request] URL];
getOwner (self)->pageFinishedLoading (nsStringToJuce ([url absoluteString]));
}
}
}
@end
};
#else
} // (juce namespace)
//==============================================================================
@interface WebViewTapDetector : NSObject <UIGestureRecognizerDelegate>
{
@@ -126,10 +117,10 @@ class WebBrowserComponentInternal;
return ownerComponent->pageAboutToLoad (nsStringToJuce (request.URL.absoluteString));
}
@end
#endif
namespace juce
{
namespace juce {
#endif
//==============================================================================
class WebBrowserComponentInternal
@@ -148,7 +139,9 @@ public:
groupName: nsEmptyString()];
setView (webView);
clickListener = [[DownloadClickDetector alloc] initWithWebBrowserOwner: owner];
static DownloadClickDetectorClass cls;
clickListener = [cls.createInstance() init];
DownloadClickDetectorClass::setOwner (clickListener, owner);
[webView setPolicyDelegate: clickListener];
[webView setFrameLoadDelegate: clickListener];
#else
@@ -238,7 +231,7 @@ public:
private:
#if JUCE_MAC
WebView* webView;
DownloadClickDetector* clickListener;
NSObject* clickListener;
#else
UIWebView* webView;
WebViewTapDetector* tapDetector;


+ 0
- 1
modules/juce_opengl/juce_opengl.cpp View File

@@ -171,7 +171,6 @@ static void clearGLError()
//==============================================================================
#if JUCE_MAC || JUCE_IOS
#include "../juce_core/native/juce_osx_ObjCHelpers.h"
#include "../juce_core/native/juce_mac_ObjCSuffix.h"
#include "../juce_graphics/native/juce_mac_CoreGraphicsHelpers.h"
#if JUCE_MAC


+ 65
- 71
modules/juce_opengl/native/juce_OpenGL_osx.h View File

@@ -23,92 +23,78 @@
==============================================================================
*/
} // (juce namespace)
#define ThreadSafeNSOpenGLView MakeObjCClassName(ThreadSafeNSOpenGLView)
//==============================================================================
@interface ThreadSafeNSOpenGLView : NSOpenGLView
struct ThreadSafeNSOpenGLViewClass : public ObjCClass <NSOpenGLView>
{
juce::CriticalSection* contextLock;
bool needsUpdate;
}
ThreadSafeNSOpenGLViewClass() : ObjCClass ("JUCEGLView_")
{
addIvar <CriticalSection*> ("lock");
addIvar <BOOL> ("needsUpdate");
- (id) initWithFrame: (NSRect) frameRect pixelFormat: (NSOpenGLPixelFormat*) format;
- (bool) makeActive;
- (void) reshape;
- (void) rightMouseDown: (NSEvent*) ev;
- (void) rightMouseUp: (NSEvent*) ev;
@end
addMethod (@selector (update), update, "v@:");
addMethod (@selector (reshape), reshape, "v@:");
addMethod (@selector (_surfaceNeedsUpdate:), surfaceNeedsUpdate, "v@:@");
addMethod (@selector (rightMouseDown:), rightMouseDown, "v@:@");
addMethod (@selector (rightMouseUp:), rightMouseUp, "v@:@");
@implementation ThreadSafeNSOpenGLView
registerClass();
}
- (id) initWithFrame: (NSRect) frameRect
pixelFormat: (NSOpenGLPixelFormat*) format
{
contextLock = new juce::CriticalSection();
self = [super initWithFrame: frameRect pixelFormat: format];
needsUpdate = true;
static void init (id self)
{
object_setInstanceVariable (self, "lock", new CriticalSection());
setNeedsUpdate (self, YES);
}
if (self != nil)
[[NSNotificationCenter defaultCenter] addObserver: self
selector: @selector (_surfaceNeedsUpdate:)
name: NSViewGlobalFrameDidChangeNotification
object: self];
return self;
}
static bool makeActive (id self)
{
const ScopedLock sl (*getLock (self));
- (void) dealloc
{
[[NSNotificationCenter defaultCenter] removeObserver: self];
delete contextLock;
[super dealloc];
}
if ([(NSOpenGLView*) self openGLContext] == nil)
return false;
- (bool) makeActive
{
const juce::ScopedLock sl (*contextLock);
[[(NSOpenGLView*) self openGLContext] makeCurrentContext];
if ([self openGLContext] == nil)
return false;
if (getIvar<BOOL> (self, "needsUpdate"))
{
sendSuperclassMessage (self, @selector (update));
setNeedsUpdate (self, NO);
}
[[self openGLContext] makeCurrentContext];
return true;
}
if (needsUpdate)
private:
static CriticalSection* getLock (id self)
{
[super update];
needsUpdate = false;
return getIvar<CriticalSection*> (self, "lock");
}
return true;
}
- (void) _surfaceNeedsUpdate: (NSNotification*) notification
{
(void) notification;
const juce::ScopedLock sl (*contextLock);
needsUpdate = true;
}
static void setNeedsUpdate (id self, BOOL b)
{
object_setInstanceVariable (self, "needsUpdate", (void*) b);
}
- (void) update
{
const juce::ScopedLock sl (*contextLock);
needsUpdate = true;
}
static void setNeedsUpdateLocked (id self, BOOL b)
{
const ScopedLock sl (*getLock (self));
setNeedsUpdate (self, b);
}
- (void) reshape
{
const juce::ScopedLock sl (*contextLock);
needsUpdate = true;
}
static void dealloc (id self, SEL)
{
delete getLock (self);
sendSuperclassMessage (self, @selector (dealloc));
}
- (void) rightMouseDown: (NSEvent*) ev { [[self superview] rightMouseDown: ev]; }
- (void) rightMouseUp: (NSEvent*) ev { [[self superview] rightMouseUp: ev]; }
static void surfaceNeedsUpdate (id self, SEL, NSNotification*) { setNeedsUpdateLocked (self, YES); }
static void update (id self, SEL) { setNeedsUpdateLocked (self, YES); }
static void reshape (id self, SEL) { setNeedsUpdateLocked (self, YES); }
@end
static void rightMouseDown (id self, SEL, NSEvent* ev) { [[(NSOpenGLView*) self superview] rightMouseDown: ev]; }
static void rightMouseUp (id self, SEL, NSEvent* ev) { [[(NSOpenGLView*) self superview] rightMouseUp: ev]; }
};
namespace juce
{
//==============================================================================
class OpenGLContext::NativeContext
@@ -137,8 +123,15 @@ public:
NSOpenGLPixelFormat* format = [[NSOpenGLPixelFormat alloc] initWithAttributes: attribs];
view = [[ThreadSafeNSOpenGLView alloc] initWithFrame: NSMakeRect (0, 0, 100.0f, 100.0f)
pixelFormat: format];
static ThreadSafeNSOpenGLViewClass cls;
view = [cls.createInstance() initWithFrame: NSMakeRect (0, 0, 100.0f, 100.0f)
pixelFormat: format];
ThreadSafeNSOpenGLViewClass::init (view);
[[NSNotificationCenter defaultCenter] addObserver: view
selector: @selector (_surfaceNeedsUpdate:)
name: NSViewGlobalFrameDidChangeNotification
object: view];
renderContext = [[[NSOpenGLContext alloc] initWithFormat: format
shareContext: (NSOpenGLContext*) contextToShareWith] autorelease];
@@ -153,6 +146,7 @@ public:
~NativeContext()
{
[[NSNotificationCenter defaultCenter] removeObserver: view];
[renderContext clearDrawable];
[renderContext setView: nil];
[view setOpenGLContext: nil];
@@ -173,7 +167,7 @@ public:
if ([renderContext view] != view)
[renderContext setView: view];
[view makeActive];
ThreadSafeNSOpenGLViewClass::makeActive (view);
return true;
}
@@ -228,7 +222,7 @@ public:
private:
NSOpenGLContext* renderContext;
ThreadSafeNSOpenGLView* view;
NSOpenGLView* view;
ReferenceCountedObjectPtr<ReferenceCountedObject> viewAttachment;
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (NativeContext);


+ 0
- 1
modules/juce_video/juce_video.cpp View File

@@ -108,7 +108,6 @@ namespace juce
#if JUCE_MAC || JUCE_IOS
#include "../juce_core/native/juce_osx_ObjCHelpers.h"
#include "../juce_core/native/juce_mac_ObjCSuffix.h"
#if JUCE_USE_CAMERA
#include "native/juce_mac_CameraDevice.mm"


+ 93
- 112
modules/juce_video/native/juce_mac_CameraDevice.mm View File

@@ -27,51 +27,21 @@
#error "On the Mac, cameras use Quicktime, so if you turn on JUCE_USE_CAMERA, you also need to enable JUCE_QUICKTIME"
#endif
//==============================================================================
#define QTCaptureCallbackDelegate MakeObjCClassName(QTCaptureCallbackDelegate)
class QTCameraDeviceInteral;
} // (juce namespace)
@interface QTCaptureCallbackDelegate : NSObject
{
@public
CameraDevice* owner;
QTCameraDeviceInteral* internal;
int64 firstPresentationTime;
int64 averageTimeOffset;
}
- (QTCaptureCallbackDelegate*) initWithOwner: (CameraDevice*) owner internalDev: (QTCameraDeviceInteral*) d;
- (void) dealloc;
- (void) captureOutput: (QTCaptureOutput*) captureOutput
didOutputVideoFrame: (CVImageBufferRef) videoFrame
withSampleBuffer: (QTSampleBuffer*) sampleBuffer
fromConnection: (QTCaptureConnection*) connection;
- (void) captureOutput: (QTCaptureFileOutput*) captureOutput
didOutputSampleBuffer: (QTSampleBuffer*) sampleBuffer
fromConnection: (QTCaptureConnection*) connection;
@end
namespace juce
{
extern Image juce_createImageFromCIImage (CIImage* im, int w, int h);
//==============================================================================
class QTCameraDeviceInteral
class QTCameraDeviceInternal
{
public:
QTCameraDeviceInteral (CameraDevice* owner, const int index)
QTCameraDeviceInternal (CameraDevice* owner, const int index)
: input (nil),
audioDevice (nil),
audioInput (nil),
session (nil),
fileOutput (nil),
imageOutput (nil)
imageOutput (nil),
firstPresentationTime (0),
averageTimeOffset (0)
{
JUCE_AUTORELEASEPOOL
@@ -79,8 +49,10 @@ public:
NSArray* devs = [QTCaptureDevice inputDevicesWithMediaType: QTMediaTypeVideo];
device = (QTCaptureDevice*) [devs objectAtIndex: index];
callbackDelegate = [[QTCaptureCallbackDelegate alloc] initWithOwner: owner
internalDev: this];
static DelegateClass cls;
callbackDelegate = [cls.createInstance() init];
DelegateClass::setOwner (callbackDelegate, this);
NSError* err = nil;
[device retain];
@@ -112,7 +84,7 @@ public:
DBG (openingError);
}
~QTCameraDeviceInteral()
~QTCameraDeviceInternal()
{
[session stopRunning];
[session removeOutput: imageOutput];
@@ -194,6 +166,33 @@ public:
}
}
void captureBuffer (QTSampleBuffer* sampleBuffer)
{
const Time now (Time::getCurrentTime());
#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_5
NSNumber* hosttime = (NSNumber*) [sampleBuffer attributeForKey: QTSampleBufferHostTimeAttribute];
#else
NSNumber* hosttime = (NSNumber*) [sampleBuffer attributeForKey: nsStringLiteral ("hostTime")];
#endif
int64 presentationTime = (hosttime != nil)
? ((int64) AudioConvertHostTimeToNanos ([hosttime unsignedLongLongValue]) / 1000000 + 40)
: (([sampleBuffer presentationTime].timeValue * 1000) / [sampleBuffer presentationTime].timeScale + 50);
const int64 timeDiff = now.toMilliseconds() - presentationTime;
if (firstPresentationTime == 0)
{
firstPresentationTime = presentationTime;
averageTimeOffset = timeDiff;
}
else
{
averageTimeOffset = (averageTimeOffset * 120 + timeDiff * 8) / 128;
}
}
QTCaptureDevice* device;
QTCaptureDeviceInput* input;
QTCaptureDevice* audioDevice;
@@ -201,87 +200,69 @@ public:
QTCaptureSession* session;
QTCaptureMovieFileOutput* fileOutput;
QTCaptureDecompressedVideoOutput* imageOutput;
QTCaptureCallbackDelegate* callbackDelegate;
NSObject* callbackDelegate;
String openingError;
int64 firstPresentationTime;
int64 averageTimeOffset;
Array<CameraDevice::Listener*> listeners;
CriticalSection listenerLock;
};
} // (juce namespace)
@implementation QTCaptureCallbackDelegate
- (QTCaptureCallbackDelegate*) initWithOwner: (CameraDevice*) owner_
internalDev: (QTCameraDeviceInteral*) d
{
[super init];
owner = owner_;
internal = d;
firstPresentationTime = 0;
averageTimeOffset = 0;
return self;
}
- (void) dealloc
{
[super dealloc];
}
- (void) captureOutput: (QTCaptureOutput*) captureOutput
didOutputVideoFrame: (CVImageBufferRef) videoFrame
withSampleBuffer: (QTSampleBuffer*) sampleBuffer
fromConnection: (QTCaptureConnection*) connection
{
if (internal->listeners.size() > 0)
private:
//==============================================================================
struct DelegateClass : public ObjCClass <NSObject>
{
JUCE_AUTORELEASEPOOL
DelegateClass() : ObjCClass ("JUCEAppDelegate_")
{
addIvar<QTCameraDeviceInternal*> ("owner");
internal->callListeners ([CIImage imageWithCVImageBuffer: videoFrame],
CVPixelBufferGetWidth (videoFrame),
CVPixelBufferGetHeight (videoFrame));
}
}
addMethod (@selector (captureOutput:didOutputVideoFrame:withSampleBuffer:fromConnection:),
didOutputVideoFrame, "v@:@", @encode (CVImageBufferRef), "@@");
addMethod (@selector (captureOutput:didOutputSampleBuffer:fromConnection:),
didOutputVideoFrame, "v@:@@@");
- (void) captureOutput: (QTCaptureFileOutput*) captureOutput
didOutputSampleBuffer: (QTSampleBuffer*) sampleBuffer
fromConnection: (QTCaptureConnection*) connection
{
const Time now (Time::getCurrentTime());
registerClass();
}
#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_5
NSNumber* hosttime = (NSNumber*) [sampleBuffer attributeForKey: QTSampleBufferHostTimeAttribute];
#else
NSNumber* hosttime = (NSNumber*) [sampleBuffer attributeForKey: nsStringLiteral ("hostTime")];
#endif
static void setOwner (id self, QTCameraDeviceInternal* owner)
{
object_setInstanceVariable (self, "owner", owner);
}
int64 presentationTime = (hosttime != nil)
? ((int64) AudioConvertHostTimeToNanos ([hosttime unsignedLongLongValue]) / 1000000 + 40)
: (([sampleBuffer presentationTime].timeValue * 1000) / [sampleBuffer presentationTime].timeScale + 50);
private:
static QTCameraDeviceInternal* getOwner (id self)
{
return getIvar<QTCameraDeviceInternal*> (self, "owner");
}
const int64 timeDiff = now.toMilliseconds() - presentationTime;
static void didOutputVideoFrame (id self, SEL, QTCaptureOutput* captureOutput,
CVImageBufferRef videoFrame, QTSampleBuffer* sampleBuffer,
QTCaptureConnection* connection)
{
QTCameraDeviceInternal* const internal = getOwner (self);
if (firstPresentationTime == 0)
{
firstPresentationTime = presentationTime;
averageTimeOffset = timeDiff;
}
else
{
averageTimeOffset = (averageTimeOffset * 120 + timeDiff * 8) / 128;
}
}
if (internal->listeners.size() > 0)
{
JUCE_AUTORELEASEPOOL
@end
internal->callListeners ([CIImage imageWithCVImageBuffer: videoFrame],
CVPixelBufferGetWidth (videoFrame),
CVPixelBufferGetHeight (videoFrame));
}
}
namespace juce
{
static void didOutputSampleBuffer (id self, SEL, QTCaptureFileOutput*, QTSampleBuffer* sampleBuffer, QTCaptureConnection*)
{
getOwner (self)->captureBuffer (sampleBuffer);
}
};
};
//==============================================================================
class QTCaptureViewerComp : public NSViewComponent
{
public:
QTCaptureViewerComp (CameraDevice* const cameraDevice, QTCameraDeviceInteral* const internal)
QTCaptureViewerComp (CameraDevice* const cameraDevice, QTCameraDeviceInternal* const internal)
{
JUCE_AUTORELEASEPOOL
captureView = [[QTCaptureView alloc] init];
@@ -306,19 +287,19 @@ CameraDevice::CameraDevice (const String& name_, int index)
: name (name_)
{
isRecording = false;
internal = new QTCameraDeviceInteral (this, index);
internal = new QTCameraDeviceInternal (this, index);
}
CameraDevice::~CameraDevice()
{
stopRecording();
delete static_cast <QTCameraDeviceInteral*> (internal);
delete static_cast <QTCameraDeviceInternal*> (internal);
internal = nullptr;
}
Component* CameraDevice::createViewerComponent()
{
return new QTCaptureViewerComp (this, static_cast <QTCameraDeviceInteral*> (internal));
return new QTCaptureViewerComp (this, static_cast <QTCameraDeviceInternal*> (internal));
}
String CameraDevice::getFileExtension()
@@ -330,8 +311,8 @@ void CameraDevice::startRecordingToFile (const File& file, int quality)
{
stopRecording();
QTCameraDeviceInteral* const d = static_cast <QTCameraDeviceInteral*> (internal);
d->callbackDelegate->firstPresentationTime = 0;
QTCameraDeviceInternal* const d = static_cast <QTCameraDeviceInternal*> (internal);
d->firstPresentationTime = 0;
file.deleteFile();
// In some versions of QT (e.g. on 10.5), if you record video without audio, the speed comes
@@ -367,9 +348,9 @@ void CameraDevice::startRecordingToFile (const File& file, int quality)
Time CameraDevice::getTimeOfFirstRecordedFrame() const
{
QTCameraDeviceInteral* const d = static_cast <QTCameraDeviceInteral*> (internal);
if (d->callbackDelegate->firstPresentationTime != 0)
return Time (d->callbackDelegate->firstPresentationTime + d->callbackDelegate->averageTimeOffset);
QTCameraDeviceInternal* const d = static_cast <QTCameraDeviceInternal*> (internal);
if (d->firstPresentationTime != 0)
return Time (d->firstPresentationTime + d->averageTimeOffset);
return Time();
}
@@ -378,7 +359,7 @@ void CameraDevice::stopRecording()
{
if (isRecording)
{
static_cast <QTCameraDeviceInteral*> (internal)->resetFile();
static_cast <QTCameraDeviceInternal*> (internal)->resetFile();
isRecording = false;
}
}
@@ -386,13 +367,13 @@ void CameraDevice::stopRecording()
void CameraDevice::addListener (Listener* listenerToAdd)
{
if (listenerToAdd != nullptr)
static_cast <QTCameraDeviceInteral*> (internal)->addListener (listenerToAdd);
static_cast <QTCameraDeviceInternal*> (internal)->addListener (listenerToAdd);
}
void CameraDevice::removeListener (Listener* listenerToRemove)
{
if (listenerToRemove != nullptr)
static_cast <QTCameraDeviceInteral*> (internal)->removeListener (listenerToRemove);
static_cast <QTCameraDeviceInternal*> (internal)->removeListener (listenerToRemove);
}
//==============================================================================
@@ -418,7 +399,7 @@ CameraDevice* CameraDevice::openDevice (int index,
{
ScopedPointer <CameraDevice> d (new CameraDevice (getAvailableDevices() [index], index));
if (static_cast <QTCameraDeviceInteral*> (d->internal)->openingError.isEmpty())
if (static_cast <QTCameraDeviceInternal*> (d->internal)->openingError.isEmpty())
return d.release();
return nullptr;


+ 23
- 39
modules/juce_video/native/juce_mac_QuickTimeMovieComponent.mm View File

@@ -25,49 +25,31 @@
#if JUCE_QUICKTIME
} // (juce namespace)
//==============================================================================
#define NonInterceptingQTMovieView MakeObjCClassName(NonInterceptingQTMovieView)
@interface NonInterceptingQTMovieView : QTMovieView
{
}
- (id) initWithFrame: (NSRect) frame;
- (BOOL) acceptsFirstMouse: (NSEvent*) theEvent;
- (NSView*) hitTest: (NSPoint) p;
@end
@implementation NonInterceptingQTMovieView
- (id) initWithFrame: (NSRect) frame
{
self = [super initWithFrame: frame];
[self setNextResponder: [self superview]];
return self;
}
- (void) dealloc
struct NonInterceptingQTMovieViewClass : public ObjCClass <QTMovieView>
{
[super dealloc];
}
NonInterceptingQTMovieViewClass() : ObjCClass ("JUCEQTMovieView_")
{
addMethod (@selector (hitTest:), hitTest, "@@:", @encode (NSPoint));
addMethod (@selector (acceptsFirstMouse:), acceptsFirstMouse, "c@:@");
- (NSView*) hitTest: (NSPoint) point
{
return [self isControllerVisible] ? [super hitTest: point] : nil;
}
registerClass();
}
- (BOOL) acceptsFirstMouse: (NSEvent*) theEvent
{
return YES;
}
private:
static NSView* hitTest (id self, SEL, NSPoint point)
{
if (! [(QTMovieView*) self isControllerVisible])
return nil;
@end
objc_super s = { self, [QTMovieView class] };
return objc_msgSendSuper (&s, @selector (hitTest:), point);
}
namespace juce
{
static BOOL acceptsFirstMouse (id, SEL, NSEvent*)
{
return YES;
}
};
//==============================================================================
#define theMovie (static_cast <QTMovie*> (movie))
@@ -79,8 +61,10 @@ QuickTimeMovieComponent::QuickTimeMovieComponent()
setOpaque (true);
setVisible (true);
QTMovieView* view = [[NonInterceptingQTMovieView alloc] initWithFrame: NSMakeRect (0, 0, 100.0f, 100.0f)];
static NonInterceptingQTMovieViewClass cls;
QTMovieView* view = [cls.createInstance() initWithFrame: NSMakeRect (0, 0, 100.0f, 100.0f)];
setView (view);
[view setNextResponder: [view superview]];
[view setWantsLayer: YES]; // prevents the view failing to redraw correctly when paused.
[view release];
}


Loading…
Cancel
Save