fix conflicts and merge with master
[ardour.git] / gtk2_ardour / ardour_ui.cc
index ec3f0becea433c5fd8d562c22c33f18a7443c015..c3d3211db1d04843a4ddcc783d35f0eb774141cf 100644 (file)
 #include <cerrno>
 #include <fstream>
 
+#ifndef WIN32
+#include <sys/resource.h>
+#endif
+
 #include <stdint.h>
 #include <fcntl.h>
 #include <signal.h>
 #include <unistd.h>
 #include <time.h>
 
-#include <sys/resource.h>
-#include <sys/types.h>
-#include <sys/sysctl.h>
+#include <glib.h>
+#include <glib/gstdio.h>
 
 #include <gtkmm/messagedialog.h>
 #include <gtkmm/accelmap.h>
@@ -48,6 +51,7 @@
 #include "pbd/memento_command.h"
 #include "pbd/openuri.h"
 #include "pbd/file_utils.h"
+#include "pbd/localtime_r.h"
 
 #include "gtkmm2ext/application.h"
 #include "gtkmm2ext/bindings.h"
@@ -157,7 +161,6 @@ ARDOUR_UI::ARDOUR_UI (int *argcp, char **argvp[], const char* localedir)
          /* start of private members */
 
        , _startup (0)
-       , engine (0)
        , nsm (0)
        , _was_dirty (false)
        , _mixer_on_top (false)
@@ -203,7 +206,7 @@ ARDOUR_UI::ARDOUR_UI (int *argcp, char **argvp[], const char* localedir)
 
        , _status_bar_visibility (X_("status-bar"))
        , _feedback_exists (false)
-
+       , _audio_midi_setup (0)
 {
        Gtkmm2ext::init(localedir);
 
@@ -214,12 +217,12 @@ ARDOUR_UI::ARDOUR_UI (int *argcp, char **argvp[], const char* localedir)
        }
 
        ui_config = new UIConfiguration();
+       _audio_midi_setup = new EngineControl;
 
        editor = 0;
        mixer = 0;
        meterbridge = 0;
        editor = 0;
-       engine = 0;
        _session_is_new = false;
        session_selector_window = 0;
        last_key_press_time = 0;
@@ -267,6 +270,10 @@ ARDOUR_UI::ARDOUR_UI (int *argcp, char **argvp[], const char* localedir)
 
        ARDOUR::Session::AskAboutPendingState.connect_same_thread (forever_connections, boost::bind (&ARDOUR_UI::pending_state_dialog, this));
 
+       /* handle Audio/MIDI setup when session requires it */
+
+       ARDOUR::Session::AudioEngineSetupRequired.connect_same_thread (forever_connections, boost::bind (&ARDOUR_UI::do_audio_midi_setup, this, _1));
+
        /* handle sr mismatch with a dialog (PROBLEM: needs to return a value and thus cannot be x-thread) */
 
        ARDOUR::Session::AskAboutSampleRateMismatch.connect_same_thread (forever_connections, boost::bind (&ARDOUR_UI::sr_mismatch_dialog, this, _1, _2));
@@ -286,25 +293,14 @@ ARDOUR_UI::ARDOUR_UI (int *argcp, char **argvp[], const char* localedir)
 
        /* and ambiguous files */
 
-       ARDOUR::FileSource::AmbiguousFileName.connect_same_thread (forever_connections, boost::bind (&ARDOUR_UI::ambiguous_file, this, _1, _2, _3));
+       ARDOUR::FileSource::AmbiguousFileName.connect_same_thread (forever_connections, boost::bind (&ARDOUR_UI::ambiguous_file, this, _1, _2));
 
        /* lets get this party started */
 
-       try {
-               if (ARDOUR::init (ARDOUR_COMMAND_LINE::use_vst, ARDOUR_COMMAND_LINE::try_hw_optimization, localedir)) {
-                       throw failed_constructor ();
-               }
-
-               setup_gtk_ardour_enums ();
-               setup_profile ();
-
-               SessionEvent::create_per_thread_pool ("GUI", 512);
+       setup_gtk_ardour_enums ();
+       setup_profile ();
 
-       } catch (failed_constructor& err) {
-               error << string_compose (_("could not initialize %1."), PROGRAM_NAME) << endmsg;
-               // pass it on up
-               throw;
-       }
+       SessionEvent::create_per_thread_pool ("GUI", 512);
 
        /* we like keyboards */
 
@@ -392,35 +388,16 @@ ARDOUR_UI::create_global_port_matrix (ARDOUR::DataType type)
 void
 ARDOUR_UI::attach_to_engine ()
 {
-       engine = AudioEngine::instance();
-
-       engine->Stopped.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::engine_stopped, this), gui_context());
-       engine->Running.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::engine_running, this), gui_context());
-       engine->SampleRateChanged.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::update_sample_rate, this, _1), gui_context());
-
-       engine->Halted.connect_same_thread (halt_connection, boost::bind (&ARDOUR_UI::engine_halted, this, _1, false));
-
+       AudioEngine::instance()->Running.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::engine_running, this), gui_context());
        ARDOUR::Port::set_connecting_blocked (ARDOUR_COMMAND_LINE::no_connect_ports);
-
-       /* if there is only one audio/midi backend, and it does not require setup, get our use of it underway
-        * right here (we need to know the client name and potential session ID
-        * to do this, which is why this is here, rather than in, say,
-        * ARDOUR::init().
-        */
-
-       if (!AudioEngine::instance()->setup_required()) {
-               const AudioBackendInfo* backend = AudioEngine::instance()->available_backends().front();
-               AudioEngine::instance()->set_backend (backend->name, ARDOUR_COMMAND_LINE::backend_client_name, ARDOUR_COMMAND_LINE::backend_session_uuid);
-               AudioEngine::instance()->start ();
-       }
 }
 
 void
 ARDOUR_UI::engine_stopped ()
 {
        ENSURE_GUI_THREAD (*this, &ARDOUR_UI::engine_stopped)
-       ActionManager::set_sensitive (ActionManager::jack_sensitive_actions, false);
-       ActionManager::set_sensitive (ActionManager::jack_opposite_sensitive_actions, true);
+       ActionManager::set_sensitive (ActionManager::engine_sensitive_actions, false);
+       ActionManager::set_sensitive (ActionManager::engine_opposite_sensitive_actions, true);
 }
 
 void
@@ -431,13 +408,13 @@ ARDOUR_UI::engine_running ()
                first_time_engine_run = false;
        }
        
-       ActionManager::set_sensitive (ActionManager::jack_sensitive_actions, true);
-       ActionManager::set_sensitive (ActionManager::jack_opposite_sensitive_actions, false);
+       ActionManager::set_sensitive (ActionManager::engine_sensitive_actions, true);
+       ActionManager::set_sensitive (ActionManager::engine_opposite_sensitive_actions, false);
 
        Glib::RefPtr<Action> action;
        const char* action_name = 0;
 
-       switch (engine->samples_per_cycle()) {
+       switch (AudioEngine::instance()->samples_per_cycle()) {
        case 32:
                action_name = X_("JACKLatency32");
                break;
@@ -478,7 +455,7 @@ ARDOUR_UI::engine_running ()
 
                update_disk_space ();
                update_cpu_load ();
-               update_sample_rate (engine->sample_rate());
+               update_sample_rate (AudioEngine::instance()->sample_rate());
                update_timecode_format ();
        }
 }
@@ -496,8 +473,8 @@ ARDOUR_UI::engine_halted (const char* reason, bool free_reason)
                return;
        }
 
-       ActionManager::set_sensitive (ActionManager::jack_sensitive_actions, false);
-       ActionManager::set_sensitive (ActionManager::jack_opposite_sensitive_actions, true);
+       ActionManager::set_sensitive (ActionManager::engine_sensitive_actions, false);
+       ActionManager::set_sensitive (ActionManager::engine_opposite_sensitive_actions, true);
 
        update_sample_rate (0);
 
@@ -534,6 +511,12 @@ ARDOUR_UI::post_engine ()
         */
 
        ARDOUR::init_post_engine ();
+       
+       /* connect to important signals */
+
+       AudioEngine::instance()->Stopped.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::engine_stopped, this), gui_context());
+       AudioEngine::instance()->SampleRateChanged.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::update_sample_rate, this, _1), gui_context());
+       AudioEngine::instance()->Halted.connect_same_thread (halt_connection, boost::bind (&ARDOUR_UI::engine_halted, this, _1, false));
 
        _tooltips.enable();
 
@@ -872,14 +855,14 @@ ARDOUR_UI::no_memory_warning ()
 void
 ARDOUR_UI::check_memory_locking ()
 {
-#ifdef __APPLE__
+#if defined(__APPLE__) || defined(WIN32)
        /* OS X doesn't support mlockall(2), and so testing for memory locking capability there is pointless */
        return;
 #else // !__APPLE__
 
        XMLNode* memory_warning_node = Config->instant_xml (X_("no-memory-warning"));
 
-       if (engine->is_realtime() && memory_warning_node == 0) {
+       if (AudioEngine::instance()->is_realtime() && memory_warning_node == 0) {
 
                struct rlimit limits;
                int64_t ram;
@@ -1020,7 +1003,7 @@ If you still wish to quit, please use the\n\n\
        }
 
        halt_connection.disconnect ();
-       engine->stop ();
+       AudioEngine::instance()->stop ();
        quit ();
 }
 
@@ -1149,13 +1132,13 @@ ARDOUR_UI::update_sample_rate (framecnt_t)
 
        ENSURE_GUI_THREAD (*this, &ARDOUR_UI::update_sample_rate, ignored)
 
-       if (!engine->connected()) {
+       if (!AudioEngine::instance()->connected()) {
 
                snprintf (buf, sizeof (buf), _("Audio: <span foreground=\"red\">none</span>"));
 
        } else {
 
-               framecnt_t rate = engine->sample_rate();
+               framecnt_t rate = AudioEngine::instance()->sample_rate();
 
                if (rate == 0) {
                        /* no sample rate available */
@@ -1165,11 +1148,11 @@ ARDOUR_UI::update_sample_rate (framecnt_t)
                        if (fmod (rate, 1000.0) != 0.0) {
                                snprintf (buf, sizeof (buf), _("Audio: <span foreground=\"green\">%.1f kHz / %4.1f ms</span>"),
                                          (float) rate / 1000.0f,
-                                         (engine->usecs_per_cycle() / 1000.0f));
+                                         (AudioEngine::instance()->usecs_per_cycle() / 1000.0f));
                        } else {
                                snprintf (buf, sizeof (buf), _("Audio: <span foreground=\"green\">%" PRId64 " kHz / %4.1f ms</span>"),
                                          rate/1000,
-                                         (engine->usecs_per_cycle() / 1000.0f));
+                                         (AudioEngine::instance()->usecs_per_cycle() / 1000.0f));
                        }
                }
        }
@@ -1240,7 +1223,7 @@ ARDOUR_UI::update_cpu_load ()
           should also be changed.
        */
 
-       float const c = engine->get_cpu_load ();
+       float const c = AudioEngine::instance()->get_cpu_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);
 }
@@ -1561,20 +1544,16 @@ ARDOUR_UI::open_recent_session ()
 bool
 ARDOUR_UI::check_audioengine ()
 {
-       if (engine) {
-               if (!engine->connected()) {
-                       MessageDialog msg (string_compose (
-                                                  _("%1 is not connected to JACK\n"
-                                                    "You cannot open or close sessions in this condition"),
-                                                  PROGRAM_NAME));
-                       pop_back_splash (msg);
-                       msg.run ();
-                       return false;
-               }
-               return true;
-       } else {
+       if (!AudioEngine::instance()->connected()) {
+               MessageDialog msg (string_compose (
+                                          _("%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 ();
                return false;
        }
+       return true;
 }
 
 void
@@ -2795,25 +2774,23 @@ ARDOUR_UI::load_session (const std::string& path, const std::string& snap_name,
        int unload_status;
        int retval = -1;
 
-       session_loaded = false;
-
-       if (!check_audioengine()) {
-               return -2;
+       if (_session) {
+               unload_status = unload_session ();
+               
+               if (unload_status < 0) {
+                       goto out;
+               } else if (unload_status > 0) {
+                       retval = 0;
+                       goto out;
+               }
        }
 
-       unload_status = unload_session ();
-
-       if (unload_status < 0) {
-               goto out;
-       } else if (unload_status > 0) {
-               retval = 0;
-               goto out;
-       }
+       session_loaded = false;
 
        loading_message (string_compose (_("Please wait while %1 loads your session"), PROGRAM_NAME));
 
        try {
-               new_session = new Session (*engine, path, snap_name, 0, mix_template);
+               new_session = new Session (*AudioEngine::instance(), path, snap_name, 0, mix_template);
        }
 
        /* this one is special */
@@ -2914,12 +2891,7 @@ ARDOUR_UI::build_session (const std::string& path, const std::string& snap_name,
        Session *new_session;
        int x;
 
-       if (!check_audioengine()) {
-               return -1;
-       }
-
        session_loaded = false;
-
        x = unload_session ();
 
        if (x < 0) {
@@ -2931,7 +2903,7 @@ ARDOUR_UI::build_session (const std::string& path, const std::string& snap_name,
        _session_is_new = true;
 
        try {
-               new_session = new Session (*engine, path, snap_name, &bus_profile);
+               new_session = new Session (*AudioEngine::instance(), path, snap_name, &bus_profile);
        }
 
        catch (...) {
@@ -3399,15 +3371,23 @@ ARDOUR_UI::start_video_server (Gtk::Window* float_window, bool popup_msg)
                if (icsd_docroot.empty()) {icsd_docroot = X_("/");}
 
                struct stat sb;
-               if (!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;
                }
-               if ( (!lstat (icsd_exec.c_str(), &sb) == 0)
+#ifndef WIN32
+               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)
+                    || (sb.st_mode & (S_IXUSR)) == 0 ) {
+                       warning << _("Given Video Server is not an executable file.") << endmsg;
+                       continue;
+               }
+#endif
 
                char **argp;
                argp=(char**) calloc(9,sizeof(char*));
@@ -3818,38 +3798,33 @@ audio may be played at the wrong sample rate.\n"), desired, PROGRAM_NAME, actual
         return 1;
 }
 
-
 void
-ARDOUR_UI::disconnect_from_jack ()
+ARDOUR_UI::disconnect_from_engine ()
 {
-       if (engine) {
-               /* drop connection to AudioEngine::Halted so that we don't act
-                *  as if the engine unexpectedly shut down
-                */
-               halt_connection.disconnect ();
-
-               if (engine->stop ()) {
-                       MessageDialog msg (*editor, _("Could not disconnect from JACK"));
-                       msg.run ();
-               } else {
-                       engine->Halted.connect_same_thread (halt_connection, boost::bind (&ARDOUR_UI::engine_halted, this, _1, false));
-               }
-
-               update_sample_rate (0);
+       /* drop connection to AudioEngine::Halted so that we don't act
+        *  as if the engine unexpectedly shut down
+        */
+       halt_connection.disconnect ();
+       
+       if (AudioEngine::instance()->stop ()) {
+               MessageDialog msg (*editor, _("Could not disconnect from JACK"));
+               msg.run ();
+       } else {
+               AudioEngine::instance()->Halted.connect_same_thread (halt_connection, boost::bind (&ARDOUR_UI::engine_halted, this, _1, false));
        }
+       
+       update_sample_rate (0);
 }
 
 void
-ARDOUR_UI::reconnect_to_jack ()
+ARDOUR_UI::reconnect_to_engine ()
 {
-       if (engine) {
-               if (engine->start ()) {
-                       MessageDialog msg (*editor,  _("Could not reconnect to JACK"));
-                       msg.run ();
-               }
-
-               update_sample_rate (0);
+       if (AudioEngine::instance()->start ()) {
+               MessageDialog msg (*editor,  _("Could not reconnect to JACK"));
+               msg.run ();
        }
+       
+       update_sample_rate (0);
 }
 
 void
@@ -4065,7 +4040,7 @@ ARDOUR_UI::missing_file (Session*s, std::string str, DataType type)
 }
 
 int
-ARDOUR_UI::ambiguous_file (std::string file, std::string /*path*/, std::vector<std::string> hits)
+ARDOUR_UI::ambiguous_file (std::string file, std::vector<std::string> hits)
 {
        AmbiguousFileDialog dialog (file, hits);
 
@@ -4156,3 +4131,47 @@ ARDOUR_UI::reset_route_peak_display (Route* route)
                reset_peak_display ();
        }
 }
+
+void
+ARDOUR_UI::toggle_audio_midi_setup ()
+{
+       Glib::RefPtr<Action> act = ActionManager::get_action (X_("Common"), X_("toggle-audio-midi-setup"));
+       if (!act) {
+               return;
+       }
+
+       Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic (act);
+
+       if (tact->get_active()) {
+               launch_audio_midi_setup ();
+       } else {
+               _audio_midi_setup->hide ();
+       }
+}
+
+void
+ARDOUR_UI::launch_audio_midi_setup ()
+{
+       if (!_audio_midi_setup) {
+               _audio_midi_setup = new EngineControl ();
+       }
+
+       _audio_midi_setup->present ();
+}
+                                               
+int
+ARDOUR_UI::do_audio_midi_setup (uint32_t desired_sample_rate)
+{
+       launch_audio_midi_setup ();
+
+       _audio_midi_setup->set_desired_sample_rate (desired_sample_rate);
+
+       switch (_audio_midi_setup->run()) {
+       case Gtk::RESPONSE_OK:
+               return 0;
+       case Gtk::RESPONSE_APPLY:
+               return 0;
+       default:
+               return -1;
+       }
+}