X-Git-Url: https://main.carlh.net/gitweb/?a=blobdiff_plain;f=gtk2_ardour%2Fardour_ui.cc;h=5846fa577fb88073a2ba14f8861065124d9b3532;hb=4c42a77441e74356cd909d994e270d1e1314aad4;hp=9c637761b0b4c767cc5d1958d799fd247a589dd9;hpb=0532e2063b73ec32d4dd108b58e90a0f20ae91b3;p=ardour.git diff --git a/gtk2_ardour/ardour_ui.cc b/gtk2_ardour/ardour_ui.cc index 9c637761b0..5846fa577f 100644 --- a/gtk2_ardour/ardour_ui.cc +++ b/gtk2_ardour/ardour_ui.cc @@ -35,6 +35,8 @@ #include #include +#include +#include #include #include @@ -73,6 +75,9 @@ #include "ardour/session_route.h" #include "ardour/session_state_utils.h" #include "ardour/session_utils.h" +#include "ardour/slave.h" + +#include "timecode/time.h" typedef uint64_t microseconds_t; @@ -94,6 +99,7 @@ typedef uint64_t microseconds_t; #include "missing_file_dialog.h" #include "missing_plugin_dialog.h" #include "mixer_ui.h" +#include "mouse_cursors.h" #include "opts.h" #include "processor_box.h" #include "prompter.h" @@ -125,7 +131,7 @@ sigc::signal ARDOUR_UI::RapidScreenUpdate; sigc::signal ARDOUR_UI::SuperRapidScreenUpdate; sigc::signal ARDOUR_UI::Clock; -ARDOUR_UI::ARDOUR_UI (int *argcp, char **argvp[]) +ARDOUR_UI::ARDOUR_UI (int *argcp, char **argvp[], const char* localedir) : Gtkmm2ext::UI (PROGRAM_NAME, argcp, argvp) @@ -148,7 +154,7 @@ ARDOUR_UI::ARDOUR_UI (int *argcp, char **argvp[]) , rec_controllable (new TransportControllable ("transport rec-enable", *this, TransportControllable::RecordEnable)) , auto_return_button (ArdourButton::led_default_elements) - , auto_play_button (ArdourButton::led_default_elements) + , follow_edits_button (ArdourButton::led_default_elements) , auto_input_button (ArdourButton::led_default_elements) , auditioning_alert_button (_("audition")) @@ -161,7 +167,7 @@ ARDOUR_UI::ARDOUR_UI (int *argcp, char **argvp[]) , _feedback_exists (false) { - Gtkmm2ext::init(); + Gtkmm2ext::init(localedir); about = 0; splash = 0; @@ -201,9 +207,6 @@ ARDOUR_UI::ARDOUR_UI (int *argcp, char **argvp[]) original_big_clock_height = -1; original_big_clock_font_size = 0; - roll_button.set_elements (ArdourButton::Element (ArdourButton::Body|ArdourButton::Text)); - play_selection_button.set_elements (ArdourButton::Element (ArdourButton::Body|ArdourButton::Text)); - roll_button.set_controllable (roll_controllable); stop_button.set_controllable (stop_controllable); goto_start_button.set_controllable (goto_start_controllable); @@ -263,16 +266,13 @@ ARDOUR_UI::ARDOUR_UI (int *argcp, char **argvp[]) /* lets get this party started */ try { - if (ARDOUR::init (ARDOUR_COMMAND_LINE::use_vst, ARDOUR_COMMAND_LINE::try_hw_optimization)) { + if (ARDOUR::init (ARDOUR_COMMAND_LINE::use_vst, ARDOUR_COMMAND_LINE::try_hw_optimization, localedir)) { throw failed_constructor (); } setup_gtk_ardour_enums (); setup_profile (); - GainMeter::setup_slider_pix (); - RouteTimeAxisView::setup_slider_pix (); - ProcessorEntry::setup_slider_pix (); SessionEvent::create_per_thread_pool ("GUI", 512); } catch (failed_constructor& err) { @@ -326,36 +326,6 @@ ARDOUR_UI::ARDOUR_UI (int *argcp, char **argvp[]) DPIReset.connect (sigc::mem_fun (*this, &ARDOUR_UI::resize_text_widgets)); } -/** @return true if a session was chosen and `apply' clicked, otherwise false if `cancel' was clicked */ -bool -ARDOUR_UI::run_startup (bool should_be_new, std::string load_template) -{ - delete _startup; - _startup = new ArdourStartup (); - - XMLNode* audio_setup = Config->extra_xml ("AudioSetup"); - - if (audio_setup && _startup->engine_control()) { - _startup->engine_control()->set_state (*audio_setup); - } - - _startup->set_new_only (should_be_new); - if (!load_template.empty()) { - _startup->set_load_template (load_template); - } - _startup->present (); - - main().run(); - - _startup->hide (); - - switch (_startup->response()) { - case RESPONSE_OK: - return true; - default: - return false; - } -} int ARDOUR_UI::create_engine () @@ -429,7 +399,7 @@ ARDOUR_UI::post_engine () vector::iterator n; vector::iterator k; for (n = names.begin(), k = keys.begin(); n != names.end(); ++n, ++k) { - cerr << "Action: " << (*n) << " bound to " << (*k) << endl; + cout << "Action: " << (*n) << " bound to " << (*k) << endl; } exit (0); @@ -457,12 +427,13 @@ ARDOUR_UI::post_engine () #ifndef GTKOSX /* OS X provides a nearly-always visible wallclock, so don't be stupid */ update_wall_clock (); - Glib::signal_timeout().connect (sigc::mem_fun(*this, &ARDOUR_UI::update_wall_clock), 60000); + Glib::signal_timeout().connect_seconds (sigc::mem_fun(*this, &ARDOUR_UI::update_wall_clock), 1); #endif update_disk_space (); update_cpu_load (); update_sample_rate (engine->frame_rate()); + update_timecode_format (); Config->ParameterChanged.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::parameter_changed, this, _1), gui_context()); boost::function pc (boost::bind (&ARDOUR_UI::parameter_changed, this, _1)); @@ -690,8 +661,14 @@ ARDOUR_UI::check_memory_locking () struct rlimit limits; int64_t ram; long pages, page_size; - - if ((page_size = sysconf (_SC_PAGESIZE)) < 0 ||(pages = sysconf (_SC_PHYS_PAGES)) < 0) { +#ifdef __FreeBSD__ + size_t pages_len=sizeof(pages); + if ((page_size = getpagesize()) < 0 || + sysctlbyname("hw.availpages", &pages, &pages_len, NULL, 0)) +#else + if ((page_size = sysconf (_SC_PAGESIZE)) < 0 ||(pages = sysconf (_SC_PHYS_PAGES)) < 0) +#endif + { ram = 0; } else { ram = (int64_t) pages * (int64_t) page_size; @@ -711,15 +688,23 @@ ARDOUR_UI::check_memory_locking () "This might cause %1 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"), - PROGRAM_NAME).c_str()); + "and it is normally controlled by %2"), + PROGRAM_NAME).c_str(), +#ifdef __FreeBSD__ + X_("/etc/login.conf") +#else + X_(" /etc/security/limits.conf") +#endif + ); + + msg.set_default_response (RESPONSE_OK); VBox* vbox = msg.get_vbox(); HBox hbox; CheckButton cb (_("Do not show this window again")); cb.signal_toggled().connect (sigc::mem_fun (*this, &ARDOUR_UI::no_memory_warning)); - + hbox.pack_start (cb, true, false); vbox->pack_start (hbox); cb.show(); @@ -795,7 +780,7 @@ If you still wish to quit, please use the\n\n\ */ save_ardour_state (); - loading_message (_("Please wait while Ardour cleans up...")); + loading_message (string_compose (_("Please wait while %1 cleans up..."), PROGRAM_NAME)); if (_session) { // _session->set_deletion_in_progress (); @@ -886,6 +871,7 @@ ARDOUR_UI::every_second () update_cpu_load (); update_buffer_load (); update_disk_space (); + update_timecode_format (); return TRUE; } @@ -1095,18 +1081,47 @@ ARDOUR_UI::update_disk_space() disk_space_label.set_markup (buf); } +void +ARDOUR_UI::update_timecode_format () +{ + char buf[64]; + + if (_session) { + bool matching; + TimecodeSlave* tcslave; + SyncSource sync_src = Config->get_sync_source(); + + if ((sync_src == LTC || sync_src == MTC) && (tcslave = dynamic_cast(_session->slave())) != 0) { + matching = (tcslave->apparent_timecode_format() == _session->config.get_timecode_format()); + } else { + matching = true; + } + + snprintf (buf, sizeof (buf), S_("Timecode|TC: %s"), + matching ? X_("green") : X_("red"), + Timecode::timecode_format_name (_session->config.get_timecode_format()).c_str()); + } else { + snprintf (buf, sizeof (buf), "TC: n/a"); + } + + timecode_format_label.set_markup (buf); +} + gint ARDOUR_UI::update_wall_clock () { time_t now; struct tm *tm_now; - char buf[16]; + static int last_min = -1; time (&now); tm_now = localtime (&now); - - sprintf (buf, "%02d:%02d", tm_now->tm_hour, tm_now->tm_min); - wall_clock_label.set_text (buf); + if (last_min != tm_now->tm_min) { + char buf[16]; + sprintf (buf, "%02d:%02d", tm_now->tm_hour, tm_now->tm_min); + wall_clock_label.set_text (buf); + last_min = tm_now->tm_min; + } return TRUE; } @@ -1173,6 +1188,7 @@ ARDOUR_UI::redisplay_recent_sessions () 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) { @@ -1186,11 +1202,12 @@ ARDOUR_UI::redisplay_recent_sessions () child_row[recent_session_columns.visible_name] = *i2; child_row[recent_session_columns.fullpath] = fullpath; + child_row[recent_session_columns.tip] = Glib::Markup::escape_text (fullpath); } } } - recent_session_display.set_tooltip_column(1); // recent_session_columns.fullpath + recent_session_display.set_tooltip_column(1); // recent_session_columns.tip recent_session_display.set_model (recent_session_model); } @@ -1378,11 +1395,7 @@ ARDOUR_UI::session_add_mixed_track (const ChanCount& input, const ChanCount& out tracks = _session->new_midi_track (input, output, instrument, ARDOUR::Normal, route_group, how_many, name_template); if (tracks.size() != how_many) { - if (how_many == 1) { - error << _("could not create a new mixed track") << endmsg; - } else { - error << string_compose (_("could not create %1 new mixed tracks"), how_many) << endmsg; - } + error << string_compose(P_("could not create %1 new mixed track", "could not create %1 new mixed tracks", how_many), how_many) << endmsg; } } @@ -1432,12 +1445,8 @@ ARDOUR_UI::session_add_audio_route ( tracks = _session->new_audio_track (input_channels, output_channels, mode, route_group, how_many, name_template); if (tracks.size() != how_many) { - if (how_many == 1) { - error << _("could not create a new audio track") << endmsg; - } else { - error << string_compose (_("could only create %1 of %2 new audio %3"), - tracks.size(), how_many, (track ? _("tracks") : _("busses"))) << endmsg; - } + error << string_compose (P_("could not create %1 new audio track", "could not create %1 new audio tracks", how_many), how_many) + << endmsg; } } else { @@ -1445,11 +1454,8 @@ ARDOUR_UI::session_add_audio_route ( routes = _session->new_audio_route (input_channels, output_channels, route_group, how_many, name_template); if (routes.size() != how_many) { - if (how_many == 1) { - error << _("could not create a new audio bus") << endmsg; - } else { - error << string_compose (_("could not create %1 new audio busses"), how_many) << endmsg; - } + error << string_compose (P_("could not create %1 new audio bus", "could not create %1 new audio busses", how_many), how_many) + << endmsg; } } } @@ -1601,7 +1607,7 @@ ARDOUR_UI::transport_roll () #if 0 if (_session->config.get_external_sync()) { - switch (_session->config.get_sync_source()) { + switch (Config->get_sync_source()) { case JACK: break; default: @@ -1625,15 +1631,18 @@ ARDOUR_UI::transport_roll () _session->request_play_range (0, true); } - if (Config->get_always_play_range()) { - _session->request_play_range (&editor->get_selection().time, true); - } - if (!rolling) { _session->request_transport_speed (1.0f); } } +bool +ARDOUR_UI::get_smart_mode() const +{ + return ( editor->get_smart_mode() ); +} + + void ARDOUR_UI::toggle_roll (bool with_abort, bool roll_out_of_bounded_mode) { @@ -1648,7 +1657,7 @@ ARDOUR_UI::toggle_roll (bool with_abort, bool roll_out_of_bounded_mode) } if (_session->config.get_external_sync()) { - switch (_session->config.get_sync_source()) { + switch (Config->get_sync_source()) { case JACK: break; default: @@ -1684,7 +1693,7 @@ 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_always_play_range() ) { _session->request_play_range (&editor->get_selection().time, true); } @@ -1730,6 +1739,15 @@ ARDOUR_UI::transport_play_selection () editor->play_selection (); } +void +ARDOUR_UI::transport_play_preroll () +{ + if (!_session) { + return; + } + editor->play_with_preroll (); +} + void ARDOUR_UI::transport_rewind (int option) { @@ -1954,10 +1972,11 @@ JACK, reconnect and save the session."), PROGRAM_NAME); MessageDialog msg (*editor, msgstr); pop_back_splash (msg); + msg.set_keep_above (true); msg.run (); - + if (free_reason) { - free ((char*) reason); + free (const_cast (reason)); } } @@ -2408,6 +2427,19 @@ ARDOUR_UI::get_session_parameters (bool quit_on_cancel, bool should_be_new, stri int ret = -1; bool likely_new = false; + /* deal with any existing DIRTY session now, rather than later. don't + * treat a non-dirty session this way, so that it stays visible + * as we bring up the new session dialog. + */ + + if (_session && _session->dirty()) { + if (unload_session (false)) { + /* unload cancelled by user */ + return 0; + } + ARDOUR_COMMAND_LINE::session_name = ""; + } + if (!load_template.empty()) { should_be_new = true; template_name = load_template; @@ -2415,7 +2447,7 @@ ARDOUR_UI::get_session_parameters (bool quit_on_cancel, bool should_be_new, stri while (ret != 0) { - if (!should_be_new && !ARDOUR_COMMAND_LINE::session_name.empty()) { + if (!ARDOUR_COMMAND_LINE::session_name.empty()) { /* if they named a specific statefile, use it, otherwise they are just giving a session folder, and we want to use it as is @@ -2432,71 +2464,82 @@ ARDOUR_UI::get_session_parameters (bool quit_on_cancel, bool should_be_new, stri session_path = ARDOUR_COMMAND_LINE::session_name; session_name = Glib::path_get_basename (ARDOUR_COMMAND_LINE::session_name); } - } else { + session_path = ""; + session_name = ""; + } - bool const apply = run_startup (should_be_new, load_template); - - if (!apply) { - if (quit_on_cancel) { - exit (1); - } else { - return ret; - } - } - - /* if we run the startup dialog again, offer more than just "new session" */ - - should_be_new = false; - - session_name = _startup->session_name (likely_new); - - string::size_type suffix = session_name.find (statefile_suffix); - - if (suffix != string::npos) { - session_name = session_name.substr (0, suffix); + delete _startup; + _startup = new ArdourStartup (should_be_new, session_name, session_path, load_template); + + if (!_startup->ready_without_display()) { + _startup->present (); + main().run(); + _startup->hide (); + } + + switch (_startup->response()) { + case RESPONSE_OK: + break; + default: + if (quit_on_cancel) { + exit (1); + } else { + return ret; } + } - /* this shouldn't happen, but we catch it just in case it does */ + /* if we run the startup dialog again, offer more than just "new session" */ + + should_be_new = false; + + session_name = _startup->session_name (likely_new); + + string::size_type suffix = session_name.find (statefile_suffix); + + if (suffix != string::npos) { + session_name = session_name.substr (0, suffix); + } + + /* this shouldn't happen, but we catch it just in case it does */ + + if (session_name.empty()) { + continue; + } + + if (_startup->use_session_template()) { + template_name = _startup->session_template_name(); + _session_is_new = true; + } + + if (session_name[0] == G_DIR_SEPARATOR || + (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)) { + + /* absolute path or cwd-relative path specified for session name: infer session folder + from what was given. + */ + + session_path = Glib::path_get_dirname (session_name); + session_name = Glib::path_get_basename (session_name); + + } else { - if (session_name.empty()) { + session_path = _startup->session_folder(); + + char illegal = Session::session_name_is_legal (session_name); + + if (illegal) { + MessageDialog msg (*_startup, + string_compose (_("To ensure compatibility with various systems\n" + "session names may not contain a '%1' character"), + illegal)); + msg.run (); + ARDOUR_COMMAND_LINE::session_name = ""; // cancel that continue; } - - if (_startup->use_session_template()) { - template_name = _startup->session_template_name(); - _session_is_new = true; - } - - if (session_name[0] == G_DIR_SEPARATOR || - (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)) { - - /* absolute path or cwd-relative path specified for session name: infer session folder - from what was given. - */ - - session_path = Glib::path_get_dirname (session_name); - session_name = Glib::path_get_basename (session_name); - - } else { - - session_path = _startup->session_folder(); - - char illegal = Session::session_name_is_legal (session_name); - - if (illegal) { - MessageDialog msg (*_startup, - string_compose (_("To ensure compatibility with various systems\n" - "session names may not contain a '%1' character"), - illegal)); - msg.run (); - ARDOUR_COMMAND_LINE::session_name = ""; // cancel that - continue; - } - } } - + if (create_engine ()) { break; } @@ -2856,8 +2899,7 @@ ARDOUR_UI::hide_splash () } void -ARDOUR_UI::display_cleanup_results (ARDOUR::CleanupReport& rep, const gchar* list_title, - const string& plural_msg, const string& singular_msg) +ARDOUR_UI::display_cleanup_results (ARDOUR::CleanupReport& rep, const gchar* list_title, const bool msg_delete) { size_t removed; @@ -2929,20 +2971,36 @@ require some unused files to continue to exist.")); bprefix = X_(""); space_adjusted = rep.space; } else if (rep.space < 1000000) { - bprefix = X_("kilo"); + bprefix = _("kilo"); space_adjusted = truncf((float)rep.space / 1000.0); } else if (rep.space < 1000000 * 1000) { - bprefix = X_("mega"); + bprefix = _("mega"); space_adjusted = truncf((float)rep.space / (1000.0 * 1000.0)); } else { - bprefix = X_("giga"); + bprefix = _("giga"); space_adjusted = truncf((float)rep.space / (1000.0 * 1000 * 1000.0)); } - if (removed > 1) { - txt.set_text (string_compose (plural_msg, removed, dead_directory, space_adjusted, bprefix, PROGRAM_NAME)); + if (msg_delete) { + txt.set_markup (string_compose (P_("\ +The following file was deleted from %2,\n\ +releasing %3 %4bytes of disk space", "\ +The following %1 files were deleted from %2,\n\ +releasing %3 %4bytes of disk space", removed), + removed, Glib::Markup::escape_text (dead_directory), space_adjusted, bprefix, PROGRAM_NAME)); } else { - txt.set_text (string_compose (singular_msg, removed, dead_directory, space_adjusted, bprefix, PROGRAM_NAME)); + txt.set_markup (string_compose (P_("\ +The following file was not in use and \n\ +has been moved to: %2\n\n\ +After a restart of %5\n\n\ +Session -> Clean-up -> Flush Wastebasket\n\n\ +will release an additional %3 %4bytes of disk space.\n", "\ +The following %1 files were not in use and \n\ +have been moved to: %2\n\n\ +After a restart of %5\n\n\ +Session -> Clean-up -> Flush Wastebasket\n\n\ +will release an additional %3 %4bytes of disk space.\n", removed), + removed, Glib::Markup::escape_text (dead_directory), space_adjusted, bprefix, PROGRAM_NAME)); } dhbox.pack_start (*dimage, true, false, 5); @@ -3036,26 +3094,7 @@ Clean-up will move all unused files to a \"dead\" location.")); editor->finish_cleanup (); checker.hide(); - display_cleanup_results (rep, - _("Cleaned Files"), - _("\ -The following %1 files were not in use and \n\ -have been moved to:\n\n\ -%2\n\n\ -After a restart of %5,\n\n\ -Session -> Clean-up -> Flush Wastebasket\n\n\ -will release an additional\n\ -%3 %4bytes of disk space.\n"), - _("\ -The following file was not in use and \n\ -has been moved to:\n \ -%2\n\n\ -After a restart of %5,\n\n\ -Session -> Clean-up -> Flush Wastebasket\n\n\ -will release an additional\n\ -%3 %4bytes of disk space.\n" - )); - + display_cleanup_results (rep, _("Cleaned Files"), false); } void @@ -3072,14 +3111,7 @@ ARDOUR_UI::flush_trash () return; } - display_cleanup_results (rep, - _("deleted file"), - _("The following %1 files were deleted from\n\ -%2,\n\ -releasing %3 %4bytes of disk space"), - _("The following file was deleted from\n\ -%2,\n\ -releasing %3 %4bytes of disk space")); + display_cleanup_results (rep, _("deleted file"), true); } void @@ -3120,6 +3152,12 @@ ARDOUR_UI::add_route (Gtk::Window* float_window) return; } + PBD::ScopedConnection idle_connection; + + if (count > 8) { + ARDOUR::GUIIdle.connect (idle_connection, MISSING_INVALIDATOR, boost::bind (&Gtkmm2ext::UI::flush_pending, this), gui_context()); + } + string template_path = add_route_dialog->track_template(); if (!template_path.empty()) { @@ -3132,7 +3170,6 @@ ARDOUR_UI::add_route (Gtk::Window* float_window) string name_template = add_route_dialog->name_template (); PluginInfoPtr instrument = add_route_dialog->requested_instrument (); RouteGroup* route_group = add_route_dialog->route_group (); - AutoConnectOption oac = Config->get_output_auto_connect(); if (oac & AutoConnectMaster) { @@ -3158,6 +3195,8 @@ 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 */ } XMLNode* @@ -3316,8 +3355,8 @@ ARDOUR_UI::pending_state_dialog () Image* image = new Image (Stock::DIALOG_QUESTION, ICON_SIZE_DIALOG); ArdourDialog dialog (_("Crash Recovery"), true); Label message (string_compose (_("\ -This session appears to have been in\n\ -middle of recording when ardour or\n\ +This session appears to have been in the\n\ +middle of recording when %1 or\n\ the computer was shutdown.\n\ \n\ %1 can recover any captured audio for\n\ @@ -3347,7 +3386,7 @@ int ARDOUR_UI::sr_mismatch_dialog (framecnt_t desired, framecnt_t actual) { HBox* hbox = new HBox(); - Image* image = new Image (Stock::DIALOG_QUESTION, ICON_SIZE_DIALOG); + Image* image = new Image (Stock::DIALOG_WARNING, ICON_SIZE_DIALOG); ArdourDialog dialog (_("Sample Rate Mismatch"), true); Label message (string_compose (_("\ This session was created with a sample rate of %1 Hz, but\n\ @@ -3521,16 +3560,16 @@ ARDOUR_UI::TransportControllable::set_value (double val) action = X_("Stop"); break; case GotoStart: - action = X_("Goto Start"); + action = X_("GotoStart"); break; case GotoEnd: - action = X_("Goto End"); + action = X_("GotoEnd"); break; case AutoLoop: action = X_("Loop"); break; case PlaySelection: - action = X_("Play Selection"); + action = X_("PlaySelection"); break; case RecordEnable: action = X_("Record");