Develop and Download Open Source Software

Browse Subversion Repository

Contents of /trunk/Classes/AUViewWindowController.m

Parent Directory Parent Directory | Revision Log Revision Log


Revision 146 - (show annotations) (download)
Sun Dec 17 04:05:28 2017 UTC (6 years, 3 months ago) by toshinagata1964
File size: 10807 byte(s)
Xcode project is updated so that ppc/i386 universal binary can be built (as before)
1 //
2 // AUViewWindowController.m
3 // Alchemusica
4 //
5 // Created by Toshi Nagata on 10/06/26.
6 // Copyright 2010-2016 Toshi Nagata. All rights reserved.
7 //
8 /*
9 This program is free software; you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation version 2 of the License.
12
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
17 */
18
19 #import "AUViewWindowController.h"
20
21 #if USE_CARBON
22 #import <Carbon/Carbon.h>
23 #endif
24
25 #import <CoreAudioKit/CoreAudioKit.h>
26 #import <AudioUnit/AUCocoaUIView.h>
27
28 #if USE_CARBON
29 // Carbon event handler.
30 static OSStatus
31 sWindowEventHandler(EventHandlerCallRef myHandler, EventRef theEvent, void* userData)
32 {
33 AUViewWindowController* cont = (AUViewWindowController *)userData;
34 UInt32 eventKind = GetEventKind(theEvent);
35 OSStatus ret;
36 if (cont->isProcessingCarbonEventHandler)
37 return eventNotHandledErr;
38 cont->isProcessingCarbonEventHandler = YES;
39 ret = eventNotHandledErr;
40 switch (eventKind) {
41 case kEventWindowActivated:
42 [[cont window] makeKeyAndOrderFront: cont];
43 ret = noErr;
44 break;
45 case kEventWindowClose:
46 [cont close];
47 [[[NSApp orderedWindows] objectAtIndex: 0] makeKeyWindow];
48 ret = noErr;
49 break;
50 }
51 cont->isProcessingCarbonEventHandler = NO;
52 return ret;
53 }
54 #endif
55
56 @implementation AUViewWindowController
57
58 static NSMutableArray *sAUViewWindowControllers = nil;
59
60 + (AUViewWindowController *)windowControllerForAudioUnit:(AudioUnit)unit cocoaView:(BOOL)cocoaView delegate:(id)delegate
61 {
62 int i, n;
63 id cont;
64 if (sAUViewWindowControllers == nil) {
65 sAUViewWindowControllers = [[NSMutableArray alloc] init];
66 }
67 n = (int)[sAUViewWindowControllers count];
68 for (i = 0; i < n; i++) {
69 cont = [sAUViewWindowControllers objectAtIndex: i];
70 if ([cont audioUnit] == unit) {
71 [[cont window] makeKeyAndOrderFront: nil];
72 return cont;
73 }
74 }
75 cont = [[[AUViewWindowController alloc] initWithAudioUnit:unit cocoaView:cocoaView delegate:delegate] autorelease];
76 if (cont != nil) {
77 // The present implementation keeps the window controller even after
78 // the window is closed. This may hog the memory and CPU time. But
79 // releasing the Cocoa window sometimes caused crash, which
80 // I were not able to fix. So I will keep this way for a while.
81 // (Toshi Nagata 2017.10.8)
82 [sAUViewWindowControllers addObject: cont];
83 [[cont window] makeKeyAndOrderFront: nil];
84 }
85 return cont;
86 }
87
88 - (void)editWindowClosed
89 {
90 // Any additional cocoa cleanup can be added here.
91 [_delegate auViewWindowWillClose: self];
92 }
93
94 + (BOOL)error:(NSString *)errString status:(OSStatus)err
95 {
96 NSString *errorString = [NSString stringWithFormat:@"%@ failed with error code %i: %s", errString, (int)err, GetMacOSStatusCommentString(err)];
97 NSLog(@"%@", errorString);
98 return NO;
99 }
100
101 #if USE_CARBON
102 - (WindowRef)carbonWindowRef
103 {
104 return carbonWindowRef;
105 }
106 #endif
107
108 - (AudioUnit)audioUnit
109 {
110 return audioUnit;
111 }
112
113 /*
114 - (BOOL)installWindowCloseHandler
115 {
116 EventTypeSpec eventList[] = {{kEventClassWindow, kEventWindowClose}};
117 EventHandlerUPP handlerUPP = NewEventHandlerUPP(sWindowEventHandler);
118 OSStatus err = InstallWindowEventHandler(carbonWindowRef, handlerUPP, 1, eventList, self, NULL);
119 if (err != noErr)
120 return [self error: @"Installation of WindowClose handler" status: err];
121 return YES;
122 }
123 */
124
125 #if USE_CARBON
126 - (void)findUIViewComponentDescription:(BOOL)forceGeneric
127 {
128 OSStatus err;
129 UInt32 propSize;
130 ComponentDescription *cds;
131
132 // set up to use generic UI component
133 viewCD.componentType = kAudioUnitCarbonViewComponentType;
134 viewCD.componentSubType = 'gnrc';
135 viewCD.componentManufacturer = 'appl';
136 viewCD.componentFlags = 0;
137 viewCD.componentFlagsMask = 0;
138
139 if (forceGeneric)
140 return;
141
142 err = AudioUnitGetPropertyInfo(audioUnit, kAudioUnitProperty_GetUIComponentList, kAudioUnitScope_Global, 0, &propSize, NULL);
143
144 if (err != noErr) {
145 NSLog(@"Error setting up carbon interface, falling back to generic interface.");
146 return;
147 }
148
149 cds = malloc(propSize);
150 err = AudioUnitGetProperty(audioUnit, kAudioUnitProperty_GetUIComponentList, kAudioUnitScope_Global, 0, cds, &propSize);
151
152 if (err == noErr)
153 viewCD = cds[0]; // Pick the first one
154
155 free(cds);
156 }
157 #endif
158
159 + (BOOL)pluginClassIsValid:(Class)pluginClass
160 {
161 if ([pluginClass conformsToProtocol: @protocol(AUCocoaUIBase)]) {
162 if ([pluginClass instancesRespondToSelector: @selector(interfaceVersion)] &&
163 [pluginClass instancesRespondToSelector: @selector(uiViewForAudioUnit:withSize:)]) {
164 return YES;
165 }
166 }
167 return NO;
168 }
169
170 - (BOOL)hasCocoaView
171 {
172 UInt32 dataSize = 0;
173 Boolean isWritable = 0;
174 OSStatus err = AudioUnitGetPropertyInfo(audioUnit, kAudioUnitProperty_CocoaUI, kAudioUnitScope_Global, 0, &dataSize, &isWritable);
175
176 return (err == noErr && dataSize > 0);
177 }
178
179 + (NSView *)getCocoaViewForAudioUnit:(AudioUnit)unit defaultViewSize:(NSSize)viewSize
180 {
181 NSView *theView = nil;
182 UInt32 dataSize = 0;
183 Boolean isWritable = 0;
184 OSStatus err = AudioUnitGetPropertyInfo(unit, kAudioUnitProperty_CocoaUI, kAudioUnitScope_Global, 0, &dataSize, &isWritable);
185
186 if (err != noErr) {
187 AUGenericView *aView = [[AUGenericView alloc] initWithAudioUnit:unit];
188 if (aView == nil) {
189 [self error: @"Cannot open cocoa view nor generic view" status: err];
190 return nil;
191 }
192 return [aView autorelease];
193 }
194
195 AudioUnitCocoaViewInfo *cvi = malloc(dataSize);
196 err = AudioUnitGetProperty(unit, kAudioUnitProperty_CocoaUI, kAudioUnitScope_Global, 0, cvi, &dataSize);
197
198 unsigned numberOfClasses = (dataSize - sizeof(CFURLRef)) / sizeof(CFStringRef);
199 NSString *viewClassName = (NSString *)(cvi->mCocoaAUViewClass[0]);
200 NSString *path = [(NSURL *)(cvi->mCocoaAUViewBundleLocation) path];
201 NSBundle *viewBundle = [NSBundle bundleWithPath:path];
202 Class viewClass = [viewBundle classNamed:viewClassName];
203
204 if ([AUViewWindowController pluginClassIsValid:viewClass]) {
205 id factory = [[[viewClass alloc] init] autorelease];
206 theView = [factory uiViewForAudioUnit:unit withSize:viewSize];
207 }
208
209 if (cvi != NULL) {
210 int i;
211 for (i = 0; i < numberOfClasses; i++)
212 CFRelease(cvi->mCocoaAUViewClass[i]);
213 CFRelease(cvi->mCocoaAUViewBundleLocation);
214 free(cvi);
215 }
216
217 return theView;
218 }
219
220
221 - (NSView *)getCocoaView
222 {
223 return [AUViewWindowController getCocoaViewForAudioUnit:audioUnit defaultViewSize:defaultViewSize];
224 }
225
226 #if USE_CARBON
227 -(NSWindow *)createCarbonWindow
228 {
229 OSStatus res;
230 Component editComponent = FindNextComponent(NULL, &viewCD);
231 OpenAComponent(editComponent, &auCarbonView);
232 if (auCarbonView == nil)
233 [NSException raise:NSGenericException format:@"Could not open audio unit editor component"];
234
235 Rect bounds = { 100, 100, 100, 100 }; // Generic resized later
236
237 // Load carbon window from the nib
238 {
239 IBNibRef nibRef;
240 res = CreateNibReference(CFSTR("AUCarbonWindow"), &nibRef);
241 if (res != noErr) {
242 [[self class] error: @"Cannot load nib for carbon window" status: res];
243 return nil;
244 }
245 res = CreateWindowFromNib(nibRef, CFSTR("Window"), &carbonWindowRef);
246 if (res != noErr) {
247 [[self class] error: @"Cannot load carbon window from nib" status: res];
248 return nil;
249 }
250 DisposeNibReference(nibRef);
251 }
252 /* res = CreateNewWindow(kDocumentWindowClass, kWindowCloseBoxAttribute | kWindowCollapseBoxAttribute | kWindowStandardHandlerAttribute | kWindowCompositingAttribute, &bounds, &carbonWindowRef);
253 if (res != noErr) {
254 [self error:@"Creating new carbon window" status:res];
255 return nil;
256 } */
257
258 ControlRef rootControl;
259 res = GetRootControl(carbonWindowRef, &rootControl);
260 if (rootControl == nil) {
261 [[self class] error:@"Getting root control of carbon window" status:res];
262 return nil;
263 }
264
265 ControlRef viewPane;
266 Float32Point loc = { 0.0f, 0.0f };
267 Float32Point size = { 0.0f, 0.0f } ;
268 AudioUnitCarbonViewCreate(auCarbonView, audioUnit, carbonWindowRef,
269 rootControl, &loc, &size, &viewPane);
270
271 // resize and move window
272 GetControlBounds(viewPane, &bounds);
273 size.x = bounds.right - bounds.left;
274 size.y = bounds.bottom - bounds.top;
275 SizeWindow(carbonWindowRef, (short) (size.x + 0.5), (short) (size.y + 0.5), true);
276 RepositionWindow(carbonWindowRef, NULL, kWindowCenterOnMainScreen);
277
278 // Install event handler
279 {
280 EventTypeSpec eventList[] = {
281 {kEventClassWindow, kEventWindowActivated},
282 // {kEventClassWindow, kEventWindowGetClickActivation},
283 {kEventClassWindow, kEventWindowClose}
284 };
285 EventHandlerUPP handlerUPP = NewEventHandlerUPP(sWindowEventHandler);
286 res = InstallWindowEventHandler(carbonWindowRef, handlerUPP, sizeof(eventList) / sizeof(eventList[0]), eventList, self, NULL);
287 if (res != noErr) {
288 [[self class] error: @"Installation of WindowClose handler" status: res];
289 return nil;
290 }
291 }
292
293 return [[[NSWindow alloc] initWithWindowRef: carbonWindowRef] autorelease];
294 }
295 #endif
296
297 - (NSWindow *)createCocoaWindow
298 {
299 if ([self hasCocoaView]) {
300 NSView *res = [self getCocoaView];
301 if (res) {
302 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];
303 [cocoaWindow setContentView:res];
304 return cocoaWindow;
305 }
306 }
307 return nil;
308 }
309
310 /*- (void)showWindow:(id)sender
311 {
312 if (cocoaWindow)
313 [super showWindow:sender];
314 else if (carbonWindowRef)
315 SelectWindow(carbonWindowRef);
316 }
317 */
318
319 - (void)close
320 {
321 [[self window] orderOut: self];
322 [super close];
323 #if USE_CARBON
324 if (carbonWindowRef) {
325 DisposeWindow(carbonWindowRef);
326 carbonWindowRef = 0;
327 }
328 #endif
329 [self editWindowClosed];
330 [sAUViewWindowControllers removeObject: self];
331 }
332
333 - (id)initWithAudioUnit:(AudioUnit)unit cocoaView:(BOOL)cocoaView delegate:(id)delegate
334 {
335 NSWindow *aWindow;
336
337 self = [super initWithWindowNibName: @"AUViewWindow"];
338 if (self == nil)
339 return nil;
340
341 audioUnit = unit;
342 _delegate = delegate;
343 defaultViewSize = NSMakeSize(400, 300);
344
345 #if USE_CARBON
346 // We need to chack this in showWindow:
347 carbonWindowRef = 0;
348 #endif
349
350 if (cocoaView) {
351 aWindow = [self createCocoaWindow];
352 } else {
353 #if USE_CARBON
354 [self findUIViewComponentDescription: NO];
355 aWindow = [self createCarbonWindow];
356 #else
357 aWindow = nil;
358 #endif
359 }
360 if (aWindow == nil) {
361 [self release];
362 return nil;
363 }
364 [self setWindow:aWindow];
365 if ([aWindow delegate] == nil) {
366 [aWindow setDelegate: self];
367 }
368 [[self window] makeKeyAndOrderFront: nil];
369 return self;
370 }
371
372 @end

Back to OSDN">Back to OSDN
ViewVC Help
Powered by ViewVC 1.1.26