Remove internal edit mode and add "content" tool.
[ardour.git] / gtk2_ardour / ardour_ui.cc
index cb1c22a8d081277181e65fbae20de1814e01f607..3bfb204df49f1695ad07a0462ebeac21556ea612 100644 (file)
@@ -19,6 +19,7 @@
 
 #ifdef WAF_BUILD
 #include "gtk2ardour-config.h"
+#include "gtk2ardour-version.h"
 #endif
 
 #include <algorithm>
 #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"
-#include "pbd/system_exec.h"
+#include "pbd/pthread_utils.h"
 
 #include "gtkmm2ext/application.h"
 #include "gtkmm2ext/bindings.h"
@@ -72,6 +74,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
+#ifdef AUDIOUNIT_SUPPORT
+#include "ardour/audio_unit.h"
+#endif
 
 #include "timecode/time.h"
 
@@ -136,24 +143,25 @@ typedef uint64_t microseconds_t;
 #include "i18n.h"
 
 using namespace ARDOUR;
+using namespace ARDOUR_UI_UTILS;
 using namespace PBD;
 using namespace Gtkmm2ext;
 using namespace Gtk;
 using namespace std;
 
 ARDOUR_UI *ARDOUR_UI::theArdourUI = 0;
-UIConfiguration *ARDOUR_UI::ui_config = 0;
 
 sigc::signal<void,bool> ARDOUR_UI::Blink;
 sigc::signal<void>      ARDOUR_UI::RapidScreenUpdate;
 sigc::signal<void>      ARDOUR_UI::SuperRapidScreenUpdate;
+sigc::signal<void>      ARDOUR_UI::FPSUpdate;
 sigc::signal<void, framepos_t, bool, framepos_t> ARDOUR_UI::Clock;
 sigc::signal<void>      ARDOUR_UI::CloseAllDialogs;
 
 ARDOUR_UI::ARDOUR_UI (int *argcp, char **argvp[], const char* localedir)
 
        : Gtkmm2ext::UI (PROGRAM_NAME, argcp, argvp)
-       
+       , ui_config (new UIConfiguration)
        , gui_object_state (new GUIObjectState)
 
        , primary_clock (new MainClock (X_("primary"), false, X_("transport"), true, true, true, false, true))
@@ -186,15 +194,14 @@ ARDOUR_UI::ARDOUR_UI (int *argcp, char **argvp[], const char* localedir)
        , follow_edits_button (ArdourButton::led_default_elements)
        , auto_input_button (ArdourButton::led_default_elements)
 
-       , auditioning_alert_button (_("audition"))
-       , solo_alert_button (_("solo"))
-       , feedback_alert_button (_("feedback"))
+       , auditioning_alert_button (_("Audition"))
+       , solo_alert_button (_("Solo"))
+       , feedback_alert_button (_("Feedback"))
 
        , editor_meter(0)
        , editor_meter_peak_display()
 
        , speaker_config_window (X_("speaker-config"), _("Speaker Configuration"))
-       , theme_manager (X_("theme-manager"), _("Theme Manager"))
        , key_editor (X_("key-editor"), _("Key Bindings"))
        , rc_option_editor (X_("rc-options-editor"), _("Preferences"))
        , add_route_dialog (X_("add-routes"), _("Add Tracks/Busses"))
@@ -218,12 +225,12 @@ ARDOUR_UI::ARDOUR_UI (int *argcp, char **argvp[], const char* localedir)
 
        splash = 0;
 
+       _numpad_locate_happening = false;
+
        if (theArdourUI == 0) {
                theArdourUI = this;
        }
 
-       ui_config = new UIConfiguration();
-
        ui_config->ParameterChanged.connect (sigc::mem_fun (*this, &ARDOUR_UI::parameter_changed));
        boost::function<void (string)> pc (boost::bind (&ARDOUR_UI::parameter_changed, this, _1));
        ui_config->map_parameters (pc);
@@ -259,10 +266,6 @@ ARDOUR_UI::ARDOUR_UI (int *argcp, char **argvp[], const char* localedir)
        rec_button.set_name ("transport recenable button");
        midi_panic_button.set_name ("transport button");
 
-       goto_start_button.set_tweaks (ArdourButton::ShowClick);
-       goto_end_button.set_tweaks (ArdourButton::ShowClick);
-       midi_panic_button.set_tweaks (ArdourButton::ShowClick);
-       
        last_configure_time= 0;
        last_peak_grab = 0;
 
@@ -304,6 +307,15 @@ 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());
+
+       Config->ParameterChanged.connect ( forever_connections, MISSING_INVALIDATOR, boost::bind(&ARDOUR_UI::set_flat_buttons, this), gui_context() );
+       set_flat_buttons();
+
        /* lets get this party started */
 
        setup_gtk_ardour_enums ();
@@ -336,7 +348,6 @@ ARDOUR_UI::ARDOUR_UI (int *argcp, char **argvp[], const char* localedir)
        const XMLNode* ui_xml = Config->extra_xml (X_("UI"));
 
        if (ui_xml) {
-               theme_manager.set_state (*ui_xml);
                key_editor.set_state (*ui_xml);
                rc_option_editor.set_state (*ui_xml);
                session_option_editor.set_state (*ui_xml);
@@ -352,7 +363,6 @@ ARDOUR_UI::ARDOUR_UI (int *argcp, char **argvp[], const char* localedir)
                midi_port_matrix.set_state (*ui_xml);
        }
 
-       WM::Manager::instance().register_window (&theme_manager);
        WM::Manager::instance().register_window (&key_editor);
        WM::Manager::instance().register_window (&rc_option_editor);
        WM::Manager::instance().register_window (&session_option_editor);
@@ -368,12 +378,9 @@ ARDOUR_UI::ARDOUR_UI (int *argcp, char **argvp[], const char* localedir)
        WM::Manager::instance().register_window (&audio_port_matrix);
        WM::Manager::instance().register_window (&midi_port_matrix);
 
-       /* We need to instantiate the theme manager because it loads our
-          theme files. This should really change so that its window
-          and its functionality are separate 
-       */
-       
-       (void) theme_manager.get (true);
+       /* Trigger setting up the color scheme and loading the GTK RC file */
+
+       ARDOUR_UI::config()->load_rc_file (false);
        
        _process_thread = new ProcessThread ();
        _process_thread->init ();
@@ -470,6 +477,14 @@ ARDOUR_UI::post_engine ()
 {
        /* Things to be done once (and once ONLY) after we have a backend running in the AudioEngine
         */
+#ifdef AUDIOUNIT_SUPPORT
+       std::string au_msg;
+       if (AUPluginInfo::au_get_crashlog(au_msg)) {
+               popup_error(_("Audio Unit Plugin Scan Failed. Automatic AU scanning has been disabled. Please see the log window for further details."));
+               error << _("Audio Unit Plugin Scan Failed:") << endmsg;
+               info << au_msg << endmsg;
+       }
+#endif
 
        ARDOUR::init_post_engine ();
        
@@ -481,8 +496,6 @@ ARDOUR_UI::post_engine ()
 
        _tooltips.enable();
 
-       ActionManager::load_menus ();
-
        if (setup_windows ()) {
                throw failed_constructor ();
        }
@@ -543,23 +556,29 @@ ARDOUR_UI::post_engine ()
        Glib::signal_timeout().connect_seconds (sigc::mem_fun(*this, &ARDOUR_UI::update_wall_clock), 1);
 #endif
 
-       Config->ParameterChanged.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::parameter_changed, this, _1), gui_context());
-       boost::function<void (string)> pc (boost::bind (&ARDOUR_UI::parameter_changed, this, _1));
-       Config->map_parameters (pc);
+       {
+               DisplaySuspender ds;
+               Config->ParameterChanged.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::parameter_changed, this, _1), gui_context());
+               boost::function<void (string)> pc (boost::bind (&ARDOUR_UI::parameter_changed, this, _1));
+               Config->map_parameters (pc);
+       }
 }
 
 ARDOUR_UI::~ARDOUR_UI ()
 {
-       if (ui_config->dirty()) {
-               ui_config->save_state();
-       }
-
-       delete keyboard;
-       delete editor;
-       delete mixer;
-       delete meterbridge;
+       ui_config->save_state();
 
        stop_video_server();
+
+       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 gui_object_state;
+               FastMeter::flush_pattern_cache ();
+       }
 }
 
 void
@@ -753,6 +772,7 @@ ARDOUR_UI::starting ()
        try {
                audio_midi_setup.get (true);
        } catch (...) {
+               std::cerr << "audio-midi engine setup failed."<< std::endl;
                return -1;
        }
 
@@ -839,6 +859,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;
                }
        }
@@ -985,7 +1006,10 @@ If you still wish to quit, please use the\n\n\
 
                second_connection.disconnect ();
                point_one_second_connection.disconnect ();
+#ifndef PLATFORM_WINDOWS
                point_zero_something_second_connection.disconnect();
+#endif
+               fps_connection.disconnect();
        }
 
        delete ARDOUR_UI::instance()->video_timeline;
@@ -1000,8 +1024,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 ();
@@ -1128,14 +1150,55 @@ ARDOUR_UI::every_point_zero_something_seconds ()
                float mpeak = editor_meter->update_meters();
                if (mpeak > editor_meter_max_peak) {
                        if (mpeak >= Config->get_meter_peak()) {
-                               editor_meter_peak_display.set_name ("meterbridge peakindicator on");
-                               editor_meter_peak_display.set_elements((ArdourButton::Element) (ArdourButton::Edge|ArdourButton::Body));
+                               editor_meter_peak_display.set_active_state ( Gtkmm2ext::ExplicitActive );
                        }
                }
        }
        return TRUE;
 }
 
+gint
+ARDOUR_UI::every_fps ()
+{
+       FPSUpdate(); /* EMIT_SIGNAL */
+#ifdef PLATFORM_WINDOWS
+       every_point_zero_something_seconds();
+#endif
+       return TRUE;
+}
+
+void
+ARDOUR_UI::set_fps_timeout_connection ()
+{
+       unsigned int interval = 40;
+       if (!_session) return;
+       if (_session->timecode_frames_per_second() != 0) {
+               /* ideally we'll use a select() to sleep and not accumulate
+                * idle time to provide a regular periodic signal.
+                * See linux_vst_gui_support.cc 'elapsed_time_ms'.
+                * However, that'll require a dedicated thread and cross-thread
+                * signals to the GUI Thread..
+                */
+               interval = floor(500. /* update twice per FPS, since Glib::signal_timeout is very irregular */
+                               * _session->frame_rate() / _session->nominal_frame_rate()
+                               / _session->timecode_frames_per_second()
+                               );
+#ifdef PLATFORM_WINDOWS
+               // the smallest windows scheduler time-slice is ~15ms.
+               // periodic GUI timeouts shorter than that will cause
+               // WaitForSingleObject to spinlock (100% of one CPU Core)
+               // and gtk never enters idle mode.
+               // also changing timeBeginPeriod(1) does not affect that in
+               // any beneficial way, so we just limit the max rate for now.
+               interval = std::max(30u, interval); // at most ~33Hz.
+#else
+               interval = std::max(8u, interval); // at most 120Hz.
+#endif
+       }
+       fps_connection.disconnect();
+       fps_connection = Glib::signal_timeout().connect (sigc::mem_fun(*this, &ARDOUR_UI::every_fps), interval);
+}
+
 void
 ARDOUR_UI::update_sample_rate (framecnt_t)
 {
@@ -1233,7 +1296,7 @@ ARDOUR_UI::update_cpu_load ()
           should also be changed.
        */
 
-       float const c = AudioEngine::instance()->get_dsp_load ();
+       double const c = AudioEngine::instance()->get_dsp_load ();
        snprintf (buf, sizeof (buf), _("DSP: <span foreground=\"%s\">%5.1f%%</span>"), c >= 90 ? X_("red") : X_("green"), c);
        cpu_load_label.set_markup (buf);
 }
@@ -1413,7 +1476,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;
 
@@ -1430,8 +1493,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;
                }
@@ -1440,14 +1504,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)
                        {
@@ -1458,6 +1522,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 ();
                }
        }
 
@@ -1656,10 +1723,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 ();
        }
 }
@@ -1717,10 +1784,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 ();
        }
@@ -1825,10 +1892,39 @@ ARDOUR_UI::transport_stop ()
        _session->request_stop (false, true);
 }
 
+/** Check if any tracks are record enabled. If none are, record enable all of them.
+ * @return true if track record-enabled status was changed, false otherwise.
+ */  
+bool
+ARDOUR_UI::trx_record_enable_all_tracks ()
+{
+       if (!_session) {
+               return false;
+       }
+
+       boost::shared_ptr<RouteList> rl = _session->get_tracks ();
+       bool none_record_enabled = true;
+
+       for (RouteList::iterator r = rl->begin(); r != rl->end(); ++r) {
+               boost::shared_ptr<Track> t = boost::dynamic_pointer_cast<Track> (*r);
+               assert (t);
+
+               if (t->record_enabled()) {
+                       none_record_enabled = false;
+                       break;
+               }
+       }
+
+       if (none_record_enabled) {
+               _session->set_record_enabled (rl, true, Session::rt_cleanup);
+       } 
+
+       return none_record_enabled;
+}
+
 void
 ARDOUR_UI::transport_record (bool roll)
 {
-
        if (_session) {
                switch (_session->record_status()) {
                case Session::Disabled:
@@ -1837,6 +1933,9 @@ ARDOUR_UI::transport_record (bool roll)
                                msg.run ();
                                return;
                        }
+                       if (Profile->get_trx()) {
+                               roll = trx_record_enable_all_tracks ();
+                       }
                        _session->maybe_enable_record ();
                        if (roll) {
                                transport_roll ();
@@ -1882,13 +1981,26 @@ 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);
-               }
-       } else if (_session->get_play_range () && !Config->get_always_play_range()) {
+
+               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 () ) {
                /* stop playing a range if we currently are */
                _session->request_play_range (0, true);
        }
@@ -1944,7 +2056,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);
@@ -1955,10 +2067,10 @@ ARDOUR_UI::toggle_roll (bool with_abort, bool roll_out_of_bounded_mode)
                if (rolling) {
                        _session->request_stop (with_abort, true);
                } else {
-                       if ( Config->get_always_play_range() ) {
+                       if ( Config->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
                        }
-
                        _session->request_transport_speed (1.0f);
                }
        }
@@ -1975,16 +2087,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_locate (looploc->start(), true);
-                       _session->request_play_loop (false);
+               _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
@@ -2112,7 +2231,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 {
 
@@ -2121,7 +2244,7 @@ ARDOUR_UI::map_transport_state ()
                        auto_loop_button.set_active (false);
                }
 
-               if (Config->get_always_play_range()) {
+               if (Config->get_follow_edits()) {
                        /* light up both roll and play-selection if they are joined */
                        roll_button.set_active (true);
                        play_selection_button.set_active (true);
@@ -2134,7 +2257,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 ();
        }
 }
@@ -2142,7 +2269,7 @@ ARDOUR_UI::map_transport_state ()
 void
 ARDOUR_UI::update_clocks ()
 {
-       if (!editor || !editor->dragging_playhead()) {
+       if (editor && !editor->dragging_playhead()) {
                Clock (_session->audible_frame(), false, editor->get_preferred_edit_position()); /* EMIT_SIGNAL */
        }
 }
@@ -2151,7 +2278,7 @@ void
 ARDOUR_UI::start_clocking ()
 {
        if (Config->get_super_rapid_clock_update()) {
-               clock_signal_connection = SuperRapidScreenUpdate.connect (sigc::mem_fun(*this, &ARDOUR_UI::update_clocks));
+               clock_signal_connection = FPSUpdate.connect (sigc::mem_fun(*this, &ARDOUR_UI::update_clocks));
        } else {
                clock_signal_connection = RapidScreenUpdate.connect (sigc::mem_fun(*this, &ARDOUR_UI::update_clocks));
        }
@@ -2413,7 +2540,7 @@ ARDOUR_UI::transport_rec_enable_blink (bool onoff)
                if (onoff) {
                        rec_button.set_active_state (Gtkmm2ext::ExplicitActive);
                } else {
-                       rec_button.set_active_state (Gtkmm2ext::ImplicitActive);
+                       rec_button.set_active_state (Gtkmm2ext::Off);
                }
        } else if (r == Session::Recording && h) {
                rec_button.set_active_state (Gtkmm2ext::ExplicitActive);
@@ -2650,6 +2777,13 @@ ARDOUR_UI::get_session_parameters (bool quit_on_cancel, bool should_be_new, stri
                                break;
                        default:
                                if (quit_on_cancel) {
+                                       // JE - Currently (July 2014) this section can only get reached if the
+                                       // user quits from the main 'Session Setup' dialog (i.e. reaching this
+                                       // point does NOT indicate an abnormal termination). Therefore, let's
+                                       // behave gracefully (i.e. let's do some cleanup) before we call exit()
+                                       ARDOUR::cleanup ();
+                                       pthread_cancel_all ();
+
                                        exit (1);
                                } else {
                                        return ret;
@@ -2688,8 +2822,14 @@ ARDOUR_UI::get_session_parameters (bool quit_on_cancel, bool should_be_new, stri
                }
                
                if (session_name[0] == G_DIR_SEPARATOR ||
+#ifdef PLATFORM_WINDOWS
+                   (session_name.length() > 3 && session_name[1] == ':' && session_name[2] == G_DIR_SEPARATOR)
+#else
                    (session_name.length() > 2 && session_name[0] == '.' && session_name[1] == G_DIR_SEPARATOR) ||
-                   (session_name.length() > 3 && session_name[0] == '.' && session_name[1] == '.' && session_name[2] == G_DIR_SEPARATOR)) {
+                   (session_name.length() > 3 && session_name[0] == '.' && session_name[1] == '.' && session_name[2] == G_DIR_SEPARATOR)
+#endif
+                        )
+               {
                        
                        /* absolute path or cwd-relative path specified for session name: infer session folder
                           from what was given.
@@ -2926,7 +3066,9 @@ ARDOUR_UI::load_session (const std::string& path, const std::string& snap_name,
 #ifdef WINDOWS_VST_SUPPORT
        fst_stop_threading();
 #endif
+
        flush_pending ();
+
 #ifdef WINDOWS_VST_SUPPORT
        fst_start_threading();
 #endif
@@ -2998,6 +3140,8 @@ ARDOUR_UI::launch_chat ()
 {
 #ifdef __APPLE__
        open_uri("http://webchat.freenode.net/?channels=ardour-osx");
+#elif defined PLATFORM_WINDOWS
+       open_uri("http://webchat.freenode.net/?channels=ardour-windows");
 #else
        open_uri("http://webchat.freenode.net/?channels=ardour");
 #endif
@@ -3015,6 +3159,46 @@ ARDOUR_UI::launch_reference ()
        PBD::open_uri (Config->get_reference_manual_url());
 }
 
+void
+ARDOUR_UI::launch_tracker ()
+{
+       PBD::open_uri ("http://tracker.ardour.org/bug_report_page.php");
+}
+
+void
+ARDOUR_UI::launch_cheat_sheet ()
+{
+#ifdef __APPLE__
+       PBD::open_uri ("http://manual.ardour.org/files/a3_mnemonic_cheat_sheet_osx.pdf");
+#else
+       PBD::open_uri ("http://manual.ardour.org/files/a3_mnemonic_cheatsheet.pdf");
+#endif
+}
+
+void
+ARDOUR_UI::launch_website ()
+{
+       PBD::open_uri ("http://ardour.org");
+}
+
+void
+ARDOUR_UI::launch_website_dev ()
+{
+       PBD::open_uri ("http://ardour.org/development.html");
+}
+
+void
+ARDOUR_UI::launch_forums ()
+{
+       PBD::open_uri ("https://community.ardour.org/forums");
+}
+
+void
+ARDOUR_UI::launch_howto_report ()
+{
+       PBD::open_uri ("http://ardour.org/reporting_bugs");
+}
+
 void
 ARDOUR_UI::loading_message (const std::string& msg)
 {
@@ -3354,9 +3538,8 @@ ARDOUR_UI::add_route (Gtk::Window* float_window)
 
        setup_order_hint();
 
-       PBD::ScopedConnection idle_connection;
-
        string template_path = add_route_dialog->track_template();
+       DisplaySuspender ds;
 
        if (!template_path.empty()) {
                if (add_route_dialog->name_template_is_default())  {
@@ -3397,8 +3580,6 @@ 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
@@ -3472,18 +3653,18 @@ ARDOUR_UI::start_video_server (Gtk::Window* float_window, bool popup_msg)
                if (icsd_docroot.empty()) {icsd_docroot = X_("/");}
 
                GStatBuf sb;
-               if (!g_lstat (icsd_docroot.c_str(), &sb) == 0 || !S_ISDIR(sb.st_mode)) {
+               if (g_lstat (icsd_docroot.c_str(), &sb) != 0 || !S_ISDIR(sb.st_mode)) {
                        warning << _("Specified docroot is not an existing directory.") << endmsg;
                        continue;
                }
 #ifndef PLATFORM_WINDOWS
-               if ( (!g_lstat (icsd_exec.c_str(), &sb) == 0)
+               if ( (g_lstat (icsd_exec.c_str(), &sb) != 0)
                     || (sb.st_mode & (S_IXUSR|S_IXGRP|S_IXOTH)) == 0 ) {
                        warning << _("Given Video Server is not an executable file.") << endmsg;
                        continue;
                }
 #else
-               if ( (!g_lstat (icsd_exec.c_str(), &sb) == 0)
+               if ( (g_lstat (icsd_exec.c_str(), &sb) != 0)
                     || (sb.st_mode & (S_IXUSR)) == 0 ) {
                        warning << _("Given Video Server is not an executable file.") << endmsg;
                        continue;
@@ -3517,7 +3698,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;
@@ -3525,6 +3706,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) {
@@ -3749,8 +3931,8 @@ ARDOUR_UI::create_xrun_marker (framepos_t where)
 void
 ARDOUR_UI::halt_on_xrun_message ()
 {
-       MessageDialog msg (*editor,
-                          _("Recording was stopped because your system could not keep up."));
+        cerr << "HALT on xrun\n";
+       MessageDialog msg (*editor, _("Recording was stopped because your system could not keep up."));
        msg.run ();
 }
 
@@ -3790,6 +3972,118 @@ 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);
+       }
+
+       assert(scan_dlg && scan_tbox && cancel_button);
+
+       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 ()
 {
@@ -4122,10 +4416,18 @@ 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 ();
+       }
+
+       if (g_getenv ("MIXBUS")) {
+               Profile->set_mixbus ();
+       }
 }
 
 int
@@ -4222,8 +4524,7 @@ ARDOUR_UI::reset_peak_display ()
        if (!_session || !_session->master_out() || !editor_meter) return;
        editor_meter->clear_meters();
        editor_meter_max_peak = -INFINITY;
-       editor_meter_peak_display.set_name ("meterbridge peakindicator");
-       editor_meter_peak_display.set_elements((ArdourButton::Element) (ArdourButton::Edge|ArdourButton::Body));
+       editor_meter_peak_display.set_active_state ( Gtkmm2ext::Off );
 }
 
 void
@@ -4261,3 +4562,53 @@ ARDOUR_UI::do_audio_midi_setup (uint32_t desired_sample_rate)
 }
 
 
+gint
+ARDOUR_UI::transport_numpad_timeout ()
+{
+       _numpad_locate_happening = false;
+       if (_numpad_timeout_connection.connected() )
+               _numpad_timeout_connection.disconnect();
+       return 1;
+}
+
+void
+ARDOUR_UI::transport_numpad_decimal ()
+{
+       _numpad_timeout_connection.disconnect();
+
+       if (_numpad_locate_happening) {
+               if (editor) editor->goto_nth_marker(_pending_locate_num - 1);
+               _numpad_locate_happening = false;
+       } else {
+               _pending_locate_num = 0;
+               _numpad_locate_happening = true;
+               _numpad_timeout_connection = Glib::signal_timeout().connect (mem_fun(*this, &ARDOUR_UI::transport_numpad_timeout), 2*1000);
+       }
+}
+
+void
+ARDOUR_UI::transport_numpad_event (int num)
+{
+       if ( _numpad_locate_happening ) {
+               _pending_locate_num = _pending_locate_num*10 + num;
+       } else {
+               switch (num) {          
+                       case 0:  toggle_roll(false, false);             break;
+                       case 1:  transport_rewind(1);                           break;
+                       case 2:  transport_forward(1);                          break;
+                       case 3:  transport_record(true);                        break;
+                       case 4:  toggle_session_auto_loop();            break;
+                       case 5:  transport_record(false); toggle_session_auto_loop();   break;
+                       case 6:  toggle_punch();                                        break;
+                       case 7:  toggle_click();                                break;
+                       case 8:  toggle_auto_return();                  break;
+                       case 9:  toggle_follow_edits();         break;
+               }
+       }
+}
+
+void
+ARDOUR_UI::set_flat_buttons ()
+{
+       CairoWidget::set_flat_buttons( config()->get_flat_buttons() );
+}