suspend route redisplay for (rec-en, solo, mute and monitor) batch changes
[ardour.git] / gtk2_ardour / ardour_ui.cc
index a771ed48b990831201d988541847bf7bca5ba8f0..cde9d0d9eeb1a13754f7a19e0cc03c6d0bb0d9bf 100644 (file)
@@ -50,6 +50,7 @@
 #include "pbd/enumwriter.h"
 #include "pbd/memento_command.h"
 #include "pbd/openuri.h"
+#include "pbd/stl_delete.h"
 #include "pbd/file_utils.h"
 #include "pbd/localtime_r.h"
 
@@ -71,6 +72,7 @@
 #include "ardour/filename_extensions.h"
 #include "ardour/filesystem_paths.h"
 #include "ardour/port.h"
+#include "ardour/plugin_manager.h"
 #include "ardour/process_thread.h"
 #include "ardour/profile.h"
 #include "ardour/recent_sessions.h"
 #include "ardour/session_state_utils.h"
 #include "ardour/session_utils.h"
 #include "ardour/slave.h"
+#include "ardour/system_exec.h"
+
+#ifdef WINDOWS_VST_SUPPORT
+#include <fst.h>
+#endif
 
 #include "timecode/time.h"
 
@@ -127,11 +134,11 @@ typedef uint64_t microseconds_t;
 #include "video_server_dialog.h"
 #include "add_video_dialog.h"
 #include "transcode_video_dialog.h"
-#include "system_exec.h"
 
 #include "i18n.h"
 
 using namespace ARDOUR;
+using namespace ARDOUR_UI_UTILS;
 using namespace PBD;
 using namespace Gtkmm2ext;
 using namespace Gtk;
@@ -166,6 +173,7 @@ ARDOUR_UI::ARDOUR_UI (int *argcp, char **argvp[], const char* localedir)
        , _was_dirty (false)
        , _mixer_on_top (false)
        , first_time_engine_run (true)
+       , blink_timeout_tag (-1)
 
          /* transport */
 
@@ -299,6 +307,12 @@ ARDOUR_UI::ARDOUR_UI (int *argcp, char **argvp[], const char* localedir)
 
        ARDOUR::FileSource::AmbiguousFileName.connect_same_thread (forever_connections, boost::bind (&ARDOUR_UI::ambiguous_file, this, _1, _2));
 
+       /* also plugin scan messages */
+       ARDOUR::PluginScanMessage.connect (forever_connections, MISSING_INVALIDATOR, boost::bind(&ARDOUR_UI::plugin_scan_dialog, this, _1, _2, _3), gui_context());
+       ARDOUR::PluginScanTimeout.connect (forever_connections, MISSING_INVALIDATOR, boost::bind(&ARDOUR_UI::plugin_scan_timeout, this, _1), gui_context());
+
+       ARDOUR::GUIIdle.connect (forever_connections, MISSING_INVALIDATOR, boost::bind(&ARDOUR_UI::gui_idle_handler, this), gui_context());
+
        /* lets get this party started */
 
        setup_gtk_ardour_enums ();
@@ -476,7 +490,7 @@ ARDOUR_UI::post_engine ()
 
        _tooltips.enable();
 
-       ActionManager::load_menus ();
+       ActionManager::load_menus (ARDOUR_COMMAND_LINE::menus_file);
 
        if (setup_windows ()) {
                throw failed_constructor ();
@@ -503,10 +517,13 @@ ARDOUR_UI::post_engine ()
 
                vector<string>::iterator n;
                vector<string>::iterator k;
-               for (n = names.begin(), k = keys.begin(); n != names.end(); ++n, ++k) {
-                       cout << "Action: " << (*n) << " bound to " << (*k) << endl;
+               vector<string>::iterator p;
+               for (n = names.begin(), k = keys.begin(), p = paths.begin(); n != names.end(); ++n, ++k, ++p) {
+                       cout << "Action: '" << (*n) << "' bound to '" << (*k) << "' Path: '" << (*p) << "'" << endl;
                }
 
+               halt_connection.disconnect ();
+               AudioEngine::instance()->stop ();
                exit (0);
        }
 
@@ -546,11 +563,6 @@ ARDOUR_UI::~ARDOUR_UI ()
                ui_config->save_state();
        }
 
-       delete keyboard;
-       delete editor;
-       delete mixer;
-       delete meterbridge;
-
        stop_video_server();
 }
 
@@ -745,6 +757,7 @@ ARDOUR_UI::starting ()
        try {
                audio_midi_setup.get (true);
        } catch (...) {
+               std::cerr << "audio-midi engine setup failed."<< std::endl;
                return -1;
        }
 
@@ -831,6 +844,7 @@ ARDOUR_UI::starting ()
                const bool new_session_required = (ARDOUR_COMMAND_LINE::new_session || brand_new_user);
 
                if (get_session_parameters (false, new_session_required, ARDOUR_COMMAND_LINE::load_template)) {
+                       std::cerr << "Cannot get session parameters."<< std::endl;
                        return -1;
                }
        }
@@ -992,8 +1006,6 @@ If you still wish to quit, please use the\n\n\
 
        close_all_dialogs ();
 
-       loading_message (string_compose (_("Please wait while %1 cleans up..."), PROGRAM_NAME));
-
        if (_session) {
                // _session->set_deletion_in_progress ();
                _session->set_clean ();
@@ -1004,6 +1016,9 @@ If you still wish to quit, please use the\n\n\
 
        halt_connection.disconnect ();
        AudioEngine::instance()->stop ();
+#ifdef WINDOWS_VST_SUPPORT
+       fst_stop_threading();
+#endif
        quit ();
 }
 
@@ -1402,7 +1417,7 @@ ARDOUR_UI::redisplay_recent_sessions ()
 
                get_state_files_in_directory (*i, state_file_paths);
 
-               vector<string*>* states;
+               vector<string> states;
                vector<const gchar*> item;
                string fullpath = *i;
 
@@ -1419,8 +1434,9 @@ ARDOUR_UI::redisplay_recent_sessions ()
                }
 
                /* now get available states for this session */
+               states = Session::possible_states (fullpath);
 
-               if ((states = Session::possible_states (fullpath)) == 0) {
+               if (states.empty()) {
                        /* no state file? */
                        continue;
                }
@@ -1429,14 +1445,14 @@ ARDOUR_UI::redisplay_recent_sessions ()
 
                Gtk::TreeModel::Row row = *(recent_session_model->append());
 
-               row[recent_session_columns.visible_name] = Glib::path_get_basename (fullpath);
                row[recent_session_columns.fullpath] = fullpath;
                row[recent_session_columns.tip] = Glib::Markup::escape_text (fullpath);
 
                if (state_file_names.size() > 1) {
+                       // multiple session files in the session directory - show the directory name.
+                       row[recent_session_columns.visible_name] = Glib::path_get_basename (fullpath);
 
                        // add the children
-
                        for (std::vector<std::string>::iterator i2 = state_file_names.begin();
                                        i2 != state_file_names.end(); ++i2)
                        {
@@ -1447,6 +1463,9 @@ ARDOUR_UI::redisplay_recent_sessions ()
                                child_row[recent_session_columns.fullpath] = fullpath;
                                child_row[recent_session_columns.tip] = Glib::Markup::escape_text (fullpath);
                        }
+               } else {
+                       // only a single session file in the directory - show its actual name.
+                       row[recent_session_columns.visible_name] = state_file_names.front ();
                }
        }
 
@@ -1645,10 +1664,10 @@ ARDOUR_UI::session_add_mixed_track (const ChanCount& input, const ChanCount& out
 
        catch (...) {
                MessageDialog msg (*editor,
-                                  string_compose (_("There are insufficient JACK ports available\n\
+                                  string_compose (_("There are insufficient ports available\n\
 to create a new track or bus.\n\
 You should save %1, exit and\n\
-restart JACK with more ports."), PROGRAM_NAME));
+restart with more ports."), PROGRAM_NAME));
                msg.run ();
        }
 }
@@ -1706,10 +1725,10 @@ ARDOUR_UI::session_add_audio_route (
 
        catch (...) {
                MessageDialog msg (*editor,
-                                  string_compose (_("There are insufficient JACK ports available\n\
+                                  string_compose (_("There are insufficient ports available\n\
 to create a new track or bus.\n\
 You should save %1, exit and\n\
-restart JACK with more ports."), PROGRAM_NAME));
+restart with more ports."), PROGRAM_NAME));
                pop_back_splash (msg);
                msg.run ();
        }
@@ -1871,12 +1890,25 @@ ARDOUR_UI::transport_roll ()
        bool rolling = _session->transport_rolling();
 
        if (_session->get_play_loop()) {
-               /* XXX it is not possible to just leave seamless loop and keep
-                  playing at present (nov 4th 2009)
+
+               /* If loop playback is not a mode, then we should cancel
+                  it when this action is requested. If it is a mode
+                  we just leave it in place.
                */
-               if (!Config->get_seamless_loop()) {
-                       _session->request_play_loop (false, true);
-               }
+
+               if (!Config->get_loop_is_mode()) {
+                       /* XXX it is not possible to just leave seamless loop and keep
+                          playing at present (nov 4th 2009)
+                       */
+                       if (!Config->get_seamless_loop()) {
+                               /* stop loop playback and stop rolling */
+                               _session->request_play_loop (false, true);
+                       } else if (rolling) {
+                               /* stop loop playback but keep rolling */
+                               _session->request_play_loop (false, false);
+                       }
+               } 
+
        } else if (_session->get_play_range () && !Config->get_always_play_range()) {
                /* stop playing a range if we currently are */
                _session->request_play_range (0, true);
@@ -1933,7 +1965,7 @@ ARDOUR_UI::toggle_roll (bool with_abort, bool roll_out_of_bounded_mode)
                                /* disk buffers are normal, so we can keep playing */
                                affect_transport = false;
                        }
-                       _session->request_play_loop (false, true);
+                       _session->request_play_loop (false, affect_transport);
                } else if (_session->get_play_range ()) {
                        affect_transport = false;
                        _session->request_play_range (0, true);
@@ -1964,16 +1996,23 @@ ARDOUR_UI::toggle_session_auto_loop ()
 
        if (_session->get_play_loop()) {
 
-               if (_session->transport_rolling()) {
+               /* looping enabled, our job is to disable it */
+
+               _session->request_play_loop (false);
 
-                       _session->request_locate (looploc->start(), true);
-                       _session->request_play_loop (false);
+       } else {
+
+               /* looping not enabled, our job is to enable it.
 
+                  loop-is-NOT-mode: this action always starts the transport rolling.
+                  loop-IS-mode:     this action simply sets the loop play mechanism, but
+                                       does not start transport.
+               */
+               if (Config->get_loop_is_mode()) {
+                       _session->request_play_loop (true, false);
                } else {
-                       _session->request_play_loop (false);
+                       _session->request_play_loop (true, true);
                }
-       } else {
-               _session->request_play_loop (true);
        }
        
        //show the loop markers
@@ -2101,7 +2140,11 @@ ARDOUR_UI::map_transport_state ()
 
                        auto_loop_button.set_active (true);
                        play_selection_button.set_active (false);
-                       roll_button.set_active (false);
+                       if (Config->get_loop_is_mode()) {
+                               roll_button.set_active (true);
+                       } else {
+                               roll_button.set_active (false);
+                       }
 
                } else {
 
@@ -2123,7 +2166,11 @@ ARDOUR_UI::map_transport_state ()
                stop_button.set_active (true);
                roll_button.set_active (false);
                play_selection_button.set_active (false);
-               auto_loop_button.set_active (false);
+               if (Config->get_loop_is_mode ()) {
+                       auto_loop_button.set_active (_session->get_play_loop());
+               } else {
+                       auto_loop_button.set_active (false);
+               }
                update_disk_space ();
        }
 }
@@ -2912,7 +2959,15 @@ ARDOUR_UI::load_session (const std::string& path, const std::string& snap_name,
                _session->set_clean ();
        }
 
+#ifdef WINDOWS_VST_SUPPORT
+       fst_stop_threading();
+#endif
+
        flush_pending ();
+
+#ifdef WINDOWS_VST_SUPPORT
+       fst_start_threading();
+#endif
        retval = 0;
 
   out:
@@ -3272,7 +3327,7 @@ ARDOUR_UI::setup_order_hint ()
        } else {
                for (TrackSelection::iterator s = editor->get_selection().tracks.begin(); s != editor->get_selection().tracks.end(); ++s) {
                        RouteTimeAxisView* tav = dynamic_cast<RouteTimeAxisView*> (*s);
-                       if (tav->route()->order_key() > order_hint) {
+                       if (tav && tav->route() && tav->route()->order_key() > order_hint) {
                                order_hint = tav->route()->order_key();
                        }
                }
@@ -3337,13 +3392,8 @@ ARDOUR_UI::add_route (Gtk::Window* float_window)
 
        setup_order_hint();
 
-       PBD::ScopedConnection idle_connection;
-
-       if (count > 8) {
-               ARDOUR::GUIIdle.connect (idle_connection, MISSING_INVALIDATOR, boost::bind (&Gtkmm2ext::UI::flush_pending, this), gui_context());
-       }
-
        string template_path = add_route_dialog->track_template();
+       DisplaySuspender ds;
 
        if (!template_path.empty()) {
                if (add_route_dialog->name_template_is_default())  {
@@ -3384,15 +3434,13 @@ ARDOUR_UI::add_route (Gtk::Window* float_window)
                session_add_audio_bus (input_chan.n_audio(), output_chan.n_audio(), route_group, count, name_template);
                break;
        }
-
-       /* idle connection will end at scope end */
 }
 
 void
 ARDOUR_UI::stop_video_server (bool ask_confirm)
 {
        if (!video_server_process && ask_confirm) {
-               warning << _("Video-Server was not launched by Ardour. The request to stop it is ignored.") << endmsg;
+               warning << string_compose (_("Video-Server was not launched by %1. The request to stop it is ignored."), PROGRAM_NAME) << endmsg;
        }
        if (video_server_process) {
                if(ask_confirm) {
@@ -3504,7 +3552,7 @@ ARDOUR_UI::start_video_server (Gtk::Window* float_window, bool popup_msg)
                        delete video_server_process;
                }
 
-               video_server_process = new SystemExec(icsd_exec, argp);
+               video_server_process = new ARDOUR::SystemExec(icsd_exec, argp);
                if (video_server_process->start()) {
                        warning << _("Cannot launch the video-server") << endmsg;
                        continue;
@@ -3512,6 +3560,7 @@ ARDOUR_UI::start_video_server (Gtk::Window* float_window, bool popup_msg)
                int timeout = 120; // 6 sec
                while (!ARDOUR_UI::instance()->video_timeline->check_server()) {
                        Glib::usleep (50000);
+                       gui_idle_handler();
                        if (--timeout <= 0 || !video_server_process->is_running()) break;
                }
                if (timeout <= 0) {
@@ -3777,6 +3826,116 @@ quickly enough to keep up with recording.\n"), PROGRAM_NAME));
        }
 }
 
+
+/* TODO: this is getting elaborate enough to warrant being split into a dedicated class */
+static MessageDialog *scan_dlg = NULL;
+static ProgressBar   *scan_pbar = NULL;
+static HBox          *scan_tbox = NULL;
+
+void
+ARDOUR_UI::cancel_plugin_scan ()
+{
+       PluginManager::instance().cancel_plugin_scan();
+}
+
+void
+ARDOUR_UI::cancel_plugin_timeout ()
+{
+       PluginManager::instance().cancel_plugin_timeout();
+       scan_tbox->hide();
+}
+
+void
+ARDOUR_UI::plugin_scan_timeout (int timeout)
+{
+       if (!scan_dlg || !scan_dlg->is_mapped() || !scan_pbar) {
+               return;
+       }
+       if (timeout > 0) {
+               scan_pbar->set_fraction ((float) timeout / (float) Config->get_vst_scan_timeout());
+               scan_tbox->show();
+       } else {
+               scan_tbox->hide();
+       }
+       gui_idle_handler();
+}
+
+void
+ARDOUR_UI::plugin_scan_dialog (std::string type, std::string plugin, bool can_cancel)
+{
+       if (type == X_("closeme") && !(scan_dlg && scan_dlg->is_mapped())) {
+               return;
+       }
+
+       const bool cancelled = PluginManager::instance().cancelled();
+       if (type != X_("closeme") && !Config->get_show_plugin_scan_window()) {
+               if (cancelled && scan_dlg->is_mapped()) {
+                       scan_dlg->hide();
+                       gui_idle_handler();
+                       return;
+               }
+               if (cancelled || !can_cancel) {
+                       return;
+               }
+       }
+
+       static Gtk::Button *cancel_button;
+       static Gtk::Button *timeout_button;
+       if (!scan_dlg) {
+               scan_dlg = new MessageDialog("", false, MESSAGE_INFO, BUTTONS_NONE); // TODO manage
+               VBox* vbox = scan_dlg->get_vbox();
+               vbox->set_size_request(400,-1);
+               scan_dlg->set_title (_("Scanning for plugins"));
+
+               cancel_button = manage(new Gtk::Button(_("Cancel plugin scan")));
+               cancel_button->set_name ("EditorGTKButton");
+               cancel_button->signal_clicked().connect ( mem_fun (*this, &ARDOUR_UI::cancel_plugin_scan) );
+               cancel_button->show();
+
+               scan_dlg->get_vbox()->pack_start ( *cancel_button, PACK_SHRINK);
+
+               scan_tbox = manage( new HBox() );
+
+               timeout_button = manage(new Gtk::Button(_("Stop Timeout")));
+               timeout_button->set_name ("EditorGTKButton");
+               timeout_button->signal_clicked().connect ( mem_fun (*this, &ARDOUR_UI::cancel_plugin_timeout) );
+               timeout_button->show();
+
+               scan_pbar = manage(new ProgressBar());
+               scan_pbar->set_orientation(Gtk::PROGRESS_RIGHT_TO_LEFT);
+               scan_pbar->set_text(_("Scan Timeout"));
+               scan_pbar->show();
+
+               scan_tbox->pack_start (*scan_pbar, PACK_EXPAND_WIDGET, 4);
+               scan_tbox->pack_start (*timeout_button, PACK_SHRINK, 4);
+
+               scan_dlg->get_vbox()->pack_start (*scan_tbox, PACK_SHRINK, 4);
+       }
+
+       if (type == X_("closeme")) {
+               scan_dlg->hide();
+       } else {
+               scan_dlg->set_message(type + ": " + Glib::path_get_basename(plugin));
+               scan_dlg->show();
+       }
+       if (!can_cancel || !cancelled) {
+               scan_tbox->hide();
+       }
+       cancel_button->set_sensitive(can_cancel && !cancelled);
+
+       gui_idle_handler();
+}
+
+void
+ARDOUR_UI::gui_idle_handler ()
+{
+       int timeout = 30;
+       /* due to idle calls, gtk_events_pending() may always return true */
+       while (gtk_events_pending() && --timeout) {
+               gtk_main_iteration ();
+       }
+}
+
 void
 ARDOUR_UI::disk_underrun_handler ()
 {
@@ -4109,10 +4268,14 @@ ARDOUR_UI::setup_profile ()
                Profile->set_small_screen ();
        }
 
-       if (getenv ("ARDOUR_SAE")) {
+       if (g_getenv ("ARDOUR_SAE")) {
                Profile->set_sae ();
                Profile->set_single_package ();
        }
+
+       if (g_getenv ("TRX")) {
+               Profile->set_trx ();
+       }
 }
 
 int