Rev. | 4 |
---|---|
大小 | 10,308 字节 |
时间 | 2011-09-03 15:22:57 |
作者 | toshinagata1964 |
Log Message | initial import |
//
// AUViewWindowController.m
// Alchemusica
//
// Created by Toshi Nagata on 10/06/26.
// Copyright 2010-2011 Toshi Nagata. All rights reserved.
//
/*
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation version 2 of the License.
This program 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.
*/
#import "AUViewWindowController.h"
#import <CoreAudioKit/CoreAudioKit.h>
#import <AudioUnit/AUCocoaUIView.h>
// Carbon event handler.
static OSStatus
sWindowEventHandler(EventHandlerCallRef myHandler, EventRef theEvent, void* userData)
{
AUViewWindowController* cont = (AUViewWindowController *)userData;
UInt32 eventKind = GetEventKind(theEvent);
OSStatus ret;
if (cont->isProcessingCarbonEventHandler)
return eventNotHandledErr;
cont->isProcessingCarbonEventHandler = YES;
ret = eventNotHandledErr;
switch (eventKind) {
case kEventWindowActivated:
[[cont window] makeKeyAndOrderFront: cont];
ret = noErr;
break;
case kEventWindowClose:
[cont close];
[[[NSApp orderedWindows] objectAtIndex: 0] makeKeyWindow];
ret = noErr;
break;
}
cont->isProcessingCarbonEventHandler = NO;
return ret;
}
@implementation AUViewWindowController
static NSMutableArray *sAUViewWindowControllers = nil;
+ (AUViewWindowController *)windowControllerForAudioUnit:(AudioUnit)unit forceGeneric:(BOOL)forceGeneric delegate:(id)delegate
{
int i, n;
id cont;
if (sAUViewWindowControllers == nil) {
sAUViewWindowControllers = [[NSMutableArray alloc] init];
}
n = [sAUViewWindowControllers count];
for (i = 0; i < n; i++) {
cont = [sAUViewWindowControllers objectAtIndex: i];
if ([cont audioUnit] == unit) {
[[cont window] makeKeyAndOrderFront: nil];
return cont;
}
}
cont = [[[AUViewWindowController alloc] initWithAudioUnit:unit forceGeneric:forceGeneric delegate:delegate] autorelease];
if (cont != nil) {
[sAUViewWindowControllers addObject: cont];
[[cont window] makeKeyAndOrderFront: nil];
}
return cont;
}
- (void)editWindowClosed
{
// Any additional cocoa cleanup can be added here.
[_delegate auViewWindowWillClose: self];
}
- (BOOL)error:(NSString *)errString status:(OSStatus)err
{
NSString *errorString = [NSString stringWithFormat:@"%@ failed with error code %i: %s", errString, (int)err, GetMacOSStatusCommentString(err)];
NSLog(@"%@", errorString);
return NO;
}
- (WindowRef)carbonWindowRef
{
return carbonWindowRef;
}
- (AudioUnit)audioUnit
{
return audioUnit;
}
/*
- (BOOL)installWindowCloseHandler
{
EventTypeSpec eventList[] = {{kEventClassWindow, kEventWindowClose}};
EventHandlerUPP handlerUPP = NewEventHandlerUPP(sWindowEventHandler);
OSStatus err = InstallWindowEventHandler(carbonWindowRef, handlerUPP, 1, eventList, self, NULL);
if (err != noErr)
return [self error: @"Installation of WindowClose handler" status: err];
return YES;
}
*/
- (void)findUIViewComponentDescription:(BOOL)forceGeneric
{
OSStatus err;
UInt32 propSize;
ComponentDescription *cds;
// set up to use generic UI component
viewCD.componentType = kAudioUnitCarbonViewComponentType;
viewCD.componentSubType = 'gnrc';
viewCD.componentManufacturer = 'appl';
viewCD.componentFlags = 0;
viewCD.componentFlagsMask = 0;
if (forceGeneric)
return;
err = AudioUnitGetPropertyInfo(audioUnit, kAudioUnitProperty_GetUIComponentList, kAudioUnitScope_Global, 0, &propSize, NULL);
if (err != noErr) {
NSLog(@"Error setting up carbon interface, falling back to generic interface.");
return;
}
cds = malloc(propSize);
err = AudioUnitGetProperty(audioUnit, kAudioUnitProperty_GetUIComponentList, kAudioUnitScope_Global, 0, cds, &propSize);
if (err == noErr)
viewCD = cds[0]; // Pick the first one
free(cds);
}
+ (BOOL)pluginClassIsValid:(Class)pluginClass
{
if ([pluginClass conformsToProtocol: @protocol(AUCocoaUIBase)]) {
if ([pluginClass instancesRespondToSelector: @selector(interfaceVersion)] &&
[pluginClass instancesRespondToSelector: @selector(uiViewForAudioUnit:withSize:)]) {
return YES;
}
}
return NO;
}
- (BOOL)hasCocoaView
{
UInt32 dataSize = 0;
Boolean isWritable = 0;
OSStatus err = AudioUnitGetPropertyInfo(audioUnit, kAudioUnitProperty_CocoaUI, kAudioUnitScope_Global, 0, &dataSize, &isWritable);
return (err == noErr && dataSize > 0);
}
- (NSView *)getCocoaView
{
NSView *theView = nil;
UInt32 dataSize = 0;
Boolean isWritable = 0;
OSStatus err = AudioUnitGetPropertyInfo(audioUnit, kAudioUnitProperty_CocoaUI, kAudioUnitScope_Global, 0, &dataSize, &isWritable);
if (err != noErr) {
[self error: @"Getting cocoa view info" status: err];
return nil;
}
AudioUnitCocoaViewInfo *cvi = malloc(dataSize);
err = AudioUnitGetProperty(audioUnit, kAudioUnitProperty_CocoaUI, kAudioUnitScope_Global, 0, cvi, &dataSize);
unsigned numberOfClasses = (dataSize - sizeof(CFURLRef)) / sizeof(CFStringRef);
NSString *viewClassName = (NSString *)(cvi->mCocoaAUViewClass[0]);
NSString *path = [(NSURL *)(cvi->mCocoaAUViewBundleLocation) path];
NSBundle *viewBundle = [NSBundle bundleWithPath:path];
Class viewClass = [viewBundle classNamed:viewClassName];
if ([AUViewWindowController pluginClassIsValid:viewClass]) {
id factory = [[[viewClass alloc] init] autorelease];
theView = [factory uiViewForAudioUnit:audioUnit withSize:defaultViewSize];
}
if (cvi != NULL) {
int i;
for (i = 0; i < numberOfClasses; i++)
CFRelease(cvi->mCocoaAUViewClass[i]);
CFRelease(cvi->mCocoaAUViewBundleLocation);
free(cvi);
}
return theView;
}
-(NSWindow *)createCarbonWindow
{
OSStatus res;
Component editComponent = FindNextComponent(NULL, &viewCD);
OpenAComponent(editComponent, &auCarbonView);
if (auCarbonView == nil)
[NSException raise:NSGenericException format:@"Could not open audio unit editor component"];
Rect bounds = { 100, 100, 100, 100 }; // Generic resized later
// Load carbon window from the nib
{
IBNibRef nibRef;
res = CreateNibReference(CFSTR("AUCarbonWindow"), &nibRef);
if (res != noErr) {
[self error: @"Cannot load nib for carbon window" status: res];
return nil;
}
res = CreateWindowFromNib(nibRef, CFSTR("Window"), &carbonWindowRef);
if (res != noErr) {
[self error: @"Cannot load carbon window from nib" status: res];
return nil;
}
DisposeNibReference(nibRef);
}
/* res = CreateNewWindow(kDocumentWindowClass, kWindowCloseBoxAttribute | kWindowCollapseBoxAttribute | kWindowStandardHandlerAttribute | kWindowCompositingAttribute, &bounds, &carbonWindowRef);
if (res != noErr) {
[self error:@"Creating new carbon window" status:res];
return nil;
} */
ControlRef rootControl;
res = GetRootControl(carbonWindowRef, &rootControl);
if (rootControl == nil) {
[self error:@"Getting root control of carbon window" status:res];
return nil;
}
ControlRef viewPane;
Float32Point loc = { 0.0, 0.0 };
Float32Point size = { 0.0, 0.0 } ;
AudioUnitCarbonViewCreate(auCarbonView, audioUnit, carbonWindowRef,
rootControl, &loc, &size, &viewPane);
// resize and move window
GetControlBounds(viewPane, &bounds);
size.x = bounds.right - bounds.left;
size.y = bounds.bottom - bounds.top;
SizeWindow(carbonWindowRef, (short) (size.x + 0.5), (short) (size.y + 0.5), true);
RepositionWindow(carbonWindowRef, NULL, kWindowCenterOnMainScreen);
// Install event handler
{
EventTypeSpec eventList[] = {
{kEventClassWindow, kEventWindowActivated},
// {kEventClassWindow, kEventWindowGetClickActivation},
{kEventClassWindow, kEventWindowClose}
};
EventHandlerUPP handlerUPP = NewEventHandlerUPP(sWindowEventHandler);
res = InstallWindowEventHandler(carbonWindowRef, handlerUPP, sizeof(eventList) / sizeof(eventList[0]), eventList, self, NULL);
if (res != noErr) {
[self error: @"Installation of WindowClose handler" status: res];
return nil;
}
}
return [[[NSWindow alloc] initWithWindowRef: carbonWindowRef] autorelease];
}
- (NSWindow *)createCocoaWindow
{
if ([self hasCocoaView]) {
NSView *res = [self getCocoaView];
if (res) {
NSWindow *cocoaWindow = [[[NSWindow alloc] initWithContentRect: NSMakeRect(100, 400, [res frame].size.width, [res frame].size.height) styleMask: NSTitledWindowMask | NSClosableWindowMask | NSMiniaturizableWindowMask | NSResizableWindowMask backing:NSBackingStoreBuffered defer:NO] autorelease];
[cocoaWindow setContentView:res];
return cocoaWindow;
}
}
return nil;
}
/*- (void)showWindow:(id)sender
{
if (cocoaWindow)
[super showWindow:sender];
else if (carbonWindowRef)
SelectWindow(carbonWindowRef);
}
*/
- (void)close
{
[[self window] orderOut: self];
[super close];
/* if (cocoaWindow) {
[super close];
cocoaWindow = nil;
}
else */
if (carbonWindowRef) {
// [carbonWindow release];
// carbonWindow = nil;
DisposeWindow(carbonWindowRef);
carbonWindowRef = 0;
}
[self editWindowClosed];
[sAUViewWindowControllers removeObject: self];
}
- (id)initWithAudioUnit:(AudioUnit)unit forceGeneric:(BOOL)forceGeneric delegate:(id)delegate
{
NSWindow *aWindow;
self = [super initWithWindowNibName: @"AUViewWindow"];
if (self == nil)
return nil;
audioUnit = unit;
_delegate = delegate;
defaultViewSize = NSMakeSize(400, 300);
// We need to chack this in showWindow:
carbonWindowRef = 0;
// Try to create carbon view first
[self findUIViewComponentDescription: forceGeneric];
if ((aWindow = [self createCarbonWindow]) != nil) {
[self setWindow: aWindow];
if ([aWindow delegate] == nil)
[aWindow setDelegate: self];
} else if ([self hasCocoaView] && (aWindow = [self createCocoaWindow]) != nil) {
[self setWindow: aWindow];
if ([aWindow delegate] == nil)
[aWindow setDelegate: self];
} else {
[self release];
return nil;
}
[[self window] makeKeyAndOrderFront: nil];
return self;
}
- (void)dealloc
{
[self setWindow:nil];
if (auCarbonView)
CloseComponent(auCarbonView);
/* if (carbonWindow)
[carbonWindow release]; */
if (carbonWindowRef)
DisposeWindow(carbonWindowRef);
[super dealloc];
}
@end