some fixes/improvements for track selection; add upload target to manual makefile...
[ardour.git] / gtk2_ardour / ardour_ui.cc
index 4875b8db89a53bf6e825fd20969c6c266f2c3cf6..7e0e06e97ffffc72e6a517404e82fd08a8232c75 100644 (file)
@@ -1,5 +1,5 @@
 /*
-    Copyright (C) 1999-2002 Paul Davis 
+    Copyright (C) 1999-2007 Paul Davis 
 
     This program is free software; you can redistribute it and/or modify
     it under the terms of the GNU General Public License as published by
@@ -28,6 +28,8 @@
 
 #include <iostream>
 
+#include <sys/resource.h>
+
 #include <gtkmm/messagedialog.h>
 #include <gtkmm/accelmap.h>
 
@@ -35,6 +37,8 @@
 #include <pbd/compose.h>
 #include <pbd/pathscanner.h>
 #include <pbd/failed_constructor.h>
+#include <pbd/enumwriter.h>
+#include <pbd/stacktrace.h>
 #include <gtkmm2ext/gtk_ui.h>
 #include <gtkmm2ext/utils.h>
 #include <gtkmm2ext/click_box.h>
@@ -85,6 +89,7 @@ ARDOUR_UI *ARDOUR_UI::theArdourUI = 0;
 
 sigc::signal<void,bool> ARDOUR_UI::Blink;
 sigc::signal<void>      ARDOUR_UI::RapidScreenUpdate;
+sigc::signal<void>      ARDOUR_UI::MidRapidScreenUpdate;
 sigc::signal<void>      ARDOUR_UI::SuperRapidScreenUpdate;
 sigc::signal<void,nframes_t> ARDOUR_UI::Clock;
 
@@ -92,10 +97,10 @@ ARDOUR_UI::ARDOUR_UI (int *argcp, char **argvp[], string rcfile)
 
        : Gtkmm2ext::UI ("ardour", argcp, argvp, rcfile),
          
-         primary_clock (X_("TransportClockDisplay"), true, false, true),
-         secondary_clock (X_("SecondaryClockDisplay"), true, false, true),
-         preroll_clock (X_("PreRollClock"), true, true),
-         postroll_clock (X_("PostRollClock"), true, true),
+         primary_clock (X_("primary"), false, X_("TransportClockDisplay"), true, false, true),
+         secondary_clock (X_("secondary"), false, X_("SecondaryClockDisplay"), true, false, true),
+         preroll_clock (X_("preroll"), false, X_("PreRollClock"), true, true),
+         postroll_clock (X_("postroll"), false, X_("PostRollClock"), true, true),
 
          /* adjuster table */
 
@@ -108,7 +113,7 @@ ARDOUR_UI::ARDOUR_UI (int *argcp, char **argvp[], string rcfile)
 
          /* big clock */
 
-         big_clock ("BigClockNonRecording", true, false, true),
+         big_clock (X_("bigclock"), false, "BigClockNonRecording", false, false, true),
 
          /* transport */
 
@@ -165,6 +170,9 @@ ARDOUR_UI::ARDOUR_UI (int *argcp, char **argvp[], string rcfile)
        last_speed_displayed = -1.0f;
        keybindings_path = ARDOUR::find_config_file ("ardour.bindings");
 
+       can_save_keybindings = false;
+       Glib::signal_idle().connect (mem_fun (*this, &ARDOUR_UI::first_idle));
+
        last_configure_time.tv_sec = 0;
        last_configure_time.tv_usec = 0;
 
@@ -244,6 +252,11 @@ ARDOUR_UI::set_engine (AudioEngine& e)
                throw failed_constructor();
        }
 
+       /* set default clock modes */
+
+       primary_clock.set_mode (AudioClock::SMPTE);
+       secondary_clock.set_mode (AudioClock::BBT);
+
        /* start the time-of-day-clock */
        
        update_wall_clock ();
@@ -351,7 +364,25 @@ ARDOUR_UI::save_ardour_state ()
 void
 ARDOUR_UI::startup ()
 {
-       // relax
+       if (engine->is_realtime()) {
+
+               struct rlimit limits;
+               
+               if (getrlimit (RLIMIT_MEMLOCK, &limits)) {
+                       return;
+               }
+               
+               if (limits.rlim_cur != RLIM_INFINITY) {
+                       MessageDialog msg (_("WARNING: Your system has a limit for maximum amount of locked memory. "
+                                            "This might cause Ardour to run out of memory before your system "
+                                            "runs out of memory. \n\n"
+                                            "You can view the memory limit with 'ulimit -l', "
+                                            "and it is normally controlled by /etc/security/limits.conf"));
+                       
+                       editor->ensure_float (msg);
+                       msg.run ();
+               }
+       }
 }
 
 void
@@ -476,6 +507,13 @@ ARDOUR_UI::every_point_one_seconds ()
        return TRUE;
 }
 
+gint
+ARDOUR_UI::every_point_oh_five_seconds ()
+{
+       MidRapidScreenUpdate(); /* EMIT_SIGNAL */
+       return true;
+}
+
 gint
 ARDOUR_UI::every_point_zero_one_seconds ()
 {
@@ -946,7 +984,7 @@ ARDOUR_UI::transport_goto_start ()
                */
                
                if (editor) {
-                       editor->reposition_x_origin (session->current_start_frame());
+                       editor->reset_x_origin (session->current_start_frame());
                }
        }
 }
@@ -963,7 +1001,7 @@ ARDOUR_UI::transport_goto_zero ()
                */
                
                if (editor) {
-                       editor->reposition_x_origin (0);
+                       editor->reset_x_origin (0);
                }
        }
 }
@@ -980,7 +1018,7 @@ ARDOUR_UI::transport_goto_end ()
                */
                
                if (editor) {
-                       editor->reposition_x_origin (frame);
+                       editor->reset_x_origin (frame);
                }
        }
 }
@@ -1234,6 +1272,49 @@ ARDOUR_UI::engine_running ()
        ENSURE_GUI_THREAD (mem_fun(*this, &ARDOUR_UI::engine_running));
        ActionManager::set_sensitive (ActionManager::jack_sensitive_actions, true);
        ActionManager::set_sensitive (ActionManager::jack_opposite_sensitive_actions, false);
+
+       Glib::RefPtr<Action> action;
+       char* action_name = 0;
+
+       switch (engine->frames_per_cycle()) {
+       case 32:
+               action_name = X_("JACKLatency32");
+               break;
+       case 64:
+               action_name = X_("JACKLatency64");
+               break;
+       case 128:
+               action_name = X_("JACKLatency128");
+               break;
+       case 512:
+               action_name = X_("JACKLatency512");
+               break;
+       case 1024:
+               action_name = X_("JACKLatency1024");
+               break;
+       case 2048:
+               action_name = X_("JACKLatency2048");
+               break;
+       case 4096:
+               action_name = X_("JACKLatency4096");
+               break;
+       case 8192:
+               action_name = X_("JACKLatency8192");
+               break;
+       default:
+               /* XXX can we do anything useful ? */
+               break;
+       }
+
+       if (action_name) {
+
+               action = ActionManager::get_action (X_("JACK"), action_name);
+               
+               if (action) {
+                       Glib::RefPtr<RadioAction> ract = Glib::RefPtr<RadioAction>::cast_dynamic (action);
+                       ract->set_active ();
+               }
+       }
 }
 
 void
@@ -1262,14 +1343,6 @@ ARDOUR_UI::do_engine_start ()
                engine->start();
        }
 
-       catch (AudioEngine::PortRegistrationFailure& err) {
-               engine->stop ();
-               error << _("Unable to create all required ports")
-                     << endmsg;
-               unload_session ();
-               return -1;
-       }
-
        catch (...) {
                engine->stop ();
                error << _("Unable to start the session running")
@@ -1414,17 +1487,18 @@ ARDOUR_UI::snapshot_session ()
 {
        ArdourPrompter prompter (true);
        string snapname;
-       string now;
+       char timebuf[128];
        time_t n;
+       struct tm local_time;
 
        time (&n);
-       now = ctime (&n);
-       now = now.substr (20, 4) + now.substr (3, 16) + " (" + now.substr (0, 3) + ")";
+       localtime_r (&n, &local_time);
+       strftime (timebuf, sizeof(timebuf), "%FT%T", &local_time);
 
        prompter.set_name ("Prompter");
        prompter.add_button (Gtk::Stock::SAVE, Gtk::RESPONSE_ACCEPT);
        prompter.set_prompt (_("Name of New Snapshot"));
-       prompter.set_initial_text (now);
+       prompter.set_initial_text (timebuf);
        
        switch (prompter.run()) {
        case RESPONSE_ACCEPT:
@@ -1588,7 +1662,7 @@ ARDOUR_UI::save_template ()
 }
 
 void
-ARDOUR_UI::new_session (bool startup, std::string predetermined_path)
+ARDOUR_UI::new_session (std::string predetermined_path)
 {
        string session_name;
        string session_path;
@@ -1796,6 +1870,7 @@ ARDOUR_UI::load_session (const string & path, const string & snap_name, string*
        Session *new_session;
        int x;
        session_loaded = false;
+       
        x = unload_session ();
 
        if (x < 0) {
@@ -1807,9 +1882,8 @@ ARDOUR_UI::load_session (const string & path, const string & snap_name, string*
        /* if it already exists, we must have write access */
 
        if (::access (path.c_str(), F_OK) == 0 && ::access (path.c_str(), W_OK)) {
-               MessageDialog msg (*editor, _("\
-You do not have write access to this session.\n\
-This prevents the session from being loaded."));
+               MessageDialog msg (*editor, _("You do not have write access to this session.\n"
+                                             "This prevents the session from being loaded."));
                msg.run ();
                return -1;
        }
@@ -2309,13 +2383,6 @@ ARDOUR_UI::reconnect_to_jack ()
        }
 }
 
-void
-ARDOUR_UI::set_jack_buffer_size (nframes_t nframes)
-{
-       engine->request_buffer_size (nframes);
-       update_sample_rate (0);
-}
-
 int
 ARDOUR_UI::cmdline_new_session (string path)
 {
@@ -2330,7 +2397,7 @@ ARDOUR_UI::cmdline_new_session (string path)
                path = str;
        }
 
-       new_session (false, path);
+       new_session (path);
 
        _will_create_new_session_automatically = false; /* done it */
        return FALSE; /* don't call it again */
@@ -2399,6 +2466,8 @@ ARDOUR_UI::update_transport_clocks (nframes_t pos)
 void
 ARDOUR_UI::record_state_changed ()
 {
+       ENSURE_GUI_THREAD (mem_fun (*this, &ARDOUR_UI::record_state_changed));
+
        if (!session || !big_clock_window) {
                /* why bother - the clock isn't visible */
                return;
@@ -2406,10 +2475,10 @@ ARDOUR_UI::record_state_changed ()
 
        switch (session->record_status()) {
        case Session::Recording:
-               big_clock.set_name ("BigClockRecording");
+               big_clock.set_widget_name ("BigClockRecording");
                break;
        default:
-               big_clock.set_name ("BigClockNonRecording");
+               big_clock.set_widget_name ("BigClockNonRecording");
                break;
        }
 }
@@ -2423,5 +2492,30 @@ ARDOUR_UI::set_keybindings_path (string path)
 void
 ARDOUR_UI::save_keybindings ()
 {
-       AccelMap::save (keybindings_path);
+       if (can_save_keybindings) {
+               AccelMap::save (keybindings_path);
+       } 
+}
+
+bool
+ARDOUR_UI::first_idle ()
+{
+       can_save_keybindings = true;
+       return false;
 }
+
+void
+ARDOUR_UI::store_clock_modes ()
+{
+       XMLNode* node = new XMLNode(X_("ClockModes"));
+
+       for (vector<AudioClock*>::iterator x = AudioClock::clocks.begin(); x != AudioClock::clocks.end(); ++x) {
+               node->add_property ((*x)->name().c_str(), enum_2_string ((*x)->mode()));
+       }
+
+       session->add_extra_xml (*node);
+       session->set_dirty ();
+}
+
+
+