GUI update: migrate group-color into the session (not GUI state)
[ardour.git] / gtk2_ardour / ardour_ui.cc
index e5b13c821cb7832ecdca542ba660e130308b06f1..d01a92ebf659c43a74f8eb22e2d9e9b964134004 100644 (file)
 #include "pbd/memento_command.h"
 #include "pbd/openuri.h"
 #include "pbd/stl_delete.h"
+#include "pbd/types_convert.h"
 #include "pbd/file_utils.h"
 #include "pbd/localtime_r.h"
 #include "pbd/pthread_utils.h"
 #include "pbd/replace_all.h"
+#include "pbd/scoped_file_descriptor.h"
 #include "pbd/xml++.h"
 
 #include "gtkmm2ext/application.h"
@@ -93,6 +95,7 @@
 #include "ardour/profile.h"
 #include "ardour/recent_sessions.h"
 #include "ardour/record_enable_control.h"
+#include "ardour/revision.h"
 #include "ardour/session_directory.h"
 #include "ardour/session_route.h"
 #include "ardour/session_state_utils.h"
@@ -124,6 +127,7 @@ typedef uint64_t microseconds_t;
 
 #include "about.h"
 #include "editing.h"
+#include "enums_convert.h"
 #include "actions.h"
 #include "add_route_dialog.h"
 #include "ambiguous_file_dialog.h"
@@ -141,6 +145,7 @@ typedef uint64_t microseconds_t;
 #include "global_port_matrix.h"
 #include "gui_object.h"
 #include "gui_thread.h"
+#include "idleometer.h"
 #include "keyboard.h"
 #include "keyeditor.h"
 #include "location_ui.h"
@@ -151,6 +156,7 @@ typedef uint64_t microseconds_t;
 #include "missing_plugin_dialog.h"
 #include "mixer_ui.h"
 #include "meterbridge.h"
+#include "meter_patterns.h"
 #include "mouse_cursors.h"
 #include "nsm.h"
 #include "opts.h"
@@ -273,6 +279,13 @@ ARDOUR_UI::ARDOUR_UI (int *argcp, char **argvp[], const char* localedir)
        , _initial_verbose_plugin_scan (false)
        , first_time_engine_run (true)
        , secondary_clock_spacer (0)
+       , roll_controllable (new TransportControllable ("transport roll", *this, TransportControllable::Roll))
+       , stop_controllable (new TransportControllable ("transport stop", *this, TransportControllable::Stop))
+       , goto_start_controllable (new TransportControllable ("transport goto start", *this, TransportControllable::GotoStart))
+       , goto_end_controllable (new TransportControllable ("transport goto end", *this, TransportControllable::GotoEnd))
+       , auto_loop_controllable (new TransportControllable ("transport auto loop", *this, TransportControllable::AutoLoop))
+       , play_selection_controllable (new TransportControllable ("transport play selection", *this, TransportControllable::PlaySelection))
+       , rec_controllable (new TransportControllable ("transport rec-enable", *this, TransportControllable::RecordEnable))
        , auto_input_button (ArdourButton::led_default_elements)
        , time_info_box (0)
        , auto_return_button (ArdourButton::led_default_elements)
@@ -283,6 +296,7 @@ ARDOUR_UI::ARDOUR_UI (int *argcp, char **argvp[], const char* localedir)
        , error_alert_button ( ArdourButton::just_led_default_elements )
        , editor_meter(0)
        , editor_meter_peak_display()
+       , _suspend_editor_meter_callbacks (false)
        , _numpad_locate_happening (false)
        , _session_is_new (false)
        , last_key_press_time (0)
@@ -298,6 +312,7 @@ ARDOUR_UI::ARDOUR_UI (int *argcp, char **argvp[], const char* localedir)
        , 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"))
+       , idleometer (X_("idle-o-meter"), _("Idle'o'Meter"))
        , session_option_editor (X_("session-options-editor"), _("Properties"), boost::bind (&ARDOUR_UI::create_session_option_editor, 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))
@@ -324,6 +339,10 @@ ARDOUR_UI::ARDOUR_UI (int *argcp, char **argvp[], const char* localedir)
        UIConfiguration::instance().post_gui_init ();
 
        if (ARDOUR::handle_old_configuration_files (boost::bind (ask_about_configuration_copy, _1, _2, _3))) {
+               {
+                       /* "touch" the been-here-before path now that config has been migrated */
+                       PBD::ScopedFileDescriptor fout (g_open (been_here_before_path ().c_str(), O_CREAT|O_TRUNC|O_RDWR, 0666));
+               }
                MessageDialog msg (string_compose (_("Your configuration files were copied. You can now restart %1."), PROGRAM_NAME), true);
                msg.run ();
                /* configuration was modified, exit immediately */
@@ -355,22 +374,13 @@ ARDOUR_UI::ARDOUR_UI (int *argcp, char **argvp[], const char* localedir)
        boost::function<void (string)> pc (boost::bind (&ARDOUR_UI::parameter_changed, this, _1));
        UIConfiguration::instance().map_parameters (pc);
 
-       Glib::RefPtr<Gtk::Action> act;
-
-       act = ActionManager::get_action ("Transport/Roll");
-       roll_button.set_related_action (act);
-       act = ActionManager::get_action ("Transport/Stop");
-       stop_button.set_related_action (act);
-       act = ActionManager::get_action ("Transport/GotoStart");
-       goto_start_button.set_related_action (act);
-       act = ActionManager::get_action ("Transport/GotoEnd");
-       goto_end_button.set_related_action (act);
-       act = ActionManager::get_action ("Transport/Loop");
-       auto_loop_button.set_related_action (act);
-       act = ActionManager::get_action ("Transport/PlaySelection");
-       play_selection_button.set_related_action (act);
-       act = ActionManager::get_action ("Transport/Record");
-       rec_button.set_related_action (act);
+       roll_button.set_controllable (roll_controllable);
+       stop_button.set_controllable (stop_controllable);
+       goto_start_button.set_controllable (goto_start_controllable);
+       goto_end_button.set_controllable (goto_end_controllable);
+       auto_loop_button.set_controllable (auto_loop_controllable);
+       play_selection_button.set_controllable (play_selection_controllable);
+       rec_button.set_controllable (rec_controllable);
 
        roll_button.set_name ("transport button");
        stop_button.set_name ("transport button");
@@ -474,6 +484,7 @@ ARDOUR_UI::ARDOUR_UI (int *argcp, char **argvp[], const char* localedir)
                midi_port_matrix.set_state (*ui_xml, 0);
                export_video_dialog.set_state (*ui_xml, 0);
                lua_script_window.set_state (*ui_xml, 0);
+               idleometer.set_state (*ui_xml, 0);
        }
 
        /* Separate windows */
@@ -493,6 +504,7 @@ ARDOUR_UI::ARDOUR_UI (int *argcp, char **argvp[], const char* localedir)
        WM::Manager::instance().register_window (&big_clock_window);
        WM::Manager::instance().register_window (&audio_port_matrix);
        WM::Manager::instance().register_window (&midi_port_matrix);
+       WM::Manager::instance().register_window (&idleometer);
 
        /* do not retain position for add route dialog */
        add_route_dialog.set_state_mask (WindowProxy::Size);
@@ -676,6 +688,55 @@ ARDOUR_UI::post_engine ()
         */
 
        if (ARDOUR_COMMAND_LINE::show_key_actions) {
+               stringstream sstr;
+               Bindings::save_all_bindings_as_html (sstr);
+
+               if (sstr.str().empty()) {
+                       return;
+               }
+               gchar* file_name;
+               GError *err = NULL;
+               gint fd;
+
+               if ((fd = g_file_open_tmp ("akprintXXXXXX.html", &file_name, &err)) < 0) {
+                       if (err) {
+                               error << string_compose (_("Could not open temporary file to print bindings (%1)"), err->message) << endmsg;
+                               g_error_free (err);
+                       }
+                       return;
+               }
+
+#ifdef PLATFORM_WINDOWS
+               ::close (fd);
+#endif
+
+               err = NULL;
+
+               if (!g_file_set_contents (file_name, sstr.str().c_str(), sstr.str().size(), &err)) {
+#ifndef PLATFORM_WINDOWS
+                       ::close (fd);
+#endif
+                       g_unlink (file_name);
+                       if (err) {
+                               error << string_compose (_("Could not save bindings to file (%1)"), err->message) << endmsg;
+                               g_error_free (err);
+                       }
+                       return;
+               }
+
+#ifndef PLATFORM_WINDOWS
+               ::close (fd);
+#endif
+
+               PBD::open_uri (string_compose ("file:///%1", file_name));
+
+               halt_connection.disconnect ();
+               AudioEngine::instance()->stop ();
+               exit (0);
+
+       }
+
+       if (ARDOUR_COMMAND_LINE::show_actions) {
 
 
                vector<string> paths;
@@ -683,21 +744,70 @@ ARDOUR_UI::post_engine ()
                vector<string> tooltips;
                vector<string> keys;
                vector<Glib::RefPtr<Gtk::Action> > actions;
+               string ver_in = revision;
+               string ver = ver_in.substr(0, ver_in.find("-"));
+
+               stringstream output;
+               output << "\n<h2>Menu actions</h2>" << endl;
+               output << "<p>\n  Every single menu item in " << PROGRAM_NAME << "'s GUI is accessible by control" << endl;
+               output << "  surfaces or scripts.\n</p>\n" << endl;
+               output << "<p>\n  The list below shows all available values of <em>action-name</em> as of" << endl;
+               output << "  " << PROGRAM_NAME << " " << ver << ". You can get the current list at any" << endl;
+               output << "  time by running " << PROGRAM_NAME << " with the -A flag.\n</p>\n" << endl;
+               output << "<table class=\"dl\">\n  <thead>" << endl;
+               output << "      <tr><th>Action Name</th><th>Menu Name</th></tr>" << endl;
+               output << "  </thead>\n  <tbody>" << endl;
 
                Gtkmm2ext::ActionMap::get_all_actions (paths, labels, tooltips, keys, actions);
 
-               vector<string>::iterator k;
                vector<string>::iterator p;
+               vector<string>::iterator l;
 
-               for (p = paths.begin(), k = keys.begin(); p != paths.end(); ++k, ++p) {
+               for (p = paths.begin(), l = labels.begin(); p != paths.end(); ++p, ++l) {
+                       output << "     <tr><th><kbd class=\"osc\">" << (*p).substr (9, string::npos);
+                       output << "</kbd></th><td>" << *l << "</td></tr>" << endl;
+               }
+               output << "  </tbody>\n  </table>" << endl;
+
+               // output this mess to a browser for easiest X-platform use
+               // it is not pretty HTML, but it works and it's main purpose
+               // is to create raw html to fit in Ardour's manual with no editing
+               gchar* file_name;
+               GError *err = NULL;
+               gint fd;
+
+               if ((fd = g_file_open_tmp ("akprintXXXXXX.html", &file_name, &err)) < 0) {
+                       if (err) {
+                               error << string_compose (_("Could not open temporary file to print bindings (%1)"), err->message) << endmsg;
+                               g_error_free (err);
+                       }
+                       return;
+               }
 
-                       if ((*k).empty()) {
-                               cout << *p << endl;
-                       } else {
-                               cout << *p << " => " << *k << endl;
+#ifdef PLATFORM_WINDOWS
+               ::close (fd);
+#endif
+
+               err = NULL;
+
+               if (!g_file_set_contents (file_name, output.str().c_str(), output.str().size(), &err)) {
+#ifndef PLATFORM_WINDOWS
+                       ::close (fd);
+#endif
+                       g_unlink (file_name);
+                       if (err) {
+                               error << string_compose (_("Could not save bindings to file (%1)"), err->message) << endmsg;
+                               g_error_free (err);
                        }
+                       return;
                }
 
+#ifndef PLATFORM_WINDOWS
+               ::close (fd);
+#endif
+
+               PBD::open_uri (string_compose ("file:///%1", file_name));
+
                halt_connection.disconnect ();
                AudioEngine::instance()->stop ();
                exit (0);
@@ -807,6 +917,54 @@ ARDOUR_UI::configure_handler (GdkEventConfigure* /*conf*/)
        return FALSE;
 }
 
+void
+ARDOUR_UI::set_transport_controllable_state (const XMLNode& node)
+{
+       std::string str;
+
+       if (node.get_property ("roll", str)){
+               roll_controllable->set_id (str);
+       }
+       if (node.get_property ("stop", str)) {
+               stop_controllable->set_id (str);
+       }
+       if (node.get_property ("goto-start", str)) {
+               goto_start_controllable->set_id (str);
+       }
+       if (node.get_property ("goto-end", str)) {
+               goto_end_controllable->set_id (str);
+       }
+       if (node.get_property ("auto-loop", str)) {
+               auto_loop_controllable->set_id (str);
+       }
+       if (node.get_property ("play-selection", str)) {
+               play_selection_controllable->set_id (str);
+       }
+       if (node.get_property ("rec", str)) {
+               rec_controllable->set_id (str);
+       }
+       if (node.get_property ("shuttle", str)) {
+               shuttle_box.controllable()->set_id (str);
+       }
+}
+
+XMLNode&
+ARDOUR_UI::get_transport_controllable_state ()
+{
+       XMLNode* node = new XMLNode(X_("TransportControllables"));
+
+       node->set_property (X_("roll"), roll_controllable->id());
+       node->set_property (X_("stop"), stop_controllable->id());
+       node->set_property (X_("goto_start"), goto_start_controllable->id());
+       node->set_property (X_("goto_end"), goto_end_controllable->id());
+       node->set_property (X_("auto_loop"), auto_loop_controllable->id());
+       node->set_property (X_("play_selection"), play_selection_controllable->id());
+       node->set_property (X_("rec"), rec_controllable->id());
+       node->set_property (X_("shuttle"), shuttle_box.controllable()->id());
+
+       return *node;
+}
+
 void
 ARDOUR_UI::save_session_at_its_request (std::string snapshot_name)
 {
@@ -2397,6 +2555,15 @@ ARDOUR_UI::transport_rec_preroll ()
        editor->rec_with_preroll ();
 }
 
+void
+ARDOUR_UI::transport_rec_count_in ()
+{
+       if (!_session) {
+               return;
+       }
+       editor->rec_with_count_in ();
+}
+
 void
 ARDOUR_UI::transport_rewind (int option)
 {
@@ -2541,11 +2708,15 @@ void
 ARDOUR_UI::blink_handler (bool blink_on)
 {
        transport_rec_enable_blink (blink_on);
-       solo_blink (blink_on);
        sync_blink (blink_on);
+
+       if (!UIConfiguration::instance().get_blink_alert_indicators()) {
+               blink_on = true;
+       }
+       error_blink (blink_on);
+       solo_blink (blink_on);
        audition_blink (blink_on);
        feedback_blink (blink_on);
-       error_blink (blink_on);
 }
 
 void
@@ -2634,16 +2805,17 @@ ARDOUR_UI::save_session_as ()
        */
 
        ArdourDialog progress_dialog (_("Save As"), true);
+       ScopedConnection c;
 
        if (sa.include_media && sa.copy_media) {
 
-               Gtk::Label label;
-               Gtk::ProgressBar progress_bar;
+               Gtk::Label* label = manage (new Gtk::Label());
+               Gtk::ProgressBar* progress_bar = manage (new Gtk::ProgressBar ());
 
-               progress_dialog.get_vbox()->pack_start (label);
-               progress_dialog.get_vbox()->pack_start (progress_bar);
-               label.show ();
-               progress_bar.show ();
+               progress_dialog.get_vbox()->pack_start (*label);
+               progress_dialog.get_vbox()->pack_start (*progress_bar);
+               label->show ();
+               progress_bar->show ();
 
                /* this signal will be emitted from within this, the calling thread,
                 * after every file is copied. It provides information on percentage
@@ -2651,9 +2823,7 @@ ARDOUR_UI::save_session_as ()
                 * copied so far, and the total number to copy.
                 */
 
-               ScopedConnection c;
-
-               sa.Progress.connect_same_thread (c, boost::bind (&ARDOUR_UI::save_as_progress_update, this, _1, _2, _3, &label, &progress_bar));
+               sa.Progress.connect_same_thread (c, boost::bind (&ARDOUR_UI::save_as_progress_update, this, _1, _2, _3, label, progress_bar));
 
                progress_dialog.show_all ();
                progress_dialog.present ();
@@ -3107,7 +3277,7 @@ void
 ARDOUR_UI::load_from_application_api (const std::string& path)
 {
        /* OS X El Capitan (and probably later) now somehow passes the command
-          line arguments to an app via the openFile delegate protocol. Ardour 
+          line arguments to an app via the openFile delegate protocol. Ardour
           already does its own command line processing, and having both
           pathways active causes crashes. So, if the command line was already
           set, do nothing here.
@@ -3558,6 +3728,16 @@ ARDOUR_UI::load_session (const std::string& path, const std::string& snap_name,
                msg.hide ();
        }
 
+
+       /* Now the session been created, add the transport controls */
+       new_session->add_controllable(roll_controllable);
+       new_session->add_controllable(stop_controllable);
+       new_session->add_controllable(goto_start_controllable);
+       new_session->add_controllable(goto_end_controllable);
+       new_session->add_controllable(auto_loop_controllable);
+       new_session->add_controllable(play_selection_controllable);
+       new_session->add_controllable(rec_controllable);
+
        set_session (new_session);
 
        session_loaded = true;
@@ -3649,8 +3829,8 @@ ARDOUR_UI::build_session (const std::string& path, const std::string& snap_name,
        /* Put the playhead at 0 and scroll fully left */
        n = new_session->instant_xml (X_("Editor"));
        if (n) {
-               n->add_property (X_("playhead"), X_("0"));
-               n->add_property (X_("left-frame"), X_("0"));
+               n->set_property (X_("playhead"), X_("0"));
+               n->set_property (X_("left-frame"), X_("0"));
        }
 
        set_session (new_session);
@@ -4176,89 +4356,6 @@ ARDOUR_UI::add_route_dialog_finished (int r)
        }
 }
 
-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 ();
-       }
-}
-
 void
 ARDOUR_UI::stop_video_server (bool ask_confirm)
 {
@@ -4378,9 +4475,8 @@ ARDOUR_UI::start_video_server (Gtk::Window* float_window, bool popup_msg)
                if (icsd_docroot == X_("/") || icsd_docroot == X_("C:\\")) {
                        Config->set_video_advanced_setup(false);
                } else {
-                       std::ostringstream osstream;
-                       osstream << "http://127.0.0.1:" << video_server_dialog->get_listenport() << "/";
-                       Config->set_video_server_url(osstream.str());
+                       std::string url_str = "http://127.0.0.1:" + to_string(video_server_dialog->get_listenport()) + "/";
+                       Config->set_video_server_url(url_str);
                        Config->set_video_server_docroot(icsd_docroot);
                        Config->set_video_advanced_setup(true);
                }
@@ -4512,11 +4608,11 @@ ARDOUR_UI::add_video (Gtk::Window* float_window)
 
        if (video_timeline->video_file_info(path, local_file)) {
                XMLNode* node = new XMLNode(X_("Videotimeline"));
-               node->add_property (X_("Filename"), path);
-               node->add_property (X_("AutoFPS"), auto_set_session_fps?X_("1"):X_("0"));
-               node->add_property (X_("LocalFile"), local_file?X_("1"):X_("0"));
+               node->set_property (X_("Filename"), path);
+               node->set_property (X_("AutoFPS"), auto_set_session_fps);
+               node->set_property (X_("LocalFile"), local_file);
                if (orig_local_file) {
-                       node->add_property (X_("OriginalVideoFile"), orig_path);
+                       node->set_property (X_("OriginalVideoFile"), orig_path);
                } else {
                        node->remove_property (X_("OriginalVideoFile"));
                }
@@ -5016,6 +5112,10 @@ Menu > Window > Audio/Midi Setup"),
 void
 ARDOUR_UI::use_config ()
 {
+       XMLNode* node = Config->extra_xml (X_("TransportControllables"));
+       if (node) {
+               set_transport_controllable_state (*node);
+       }
 }
 
 void
@@ -5099,9 +5199,9 @@ ARDOUR_UI::store_clock_modes ()
        for (vector<AudioClock*>::iterator x = AudioClock::clocks.begin(); x != AudioClock::clocks.end(); ++x) {
                XMLNode* child = new XMLNode (X_("Clock"));
 
-               child->add_property (X_("name"), (*x)->name());
-               child->add_property (X_("mode"), enum_2_string ((*x)->mode()));
-               child->add_property (X_("on"), ((*x)->off() ? X_("no") : X_("yes")));
+               child->set_property (X_("name"), (*x)->name());
+               child->set_property (X_("mode"), (*x)->mode());
+               child->set_property (X_("on"), (*x)->on());
 
                node->add_child_nocopy (*child);
        }
@@ -5110,6 +5210,86 @@ ARDOUR_UI::store_clock_modes ()
        _session->set_dirty ();
 }
 
+ARDOUR_UI::TransportControllable::TransportControllable (std::string name, ARDOUR_UI& u, ToggleType tp)
+       : Controllable (name), ui (u), type(tp)
+{
+
+}
+
+void
+ARDOUR_UI::TransportControllable::set_value (double val, PBD::Controllable::GroupControlDisposition /*group_override*/)
+{
+       if (val < 0.5) {
+               /* do nothing: these are radio-style actions */
+               return;
+       }
+
+       const char *action = 0;
+
+       switch (type) {
+       case Roll:
+               action = X_("Roll");
+               break;
+       case Stop:
+               action = X_("Stop");
+               break;
+       case GotoStart:
+               action = X_("GotoStart");
+               break;
+       case GotoEnd:
+               action = X_("GotoEnd");
+               break;
+       case AutoLoop:
+               action = X_("Loop");
+               break;
+       case PlaySelection:
+               action = X_("PlaySelection");
+               break;
+       case RecordEnable:
+               action = X_("Record");
+               break;
+       default:
+               break;
+       }
+
+       if (action == 0) {
+               return;
+       }
+
+       Glib::RefPtr<Action> act = ActionManager::get_action ("Transport", action);
+
+       if (act) {
+               act->activate ();
+       }
+}
+
+double
+ARDOUR_UI::TransportControllable::get_value (void) const
+{
+       float val = 0.0;
+
+       switch (type) {
+       case Roll:
+               break;
+       case Stop:
+               break;
+       case GotoStart:
+               break;
+       case GotoEnd:
+               break;
+       case AutoLoop:
+               break;
+       case PlaySelection:
+               break;
+       case RecordEnable:
+               break;
+       default:
+               break;
+       }
+
+       return val;
+}
+
 void
 ARDOUR_UI::setup_profile ()
 {
@@ -5214,6 +5394,52 @@ ARDOUR_UI::session_format_mismatch (std::string xml_path, std::string backup_pat
        msg.run ();
 }
 
+void
+ARDOUR_UI::add_editor_meter_type_item (Menu_Helpers::MenuList& items, RadioMenuItem::Group& group, string const & name, MeterType type)
+{
+       using namespace Menu_Helpers;
+
+       items.push_back (RadioMenuElem (group, name, sigc::bind (sigc::mem_fun (editor_meter, &LevelMeterHBox::set_meter_type), type)));
+       RadioMenuItem* i = dynamic_cast<RadioMenuItem *> (&items.back ());
+       i->set_active (editor_meter->meter_type () == type);
+}
+
+void
+ARDOUR_UI::popup_editor_meter_menu (GdkEventButton* ev)
+{
+       using namespace Gtk::Menu_Helpers;
+
+       Gtk::Menu* m = manage (new Menu);
+       MenuList& items = m->items ();
+
+       RadioMenuItem::Group group;
+
+       _suspend_editor_meter_callbacks = true;
+       add_editor_meter_type_item (items, group, ArdourMeter::meter_type_string(MeterPeak), MeterPeak);
+       add_editor_meter_type_item (items, group, ArdourMeter::meter_type_string(MeterPeak0dB), MeterPeak0dB);
+       add_editor_meter_type_item (items, group, ArdourMeter::meter_type_string(MeterKrms),  MeterKrms);
+       add_editor_meter_type_item (items, group, ArdourMeter::meter_type_string(MeterIEC1DIN), MeterIEC1DIN);
+       add_editor_meter_type_item (items, group, ArdourMeter::meter_type_string(MeterIEC1NOR), MeterIEC1NOR);
+       add_editor_meter_type_item (items, group, ArdourMeter::meter_type_string(MeterIEC2BBC), MeterIEC2BBC);
+       add_editor_meter_type_item (items, group, ArdourMeter::meter_type_string(MeterIEC2EBU), MeterIEC2EBU);
+       add_editor_meter_type_item (items, group, ArdourMeter::meter_type_string(MeterK20), MeterK20);
+       add_editor_meter_type_item (items, group, ArdourMeter::meter_type_string(MeterK14), MeterK14);
+       add_editor_meter_type_item (items, group, ArdourMeter::meter_type_string(MeterK12), MeterK12);
+       add_editor_meter_type_item (items, group, ArdourMeter::meter_type_string(MeterVU),  MeterVU);
+
+       m->popup (ev->button, ev->time);
+       _suspend_editor_meter_callbacks = false;
+}
+
+bool
+ARDOUR_UI::editor_meter_button_press (GdkEventButton* ev)
+{
+       if (ev->button == 3 && editor_meter) {
+               popup_editor_meter_menu (ev);
+               return true;
+       }
+       return false;
+}
 
 void
 ARDOUR_UI::reset_peak_display ()
@@ -5248,19 +5474,27 @@ 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);
 
-       if (Config->get_try_autostart_engine () || getenv ("TRY_AUTOSTART_ENGINE")) {
-               audio_midi_setup->try_autostart ();
-               if (ARDOUR::AudioEngine::instance()->running()) {
-                       return 0;
+       if (desired_sample_rate != 0) {
+               if (Config->get_try_autostart_engine () || getenv ("TRY_AUTOSTART_ENGINE")) {
+                       audio_midi_setup->try_autostart ();
+                       if (ARDOUR::AudioEngine::instance()->running()) {
+                               return 0;
+                       }
                }
        }
 
        while (true) {
                int response = audio_midi_setup->run();
-               printf("RESPONSE %d\n", response);
                switch (response) {
                case Gtk::RESPONSE_DELETE_EVENT:
-                       return -1;
+                       // after latency callibration engine may run,
+                       // Running() signal was emitted, but dialog will not
+                       // have emitted a response. The user needs to close
+                       // the dialog -> Gtk::RESPONSE_DELETE_EVENT
+                       if (!AudioEngine::instance()->running()) {
+                               return -1;
+                       }
+                       // fall through
                default:
                        if (!AudioEngine::instance()->running()) {
                                continue;