hardour does not yet support wine-builds
[ardour.git] / gtk2_ardour / ardour_ui.cc
index 7921dc4274b85377da96a1aa369df78071f47479..10de8e795d8953068b9cbfbc8e1863365e99544f 100644 (file)
 #include <cerrno>
 #include <fstream>
 
+#ifndef PLATFORM_WINDOWS
+#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,8 @@
 #include "pbd/memento_command.h"
 #include "pbd/openuri.h"
 #include "pbd/file_utils.h"
+#include "pbd/localtime_r.h"
+#include "pbd/system_exec.h"
 
 #include "gtkmm2ext/application.h"
 #include "gtkmm2ext/bindings.h"
@@ -67,6 +72,7 @@
 #include "ardour/filename_extensions.h"
 #include "ardour/filesystem_paths.h"
 #include "ardour/port.h"
+#include "ardour/plugin_manager.h"
 #include "ardour/process_thread.h"
 #include "ardour/profile.h"
 #include "ardour/recent_sessions.h"
 #include "ardour/session_utils.h"
 #include "ardour/slave.h"
 
+#ifdef WINDOWS_VST_SUPPORT
+#include <fst.h>
+#endif
+
 #include "timecode/time.h"
 
 typedef uint64_t microseconds_t;
@@ -123,7 +133,6 @@ typedef uint64_t microseconds_t;
 #include "video_server_dialog.h"
 #include "add_video_dialog.h"
 #include "transcode_video_dialog.h"
-#include "system_exec.h"
 
 #include "i18n.h"
 
@@ -162,6 +171,7 @@ ARDOUR_UI::ARDOUR_UI (int *argcp, char **argvp[], const char* localedir)
        , _was_dirty (false)
        , _mixer_on_top (false)
        , first_time_engine_run (true)
+       , blink_timeout_tag (-1)
 
          /* transport */
 
@@ -293,7 +303,10 @@ 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));
+
+       /* also plugin scan messages */
+       ARDOUR::PluginScanMessage.connect (forever_connections, MISSING_INVALIDATOR, boost::bind(&ARDOUR_UI::plugin_scan_dialog, this, _1, _2), gui_context());
 
        /* lets get this party started */
 
@@ -499,10 +512,13 @@ ARDOUR_UI::post_engine ()
 
                vector<string>::iterator n;
                vector<string>::iterator k;
-               for (n = names.begin(), k = keys.begin(); n != names.end(); ++n, ++k) {
-                       cout << "Action: " << (*n) << " bound to " << (*k) << endl;
+               vector<string>::iterator p;
+               for (n = names.begin(), k = keys.begin(), p = paths.begin(); n != names.end(); ++n, ++k, ++p) {
+                       cout << "Action: '" << (*n) << "' bound to '" << (*k) << "' Path: '" << (*p) << "'" << endl;
                }
 
+               halt_connection.disconnect ();
+               AudioEngine::instance()->stop ();
                exit (0);
        }
 
@@ -722,7 +738,7 @@ int
 ARDOUR_UI::starting ()
 {
        Application* app = Application::instance ();
-       char *nsm_url;
+       const char *nsm_url;
        bool brand_new_user = ArdourStartup::required ();
 
        app->ShouldQuit.connect (sigc::mem_fun (*this, &ARDOUR_UI::queue_finish));
@@ -734,9 +750,17 @@ ARDOUR_UI::starting ()
 
        app->ready ();
 
-       nsm_url = getenv ("NSM_URL");
+       /* we need to create this early because it may need to set the
+        *  audio backend end up.
+        */
+       
+       try {
+               audio_midi_setup.get (true);
+       } catch (...) {
+               return -1;
+       }
 
-       if (nsm_url) {
+       if ((nsm_url = g_getenv ("NSM_URL")) != 0) {
                nsm = new NSM_Client;
                if (!nsm->init (nsm_url)) {
                        nsm->announce (PROGRAM_NAME, ":dirty:", "ardour3");
@@ -745,20 +769,35 @@ ARDOUR_UI::starting ()
                        // wait for announce reply from nsm server
                        for ( i = 0; i < 5000; ++i) {
                                nsm->check ();
-                               usleep (i);
-                               if (nsm->is_active())
+
+                               Glib::usleep (i);
+                               if (nsm->is_active()) {
                                        break;
+                               }
+                       }
+                       if (i == 5000) {
+                               error << _("NSM server did not announce itself") << endmsg;
+                               return -1;
                        }
                        // wait for open command from nsm server
                        for ( i = 0; i < 5000; ++i) {
                                nsm->check ();
-                               usleep (1000);
-                               if (nsm->client_id ())
+                               Glib::usleep (1000);
+                               if (nsm->client_id ()) {
                                        break;
+                               }
+                       }
+
+                       if (i == 5000) {
+                               error << _("NSM: no client ID provided") << endmsg;
+                               return -1;
                        }
 
                        if (_session && nsm) {
                                _session->set_nsm_state( nsm->is_active() );
+                       } else {
+                               error << _("NSM: no session created") << endmsg;
+                               return -1;
                        }
 
                        // nsm requires these actions disabled
@@ -777,10 +816,11 @@ ARDOUR_UI::starting ()
                                }
                        }
 
-               }
-               else {
+               } else {
                        delete nsm;
                        nsm = 0;
+                       error << _("NSM: initialization failed") << endmsg;
+                       return -1;
                }
 
        } else  {
@@ -798,16 +838,6 @@ ARDOUR_UI::starting ()
                        }
                }
 
-               /* we need to create this early because it may need to set the
-                *  audio backend end up.
-                */
-
-               try {
-                       audio_midi_setup.get (true);
-               } catch (...) {
-                       return -1;
-               }
-
                /* go get a session */
 
                const bool new_session_required = (ARDOUR_COMMAND_LINE::new_session || brand_new_user);
@@ -835,7 +865,7 @@ ARDOUR_UI::starting ()
 void
 ARDOUR_UI::check_memory_locking ()
 {
-#ifdef __APPLE__
+#if defined(__APPLE__) || defined(PLATFORM_WINDOWS)
        /* OS X doesn't support mlockall(2), and so testing for memory locking capability there is pointless */
        return;
 #else // !__APPLE__
@@ -986,6 +1016,9 @@ If you still wish to quit, please use the\n\n\
 
        halt_connection.disconnect ();
        AudioEngine::instance()->stop ();
+#ifdef WINDOWS_VST_SUPPORT
+       fst_stop_threading();
+#endif
        quit ();
 }
 
@@ -1204,7 +1237,7 @@ ARDOUR_UI::update_cpu_load ()
           should also be changed.
        */
 
-       float const c = AudioEngine::instance()->get_cpu_load ();
+       float 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);
 }
@@ -2181,8 +2214,13 @@ ARDOUR_UI::snapshot_session (bool switch_to_it)
 
        prompter.set_name ("Prompter");
        prompter.add_button (Gtk::Stock::SAVE, Gtk::RESPONSE_ACCEPT);
-       prompter.set_title (_("Take Snapshot"));
-       prompter.set_prompt (_("Name of new snapshot"));
+       if (switch_to_it) {
+               prompter.set_title (_("Save as..."));
+               prompter.set_prompt (_("New session name"));
+       } else {
+               prompter.set_title (_("Take Snapshot"));
+               prompter.set_prompt (_("Name of new snapshot"));
+       }
 
        if (!switch_to_it) {
                char timebuf[128];
@@ -2889,7 +2927,13 @@ ARDOUR_UI::load_session (const std::string& path, const std::string& snap_name,
                _session->set_clean ();
        }
 
+#ifdef WINDOWS_VST_SUPPORT
+       fst_stop_threading();
+#endif
        flush_pending ();
+#ifdef WINDOWS_VST_SUPPORT
+       fst_start_threading();
+#endif
        retval = 0;
 
   out:
@@ -3084,13 +3128,13 @@ require some unused files to continue to exist."));
                space_adjusted = rep.space;
        } else if (rep.space < 1000000) {
                bprefix = _("kilo");
-               space_adjusted = truncf((float)rep.space / 1000.0);
+               space_adjusted = floorf((float)rep.space / 1000.0);
        } else if (rep.space < 1000000 * 1000) {
                bprefix = _("mega");
-               space_adjusted = truncf((float)rep.space / (1000.0 * 1000.0));
+               space_adjusted = floorf((float)rep.space / (1000.0 * 1000.0));
        } else {
                bprefix = _("giga");
-               space_adjusted = truncf((float)rep.space / (1000.0 * 1000 * 1000.0));
+               space_adjusted = floorf((float)rep.space / (1000.0 * 1000 * 1000.0));
        }
 
        if (msg_delete) {
@@ -3226,6 +3270,57 @@ ARDOUR_UI::flush_trash ()
        display_cleanup_results (rep, _("deleted file"), true);
 }
 
+void
+ARDOUR_UI::setup_order_hint ()
+{
+       uint32_t order_hint = 0;
+
+       /*
+         we want the new routes to have their order keys set starting from 
+         the highest order key in the selection + 1 (if available).
+       */
+       if (add_route_dialog->get_transient_for () == mixer->get_toplevel()) {
+               for (RouteUISelection::iterator s = mixer->selection().routes.begin(); s != mixer->selection().routes.end(); ++s) {
+                       if ((*s)->route()->order_key() > order_hint) {
+                               order_hint = (*s)->route()->order_key();
+                       }
+               }
+
+               if (!mixer->selection().routes.empty()) {
+                       order_hint++;
+               }
+
+       } else {
+               for (TrackSelection::iterator s = editor->get_selection().tracks.begin(); s != editor->get_selection().tracks.end(); ++s) {
+                       RouteTimeAxisView* tav = dynamic_cast<RouteTimeAxisView*> (*s);
+                       if (tav && tav->route() && tav->route()->order_key() > order_hint) {
+                               order_hint = tav->route()->order_key();
+                       }
+               }
+
+               if (!editor->get_selection().tracks.empty()) {
+                       order_hint++;
+               }
+       }
+
+       _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());
+               }
+       }
+}
+
 void
 ARDOUR_UI::add_route (Gtk::Window* float_window)
 {
@@ -3241,6 +3336,7 @@ ARDOUR_UI::add_route (Gtk::Window* float_window)
        }
 
        if (float_window) {
+               add_route_dialog->unset_transient_for ();
                add_route_dialog->set_transient_for (*float_window);
        }
 
@@ -3260,11 +3356,9 @@ ARDOUR_UI::add_route (Gtk::Window* float_window)
                return;
        }
 
-       PBD::ScopedConnection idle_connection;
+       setup_order_hint();
 
-       if (count > 8) {
-               ARDOUR::GUIIdle.connect (idle_connection, MISSING_INVALIDATOR, boost::bind (&Gtkmm2ext::UI::flush_pending, this), gui_context());
-       }
+       PBD::ScopedConnection idle_connection;
 
        string template_path = add_route_dialog->track_template();
 
@@ -3315,7 +3409,7 @@ void
 ARDOUR_UI::stop_video_server (bool ask_confirm)
 {
        if (!video_server_process && ask_confirm) {
-               warning << _("Video-Server was not launched by Ardour. The request to stop it is ignored.") << endmsg;
+               warning << string_compose (_("Video-Server was not launched by %1. The request to stop it is ignored."), PROGRAM_NAME) << endmsg;
        }
        if (video_server_process) {
                if(ask_confirm) {
@@ -3381,16 +3475,24 @@ ARDOUR_UI::start_video_server (Gtk::Window* float_window, bool popup_msg)
                std::string icsd_docroot = video_server_dialog->get_docroot();
                if (icsd_docroot.empty()) {icsd_docroot = X_("/");}
 
-               struct stat sb;
-               if (!lstat (icsd_docroot.c_str(), &sb) == 0 || !S_ISDIR(sb.st_mode)) {
+               GStatBuf sb;
+               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 PLATFORM_WINDOWS
+               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*));
@@ -3426,7 +3528,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()) {
-                       usleep (50000);
+                       Glib::usleep (50000);
                        if (--timeout <= 0 || !video_server_process->is_running()) break;
                }
                if (timeout <= 0) {
@@ -3497,7 +3599,8 @@ ARDOUR_UI::add_video (Gtk::Window* float_window)
                                if (!transcode_video_dialog->get_audiofile().empty()) {
                                        editor->embed_audio_from_video(
                                                        transcode_video_dialog->get_audiofile(),
-                                                       video_timeline->get_offset()
+                                                       video_timeline->get_offset(),
+                                                       (transcode_video_dialog->import_option() != VTL_IMPORT_NO_VIDEO)
                                                        );
                                }
                                switch (transcode_video_dialog->import_option()) {
@@ -3691,6 +3794,41 @@ quickly enough to keep up with recording.\n"), PROGRAM_NAME));
        }
 }
 
+void
+ARDOUR_UI::cancel_plugin_scan ()
+{
+       PluginManager::instance().cancel_plugin_scan();
+}
+
+static MessageDialog *scan_dlg = NULL;
+
+void
+ARDOUR_UI::plugin_scan_dialog (std::string type, std::string plugin)
+{
+       if (!Config->get_show_plugin_scan_window()) { return; }
+       if (!scan_dlg) {
+               scan_dlg = new MessageDialog("", false, MESSAGE_INFO, BUTTONS_NONE);
+               VBox* vbox = scan_dlg->get_vbox();
+               vbox->set_size_request(400,-1);
+               scan_dlg->set_title (_("Scanning for plugins"));
+
+               Gtk::Button *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) );
+
+               scan_dlg->get_vbox()->pack_start ( *cancel_button, PACK_SHRINK);
+       }
+
+       if (type == X_("closeme")) {
+               scan_dlg->hide();
+       } else {
+               scan_dlg->set_message(type + ": " + Glib::path_get_basename(plugin));
+               scan_dlg->show_all();
+       }
+
+       gtk_main_iteration ();
+}
+
 void
 ARDOUR_UI::disk_underrun_handler ()
 {
@@ -4053,7 +4191,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);