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