GUI limitation: Require engine to add/remove tracks/busses
[ardour.git] / gtk2_ardour / mac_vst_plugin_ui.mm
index a1803b6e60101be4430eb6ad0abd075a947ff0f4..50665d6734d3d938e56720cc217afffabac8a829 100644 (file)
@@ -40,6 +40,24 @@ struct ERect{
     short right;
 };
 
+
+@implementation ResizeNotificationObject
+
+- (ResizeNotificationObject*) initWithPluginUI: (MacVSTPluginUI*) vstui
+{
+       self = [ super init ];
+       plugin_ui = vstui;
+       return self;
+}
+
+- (void)viewResized:(NSNotification *)notification
+{
+       (void) notification; // unused
+       plugin_ui->view_resized();
+}
+
+@end
+
 VSTPluginUI*
 create_mac_vst_gui (boost::shared_ptr<PluginInsert> insert)
 {
@@ -55,18 +73,45 @@ MacVSTPluginUI::MacVSTPluginUI (boost::shared_ptr<PluginInsert> pi, boost::share
 {
        low_box.add_events (Gdk::VISIBILITY_NOTIFY_MASK | Gdk::EXPOSURE_MASK);
        low_box.signal_realize().connect (mem_fun (this, &MacVSTPluginUI::lower_box_realized));
+       low_box.signal_visibility_notify_event ().connect (mem_fun (this, &MacVSTPluginUI::lower_box_visibility_notify));
+       low_box.signal_size_request ().connect (mem_fun (this, &MacVSTPluginUI::lower_box_size_request));
+       low_box.signal_size_allocate ().connect (mem_fun (this, &MacVSTPluginUI::lower_box_size_allocate));
+       low_box.signal_map ().connect (mem_fun (this, &MacVSTPluginUI::lower_box_map));
+       low_box.signal_unmap ().connect (mem_fun (this, &MacVSTPluginUI::lower_box_unmap));
+
        pack_start (low_box, true, true);
        low_box.show ();
+
        vst->LoadPresetProgram.connect (_program_connection, invalidator (*this), boost::bind (&MacVSTPluginUI::set_program, this), gui_context());
 
+       _ns_view = [[NSView new] retain];
+
+       AEffect* plugin = _vst->state()->plugin;
+       plugin->dispatcher (plugin, effEditOpen, 0, 0, _ns_view, 0.0f);
+       _idle_connection = Glib::signal_idle().connect (sigc::mem_fun (*this, &MacVSTPluginUI::idle));
+
+       _resize_notifier = [[ResizeNotificationObject alloc] initWithPluginUI:this];
+       [[NSNotificationCenter defaultCenter] addObserver:_resize_notifier
+               selector:@selector(viewResized:) name:NSViewFrameDidChangeNotification
+               object:_ns_view];
+
+       NSArray* subviews = [_ns_view subviews];
+       assert ([subviews count] < 2);
+       for (unsigned long i = 0; i < [subviews count]; ++i) {
+               NSView* subview = [subviews objectAtIndex:i];
+               [[NSNotificationCenter defaultCenter] addObserver:_resize_notifier
+                       selector:@selector(viewResized:) name:NSViewFrameDidChangeNotification
+                       object:subview];
+       }
 }
 
 MacVSTPluginUI::~MacVSTPluginUI ()
 {
-       if (_ns_view) {
-               [_ns_view removeFromSuperview];
-               [_ns_view release];
-       }
+       [[NSNotificationCenter defaultCenter] removeObserver:_resize_notifier];
+       [_resize_notifier release];
+
+       [_ns_view removeFromSuperview];
+       [_ns_view release];
 
        AEffect* plugin = _vst->state()->plugin;
        plugin->dispatcher (plugin, effEditClose, 0, 0, 0, 0.0f);
@@ -101,6 +146,21 @@ MacVSTPluginUI::package (Gtk::Window& win)
 void
 MacVSTPluginUI::forward_key_event (GdkEventKey* ev)
 {
+       NSEvent* nsevent = gdk_quartz_event_get_nsevent ((GdkEvent*)ev);
+
+       if (_ns_view && nsevent) {
+               /* filter on nsevent type here because GDK massages FlagsChanged
+                * messages into GDK_KEY_{PRESS,RELEASE} but Cocoa won't
+                * handle a FlagsChanged message as a keyDown or keyUp
+                */
+               if ([nsevent type] == NSKeyDown) {
+                       [[[_ns_view window] firstResponder] keyDown:nsevent];
+               } else if ([nsevent type] == NSKeyUp) {
+                       [[[_ns_view window] firstResponder] keyUp:nsevent];
+               } else if ([nsevent type] == NSFlagsChanged) {
+                       [[[_ns_view window] firstResponder] flagsChanged:nsevent];
+               }
+       }
 }
 
 void
@@ -114,35 +174,68 @@ MacVSTPluginUI::lower_box_realized ()
        [win setAutodisplay:1]; // turn off GTK stuff for this window
 
        NSView* view = gdk_quartz_window_get_nsview (low_box.get_window()->gobj());
-       _ns_view = [[NSView new] retain];
        [view addSubview:_ns_view];
+       low_box.queue_resize ();
+}
 
-       AEffect* plugin = _vst->state()->plugin;
-       plugin->dispatcher (plugin, effEditOpen, 0, 0, _ns_view, 0.0f);
+bool
+MacVSTPluginUI::lower_box_visibility_notify (GdkEventVisibility* ev)
+{
+       return false;
+}
+void
+MacVSTPluginUI::lower_box_map ()
+{
+       [_ns_view setHidden:0];
+}
+
+void
+MacVSTPluginUI::lower_box_unmap ()
+{
+       [_ns_view setHidden:1];
+}
 
+void
+MacVSTPluginUI::lower_box_size_request (GtkRequisition* requisition)
+{
        struct ERect* er = NULL;
+       AEffect* plugin = _vst->state()->plugin;
        plugin->dispatcher (plugin, effEditGetRect, 0, 0, &er, 0 );
        if (er) {
-               int req_width = er->right - er->left;
-               int req_height = er->bottom - er->top;
-
-               low_box.set_size_request (req_width, req_height);
+               requisition->width  = er->right - er->left;
+               requisition->height = er->bottom - er->top;
+       } else {
+               requisition->width  = 600;
+               requisition->height = 400;
+       }
+}
 
-               gint xx, yy;
-               gtk_widget_translate_coordinates(
-                               GTK_WIDGET(low_box.gobj()),
-                               GTK_WIDGET(low_box.get_parent()->gobj()),
-                               8, 6, &xx, &yy);
-               [_ns_view setFrame:NSMakeRect(xx, yy, req_width, req_height)];
+void
+MacVSTPluginUI::lower_box_size_allocate (Gtk::Allocation& allocation)
+{
+       gint xx, yy;
+       gtk_widget_translate_coordinates(
+                       GTK_WIDGET(low_box.gobj()),
+                       GTK_WIDGET(low_box.get_parent()->gobj()),
+                       8, 6, &xx, &yy);
+       [_ns_view setFrame:NSMakeRect (xx, yy, allocation.get_width (), allocation.get_height ())];
+       NSArray* subviews = [_ns_view subviews];
+       for (unsigned long i = 0; i < [subviews count]; ++i) {
+               NSView* subview = [subviews objectAtIndex:i];
+               [subview setFrame:NSMakeRect (0, 0, allocation.get_width (), allocation.get_height ())];
        }
+}
 
-       _idle_connection = Glib::signal_idle().connect (sigc::mem_fun (*this, &MacVSTPluginUI::idle));
+void
+MacVSTPluginUI::view_resized ()
+{
+       low_box.queue_resize ();
 }
 
 int
 MacVSTPluginUI::get_XID ()
 {
-       return _vst->state()->xid;
+       return _vst->state()->xid; // unused
 }
 
 bool
@@ -156,26 +249,5 @@ MacVSTPluginUI::idle ()
 void
 MacVSTPluginUI::set_program ()
 {
-       VSTState* vstfx = _vst->state();
-
-       if (vstfx->want_program != -1) {
-               if (vstfx->vst_version >= 2) {
-                       vstfx->plugin->dispatcher (vstfx->plugin, 67 /* effBeginSetProgram */, 0, 0, NULL, 0);
-               }
-
-               vstfx->plugin->dispatcher (vstfx->plugin, effSetProgram, 0, vstfx->want_program, NULL, 0);
-
-               if (vstfx->vst_version >= 2) {
-                       vstfx->plugin->dispatcher (vstfx->plugin, 68 /* effEndSetProgram */, 0, 0, NULL, 0);
-               }
-
-               vstfx->want_program = -1;
-       }
-
-       if (vstfx->want_chunk == 1) {
-               pthread_mutex_lock (&vstfx->state_lock);
-               vstfx->plugin->dispatcher (vstfx->plugin, 24 /* effSetChunk */, 1, vstfx->wanted_chunk_size, vstfx->wanted_chunk, 0);
-               vstfx->want_chunk = 0;
-               pthread_mutex_unlock (&vstfx->state_lock);
-       }
+       vststate_maybe_set_program (_vst->state());
 }