stop-and-forget-capture should not toggle transport state, only stop it
[ardour.git] / gtk2_ardour / ardour_ui.cc
index 3efd8159517bc98299f5f2d773283859f78a8c15..4778b6c47db0b94885da56cd8424e2123d4aa976 100644 (file)
 #include <sys/resource.h>
 #endif
 
+#ifdef __FreeBSD__
+#include <sys/types.h>
+#include <sys/sysctl.h>
+#endif
+
 #include <stdint.h>
 #include <fcntl.h>
 #include <signal.h>
 
 #include <gtkmm/messagedialog.h>
 #include <gtkmm/accelmap.h>
+#include <gtkmm/stock.h>
 
 #include "pbd/error.h"
 #include "pbd/basename.h"
 #include "pbd/compose.h"
+#include "pbd/convert.h"
 #include "pbd/failed_constructor.h"
 #include "pbd/enumwriter.h"
 #include "pbd/memento_command.h"
@@ -70,6 +77,7 @@
 
 #include "ardour/ardour.h"
 #include "ardour/audio_backend.h"
+#include "ardour/audio_track.h"
 #include "ardour/audioengine.h"
 #include "ardour/audiofilesource.h"
 #include "ardour/automation_watch.h"
 #include "ardour/filename_extensions.h"
 #include "ardour/filesystem_paths.h"
 #include "ardour/ltc_file_reader.h"
+#include "ardour/midi_track.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/record_enable_control.h"
 #include "ardour/session_directory.h"
 #include "ardour/session_route.h"
 #include "ardour/session_state_utils.h"
 #include "ardour/source_factory.h"
 #include "ardour/slave.h"
 #include "ardour/system_exec.h"
+#include "ardour/track.h"
+#include "ardour/vca_manager.h"
+#include "ardour/utils.h"
+
+#include "LuaBridge/LuaBridge.h"
 
 #ifdef WINDOWS_VST_SUPPORT
 #include <fst.h>
 #include "ardour/audio_unit.h"
 #endif
 
+// fix for OSX (nsm.h has a check function, AU/Apple defines check)
+#ifdef check
+#undef check
+#endif
+
 #include "timecode/time.h"
 
 typedef uint64_t microseconds_t;
@@ -112,6 +132,7 @@ typedef uint64_t microseconds_t;
 #include "big_clock_window.h"
 #include "bundle_manager.h"
 #include "duplicate_routes_dialog.h"
+#include "debug.h"
 #include "engine_dialog.h"
 #include "export_video_dialog.h"
 #include "export_video_infobox.h"
@@ -122,6 +143,8 @@ typedef uint64_t microseconds_t;
 #include "keyboard.h"
 #include "keyeditor.h"
 #include "location_ui.h"
+#include "lua_script_manager.h"
+#include "luawindow.h"
 #include "main_clock.h"
 #include "missing_file_dialog.h"
 #include "missing_plugin_dialog.h"
@@ -138,6 +161,7 @@ typedef uint64_t microseconds_t;
 #include "route_time_axis.h"
 #include "route_params_ui.h"
 #include "save_as_dialog.h"
+#include "script_selector.h"
 #include "session_dialog.h"
 #include "session_metadata_dialog.h"
 #include "session_option_editor.h"
@@ -212,19 +236,23 @@ libxml_structured_error_func (void* /* parsing_context*/,
 
        replace_all (msg, "\n", "");
 
-       if (err->file && err->line) {
-               error << X_("XML error: ") << msg << " in " << err->file << " at line " << err->line;
+       if (!msg.empty()) {
+               if (err->file && err->line) {
+                       error << X_("XML error: ") << msg << " in " << err->file << " at line " << err->line;
 
-               if (err->int2) {
-                       error << ':' << err->int2;
+                       if (err->int2) {
+                               error << ':' << err->int2;
+                       }
+
+                       error << endmsg;
+               } else {
+                       error << X_("XML error: ") << msg << endmsg;
                }
        }
-       error << endmsg;
 }
 
 
 ARDOUR_UI::ARDOUR_UI (int *argcp, char **argvp[], const char* localedir)
-
        : Gtkmm2ext::UI (PROGRAM_NAME, X_("gui"), argcp, argvp)
        , session_loaded (false)
        , gui_object_state (new GUIObjectState)
@@ -232,7 +260,9 @@ ARDOUR_UI::ARDOUR_UI (int *argcp, char **argvp[], const char* localedir)
        , secondary_clock (new MainClock (X_("secondary"), X_("secondary"), false))
        , big_clock (new AudioClock (X_("bigclock"), false, "big", true, true, false, false))
        , video_timeline(0)
+       , global_actions (X_("global"))
        , ignore_dual_punch (false)
+       , main_window_visibility (0)
        , editor (0)
        , mixer (0)
        , nsm (0)
@@ -261,21 +291,23 @@ ARDOUR_UI::ARDOUR_UI (int *argcp, char **argvp[], const char* localedir)
        , last_key_press_time (0)
        , save_as_dialog (0)
        , meterbridge (0)
+       , luawindow (0)
+       , rc_option_editor (0)
        , speaker_config_window (X_("speaker-config"), _("Speaker Configuration"))
-       , key_editor (X_("key-editor"), _("Key Bindings"))
-       , rc_option_editor (X_("rc-options-editor"), _("Preferences"))
        , add_route_dialog (X_("add-routes"), _("Add Tracks/Busses"))
        , about (X_("about"), _("About"))
-       , location_ui (X_("locations"), _("Locations"))
+       , location_ui (X_("locations"), S_("Ranges|Locations"))
        , route_params (X_("inspector"), _("Tracks and Busses"))
        , audio_midi_setup (X_("audio-midi-setup"), _("Audio/MIDI Setup"))
        , export_video_dialog (X_("video-export"), _("Video Export Dialog"))
+       , lua_script_window (X_("script-manager"), _("Script Manager"))
        , session_option_editor (X_("session-options-editor"), _("Properties"), boost::bind (&ARDOUR_UI::create_session_option_editor, this))
-       , add_video_dialog (X_("add-video"), _("Add Tracks/Busses"), boost::bind (&ARDOUR_UI::create_add_video_dialog, this))
+       , add_video_dialog (X_("add-video"), _("Add Video"), boost::bind (&ARDOUR_UI::create_add_video_dialog, this))
        , bundle_manager (X_("bundle-manager"), _("Bundle Manager"), boost::bind (&ARDOUR_UI::create_bundle_manager, this))
        , big_clock_window (X_("big-clock"), _("Big Clock"), boost::bind (&ARDOUR_UI::create_big_clock_window, this))
        , audio_port_matrix (X_("audio-connection-manager"), _("Audio Connections"), boost::bind (&ARDOUR_UI::create_global_port_matrix, this, ARDOUR::DataType::AUDIO))
        , midi_port_matrix (X_("midi-connection-manager"), _("MIDI Connections"), boost::bind (&ARDOUR_UI::create_global_port_matrix, this, ARDOUR::DataType::MIDI))
+       , key_editor (X_("key-editor"), _("Bindings Editor"), boost::bind (&ARDOUR_UI::create_key_editor, this))
        , video_server_process (0)
        , splash (0)
        , have_configure_timeout (false)
@@ -286,6 +318,9 @@ ARDOUR_UI::ARDOUR_UI (int *argcp, char **argvp[], const char* localedir)
        , _feedback_exists (false)
        , _log_not_acknowledged (LogLevelNone)
        , duplicate_routes_dialog (0)
+       , editor_visibility_button (S_("Window|Editor"))
+       , mixer_visibility_button (S_("Window|Mixer"))
+       , prefs_visibility_button (S_("Window|Preferences"))
 {
        Gtkmm2ext::init (localedir);
 
@@ -298,10 +333,22 @@ ARDOUR_UI::ARDOUR_UI (int *argcp, char **argvp[], const char* localedir)
                _exit (0);
        }
 
+
+       if (string (VERSIONSTRING).find (".pre") != string::npos) {
+               /* check this is not being run from ./ardev etc. */
+               if (!running_from_source_tree ()) {
+                       pre_release_dialog ();
+               }
+       }
+
        if (theArdourUI == 0) {
                theArdourUI = this;
        }
 
+       /* track main window visibility */
+
+       main_window_visibility = new VisibilityTracker (_main_window);
+
        /* stop libxml from spewing to stdout/stderr */
 
        xmlSetGenericErrorFunc (this, libxml_generic_error_func);
@@ -349,6 +396,9 @@ ARDOUR_UI::ARDOUR_UI (int *argcp, char **argvp[], const char* localedir)
 
        ARDOUR::Session::AskAboutSampleRateMismatch.connect_same_thread (forever_connections, boost::bind (&ARDOUR_UI::sr_mismatch_dialog, this, _1, _2));
 
+       /* handle sr mismatch with a dialog - cross-thread from engine */
+       ARDOUR::Session::NotifyAboutSampleRateMismatch.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::sr_mismatch_message, this, _1, _2), gui_context ());
+
        /* handle requests to quit (coming from JACK session) */
 
        ARDOUR::Session::Quit.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::finish, this), gui_context ());
@@ -391,9 +441,6 @@ ARDOUR_UI::ARDOUR_UI (int *argcp, char **argvp[], const char* localedir)
                keyboard->set_state (*node, Stateful::loading_state_version);
        }
 
-       /* we don't like certain modifiers */
-       Bindings::set_ignored_state (GDK_LOCK_MASK|GDK_MOD2_MASK|GDK_MOD3_MASK);
-
        UIConfiguration::instance().reset_dpi ();
 
        TimeAxisViewItem::set_constant_heights ();
@@ -407,24 +454,25 @@ ARDOUR_UI::ARDOUR_UI (int *argcp, char **argvp[], const char* localedir)
        const XMLNode* ui_xml = Config->extra_xml (X_("UI"));
 
        if (ui_xml) {
-               key_editor.set_state (*ui_xml);
-               rc_option_editor.set_state (*ui_xml);
-               session_option_editor.set_state (*ui_xml);
-               speaker_config_window.set_state (*ui_xml);
-               about.set_state (*ui_xml);
-               add_route_dialog.set_state (*ui_xml);
-               add_video_dialog.set_state (*ui_xml);
-               route_params.set_state (*ui_xml);
-               bundle_manager.set_state (*ui_xml);
-               location_ui.set_state (*ui_xml);
-               big_clock_window.set_state (*ui_xml);
-               audio_port_matrix.set_state (*ui_xml);
-               midi_port_matrix.set_state (*ui_xml);
-               export_video_dialog.set_state (*ui_xml);
-       }
+               key_editor.set_state (*ui_xml, 0);
+               session_option_editor.set_state (*ui_xml, 0);
+               speaker_config_window.set_state (*ui_xml, 0);
+               about.set_state (*ui_xml, 0);
+               add_route_dialog.set_state (*ui_xml, 0);
+               add_video_dialog.set_state (*ui_xml, 0);
+               route_params.set_state (*ui_xml, 0);
+               bundle_manager.set_state (*ui_xml, 0);
+               location_ui.set_state (*ui_xml, 0);
+               big_clock_window.set_state (*ui_xml, 0);
+               audio_port_matrix.set_state (*ui_xml, 0);
+               midi_port_matrix.set_state (*ui_xml, 0);
+               export_video_dialog.set_state (*ui_xml, 0);
+               lua_script_window.set_state (*ui_xml, 0);
+       }
+
+       /* Separate windows */
 
        WM::Manager::instance().register_window (&key_editor);
-       WM::Manager::instance().register_window (&rc_option_editor);
        WM::Manager::instance().register_window (&session_option_editor);
        WM::Manager::instance().register_window (&speaker_config_window);
        WM::Manager::instance().register_window (&about);
@@ -433,12 +481,16 @@ ARDOUR_UI::ARDOUR_UI (int *argcp, char **argvp[], const char* localedir)
        WM::Manager::instance().register_window (&route_params);
        WM::Manager::instance().register_window (&audio_midi_setup);
        WM::Manager::instance().register_window (&export_video_dialog);
+       WM::Manager::instance().register_window (&lua_script_window);
        WM::Manager::instance().register_window (&bundle_manager);
        WM::Manager::instance().register_window (&location_ui);
        WM::Manager::instance().register_window (&big_clock_window);
        WM::Manager::instance().register_window (&audio_port_matrix);
        WM::Manager::instance().register_window (&midi_port_matrix);
 
+       /* do not retain position for add route dialog */
+       add_route_dialog.set_state_mask (WindowProxy::Size);
+
        /* Trigger setting up the color scheme and loading the GTK RC file */
 
        UIConfiguration::instance().load_rc_file (false);
@@ -451,6 +503,40 @@ ARDOUR_UI::ARDOUR_UI (int *argcp, char **argvp[], const char* localedir)
        attach_to_engine ();
 }
 
+void
+ARDOUR_UI::pre_release_dialog ()
+{
+       ArdourDialog d (_("Pre-Release Warning"), true, false);
+       d.add_button (Gtk::Stock::OK, Gtk::RESPONSE_OK);
+
+        Label* label = manage (new Label);
+        label->set_markup (string_compose (_("<b>Welcome to this pre-release build of %1 %2</b>\n\n\
+There are still several issues and bugs to be worked on,\n\
+as well as general workflow improvements, before this can be considered\n\
+release software. So, a few guidelines:\n\
+\n\
+1) Please do <b>NOT</b> use this software with the expectation that it is stable or reliable\n\
+   though it may be so, depending on your workflow.\n\
+2) Please wait for a helpful writeup of new features.\n\
+3) <b>Please do NOT use the forums at ardour.org to report issues</b>.\n\
+4) Please <b>DO</b> use the bugtracker at http://tracker.ardour.org/ to report issues\n\
+   making sure to note the product version number as 5.0-pre.\n\
+5) Please <b>DO</b> use the ardour-users mailing list to discuss ideas and pass on comments.\n\
+6) Please <b>DO</b> join us on IRC for real time discussions about %1 %2. You\n\
+   can get there directly from within the program via the Help->Chat menu option.\n\
+\n\
+Full information on all the above can be found on the support page at\n\
+\n\
+                http://ardour.org/support\n\
+"), PROGRAM_NAME, VERSIONSTRING));
+
+        d.get_vbox()->set_border_width (12);
+        d.get_vbox()->pack_start (*label, false, false, 12);
+        d.get_vbox()->show_all ();
+
+        d.run ();
+}
+
 GlobalPortMatrixWindow*
 ARDOUR_UI::create_global_port_matrix (ARDOUR::DataType type)
 {
@@ -533,7 +619,7 @@ was not fast enough. Try to restart\n\
 the audio backend and save the session."), PROGRAM_NAME);
        }
 
-       MessageDialog msg (*editor, msgstr);
+       MessageDialog msg (_main_window, msgstr);
        pop_back_splash (msg);
        msg.run ();
 
@@ -578,22 +664,32 @@ ARDOUR_UI::post_engine ()
 
        check_memory_locking();
 
-       /* this is the first point at which all the keybindings are available */
+       /* this is the first point at which all the possible actions are
+        * available, because some of the available actions are dependent on
+        * aspects of the engine/backend.
+        */
 
        if (ARDOUR_COMMAND_LINE::show_key_actions) {
-               vector<string> names;
+
+
                vector<string> paths;
+               vector<string> labels;
                vector<string> tooltips;
                vector<string> keys;
-               vector<AccelKey> bindings;
+               vector<Glib::RefPtr<Gtk::Action> > actions;
 
-               ActionManager::get_all_actions (names, paths, tooltips, keys, bindings);
+               Gtkmm2ext::ActionMap::get_all_actions (paths, labels, tooltips, keys, actions);
 
-               vector<string>::iterator n;
                vector<string>::iterator k;
                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;
+
+               for (p = paths.begin(), k = keys.begin(); p != paths.end(); ++k, ++p) {
+
+                       if ((*k).empty()) {
+                               cout << *p << endl;
+                       } else {
+                               cout << *p << " => " << *k << endl;
+                       }
                }
 
                halt_connection.disconnect ();
@@ -608,17 +704,12 @@ ARDOUR_UI::post_engine ()
 
        /* set default clock modes */
 
-       if (Profile->get_sae()) {
-               primary_clock->set_mode (AudioClock::BBT);
-               secondary_clock->set_mode (AudioClock::MinSec);
-       }  else {
-               primary_clock->set_mode (AudioClock::Timecode);
-               secondary_clock->set_mode (AudioClock::BBT);
-       }
+       primary_clock->set_mode (AudioClock::Timecode);
+       secondary_clock->set_mode (AudioClock::BBT);
 
        /* start the time-of-day-clock */
 
-#ifndef GTKOSX
+#ifndef __APPLE__
        /* OS X provides a nearly-always visible wallclock, so don't be stupid */
        update_wall_clock ();
        Glib::signal_timeout().connect_seconds (sigc::mem_fun(*this, &ARDOUR_UI::update_wall_clock), 1);
@@ -642,15 +733,17 @@ ARDOUR_UI::~ARDOUR_UI ()
 
        if (getenv ("ARDOUR_RUNNING_UNDER_VALGRIND")) {
                // don't bother at 'real' exit. the OS cleans up for us.
-               delete big_clock;
-               delete primary_clock;
-               delete secondary_clock;
-               delete _process_thread;
-               delete meterbridge;
-               delete editor;
-               delete mixer;
-               delete nsm;
-               delete gui_object_state;
+               delete big_clock; big_clock = 0;
+               delete primary_clock; primary_clock = 0;
+               delete secondary_clock; secondary_clock = 0;
+               delete _process_thread; _process_thread = 0;
+               delete meterbridge; meterbridge = 0;
+               delete luawindow; luawindow = 0;
+               delete editor; editor = 0;
+               delete mixer; mixer = 0;
+               delete nsm; nsm = 0;
+               delete gui_object_state; gui_object_state = 0;
+               delete main_window_visibility;
                FastMeter::flush_pattern_cache ();
                PixFader::flush_pattern_cache ();
        }
@@ -709,7 +802,7 @@ ARDOUR_UI::configure_handler (GdkEventConfigure* /*conf*/)
 void
 ARDOUR_UI::set_transport_controllable_state (const XMLNode& node)
 {
-       const XMLProperty* prop;
+       XMLProperty const * prop;
 
        if ((prop = node.property ("roll")) != 0) {
                roll_controllable->set_id (prop->value());
@@ -794,10 +887,15 @@ ARDOUR_UI::autosave_session ()
 }
 
 void
-ARDOUR_UI::update_autosave ()
+ARDOUR_UI::session_dirty_changed ()
 {
-       ENSURE_GUI_THREAD (*this, &ARDOUR_UI::update_autosave)
+       update_autosave ();
+       update_title ();
+}
 
+void
+ARDOUR_UI::update_autosave ()
+{
        if (_session && _session->dirty()) {
                if (_autosave_connection.connected()) {
                        _autosave_connection.disconnect();
@@ -848,6 +946,13 @@ ARDOUR_UI::check_announcements ()
 #endif
 }
 
+static bool
+_hide_splash (gpointer arg)
+{
+       ((ARDOUR_UI*)arg)->hide_splash();
+       return false;
+}
+
 int
 ARDOUR_UI::starting ()
 {
@@ -1020,8 +1125,6 @@ ARDOUR_UI::starting ()
 
        use_config ();
 
-       goto_editor_window ();
-
        WM::Manager::instance().show_visible ();
 
        /* We have to do this here since goto_editor_window() ends up calling show_all() on the
@@ -1030,6 +1133,14 @@ ARDOUR_UI::starting ()
        _status_bar_visibility.update ();
 
        BootMessage (string_compose (_("%1 is ready for use"), PROGRAM_NAME));
+
+       if (splash && splash->is_visible()) {
+               // in 1 second, hide the splash screen
+               Glib::signal_timeout().connect (sigc::bind (sigc::ptr_fun (_hide_splash), this), 1000);
+       }
+
+       /* all other dialogs are created conditionally */
+
        return 0;
 }
 
@@ -1097,7 +1208,6 @@ ARDOUR_UI::check_memory_locking ()
 
                                pop_back_splash (msg);
 
-                               editor->ensure_float (msg);
                                msg.run ();
 
                                if (cb.get_active()) {
@@ -1143,7 +1253,7 @@ ARDOUR_UI::finish()
                                /* use the default name */
                                if (save_state_canfail ("")) {
                                        /* failed - don't quit */
-                                       MessageDialog msg (*editor,
+                                       MessageDialog msg (_main_window,
                                                           string_compose (_("\
 %1 was unable to save your session.\n\n\
 If you still wish to quit, please use the\n\n\
@@ -1514,7 +1624,7 @@ void
 ARDOUR_UI::count_recenabled_streams (Route& route)
 {
        Track* track = dynamic_cast<Track*>(&route);
-       if (track && track->record_enabled()) {
+       if (track && track->rec_enable_control()->get_value()) {
                rec_enabled_streams += track->n_inputs().n_total();
        }
 }
@@ -1665,6 +1775,10 @@ ARDOUR_UI::open_recent_session ()
 
                can_return = false;
        }
+       if (splash && splash->is_visible()) {
+               // in 1 second, hide the splash screen
+               Glib::signal_timeout().connect (sigc::bind (sigc::ptr_fun (_hide_splash), this), 1000);
+       }
 }
 
 bool
@@ -1672,8 +1786,8 @@ ARDOUR_UI::check_audioengine (Gtk::Window& parent)
 {
        if (!AudioEngine::instance()->connected()) {
                MessageDialog msg (parent, string_compose (
-                                          _("%1 is not connected to any audio backend.\n"
-                                            "You cannot open or close sessions in this condition"),
+                                          _("%1 is not connected to any audio backend.\n"
+                                            "You cannot open or close sessions in this condition"),
                                           PROGRAM_NAME));
                pop_back_splash (msg);
                msg.run ();
@@ -1685,7 +1799,7 @@ ARDOUR_UI::check_audioengine (Gtk::Window& parent)
 void
 ARDOUR_UI::open_session ()
 {
-       if (!check_audioengine(*editor)) {
+       if (!check_audioengine (_main_window)) {
                return;
        }
 
@@ -1737,10 +1851,27 @@ ARDOUR_UI::open_session ()
        }
 }
 
+void
+ARDOUR_UI::session_add_vca (const string& name_template, uint32_t n)
+{
+       if (!_session) {
+               return;
+       }
+
+       _session->vca_manager().create_vca (n, name_template);
+}
 
 void
-ARDOUR_UI::session_add_mixed_track (const ChanCount& input, const ChanCount& output, RouteGroup* route_group,
-                                   uint32_t how_many, const string& name_template, PluginInfoPtr instrument)
+ARDOUR_UI::session_add_mixed_track (
+               const ChanCount& input,
+               const ChanCount& output,
+               RouteGroup* route_group,
+               uint32_t how_many,
+               const string& name_template,
+               bool strict_io,
+               PluginInfoPtr instrument,
+               Plugin::PresetRecord* pset,
+               ARDOUR::PresentationInfo::order_t order)
 {
        list<boost::shared_ptr<MidiTrack> > tracks;
 
@@ -1750,7 +1881,7 @@ ARDOUR_UI::session_add_mixed_track (const ChanCount& input, const ChanCount& out
        }
 
        try {
-               tracks = _session->new_midi_track (input, output, instrument, ARDOUR::Normal, route_group, how_many, name_template);
+               tracks = _session->new_midi_track (input, output, instrument, pset, route_group, how_many, name_template, order, ARDOUR::Normal);
 
                if (tracks.size() != how_many) {
                        error << string_compose(P_("could not create %1 new mixed track", "could not create %1 new mixed tracks", how_many), how_many) << endmsg;
@@ -1758,24 +1889,72 @@ ARDOUR_UI::session_add_mixed_track (const ChanCount& input, const ChanCount& out
        }
 
        catch (...) {
-               MessageDialog msg (*editor,
-                                  string_compose (_("There are insufficient ports available\n\
-to create a new track or bus.\n\
-You should save %1, exit and\n\
-restart with more ports."), PROGRAM_NAME));
-               msg.run ();
+               display_insufficient_ports_message ();
+               return;
+       }
+
+       if (strict_io) {
+               for (list<boost::shared_ptr<MidiTrack> >::iterator i = tracks.begin(); i != tracks.end(); ++i) {
+                       (*i)->set_strict_io (true);
+               }
        }
 }
 
+void
+ARDOUR_UI::session_add_midi_bus (
+               RouteGroup* route_group,
+               uint32_t how_many,
+               const string& name_template,
+               bool strict_io,
+               PluginInfoPtr instrument,
+               Plugin::PresetRecord* pset,
+               ARDOUR::PresentationInfo::order_t order)
+{
+       RouteList routes;
+
+       if (_session == 0) {
+               warning << _("You cannot add a track without a session already loaded.") << endmsg;
+               return;
+       }
+
+       try {
+
+               routes = _session->new_midi_route (route_group, how_many, name_template, instrument, pset, PresentationInfo::MidiBus, order);
+               if (routes.size() != how_many) {
+                       error << string_compose(P_("could not create %1 new Midi Bus", "could not create %1 new Midi Busses", how_many), how_many) << endmsg;
+               }
+
+       }
+       catch (...) {
+               display_insufficient_ports_message ();
+               return;
+       }
+
+       if (strict_io) {
+               for (RouteList::iterator i = routes.begin(); i != routes.end(); ++i) {
+                       (*i)->set_strict_io (true);
+               }
+       }
+}
 
 void
-ARDOUR_UI::session_add_midi_route (bool disk, RouteGroup* route_group, uint32_t how_many, const string& name_template, PluginInfoPtr instrument)
+ARDOUR_UI::session_add_midi_route (
+               bool disk,
+               RouteGroup* route_group,
+               uint32_t how_many,
+               const string& name_template,
+               bool strict_io,
+               PluginInfoPtr instrument,
+               Plugin::PresetRecord* pset,
+               ARDOUR::PresentationInfo::order_t order)
 {
        ChanCount one_midi_channel;
        one_midi_channel.set (DataType::MIDI, 1);
 
        if (disk) {
-               session_add_mixed_track (one_midi_channel, one_midi_channel, route_group, how_many, name_template, instrument);
+               session_add_mixed_track (one_midi_channel, one_midi_channel, route_group, how_many, name_template, strict_io, instrument, pset, order);
+       } else {
+               session_add_midi_bus (route_group, how_many, name_template, strict_io, instrument, pset, order);
        }
 }
 
@@ -1787,8 +1966,9 @@ ARDOUR_UI::session_add_audio_route (
        ARDOUR::TrackMode mode,
        RouteGroup* route_group,
        uint32_t how_many,
-       string const & name_template
-       )
+       string const & name_template,
+       bool strict_io,
+       ARDOUR::PresentationInfo::order_t order)
 {
        list<boost::shared_ptr<AudioTrack> > tracks;
        RouteList routes;
@@ -1800,7 +1980,7 @@ ARDOUR_UI::session_add_audio_route (
 
        try {
                if (track) {
-                       tracks = _session->new_audio_track (input_channels, output_channels, mode, route_group, how_many, name_template);
+                       tracks = _session->new_audio_track (input_channels, output_channels, route_group, how_many, name_template, order, mode);
 
                        if (tracks.size() != how_many) {
                                error << string_compose (P_("could not create %1 new audio track", "could not create %1 new audio tracks", how_many), how_many)
@@ -1809,7 +1989,7 @@ ARDOUR_UI::session_add_audio_route (
 
                } else {
 
-                       routes = _session->new_audio_route (input_channels, output_channels, route_group, how_many, name_template);
+                       routes = _session->new_audio_route (input_channels, output_channels, route_group, how_many, name_template, PresentationInfo::AudioBus, order);
 
                        if (routes.size() != how_many) {
                                error << string_compose (P_("could not create %1 new audio bus", "could not create %1 new audio busses", how_many), how_many)
@@ -1819,14 +1999,30 @@ ARDOUR_UI::session_add_audio_route (
        }
 
        catch (...) {
-               MessageDialog msg (*editor,
-                                  string_compose (_("There are insufficient ports available\n\
+               display_insufficient_ports_message ();
+               return;
+       }
+
+       if (strict_io) {
+               for (list<boost::shared_ptr<AudioTrack> >::iterator i = tracks.begin(); i != tracks.end(); ++i) {
+                       (*i)->set_strict_io (true);
+               }
+               for (RouteList::iterator i = routes.begin(); i != routes.end(); ++i) {
+                       (*i)->set_strict_io (true);
+               }
+       }
+}
+
+void
+ARDOUR_UI::display_insufficient_ports_message ()
+{
+       MessageDialog msg (_main_window,
+                       string_compose (_("There are insufficient ports available\n\
 to create a new track or bus.\n\
 You should save %1, exit and\n\
 restart with more ports."), PROGRAM_NAME));
-               pop_back_splash (msg);
-               msg.run ();
-       }
+       pop_back_splash (msg);
+       msg.run ();
 }
 
 void
@@ -1945,14 +2141,14 @@ ARDOUR_UI::trx_record_enable_all_tracks ()
                boost::shared_ptr<Track> t = boost::dynamic_pointer_cast<Track> (*r);
                assert (t);
 
-               if (t->record_enabled()) {
+               if (t->rec_enable_control()->get_value()) {
                        none_record_enabled = false;
                        break;
                }
        }
 
        if (none_record_enabled) {
-               _session->set_record_enabled (rl, true, Session::rt_cleanup);
+               _session->set_controls (route_list_to_control_list (rl, &Stripable::rec_enable_control), 1.0, Controllable::NoGroup);
        }
 
        return none_record_enabled;
@@ -1965,7 +2161,7 @@ ARDOUR_UI::transport_record (bool roll)
                switch (_session->record_status()) {
                case Session::Disabled:
                        if (_session->ntracks() == 0) {
-                               MessageDialog msg (*editor, _("Please create one or more tracks before trying to record.\nYou can do this with the \"Add Track or Bus\" option in the Session menu."));
+                               MessageDialog msg (_main_window, _("Please create one or more tracks before trying to record.\nYou can do this with the \"Add Track or Bus\" option in the Session menu."));
                                msg.run ();
                                return;
                        }
@@ -2110,7 +2306,17 @@ ARDOUR_UI::toggle_roll (bool with_abort, bool roll_out_of_bounded_mode)
        if (affect_transport) {
                if (rolling) {
                        _session->request_stop (with_abort, true);
-               } else if (!_session->config.get_external_sync()) {
+
+               } else if (!with_abort) { /* with_abort == true means the
+                                          * command was intended to stop
+                                          * transport, not start.
+                                          */
+
+                       /* the only external sync condition we can be in here
+                        * would be Engine (JACK) sync, in which case we still
+                        * want to do this.
+                        */
+
                        if (UIConfiguration::instance().get_follow_edits() && ( editor->get_selection().time.front().start == _session->transport_frame() ) ) {  //if playhead is exactly at the start of a range, we can assume it was placed there by follow_edits
                                _session->request_play_range (&editor->get_selection().time, true);
                                _session->set_requested_return_frame( editor->get_selection().time.front().start );  //force an auto-return here
@@ -2232,7 +2438,7 @@ ARDOUR_UI::transport_forward (int option)
 }
 
 void
-ARDOUR_UI::toggle_record_enable (uint32_t rid)
+ARDOUR_UI::toggle_record_enable (uint16_t rid)
 {
        if (!_session) {
                return;
@@ -2240,12 +2446,12 @@ ARDOUR_UI::toggle_record_enable (uint32_t rid)
 
        boost::shared_ptr<Route> r;
 
-       if ((r = _session->route_by_remote_id (rid)) != 0) {
+       if ((r = _session->get_remote_nth_route (rid)) != 0) {
 
-               Track* t;
+               boost::shared_ptr<Track> t;
 
-               if ((t = dynamic_cast<Track*>(r.get())) != 0) {
-                       t->set_record_enabled (!t->record_enabled(), this);
+               if ((t = boost::dynamic_pointer_cast<Track>(r)) != 0) {
+                       t->rec_enable_control()->set_value (!t->rec_enable_control()->get_value(), Controllable::UseGroup);
                }
        }
 }
@@ -2448,6 +2654,21 @@ ARDOUR_UI::save_session_as ()
        }
 }
 
+void
+ARDOUR_UI::quick_snapshot_session (bool switch_to_it)
+{
+               char timebuf[128];
+               time_t n;
+               struct tm local_time;
+
+               time (&n);
+               localtime_r (&n, &local_time);
+               strftime (timebuf, sizeof(timebuf), "%FT%H.%M.%S", &local_time);
+
+               save_state (timebuf, switch_to_it);
+}
+
+
 bool
 ARDOUR_UI::process_snapshot_session_prompter (ArdourPrompter& prompter, bool switch_to_it)
 {
@@ -2500,7 +2721,7 @@ ARDOUR_UI::snapshot_session (bool switch_to_it)
        prompter.set_name ("Prompter");
        prompter.add_button (Gtk::Stock::SAVE, Gtk::RESPONSE_ACCEPT);
        if (switch_to_it) {
-               prompter.set_title (_("Save as..."));
+               prompter.set_title (_("Snapshot and switch"));
                prompter.set_prompt (_("New session name"));
        } else {
                prompter.set_title (_("Take Snapshot"));
@@ -2719,7 +2940,7 @@ ARDOUR_UI::save_template ()
 {
        ArdourPrompter prompter (true);
 
-       if (!check_audioengine(*editor)) {
+       if (!check_audioengine (_main_window)) {
                return;
        }
 
@@ -2791,7 +3012,7 @@ ARDOUR_UI::build_session_from_dialog (SessionDialog& sd, const std::string& sess
 {
        BusProfile bus_profile;
 
-       if (nsm || Profile->get_sae()) {
+       if (nsm) {
 
                bus_profile.master_out_channels = 2;
                bus_profile.input_ac = AutoConnectPhysical;
@@ -2839,7 +3060,6 @@ ARDOUR_UI::build_session_from_dialog (SessionDialog& sd, const std::string& sess
 void
 ARDOUR_UI::load_from_application_api (const std::string& path)
 {
-       printf("ARDOUR_UI::load_from_application_api\n");
        ARDOUR_COMMAND_LINE::session_name = path;
        /* Cancel SessionDialog if it's visible to make OSX delegates work.
         *
@@ -2880,8 +3100,6 @@ ARDOUR_UI::load_from_application_api (const std::string& path)
                if (get_session_parameters (true, false)) {
                        exit (1);
                }
-
-               goto_editor_window ();
        }
 }
 
@@ -3128,7 +3346,7 @@ ARDOUR_UI::get_session_parameters (bool quit_on_cancel, bool should_be_new, stri
 void
 ARDOUR_UI::close_session()
 {
-       if (!check_audioengine(*editor)) {
+       if (!check_audioengine (_main_window)) {
                return;
        }
 
@@ -3141,8 +3359,10 @@ ARDOUR_UI::close_session()
        if (get_session_parameters (true, false)) {
                exit (1);
        }
-
-       goto_editor_window ();
+       if (splash && splash->is_visible()) {
+               // in 1 second, hide the splash screen
+               Glib::signal_timeout().connect (sigc::bind (sigc::ptr_fun (_hide_splash), this), 1000);
+       }
 }
 
 /** @param snap_name Snapshot name (without .ardour suffix).
@@ -3279,8 +3499,6 @@ ARDOUR_UI::load_session (const std::string& path, const std::string& snap_name,
 
        session_loaded = true;
 
-       goto_editor_window ();
-
        if (_session) {
                _session->set_clean ();
        }
@@ -3496,7 +3714,7 @@ ARDOUR_UI::display_cleanup_results (ARDOUR::CleanupReport& rep, const gchar* lis
        removed = rep.paths.size();
 
        if (removed == 0) {
-               MessageDialog msgd (*editor,
+               MessageDialog msgd (_main_window,
                                    _("No files were ready for clean-up"),
                                    true,
                                    Gtk::MESSAGE_INFO,
@@ -3745,15 +3963,15 @@ ARDOUR_UI::cleanup_peakfiles ()
        }
 }
 
-void
-ARDOUR_UI::setup_order_hint (AddRouteDialog::InsertAt place)
+PresentationInfo::order_t
+ARDOUR_UI::translate_order (AddRouteDialog::InsertAt place)
 {
-       uint32_t order_hint = UINT32_MAX;
-
        if (editor->get_selection().tracks.empty()) {
-               return;
+               return PresentationInfo::max_order;
        }
 
+       PresentationInfo::order_t order_hint = PresentationInfo::max_order;
+
        /*
          we want the new routes to have their order keys set starting from
          the highest order key in the selection + 1 (if available).
@@ -3762,42 +3980,21 @@ ARDOUR_UI::setup_order_hint (AddRouteDialog::InsertAt place)
        if (place == AddRouteDialog::AfterSelection) {
                RouteTimeAxisView *rtav = dynamic_cast<RouteTimeAxisView*> (editor->get_selection().tracks.back());
                if (rtav) {
-                       order_hint = rtav->route()->order_key();
+                       order_hint = rtav->route()->presentation_info().order();
                        order_hint++;
                }
        } else if (place == AddRouteDialog::BeforeSelection) {
                RouteTimeAxisView *rtav = dynamic_cast<RouteTimeAxisView*> (editor->get_selection().tracks.front());
                if (rtav) {
-                       order_hint = rtav->route()->order_key();
+                       order_hint = rtav->route()->presentation_info().order();
                }
        } else if (place == AddRouteDialog::First) {
                order_hint = 0;
        } else {
-               /* leave order_hint at UINT32_MAX */
-       }
-
-       if (order_hint == UINT32_MAX) {
-               /** AddRouteDialog::Last or selection with first/last not a RouteTimeAxisView
-                * not setting an order hint will place new routes last.
-                */
-               return;
+               /* leave order_hint at max_order */
        }
 
-       _session->set_order_hint (order_hint);
-
-       /* create a gap in the existing route order keys to accomodate new routes.*/
-       boost::shared_ptr <RouteList> rd = _session->get_routes();
-       for (RouteList::iterator ri = rd->begin(); ri != rd->end(); ++ri) {
-               boost::shared_ptr<Route> rt (*ri);
-
-               if (rt->is_monitor()) {
-                       continue;
-               }
-
-               if (rt->order_key () >= order_hint) {
-                       rt->set_order_key (rt->order_key () + add_route_dialog->count());
-               }
-       }
+       return order_hint;
 }
 
 void
@@ -3815,9 +4012,11 @@ ARDOUR_UI::start_duplicate_routes ()
 }
 
 void
-ARDOUR_UI::add_route (Gtk::Window* /* ignored */)
+ARDOUR_UI::add_route ()
 {
-       int count;
+       if (!add_route_dialog.get (false)) {
+               add_route_dialog->signal_response().connect (sigc::mem_fun (*this, &ARDOUR_UI::add_route_dialog_finished));
+       }
 
        if (!_session) {
                return;
@@ -3828,7 +4027,14 @@ ARDOUR_UI::add_route (Gtk::Window* /* ignored */)
                return;
        }
 
-       ResponseType r = (ResponseType) add_route_dialog->run ();
+       add_route_dialog->set_position (WIN_POS_MOUSE);
+       add_route_dialog->present();
+}
+
+void
+ARDOUR_UI::add_route_dialog_finished (int r)
+{
+       int count;
 
        add_route_dialog->hide();
 
@@ -3844,8 +4050,7 @@ ARDOUR_UI::add_route (Gtk::Window* /* ignored */)
                return;
        }
 
-       setup_order_hint(add_route_dialog->insert_at());
-
+       PresentationInfo::order_t order = translate_order (add_route_dialog->insert_at());
        string template_path = add_route_dialog->track_template();
        DisplaySuspender ds;
 
@@ -3864,6 +4069,7 @@ ARDOUR_UI::add_route (Gtk::Window* /* ignored */)
        PluginInfoPtr instrument = add_route_dialog->requested_instrument ();
        RouteGroup* route_group = add_route_dialog->route_group ();
        AutoConnectOption oac = Config->get_output_auto_connect();
+       bool strict_io = add_route_dialog->use_strict_io ();
 
        if (oac & AutoConnectMaster) {
                output_chan.set (DataType::AUDIO, (_session->master_out() ? _session->master_out()->n_inputs().n_audio() : input_chan.n_audio()));
@@ -3876,17 +4082,106 @@ ARDOUR_UI::add_route (Gtk::Window* /* ignored */)
 
        switch (add_route_dialog->type_wanted()) {
        case AddRouteDialog::AudioTrack:
-               session_add_audio_track (input_chan.n_audio(), output_chan.n_audio(), add_route_dialog->mode(), route_group, count, name_template);
+               session_add_audio_track (input_chan.n_audio(), output_chan.n_audio(), add_route_dialog->mode(), route_group, count, name_template, strict_io, order);
                break;
        case AddRouteDialog::MidiTrack:
-               session_add_midi_track (route_group, count, name_template, instrument);
+               session_add_midi_track (route_group, count, name_template, strict_io, instrument, 0, order);
                break;
        case AddRouteDialog::MixedTrack:
-               session_add_mixed_track (input_chan, output_chan, route_group, count, name_template, instrument);
+               session_add_mixed_track (input_chan, output_chan, route_group, count, name_template, strict_io, instrument, 0, order);
                break;
        case AddRouteDialog::AudioBus:
-               session_add_audio_bus (input_chan.n_audio(), output_chan.n_audio(), route_group, count, name_template);
+               session_add_audio_bus (input_chan.n_audio(), output_chan.n_audio(), route_group, count, name_template, strict_io, order);
+               break;
+       case AddRouteDialog::MidiBus:
+               session_add_midi_bus (route_group, count, name_template, strict_io, instrument, 0, order);
                break;
+       case AddRouteDialog::VCAMaster:
+               session_add_vca (name_template, count);
+               break;
+       }
+}
+
+void
+ARDOUR_UI::add_lua_script ()
+{
+       if (!_session) {
+               return;
+       }
+
+       LuaScriptInfoPtr spi;
+       ScriptSelector ss ("Add Lua Session Script", LuaScriptInfo::Session);
+       switch (ss.run ()) {
+               case Gtk::RESPONSE_ACCEPT:
+                       spi = ss.script();
+                       break;
+               default:
+                       return;
+       }
+       ss.hide();
+
+       std::string script = "";
+
+       try {
+               script = Glib::file_get_contents (spi->path);
+       } catch (Glib::FileError e) {
+               string msg = string_compose (_("Cannot read session script '%1': %2"), spi->path, e.what());
+               MessageDialog am (msg);
+               am.run ();
+               return;
+       }
+
+       LuaScriptParamList lsp = LuaScriptParams::script_params (spi, "sess_params");
+       std::vector<std::string> reg = _session->registered_lua_functions ();
+
+       ScriptParameterDialog spd (_("Set Script Parameters"), spi, reg, lsp);
+       switch (spd.run ()) {
+               case Gtk::RESPONSE_ACCEPT:
+                       break;
+               default:
+                       return;
+       }
+
+       try {
+               _session->register_lua_function (spd.name(), script, lsp);
+       } catch (luabridge::LuaException const& e) {
+               string msg = string_compose (_("Session script '%1' instantiation failed: %2"), spd.name(), e.what ());
+               MessageDialog am (msg);
+               am.run ();
+       } catch (SessionException e) {
+               string msg = string_compose (_("Loading Session script '%1' failed: %2"), spd.name(), e.what ());
+               MessageDialog am (msg);
+               am.run ();
+       }
+}
+
+void
+ARDOUR_UI::remove_lua_script ()
+{
+       if (!_session) {
+               return;
+       }
+       if (_session->registered_lua_function_count () ==  0) {
+               string msg = _("There are no active Lua session scripts present in this session.");
+               MessageDialog am (msg);
+               am.run ();
+               return;
+       }
+
+       std::vector<std::string> reg = _session->registered_lua_functions ();
+       SessionScriptManager sm ("Remove Lua Session Script", reg);
+       switch (sm.run ()) {
+               case Gtk::RESPONSE_ACCEPT:
+                       break;
+               default:
+                       return;
+       }
+       try {
+               _session->unregister_lua_function (sm.name());
+       } catch (luabridge::LuaException const& e) {
+               string msg = string_compose (_("Session script '%1' removal failed: %2"), sm.name(), e.what ());
+               MessageDialog am (msg);
+               am.run ();
        }
 }
 
@@ -4267,6 +4562,30 @@ ARDOUR_UI::mixer_settings () const
        return node;
 }
 
+XMLNode*
+ARDOUR_UI::main_window_settings () const
+{
+       XMLNode* node = 0;
+
+       if (_session) {
+               node = _session->instant_xml(X_("Main"));
+       } else {
+               node = Config->instant_xml(X_("Main"));
+       }
+
+       if (!node) {
+               if (getenv("ARDOUR_INSTANT_XML_PATH")) {
+                       node = Config->instant_xml(getenv("ARDOUR_INSTANT_XML_PATH"));
+               }
+       }
+
+       if (!node) {
+               node = new XMLNode (X_("Main"));
+       }
+
+       return node;
+}
+
 XMLNode*
 ARDOUR_UI::editor_settings () const
 {
@@ -4318,7 +4637,7 @@ void
 ARDOUR_UI::halt_on_xrun_message ()
 {
         cerr << "HALT on xrun\n";
-       MessageDialog msg (*editor, _("Recording was stopped because your system could not keep up."));
+        MessageDialog msg (_main_window, _("Recording was stopped because your system could not keep up."));
        msg.run ();
 }
 
@@ -4347,7 +4666,7 @@ ARDOUR_UI::disk_overrun_handler ()
 
        if (!have_disk_speed_dialog_displayed) {
                have_disk_speed_dialog_displayed = true;
-               MessageDialog* msg = new MessageDialog (*editor, string_compose (_("\
+               MessageDialog* msg = new MessageDialog (_main_window, string_compose (_("\
 The disk system on your computer\n\
 was not able to keep up with %1.\n\
 \n\
@@ -4482,7 +4801,7 @@ ARDOUR_UI::disk_underrun_handler ()
        if (!have_disk_speed_dialog_displayed) {
                have_disk_speed_dialog_displayed = true;
                MessageDialog* msg = new MessageDialog (
-                       *editor, string_compose (_("The disk system on your computer\n\
+                       _main_window, string_compose (_("The disk system on your computer\n\
 was not able to keep up with %1.\n\
 \n\
 Specifically, it failed to read data from disk\n\
@@ -4506,12 +4825,7 @@ ARDOUR_UI::session_dialog (std::string msg)
 
        MessageDialog* d;
 
-       if (editor) {
-               d = new MessageDialog (*editor, msg, false, MESSAGE_INFO, BUTTONS_OK, true);
-       } else {
-               d = new MessageDialog (msg, false, MESSAGE_INFO, BUTTONS_OK, true);
-       }
-
+       d = new MessageDialog (msg, false, MESSAGE_INFO, BUTTONS_OK, true);
        d->show_all ();
        d->run ();
        delete d;
@@ -4584,6 +4898,21 @@ audio may be played at the wrong sample rate.\n"), desired, PROGRAM_NAME, actual
         return 1;
 }
 
+void
+ARDOUR_UI::sr_mismatch_message (framecnt_t desired, framecnt_t actual)
+{
+       MessageDialog msg (string_compose (_("\
+This session was created with a sample rate of %1 Hz, but\n\
+%2 is currently running at %3 Hz.\n\
+Audio will be recorded and played at the wrong sample rate.\n\
+Re-Configure the Audio Engine in\n\
+Menu > Window > Audio/Midi Setup"),
+                               desired, PROGRAM_NAME, actual),
+                       true,
+                       Gtk::MESSAGE_WARNING);
+       msg.run ();
+}
+
 void
 ARDOUR_UI::use_config ()
 {
@@ -4767,11 +5096,6 @@ ARDOUR_UI::setup_profile ()
                Profile->set_small_screen ();
        }
 
-       if (g_getenv ("ARDOUR_SAE")) {
-               Profile->set_sae ();
-               Profile->set_single_package ();
-       }
-
        if (g_getenv ("TRX")) {
                Profile->set_trx ();
        }
@@ -4861,7 +5185,7 @@ ARDOUR_UI::session_format_mismatch (std::string xml_path, std::string backup_pat
 
        MessageDialog msg (string_compose (_("%4This is a session from an older version of %3%5\n\n"
                                             "%3 has copied the old session file\n\n%6%1%7\n\nto\n\n%6%2%7\n\n"
-                                            "From now on, use the -2000 version with older versions of %3"),
+                                            "From now on, use the backup copy with older versions of %3"),
                                           xml_path, backup_path, PROGRAM_NAME,
                                           start_big, end_big,
                                           start_mono, end_mono), true);
@@ -4903,10 +5227,15 @@ ARDOUR_UI::do_audio_midi_setup (uint32_t desired_sample_rate)
        audio_midi_setup->set_desired_sample_rate (desired_sample_rate);
        audio_midi_setup->set_position (WIN_POS_CENTER);
 
-       int response;
+       if (Config->get_try_autostart_engine () || getenv ("TRY_AUTOSTART_ENGINE")) {
+               audio_midi_setup->try_autostart ();
+               if (ARDOUR::AudioEngine::instance()->running()) {
+                       return 0;
+               }
+       }
 
        while (true) {
-               response = audio_midi_setup->run();
+               int response = audio_midi_setup->run();
                switch (response) {
                case Gtk::RESPONSE_OK:
                        if (!AudioEngine::instance()->running()) {
@@ -5036,16 +5365,282 @@ ARDOUR_UI::hide_application ()
     Application::instance ()-> hide ();
 }
 
+void
+ARDOUR_UI::setup_toplevel_window (Gtk::Window& window, const string& name, void* owner)
+{
+       /* icons, titles, WM stuff */
+
+       static list<Glib::RefPtr<Gdk::Pixbuf> > window_icons;
+
+       if (window_icons.empty()) {
+               Glib::RefPtr<Gdk::Pixbuf> icon;
+               if ((icon = ::get_icon (PROGRAM_NAME "-icon_16px")) != 0) {
+                       window_icons.push_back (icon);
+               }
+               if ((icon = ::get_icon (PROGRAM_NAME "-icon_22px")) != 0) {
+                       window_icons.push_back (icon);
+               }
+               if ((icon = ::get_icon (PROGRAM_NAME "-icon_32px")) != 0) {
+                       window_icons.push_back (icon);
+               }
+               if ((icon = ::get_icon (PROGRAM_NAME "-icon_48px")) != 0) {
+                       window_icons.push_back (icon);
+               }
+       }
+
+       if (!window_icons.empty()) {
+               window.set_default_icon_list (window_icons);
+       }
+
+       Gtkmm2ext::WindowTitle title (Glib::get_application_name());
+
+       if (!name.empty()) {
+               title += name;
+       }
+
+       window.set_title (title.get_string());
+       window.set_wmclass (string_compose (X_("%1_%1"), downcase (PROGRAM_NAME), downcase (name)), PROGRAM_NAME);
+
+       window.set_flags (CAN_FOCUS);
+       window.add_events (Gdk::KEY_PRESS_MASK|Gdk::KEY_RELEASE_MASK);
+
+       /* This is a hack to ensure that GTK-accelerators continue to
+        * work. Once we switch over to entirely native bindings, this will be
+        * unnecessary and should be removed
+        */
+       window.add_accel_group (ActionManager::ui_manager->get_accel_group());
+
+       window.signal_configure_event().connect (sigc::mem_fun (*this, &ARDOUR_UI::configure_handler));
+       window.signal_window_state_event().connect (sigc::bind (sigc::mem_fun (*this, &ARDOUR_UI::tabbed_window_state_event_handler), owner));
+       window.signal_key_press_event().connect (sigc::bind (sigc::mem_fun (*this, &ARDOUR_UI::key_event_handler), &window), false);
+       window.signal_key_release_event().connect (sigc::bind (sigc::mem_fun (*this, &ARDOUR_UI::key_event_handler), &window), false);
+}
+
+bool
+ARDOUR_UI::key_event_handler (GdkEventKey* ev, Gtk::Window* event_window)
+{
+       Gtkmm2ext::Bindings* bindings = 0;
+       Gtk::Window* window = 0;
+
+       /* until we get ardour bindings working, we are not handling key
+        * releases yet.
+        */
+
+       if (ev->type != GDK_KEY_PRESS) {
+               return false;
+       }
+
+       if (event_window == &_main_window) {
+
+               window = event_window;
+
+               /* find current tab contents */
+
+               Gtk::Widget* w = _tabs.get_nth_page (_tabs.get_current_page());
+
+               /* see if it uses the ardour binding system */
+
+               if (w) {
+                       bindings = reinterpret_cast<Gtkmm2ext::Bindings*>(w->get_data ("ardour-bindings"));
+               }
+
+               DEBUG_TRACE (DEBUG::Accelerators, string_compose ("main window key event, bindings = %1, global = %2\n", bindings, &global_bindings));
+
+       } else {
+
+               window = event_window;
+
+               /* see if window uses ardour binding system */
+
+               bindings = reinterpret_cast<Gtkmm2ext::Bindings*>(window->get_data ("ardour-bindings"));
+       }
+
+       /* An empty binding set is treated as if it doesn't exist */
+
+       if (bindings && bindings->empty()) {
+               bindings = 0;
+       }
+
+       return key_press_focus_accelerator_handler (*window, ev, bindings);
+}
+
+static Gtkmm2ext::Bindings*
+get_bindings_from_widget_heirarchy (GtkWidget* w)
+{
+       void* p = NULL;
+
+       while (w) {
+               if ((p = g_object_get_data (G_OBJECT(w), "ardour-bindings")) != 0) {
+                       break;
+               }
+               w = gtk_widget_get_parent (w);
+       }
+
+       return reinterpret_cast<Gtkmm2ext::Bindings*> (p);
+}
+
+bool
+ARDOUR_UI::key_press_focus_accelerator_handler (Gtk::Window& window, GdkEventKey* ev, Gtkmm2ext::Bindings* bindings)
+{
+       GtkWindow* win = window.gobj();
+       GtkWidget* focus = gtk_window_get_focus (win);
+       bool special_handling_of_unmodified_accelerators = false;
+       const guint mask = (Keyboard::RelevantModifierKeyMask & ~(Gdk::SHIFT_MASK|Gdk::LOCK_MASK));
+
+        if (focus) {
+
+               /* some widget has keyboard focus */
+
+               if (GTK_IS_ENTRY(focus) || Keyboard::some_magic_widget_has_focus()) {
+
+                       /* A particular kind of focusable widget currently has keyboard
+                        * focus. All unmodified key events should go to that widget
+                        * first and not be used as an accelerator by default
+                        */
+
+                       special_handling_of_unmodified_accelerators = true;
+
+               } else {
+
+                       Gtkmm2ext::Bindings* focus_bindings = get_bindings_from_widget_heirarchy (focus);
+                       if (focus_bindings) {
+                               bindings = focus_bindings;
+                               DEBUG_TRACE (DEBUG::Accelerators, string_compose ("Switch bindings based on focus widget, now using %1\n", bindings->name()));
+                       }
+               }
+       }
+
+        DEBUG_TRACE (DEBUG::Accelerators, string_compose ("Win = %1 [title = %9] focus = %7 (%8) Key event: code = %2  state = %3 special handling ? %4 magic widget focus ? %5 focus widget %6 named %7 mods ? %8\n",
+                                                          win,
+                                                          ev->keyval,
+                                                         show_gdk_event_state (ev->state),
+                                                          special_handling_of_unmodified_accelerators,
+                                                          Keyboard::some_magic_widget_has_focus(),
+                                                         focus,
+                                                          (focus ? gtk_widget_get_name (focus) : "no focus widget"),
+                                                          ((ev->state & mask) ? "yes" : "no"),
+                                                          window.get_title()));
+
+       /* This exists to allow us to override the way GTK handles
+          key events. The normal sequence is:
+
+          a) event is delivered to a GtkWindow
+          b) accelerators/mnemonics are activated
+          c) if (b) didn't handle the event, propagate to
+              the focus widget and/or focus chain
+
+          The problem with this is that if the accelerators include
+          keys without modifiers, such as the space bar or the
+          letter "e", then pressing the key while typing into
+          a text entry widget results in the accelerator being
+          activated, instead of the desired letter appearing
+          in the text entry.
+
+          There is no good way of fixing this, but this
+          represents a compromise. The idea is that
+          key events involving modifiers (not Shift)
+          get routed into the activation pathway first, then
+          get propagated to the focus widget if necessary.
+
+          If the key event doesn't involve modifiers,
+          we deliver to the focus widget first, thus allowing
+          it to get "normal text" without interference
+          from acceleration.
+
+          Of course, this can also be problematic: if there
+          is a widget with focus, then it will swallow
+          all "normal text" accelerators.
+       */
+
+
+       if (!special_handling_of_unmodified_accelerators || (ev->state & mask)) {
+
+               /* no special handling or there are modifiers in effect: accelerate first */
+
+                DEBUG_TRACE (DEBUG::Accelerators, "\tactivate, then propagate\n");
+               DEBUG_TRACE (DEBUG::Accelerators, string_compose ("\tevent send-event:%1 time:%2 length:%3 name %7 string:%4 hardware_keycode:%5 group:%6\n",
+                                                                 ev->send_event, ev->time, ev->length, ev->string, ev->hardware_keycode, ev->group, gdk_keyval_name (ev->keyval)));
+
+               DEBUG_TRACE (DEBUG::Accelerators, "\tsending to window\n");
+               KeyboardKey k (ev->state, ev->keyval);
+
+               if (bindings) {
+
+                       DEBUG_TRACE (DEBUG::Accelerators, string_compose ("\tusing Ardour bindings %1 @ %2 for this event\n", bindings->name(), bindings));
+
+                       if (bindings->activate (k, Bindings::Press)) {
+                               DEBUG_TRACE (DEBUG::Accelerators, "\t\thandled\n");
+                               return true;
+                       }
+               }
+
+               DEBUG_TRACE (DEBUG::Accelerators, "\tnot yet handled, try global bindings\n");
+
+               if (global_bindings && global_bindings->activate (k, Bindings::Press)) {
+                       DEBUG_TRACE (DEBUG::Accelerators, "\t\thandled\n");
+                       return true;
+               }
+
+                DEBUG_TRACE (DEBUG::Accelerators, "\tnot accelerated, now propagate\n");
+
+                if (gtk_window_propagate_key_event (win, ev)) {
+                       DEBUG_TRACE (DEBUG::Accelerators, "\tpropagate handled\n");
+                       return true;
+                }
+
+       } else {
+
+               /* no modifiers, propagate first */
+
+               DEBUG_TRACE (DEBUG::Accelerators, "\tpropagate, then activate\n");
+
+               if (gtk_window_propagate_key_event (win, ev)) {
+                       DEBUG_TRACE (DEBUG::Accelerators, "\thandled by propagate\n");
+                       return true;
+               }
+
+               DEBUG_TRACE (DEBUG::Accelerators, "\tpropagation didn't handle, so activate\n");
+               KeyboardKey k (ev->state, ev->keyval);
+
+               if (bindings) {
+
+                       DEBUG_TRACE (DEBUG::Accelerators, "\tusing Ardour bindings for this window\n");
+
+
+                       if (bindings->activate (k, Bindings::Press)) {
+                               DEBUG_TRACE (DEBUG::Accelerators, "\t\thandled\n");
+                               return true;
+                       }
+
+               }
+
+               DEBUG_TRACE (DEBUG::Accelerators, "\tnot yet handled, try global bindings\n");
+
+               if (global_bindings && global_bindings->activate (k, Bindings::Press)) {
+                       DEBUG_TRACE (DEBUG::Accelerators, "\t\thandled\n");
+                       return true;
+               }
+       }
+
+       DEBUG_TRACE (DEBUG::Accelerators, "\tnot handled\n");
+       return true;
+}
+
+void
+ARDOUR_UI::load_bindings ()
+{
+       if ((global_bindings = Bindings::get_bindings (X_("Global"), global_actions)) == 0) {
+               error << _("Global keybindings are missing") << endmsg;
+       }
+}
+
 void
 ARDOUR_UI::cancel_solo ()
 {
        if (_session) {
-               if (_session->soloing()) {
-                       _session->set_solo (_session->get_routes(), false);
-               } else if (_session->listening()) {
-                       _session->set_listen (_session->get_routes(), false);
+               if (_session) {
+                       _session->set_controls (route_list_to_control_list (_session->get_routes(), &Stripable::solo_control), 0.0, Controllable::NoGroup);
                }
-
                _session->clear_all_solo_state (_session->get_routes()); // safeguard, ideally this won't do anything, check the log-window
        }
 }