Merge branch 'cairocanvas'
[ardour.git] / gtk2_ardour / au_pluginui.mm
1 #undef  Marker
2 #define Marker FuckYouAppleAndYourLackOfNameSpaces
3
4 #include <gtkmm/button.h>
5 #include <gdk/gdkquartz.h>
6
7 #include "pbd/convert.h"
8 #include "pbd/error.h"
9
10 #include "ardour/audio_unit.h"
11 #include "ardour/debug.h"
12 #include "ardour/plugin_insert.h"
13
14 #undef check // stupid gtk, stupid apple
15
16 #include <gtkmm2ext/utils.h>
17
18 #include "au_pluginui.h"
19 #include "gui_thread.h"
20
21 #include "appleutility/CAAudioUnit.h"
22 #include "appleutility/CAComponent.h"
23
24 #import <AudioUnit/AUCocoaUIView.h>
25 #import <CoreAudioKit/AUGenericView.h>
26
27 #undef Marker
28
29 #include "keyboard.h"
30 #include "utils.h"
31 #include "public_editor.h"
32 #include "i18n.h"
33
34 using namespace ARDOUR;
35 using namespace Gtk;
36 using namespace Gtkmm2ext;
37 using namespace std;
38 using namespace PBD;
39
40 vector<string> AUPluginUI::automation_mode_strings;
41
42 static const gchar* _automation_mode_strings[] = {
43         X_("Manual"),
44         X_("Play"),
45         X_("Write"),
46         X_("Touch"),
47         0
48 };
49
50 static void
51 dump_view_tree (NSView* view, int depth)
52 {
53         NSArray* subviews = [view subviews];
54         unsigned long cnt = [subviews count];
55
56         for (int d = 0; d < depth; d++) {
57                 cerr << '\t';
58         }
59         NSRect frame = [view frame];
60         cerr << " view @ " <<  frame.origin.x << ", " << frame.origin.y
61              << ' ' << frame.size.width << " x " << frame.size.height
62              << endl;
63         
64         for (unsigned long i = 0; i < cnt; ++i) {
65                 NSView* subview = [subviews objectAtIndex:i];
66                 dump_view_tree (subview, depth+1);
67         }
68 }
69
70 @implementation NotificationObject
71
72 - (NotificationObject*) initWithPluginUI: (AUPluginUI*) apluginui andCocoaParent: (NSWindow*) cp andTopLevelParent: (NSWindow*) tlp
73 {
74         self = [ super init ];
75
76         if (self) {
77                 plugin_ui = apluginui; 
78                 top_level_parent = tlp;
79                 
80                 if (cp) {
81                         cocoa_parent = cp;
82                         
83                         [[NSNotificationCenter defaultCenter] addObserver:self
84                          selector:@selector(cocoaParentActivationHandler:)
85                          name:NSWindowDidBecomeMainNotification
86                          object:NULL];
87                         
88                         [[NSNotificationCenter defaultCenter] addObserver:self
89                          selector:@selector(cocoaParentBecameKeyHandler:)
90                          name:NSWindowDidBecomeKeyNotification
91                          object:NULL];
92                 }
93         }
94
95         return self;
96 }
97                 
98 - (void)cocoaParentActivationHandler:(NSNotification *)notification
99 {
100         NSWindow* notification_window = (NSWindow *)[notification object];
101
102         if (top_level_parent == notification_window || cocoa_parent == notification_window) {
103                 if ([notification_window isMainWindow]) {
104                         plugin_ui->activate();
105                 } else {
106                         plugin_ui->deactivate();
107                 }
108         } 
109 }
110
111 - (void)cocoaParentBecameKeyHandler:(NSNotification *)notification
112 {
113         NSWindow* notification_window = (NSWindow *)[notification object];
114
115         if (top_level_parent == notification_window || cocoa_parent == notification_window) {
116                 if ([notification_window isKeyWindow]) {
117                         plugin_ui->activate();
118                 } else {
119                         plugin_ui->deactivate();
120                 }
121         } 
122 }
123
124 - (void)auViewResized:(NSNotification *)notification;
125 {
126         (void) notification; // stop complaints about unusued argument
127         plugin_ui->cocoa_view_resized();
128 }
129
130 @end
131
132 AUPluginUI::AUPluginUI (boost::shared_ptr<PluginInsert> insert)
133         : PlugUIBase (insert)
134         , automation_mode_label (_("Automation"))
135         , preset_label (_("Presets"))
136         
137 {
138         if (automation_mode_strings.empty()) {
139                 automation_mode_strings = I18N (_automation_mode_strings);
140         }
141         
142         set_popdown_strings (automation_mode_selector, automation_mode_strings);
143         automation_mode_selector.set_active_text (automation_mode_strings.front());
144
145         if ((au = boost::dynamic_pointer_cast<AUPlugin> (insert->plugin())) == 0) {
146                 error << _("unknown type of editor-supplying plugin (note: no AudioUnit support in this version of ardour)") << endmsg;
147                 throw failed_constructor ();
148         }
149
150         /* stuff some stuff into the top of the window */
151
152         HBox* smaller_hbox = manage (new HBox);
153
154         smaller_hbox->set_spacing (6);
155         smaller_hbox->pack_start (preset_label, false, false, 4);
156         smaller_hbox->pack_start (_preset_combo, false, false);
157         smaller_hbox->pack_start (save_button, false, false);
158 #if 0
159         /* one day these might be useful with an AU plugin, but not yet */
160         smaller_hbox->pack_start (automation_mode_label, false, false);
161         smaller_hbox->pack_start (automation_mode_selector, false, false);
162 #endif
163         smaller_hbox->pack_start (bypass_button, false, true);
164
165         VBox* v1_box = manage (new VBox);
166         VBox* v2_box = manage (new VBox);
167
168         v1_box->pack_start (*smaller_hbox, false, true);
169         v2_box->pack_start (focus_button, false, true);
170
171         top_box.set_homogeneous (false);
172         top_box.set_spacing (6);
173         top_box.set_border_width (6);
174
175         top_box.pack_end (*v2_box, false, false);
176         top_box.pack_end (*v1_box, false, false);
177
178         set_spacing (6);
179         pack_start (top_box, false, false);
180         pack_start (low_box, false, false);
181
182         preset_label.show ();
183         _preset_combo.show ();
184         automation_mode_label.show ();
185         automation_mode_selector.show ();
186         bypass_button.show ();
187         top_box.show ();
188         low_box.show ();
189
190         cocoa_parent = 0;
191         cocoa_window = 0;
192
193 #ifdef WITH_CARBBON
194         _activating_from_app = false;
195         _notify = 0;
196         au_view = 0;
197         editView = 0;
198         carbon_window = 0;
199 #endif
200
201         /* prefer cocoa, fall back to cocoa, but use carbon if its there */
202
203         if (test_cocoa_view_support()) {
204                 create_cocoa_view ();
205 #ifdef WITH_CARBON
206         } else if (test_carbon_view_support()) {
207                 create_carbon_view ();
208 #endif
209         } else {
210                 create_cocoa_view ();
211         }
212
213         low_box.signal_realize().connect (mem_fun (this, &AUPluginUI::lower_box_realized));
214 }
215
216 AUPluginUI::~AUPluginUI ()
217 {
218         if (_notify) {
219                 [[NSNotificationCenter defaultCenter] removeObserver:_notify];
220         }
221
222         if (cocoa_parent) {
223                 NSWindow* win = get_nswindow();
224                 [win removeChildWindow:cocoa_parent];
225         } 
226
227 #ifdef WITH_CARBON
228         if (carbon_window) {
229                 /* not parented, just overlaid on top of our window */
230                 DisposeWindow (carbon_window);
231         }
232 #endif
233
234         if (editView) {
235                 CloseComponent (editView);
236         }
237
238         if (au_view) {
239                 /* remove whatever we packed into low_box so that GTK doesn't
240                    mess with it.
241                 */
242
243                 [au_view removeFromSuperview];
244         }
245 }
246
247 bool
248 AUPluginUI::test_carbon_view_support ()
249 {
250 #ifdef WITH_CARBON
251         bool ret = false;
252         
253         carbon_descriptor.componentType = kAudioUnitCarbonViewComponentType;
254         carbon_descriptor.componentSubType = 'gnrc';
255         carbon_descriptor.componentManufacturer = 'appl';
256         carbon_descriptor.componentFlags = 0;
257         carbon_descriptor.componentFlagsMask = 0;
258         
259         OSStatus err;
260
261         // ask the AU for its first editor component
262         UInt32 propertySize;
263         err = AudioUnitGetPropertyInfo(*au->get_au(), kAudioUnitProperty_GetUIComponentList, kAudioUnitScope_Global, 0, &propertySize, NULL);
264         if (!err) {
265                 int nEditors = propertySize / sizeof(ComponentDescription);
266                 ComponentDescription *editors = new ComponentDescription[nEditors];
267                 err = AudioUnitGetProperty(*au->get_au(), kAudioUnitProperty_GetUIComponentList, kAudioUnitScope_Global, 0, editors, &propertySize);
268                 if (!err) {
269                         // just pick the first one for now
270                         carbon_descriptor = editors[0];
271                         ret = true;
272                 }
273                 delete[] editors;
274         }
275
276         return ret;
277 #else
278         return false;
279 #endif
280 }
281         
282 bool
283 AUPluginUI::test_cocoa_view_support ()
284 {
285         UInt32 dataSize   = 0;
286         Boolean isWritable = 0;
287         OSStatus err = AudioUnitGetPropertyInfo(*au->get_au(),
288                                                 kAudioUnitProperty_CocoaUI, kAudioUnitScope_Global,
289                                                 0, &dataSize, &isWritable);
290         
291         return dataSize > 0 && err == noErr;
292 }
293
294 bool
295 AUPluginUI::plugin_class_valid (Class pluginClass)
296 {
297         if([pluginClass conformsToProtocol: @protocol(AUCocoaUIBase)]) {
298                 if([pluginClass instancesRespondToSelector: @selector(interfaceVersion)] &&
299                    [pluginClass instancesRespondToSelector: @selector(uiViewForAudioUnit:withSize:)]) {
300                                 return true;
301                 }
302         }
303         return false;
304 }
305
306 int
307 AUPluginUI::create_cocoa_view ()
308 {
309         bool wasAbleToLoadCustomView = false;
310         AudioUnitCocoaViewInfo* cocoaViewInfo = NULL;
311         UInt32               numberOfClasses = 0;
312         UInt32     dataSize;
313         Boolean    isWritable;
314         NSString*           factoryClassName = 0;
315         NSURL*              CocoaViewBundlePath = NULL;
316
317         OSStatus result = AudioUnitGetPropertyInfo (*au->get_au(),
318                                                     kAudioUnitProperty_CocoaUI,
319                                                     kAudioUnitScope_Global, 
320                                                     0,
321                                                     &dataSize,
322                                                     &isWritable );
323
324         numberOfClasses = (dataSize - sizeof(CFURLRef)) / sizeof(CFStringRef);
325
326         // Does view have custom Cocoa UI?
327         
328         if ((result == noErr) && (numberOfClasses > 0) ) {
329
330                 DEBUG_TRACE(DEBUG::AudioUnits,
331                             string_compose ( "based on %1, there are %2 cocoa UI classes\n", dataSize, numberOfClasses));
332
333                 cocoaViewInfo = (AudioUnitCocoaViewInfo *)malloc(dataSize);
334
335                 if(AudioUnitGetProperty(*au->get_au(),
336                                         kAudioUnitProperty_CocoaUI,
337                                         kAudioUnitScope_Global,
338                                         0,
339                                         cocoaViewInfo,
340                                         &dataSize) == noErr) {
341
342                         CocoaViewBundlePath     = (NSURL *)cocoaViewInfo->mCocoaAUViewBundleLocation;
343                                 
344                         // we only take the first view in this example.
345                         factoryClassName        = (NSString *)cocoaViewInfo->mCocoaAUViewClass[0];
346                         
347                         DEBUG_TRACE (DEBUG::AudioUnits, string_compose ("the factory name is %1 bundle is %2\n",
348                                                                         [factoryClassName UTF8String], CocoaViewBundlePath));
349                         
350                 } else {
351
352                         DEBUG_TRACE (DEBUG::AudioUnits, string_compose ("No cocoaUI property cocoaViewInfo = %1\n", cocoaViewInfo));
353
354                         if (cocoaViewInfo != NULL) {
355                                 free (cocoaViewInfo);
356                                 cocoaViewInfo = NULL;
357                         }
358                 }
359         }
360
361         // [A] Show custom UI if view has it
362
363         if (CocoaViewBundlePath && factoryClassName) {
364                 NSBundle *viewBundle    = [NSBundle bundleWithPath:[CocoaViewBundlePath path]];
365
366                 DEBUG_TRACE (DEBUG::AudioUnits, string_compose ("tried to create bundle, result = %1\n", viewBundle));
367
368                 if (viewBundle == NULL) {
369                         error << _("AUPluginUI: error loading AU view's bundle") << endmsg;
370                         return -1;
371                 } else {
372                         Class factoryClass = [viewBundle classNamed:factoryClassName];
373                         DEBUG_TRACE (DEBUG::AudioUnits, string_compose ("tried to create factory class, result = %1\n", factoryClass));
374                         if (!factoryClass) {
375                                 error << _("AUPluginUI: error getting AU view's factory class from bundle") << endmsg;
376                                 return -1;
377                         }
378                         
379                         // make sure 'factoryClass' implements the AUCocoaUIBase protocol
380                         if (!plugin_class_valid (factoryClass)) {
381                                 error << _("AUPluginUI: U view's factory class does not properly implement the AUCocoaUIBase protocol") << endmsg;
382                                 return -1;
383                         }
384                         // make a factory
385                         id factory = [[[factoryClass alloc] init] autorelease];
386                         if (factory == NULL) {
387                                 error << _("AUPluginUI: Could not create an instance of the AU view factory") << endmsg;
388                                 return -1;
389                         }
390
391                         DEBUG_TRACE (DEBUG::AudioUnits, "got a factory instance\n");
392
393                         // make a view
394                         au_view = [factory uiViewForAudioUnit:*au->get_au() withSize:NSZeroSize];
395
396                         DEBUG_TRACE (DEBUG::AudioUnits, string_compose ("view created @ %1\n", au_view));
397                         
398                         // cleanup
399                         [CocoaViewBundlePath release];
400                         if (cocoaViewInfo) {
401                                 UInt32 i;
402                                 for (i = 0; i < numberOfClasses; i++)
403                                         CFRelease(cocoaViewInfo->mCocoaAUViewClass[i]);
404                                 
405                                 free (cocoaViewInfo);
406                         }
407                         wasAbleToLoadCustomView = true;
408                 }
409         }
410
411         if (!wasAbleToLoadCustomView) {
412                 // load generic Cocoa view
413                 DEBUG_TRACE (DEBUG::AudioUnits, string_compose ("Loading generic view using %1 -> %2\n", au,
414                                                                 au->get_au()));
415                 au_view = [[AUGenericView alloc] initWithAudioUnit:*au->get_au()];
416                 DEBUG_TRACE (DEBUG::AudioUnits, string_compose ("view created @ %1\n", au_view));
417                 [(AUGenericView *)au_view setShowsExpertParameters:1];
418         }
419
420         // Get the initial size of the new AU View's frame 
421         
422         NSRect rect = [au_view frame];
423         prefheight = rect.size.height;
424         prefwidth = rect.size.width;
425         low_box.set_size_request (rect.size.width, rect.size.height);
426
427         return 0;
428 }
429
430 void
431 AUPluginUI::cocoa_view_resized ()
432 {
433         GtkRequisition topsize = top_box.size_request ();
434         NSWindow* window = get_nswindow ();
435         NSRect windowFrame= [window frame];
436         NSRect new_frame = [au_view frame];
437
438         float dy = last_au_frame.size.height - new_frame.size.height;
439         float dx = last_au_frame.size.width - new_frame.size.width;
440
441         windowFrame.origin.y    += dy;
442         windowFrame.origin.x    += dx;
443         windowFrame.size.height -= dy;
444         windowFrame.size.width  -= dx;
445         
446         [[NSNotificationCenter defaultCenter] removeObserver:_notify
447          name:NSViewFrameDidChangeNotification 
448          object:au_view];
449
450         NSUInteger old_auto_resize = [au_view autoresizingMask];
451
452         [au_view setAutoresizingMask:NSViewNotSizable];
453         [window setFrame:windowFrame display:1];
454
455         /* Some stupid AU Views change the origin of the original AU View
456            when they are resized (I'm looking at you AUSampler). If the origin
457            has been moved, move it back.
458         */
459
460         if (last_au_frame.origin.x != new_frame.origin.x ||
461             last_au_frame.origin.y != new_frame.origin.y) {
462                 new_frame.origin = last_au_frame.origin;
463                 [au_view setFrame:new_frame];
464                 /* also be sure to redraw the topbox because this can
465                    also go wrong.
466                  */
467                 top_box.queue_draw ();
468         }
469
470         [au_view setAutoresizingMask:old_auto_resize];
471
472         [[NSNotificationCenter defaultCenter] addObserver:_notify
473          selector:@selector(auViewResized:) name:NSViewFrameDidChangeNotification
474          object:au_view];
475
476         last_au_frame = new_frame;
477 }
478
479 int
480 AUPluginUI::create_carbon_view ()
481 {
482 #ifdef WITH_CARBON
483         OSStatus err;
484         ControlRef root_control;
485
486         Component editComponent = FindNextComponent(NULL, &carbon_descriptor);
487         
488         OpenAComponent(editComponent, &editView);
489         if (!editView) {
490                 error << _("AU Carbon view: cannot open AU Component") << endmsg;
491                 return -1;
492         }
493         
494         Rect r = { 100, 100, 100, 100 };
495         WindowAttributes attr = WindowAttributes (kWindowStandardHandlerAttribute |
496                                                   kWindowCompositingAttribute|
497                                                   kWindowNoShadowAttribute|
498                                                   kWindowNoTitleBarAttribute);
499
500         if ((err = CreateNewWindow(kDocumentWindowClass, attr, &r, &carbon_window)) != noErr) {
501                 error << string_compose (_("AUPluginUI: cannot create carbon window (err: %1)"), err) << endmsg;
502                 CloseComponent (editView);
503                 return -1;
504         }
505         
506         if ((err = GetRootControl(carbon_window, &root_control)) != noErr) {
507                 error << string_compose (_("AUPlugin: cannot get root control of carbon window (err: %1)"), err) << endmsg;
508                 DisposeWindow (carbon_window);
509                 CloseComponent (editView);
510                 return -1;
511         }
512
513         ControlRef viewPane;
514         Float32Point location  = { 0.0, 0.0 };
515         Float32Point size = { 0.0, 0.0 } ;
516
517         if ((err = AudioUnitCarbonViewCreate (editView, *au->get_au(), carbon_window, root_control, &location, &size, &viewPane)) != noErr) {
518                 error << string_compose (_("AUPluginUI: cannot create carbon plugin view (err: %1)"), err) << endmsg;
519                 DisposeWindow (carbon_window);
520                 CloseComponent (editView);
521                 return -1;
522         }
523
524         // resize window
525
526         Rect bounds;
527         GetControlBounds(viewPane, &bounds);
528         size.x = bounds.right-bounds.left;
529         size.y = bounds.bottom-bounds.top;
530
531         prefwidth = (int) (size.x + 0.5);
532         prefheight = (int) (size.y + 0.5);
533
534         SizeWindow (carbon_window, prefwidth, prefheight,  true);
535         low_box.set_size_request (prefwidth, prefheight);
536
537         return 0;
538 #else
539         error << _("AU Carbon GUI is not supported.") << endmsg;
540         return -1;
541 #endif
542 }
543
544 NSWindow*
545 AUPluginUI::get_nswindow ()
546 {
547         Gtk::Container* toplevel = get_toplevel();
548
549         if (!toplevel || !toplevel->is_toplevel()) {
550                 error << _("AUPluginUI: no top level window!") << endmsg;
551                 return 0;
552         }
553
554         NSWindow* true_parent = gdk_quartz_window_get_nswindow (toplevel->get_window()->gobj());
555
556         if (!true_parent) {
557                 error << _("AUPluginUI: no top level window!") << endmsg;
558                 return 0;
559         }
560
561         return true_parent;
562 }
563
564 void
565 AUPluginUI::activate ()
566 {
567 #ifdef WITH_CARBON
568         ActivateWindow (carbon_window, TRUE);
569 #endif
570 }
571
572 void
573 AUPluginUI::deactivate ()
574 {
575 #ifdef WITH_CARBON
576         ActivateWindow (carbon_window, FALSE);
577 #endif
578 }
579
580 int
581 AUPluginUI::parent_carbon_window ()
582 {
583 #ifdef WITH_CARBON
584         NSWindow* win = get_nswindow ();
585         Rect windowStructureBoundsRect;
586
587         if (!win) {
588                 return -1;
589         }
590
591         Gtk::Container* toplevel = get_toplevel();
592
593         if (!toplevel || !toplevel->is_toplevel()) {
594                 error << _("AUPluginUI: no top level window!") << endmsg;
595                 return -1;
596         }
597         
598         /* figure out where the cocoa parent window is in carbon-coordinate space, which
599            differs from both cocoa-coordinate space and GTK-coordinate space
600         */
601
602         GetWindowBounds((WindowRef) [win windowRef], kWindowStructureRgn, &windowStructureBoundsRect);
603
604         /* compute how tall the title bar is, because we have to offset the position of the carbon window
605            by that much.
606         */
607
608         NSRect content_frame = [NSWindow contentRectForFrameRect:[win frame] styleMask:[win styleMask]];
609         NSRect wm_frame = [NSWindow frameRectForContentRect:content_frame styleMask:[win styleMask]];
610
611         int titlebar_height = wm_frame.size.height - content_frame.size.height;
612
613         int packing_extra = 6; // this is the total vertical packing in our top level window
614
615         /* move into position, based on parent window position */
616         MoveWindow (carbon_window, 
617                     windowStructureBoundsRect.left, 
618                     windowStructureBoundsRect.top + titlebar_height + top_box.get_height() + packing_extra, 
619                     false);
620         ShowWindow (carbon_window);
621
622         // create the cocoa window for the carbon one and make it visible
623         cocoa_parent = [[NSWindow alloc] initWithWindowRef: carbon_window];
624
625         SetWindowActivationScope (carbon_window, kWindowActivationScopeNone);
626
627         _notify = [ [NotificationObject alloc] initWithPluginUI:this andCocoaParent:cocoa_parent andTopLevelParent:win ]; 
628
629         [win addChildWindow:cocoa_parent ordered:NSWindowAbove];
630
631         return 0;
632 #else
633         return -1;
634 #endif
635 }       
636
637 int
638 AUPluginUI::parent_cocoa_window ()
639 {
640         NSWindow* win = get_nswindow ();
641
642         if (!win) {
643                 return -1;
644         }
645
646         [win setAutodisplay:1]; // turn of GTK stuff for this window
647
648         Gtk::Container* toplevel = get_toplevel();
649
650         if (!toplevel || !toplevel->is_toplevel()) {
651                 error << _("AUPluginUI: no top level window!") << endmsg;
652                 return -1;
653         }
654
655         NSView* view = gdk_quartz_window_get_nsview (get_toplevel()->get_window()->gobj());
656         GtkRequisition a = top_box.size_request ();
657
658         /* move the au_view down so that it doesn't overlap the top_box contents */
659
660         NSPoint origin = { 0, static_cast<CGFloat> (a.height) };
661
662         [au_view setFrameOrigin:origin];
663         [view addSubview:au_view positioned:NSWindowBelow relativeTo:NULL];
664
665         last_au_frame = [au_view frame];
666
667         // watch for size changes of the view
668
669         _notify = [ [NotificationObject alloc] initWithPluginUI:this andCocoaParent:NULL andTopLevelParent:win ];
670
671         [[NSNotificationCenter defaultCenter] addObserver:_notify
672          selector:@selector(auViewResized:) name:NSViewFrameDidChangeNotification
673          object:au_view];
674
675         return 0;
676 }
677
678 void
679 AUPluginUI::forward_key_event (GdkEventKey* ev)
680 {
681         NSEvent* nsevent = gdk_quartz_event_get_nsevent ((GdkEvent*)ev);
682
683         if (au_view && nsevent) {
684
685                 /* filter on nsevent type here because GDK massages FlagsChanged
686                    messages into GDK_KEY_{PRESS,RELEASE} but Cocoa won't
687                    handle a FlagsChanged message as a keyDown or keyUp
688                 */
689
690                 if ([nsevent type] == NSKeyDown) {
691                         [[[au_view window] firstResponder] keyDown:nsevent];
692                 } else if ([nsevent type] == NSKeyUp) {
693                         [[[au_view window] firstResponder] keyUp:nsevent];
694                 } else if ([nsevent type] == NSFlagsChanged) {
695                         [[[au_view window] firstResponder] flagsChanged:nsevent];
696                 }
697         }
698 }
699
700 void
701 AUPluginUI::on_realize ()
702 {
703         VBox::on_realize ();
704
705         /* our windows should not have that resize indicator */
706
707         NSWindow* win = get_nswindow ();
708         if (win) {
709                 [win setShowsResizeIndicator:0];
710         }
711 }
712
713 void
714 AUPluginUI::lower_box_realized ()
715 {
716         if (au_view) {
717                 parent_cocoa_window ();
718         } else if (carbon_window) {
719                 parent_carbon_window ();
720         }
721 }
722
723 void
724 AUPluginUI::on_window_hide ()
725 {
726 #ifdef WITH_CARBON
727         if (carbon_window) {
728                 HideWindow (carbon_window);
729                 ActivateWindow (carbon_window, FALSE);
730         }
731 #endif
732         hide_all ();
733         
734 #if 0
735         NSArray* wins = [NSApp windows];
736         for (uint32_t i = 0; i < [wins count]; i++) {
737                 id win = [wins objectAtIndex:i];
738         }
739 #endif
740 }
741
742 bool
743 AUPluginUI::on_window_show (const string& /*title*/)
744 {
745         /* this is idempotent so just call it every time we show the window */
746
747         gtk_widget_realize (GTK_WIDGET(low_box.gobj()));
748
749         show_all ();
750
751 #ifdef WITH_CARBON
752         if (carbon_window) {
753                 ShowWindow (carbon_window);
754                 ActivateWindow (carbon_window, TRUE);
755         }
756 #endif
757
758         return true;
759 }
760
761 bool
762 AUPluginUI::start_updating (GdkEventAny*)
763 {
764         return false;
765 }
766
767 bool
768 AUPluginUI::stop_updating (GdkEventAny*)
769 {
770         return false;
771 }
772
773 PlugUIBase*
774 create_au_gui (boost::shared_ptr<PluginInsert> plugin_insert, VBox** box)
775 {
776         AUPluginUI* aup = new AUPluginUI (plugin_insert);
777         (*box) = aup;
778         return aup;
779 }
780
781