X-Git-Url: https://main.carlh.net/gitweb/?a=blobdiff_plain;f=gtk2_ardour%2Fardour_ui.cc;h=5bef863c955e964a736535c3bc62529626c88207;hb=c08b336292cd66e066eae23bc6272dce42ae28c2;hp=4fb5375321dedcc23d570f622c70a2efe49db703;hpb=759918dcc8dee5cb1a62fa83d06e46d4b8173155;p=ardour.git diff --git a/gtk2_ardour/ardour_ui.cc b/gtk2_ardour/ardour_ui.cc index 4fb5375321..5bef863c95 100644 --- a/gtk2_ardour/ardour_ui.cc +++ b/gtk2_ardour/ardour_ui.cc @@ -1,5 +1,5 @@ /* - Copyright (C) 1999-2007 Paul Davis + Copyright (C) 1999-2013 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 @@ -21,20 +21,25 @@ #include "gtk2ardour-config.h" #endif -#include - #include #include +#include +#include +#include + +#ifndef WIN32 +#include +#endif + +#include #include #include #include #include -#include -#include - -#include #include +#include +#include #include #include @@ -47,6 +52,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" @@ -65,6 +71,7 @@ #include "ardour/automation_watch.h" #include "ardour/diskstream.h" #include "ardour/filename_extensions.h" +#include "ardour/filesystem_paths.h" #include "ardour/port.h" #include "ardour/process_thread.h" #include "ardour/profile.h" @@ -85,6 +92,7 @@ typedef uint64_t microseconds_t; #include "ambiguous_file_dialog.h" #include "ardour_ui.h" #include "audio_clock.h" +#include "big_clock_window.h" #include "bundle_manager.h" #include "engine_dialog.h" #include "gain_meter.h" @@ -92,17 +100,23 @@ typedef uint64_t microseconds_t; #include "gui_object.h" #include "gui_thread.h" #include "keyboard.h" +#include "keyeditor.h" #include "location_ui.h" #include "main_clock.h" #include "missing_file_dialog.h" #include "missing_plugin_dialog.h" #include "mixer_ui.h" +#include "mouse_cursors.h" #include "opts.h" +#include "pingback.h" #include "processor_box.h" #include "prompter.h" #include "public_editor.h" +#include "rc_option_editor.h" #include "route_time_axis.h" +#include "route_params_ui.h" #include "session_metadata_dialog.h" +#include "session_option_editor.h" #include "shuttle_control.h" #include "speaker_dialog.h" #include "splash.h" @@ -110,7 +124,10 @@ typedef uint64_t microseconds_t; #include "theme_manager.h" #include "time_axis_view_item.h" #include "utils.h" -#include "window_proxy.h" +#include "video_server_dialog.h" +#include "add_video_dialog.h" +#include "transcode_video_dialog.h" +#include "system_exec.h" #include "i18n.h" @@ -127,18 +144,29 @@ sigc::signal ARDOUR_UI::Blink; sigc::signal ARDOUR_UI::RapidScreenUpdate; sigc::signal ARDOUR_UI::SuperRapidScreenUpdate; sigc::signal ARDOUR_UI::Clock; +sigc::signal ARDOUR_UI::CloseAllDialogs; -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) - + , gui_object_state (new GUIObjectState) + , primary_clock (new MainClock (X_("primary"), false, X_("transport"), true, true, true, false, true)) , secondary_clock (new MainClock (X_("secondary"), false, X_("secondary"), true, true, false, false, true)) /* big clock */ , big_clock (new AudioClock (X_("bigclock"), false, "big", true, true, false, false)) + , video_timeline(0) + + /* start of private members */ + + , _startup (0) + , engine (0) + , nsm (0) + , _was_dirty (false) + , _mixer_on_top (false) /* transport */ @@ -151,62 +179,59 @@ 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")) , solo_alert_button (_("solo")) , feedback_alert_button (_("feedback")) + , speaker_config_window (X_("speaker-config"), _("Speaker Configuration")) + , theme_manager (X_("theme-manager"), _("Theme Manager")) + , key_editor (X_("key-editor"), _("Key Bindings")) + , rc_option_editor (X_("rc-options-editor"), _("Preferences")) + , add_route_dialog (X_("add-routes"), _("Add Tracks/Busses")) + , about (X_("about"), _("About")) + , location_ui (X_("locations"), _("Locations")) + , route_params (X_("inspector"), _("Tracks and Busses")) + , session_option_editor (X_("session-options-editor"), _("Properties"), boost::bind (&ARDOUR_UI::create_session_option_editor, this)) + , add_video_dialog (X_("add-video"), _("Add Tracks/Busses"), boost::bind (&ARDOUR_UI::create_add_video_dialog, this)) + , bundle_manager (X_("bundle-manager"), _("Bundle Manager"), boost::bind (&ARDOUR_UI::create_bundle_manager, this)) + , big_clock_window (X_("big-clock"), _("Big Clock"), boost::bind (&ARDOUR_UI::create_big_clock_window, this)) + , audio_port_matrix (X_("audio-connection-manager"), _("Audio Connections"), boost::bind (&ARDOUR_UI::create_global_port_matrix, this, ARDOUR::DataType::AUDIO)) + , midi_port_matrix (X_("midi-connection-manager"), _("MIDI Connections"), boost::bind (&ARDOUR_UI::create_global_port_matrix, this, ARDOUR::DataType::MIDI)) + , error_log_button (_("Errors")) , _status_bar_visibility (X_("status-bar")) , _feedback_exists (false) { - Gtkmm2ext::init(); + Gtkmm2ext::init(localedir); - about = 0; splash = 0; - _startup = 0; if (theArdourUI == 0) { theArdourUI = this; } ui_config = new UIConfiguration(); - theme_manager = new ThemeManager(); - - key_editor = 0; editor = 0; mixer = 0; + meterbridge = 0; editor = 0; engine = 0; _session_is_new = false; - big_clock_window = 0; - big_clock_height = 0; - big_clock_resize_in_progress = false; session_selector_window = 0; last_key_press_time = 0; - add_route_dialog = 0; - route_params = 0; - bundle_manager = 0; - rc_option_editor = 0; - session_option_editor = 0; - location_ui = 0; + video_server_process = 0; open_session_selector = 0; have_configure_timeout = false; have_disk_speed_dialog_displayed = false; session_loaded = false; ignore_dual_punch = false; - original_big_clock_width = -1; - 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); @@ -234,6 +259,8 @@ ARDOUR_UI::ARDOUR_UI (int *argcp, char **argvp[]) ARDOUR::Diskstream::DiskOverrun.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::disk_overrun_handler, this), gui_context()); ARDOUR::Diskstream::DiskUnderrun.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::disk_underrun_handler, this), gui_context()); + ARDOUR::Session::VersionMismatch.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::session_format_mismatch, this, _1, _2), gui_context()); + /* handle dialog requests */ ARDOUR::Session::Dialog.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::session_dialog, this, _1), gui_context()); @@ -266,16 +293,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) { @@ -300,26 +324,53 @@ ARDOUR_UI::ARDOUR_UI (int *argcp, char **argvp[]) TimeAxisViewItem::set_constant_heights (); - /* The following must happen after ARDOUR::init() so that Config is set up */ - - location_ui = new ActionWindowProxy (X_("locations"), Config->extra_xml (X_("UI")), X_("ToggleLocations")); - big_clock_window = new ActionWindowProxy (X_("bigclock"), Config->extra_xml (X_("UI")), X_("ToggleBigClock")); - speaker_config_window = new ActionWindowProxy (X_("speakerconf"), Config->extra_xml (X_("UI")), X_("toggle-speaker-config")); - - for (ARDOUR::DataType::iterator i = ARDOUR::DataType::begin(); i != ARDOUR::DataType::end(); ++i) { - _global_port_matrix[*i] = new ActionWindowProxy ( - string_compose ("GlobalPortMatrix-%1", (*i).to_string()), - Config->extra_xml (X_("UI")), - string_compose ("toggle-%1-connection-manager", (*i).to_string()) - ); - } + /* Set this up so that our window proxies can register actions */ - setup_clock (); + ActionManager::init (); - SpeakerDialog* s = new SpeakerDialog (); - s->signal_unmap().connect (sigc::bind (sigc::ptr_fun (&ActionManager::uncheck_toggleaction), X_("/Common/toggle-speaker-config"))); - speaker_config_window->set (s); + /* The following must happen after ARDOUR::init() so that Config is set up */ + const XMLNode* ui_xml = Config->extra_xml (X_("UI")); + + if (ui_xml) { + theme_manager.set_state (*ui_xml); + key_editor.set_state (*ui_xml); + rc_option_editor.set_state (*ui_xml); + session_option_editor.set_state (*ui_xml); + speaker_config_window.set_state (*ui_xml); + about.set_state (*ui_xml); + add_route_dialog.set_state (*ui_xml); + add_video_dialog.set_state (*ui_xml); + route_params.set_state (*ui_xml); + bundle_manager.set_state (*ui_xml); + location_ui.set_state (*ui_xml); + big_clock_window.set_state (*ui_xml); + audio_port_matrix.set_state (*ui_xml); + midi_port_matrix.set_state (*ui_xml); + } + + WM::Manager::instance().register_window (&theme_manager); + WM::Manager::instance().register_window (&key_editor); + WM::Manager::instance().register_window (&rc_option_editor); + WM::Manager::instance().register_window (&session_option_editor); + WM::Manager::instance().register_window (&speaker_config_window); + WM::Manager::instance().register_window (&about); + WM::Manager::instance().register_window (&add_route_dialog); + WM::Manager::instance().register_window (&add_video_dialog); + WM::Manager::instance().register_window (&route_params); + WM::Manager::instance().register_window (&bundle_manager); + WM::Manager::instance().register_window (&location_ui); + WM::Manager::instance().register_window (&big_clock_window); + WM::Manager::instance().register_window (&audio_port_matrix); + WM::Manager::instance().register_window (&midi_port_matrix); + + /* We need to instantiate the theme manager because it loads our + theme files. This should really change so that its window + and its functionality are separate + */ + + (void) theme_manager.get (true); + starting.connect (sigc::mem_fun(*this, &ARDOUR_UI::startup)); stopping.connect (sigc::mem_fun(*this, &ARDOUR_UI::shutdown)); @@ -329,6 +380,15 @@ ARDOUR_UI::ARDOUR_UI (int *argcp, char **argvp[]) DPIReset.connect (sigc::mem_fun (*this, &ARDOUR_UI::resize_text_widgets)); } +GlobalPortMatrixWindow* +ARDOUR_UI::create_global_port_matrix (ARDOUR::DataType type) +{ + if (!_session) { + return 0; + } + return new GlobalPortMatrixWindow (_session, type); +} + int ARDOUR_UI::create_engine () { @@ -369,12 +429,10 @@ ARDOUR_UI::post_engine () ARDOUR::init_post_engine (); - /* load up the UI manager */ - - ActionManager::init (); - _tooltips.enable(); + ActionManager::load_menus (); + if (setup_windows ()) { throw failed_constructor (); } @@ -401,7 +459,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); @@ -429,7 +487,7 @@ 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 (); @@ -458,7 +516,9 @@ ARDOUR_UI::~ARDOUR_UI () delete keyboard; delete editor; delete mixer; - delete add_route_dialog; + delete meterbridge; + + stop_video_server(); } void @@ -602,21 +662,98 @@ ARDOUR_UI::update_autosave () } } +void +ARDOUR_UI::check_announcements () +{ +#ifdef PHONE_HOME + string _annc_filename; + +#ifdef __APPLE__ + _annc_filename = PROGRAM_NAME "_announcements_osx_"; +#else + _annc_filename = PROGRAM_NAME "_announcements_linux_"; +#endif + _annc_filename.append (VERSIONSTRING); + + std::string path = Glib::build_filename (user_config_directory(), _annc_filename); + std::ifstream announce_file (path.c_str()); + if ( announce_file.fail() ) + _announce_string = ""; + else { + std::stringstream oss; + oss << announce_file.rdbuf(); + _announce_string = oss.str(); + } + + pingback (VERSIONSTRING, path); +#endif +} + void ARDOUR_UI::startup () { Application* app = Application::instance (); - + char *nsm_url; app->ShouldQuit.connect (sigc::mem_fun (*this, &ARDOUR_UI::queue_finish)); app->ShouldLoad.connect (sigc::mem_fun (*this, &ARDOUR_UI::idle_load)); -#ifdef PHONE_HOME - call_the_mothership (VERSIONSTRING); -#endif + if (ARDOUR_COMMAND_LINE::check_announcements) { + check_announcements (); + } app->ready (); - if (get_session_parameters (true, ARDOUR_COMMAND_LINE::new_session, ARDOUR_COMMAND_LINE::load_template)) { + nsm_url = getenv ("NSM_URL"); + + if (nsm_url) { + nsm = new NSM_Client; + if (!nsm->init (nsm_url)) { + nsm->announce (PROGRAM_NAME, ":dirty:", "ardour3"); + + unsigned int i = 0; + // wait for announce reply from nsm server + for ( i = 0; i < 5000; ++i) { + nsm->check (); + usleep (i); + if (nsm->is_active()) + break; + } + // wait for open command from nsm server + for ( i = 0; i < 5000; ++i) { + nsm->check (); + usleep (1000); + if (nsm->client_id ()) + break; + } + + if (_session && nsm) { + _session->set_nsm_state( nsm->is_active() ); + } + + // nsm requires these actions disabled + vector action_names; + action_names.push_back("SaveAs"); + action_names.push_back("Rename"); + action_names.push_back("New"); + action_names.push_back("Open"); + action_names.push_back("Recent"); + action_names.push_back("Close"); + + for (vector::const_iterator n = action_names.begin(); n != action_names.end(); ++n) { + Glib::RefPtr act = ActionManager::get_action (X_("Main"), (*n).c_str()); + if (act) { + act->set_sensitive (false); + } + } + + } + else { + delete nsm; + nsm = 0; + } + } + + else if (get_session_parameters (true, ARDOUR_COMMAND_LINE::new_session, ARDOUR_COMMAND_LINE::load_template)) { exit (1); } @@ -624,14 +761,7 @@ ARDOUR_UI::startup () goto_editor_window (); - /* Add the window proxies here; their addition may cause windows to be opened, and we want them - to be opened on top of the editor window that goto_editor_window() just opened. - */ - add_window_proxy (location_ui); - add_window_proxy (big_clock_window); - for (ARDOUR::DataType::iterator i = ARDOUR::DataType::begin(); i != ARDOUR::DataType::end(); ++i) { - add_window_proxy (_global_port_matrix[*i]); - } + WM::Manager::instance().show_visible (); /* We have to do this here since goto_editor_window() ends up calling show_all() on the * editor window, and we may want stuff to be hidden. @@ -651,7 +781,7 @@ 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__ @@ -663,8 +793,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; @@ -684,15 +820,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, +#ifdef __FreeBSD__ + X_("/etc/login.conf") +#else + X_(" /etc/security/limits.conf") +#endif + ).c_str()); + + 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(); @@ -727,6 +871,7 @@ void ARDOUR_UI::finish() { if (_session) { + ARDOUR_UI::instance()->video_timeline->sync_session_state(); if (_session->dirty()) { vector actions; @@ -762,12 +907,18 @@ If you still wish to quit, please use the\n\n\ point_zero_one_second_connection.disconnect(); } + delete ARDOUR_UI::instance()->video_timeline; + ARDOUR_UI::instance()->video_timeline = NULL; + stop_video_server(); + /* Save state before deleting the session, as that causes some windows to be destroyed before their visible state can be saved. */ save_ardour_state (); + close_all_dialogs (); + loading_message (string_compose (_("Please wait while %1 cleans up..."), PROGRAM_NAME)); if (_session) { @@ -778,7 +929,6 @@ If you still wish to quit, please use the\n\n\ _session = 0; } - ArdourDialog::close_all_dialogs (); engine->stop (true); quit (); } @@ -825,7 +975,6 @@ ARDOUR_UI::ask_about_saving_session (const vector& actions) window.get_vbox()->pack_start (dhbox); window.set_name (_("Prompter")); - window.set_position (Gtk::WIN_POS_MOUSE); window.set_modal (true); window.set_resizable (false); @@ -860,6 +1009,19 @@ ARDOUR_UI::every_second () update_buffer_load (); update_disk_space (); update_timecode_format (); + + if (nsm && nsm->is_active ()) { + nsm->check (); + + if (!_was_dirty && _session->dirty ()) { + nsm->is_dirty (); + _was_dirty = true; + } + else if (_was_dirty && !_session->dirty ()){ + nsm->is_clean (); + _was_dirty = false; + } + } return TRUE; } @@ -1100,13 +1262,16 @@ 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 +1338,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 +1352,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); } @@ -1241,8 +1408,6 @@ ARDOUR_UI::open_recent_session () while (true) { - session_selector_window->set_position (WIN_POS_MOUSE); - ResponseType r = (ResponseType) session_selector_window->run (); switch (r) { @@ -1378,11 +1543,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 +1593,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 +1602,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; } } } @@ -1625,15 +1779,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) { @@ -1684,7 +1841,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 +1887,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,8 +2120,9 @@ 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 (const_cast (reason)); } @@ -1990,7 +2157,11 @@ ARDOUR_UI::update_clocks () void ARDOUR_UI::start_clocking () { - clock_signal_connection = RapidScreenUpdate.connect (sigc::mem_fun(*this, &ARDOUR_UI::update_clocks)); + if (Config->get_super_rapid_clock_update()) { + clock_signal_connection = SuperRapidScreenUpdate.connect (sigc::mem_fun(*this, &ARDOUR_UI::update_clocks)); + } else { + clock_signal_connection = RapidScreenUpdate.connect (sigc::mem_fun(*this, &ARDOUR_UI::update_clocks)); + } } void @@ -2174,11 +2345,7 @@ ARDOUR_UI::save_state (const string & name, bool switch_to_it) { XMLNode* node = new XMLNode (X_("UI")); - for (list::iterator i = _window_proxies.begin(); i != _window_proxies.end(); ++i) { - if (!(*i)->rc_configured()) { - node->add_child_nocopy (*((*i)->get_state ())); - } - } + WM::Manager::instance().add_state (*node); node->add_child_nocopy (gui_object_state->get_state()); @@ -2336,7 +2503,7 @@ ARDOUR_UI::build_session_from_nsd (const std::string& session_path, const std::s { BusProfile bus_profile; - if (Profile->get_sae()) { + if (nsm || Profile->get_sae()) { bus_profile.master_out_channels = 2; bus_profile.input_ac = AutoConnectPhysical; @@ -2413,6 +2580,10 @@ ARDOUR_UI::get_session_parameters (bool quit_on_cancel, bool should_be_new, stri * as we bring up the new session dialog. */ + if (_session && ARDOUR_UI::instance()->video_timeline) { + ARDOUR_UI::instance()->video_timeline->sync_session_state(); + } + if (_session && _session->dirty()) { if (unload_session (false)) { /* unload cancelled by user */ @@ -2445,6 +2616,9 @@ 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 = ""; } delete _startup; @@ -2473,6 +2647,10 @@ ARDOUR_UI::get_session_parameters (bool quit_on_cancel, bool should_be_new, stri session_name = _startup->session_name (likely_new); + if (nsm) { + likely_new = true; + } + string::size_type suffix = session_name.find (statefile_suffix); if (suffix != string::npos) { @@ -2524,7 +2702,7 @@ ARDOUR_UI::get_session_parameters (bool quit_on_cancel, bool should_be_new, stri if (Glib::file_test (session_path, Glib::FileTest (G_FILE_TEST_EXISTS | G_FILE_TEST_IS_DIR))) { - if (likely_new) { + if (likely_new && !nsm) { std::string existing = Glib::build_filename (session_path, session_name); @@ -2802,43 +2980,16 @@ ARDOUR_UI::launch_chat () #endif } -void -ARDOUR_UI::show_about () -{ - if (about == 0) { - about = new About; - about->signal_response().connect (sigc::mem_fun (*this, &ARDOUR_UI::about_signal_response)); - } - - about->set_transient_for(*editor); - about->show_all (); -} - void ARDOUR_UI::launch_manual () { - PBD::open_uri("http://ardour.org/flossmanual"); + PBD::open_uri (Config->get_tutorial_manual_url()); } void ARDOUR_UI::launch_reference () { - PBD::open_uri ("http://ardour.org/refmanual"); -} - -void -ARDOUR_UI::hide_about () -{ - if (about) { - about->get_window()->set_cursor (); - about->hide (); - } -} - -void -ARDOUR_UI::about_signal_response (int /*response*/) -{ - hide_about(); + PBD::open_uri (Config->get_reference_manual_url()); } void @@ -2877,8 +3028,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; @@ -2947,7 +3097,7 @@ require some unused files to continue to exist.")); double space_adjusted = 0; if (rep.space < 1000) { - bprefix = _(""); + bprefix = X_(""); space_adjusted = rep.space; } else if (rep.space < 1000000) { bprefix = _("kilo"); @@ -2960,10 +3110,26 @@ require some unused files to continue to exist.")); space_adjusted = truncf((float)rep.space / (1000.0 * 1000 * 1000.0)); } - if (removed > 1) { - txt.set_markup (string_compose (plural_msg, removed, Glib::Markup::escape_text (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_markup (string_compose (singular_msg, removed, Glib::Markup::escape_text (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); @@ -3057,22 +3223,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: %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 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" - )); - + display_cleanup_results (rep, _("Cleaned Files"), false); } void @@ -3089,12 +3240,7 @@ ARDOUR_UI::flush_trash () return; } - display_cleanup_results (rep, - _("deleted file"), - _("The following %1 files were deleted from %2,\n\ -releasing %3 %4bytes of disk space"), - _("The following file was deleted from %2,\n\ -releasing %3 %4bytes of disk space")); + display_cleanup_results (rep, _("deleted file"), true); } void @@ -3106,19 +3252,15 @@ ARDOUR_UI::add_route (Gtk::Window* float_window) return; } - if (add_route_dialog == 0) { - add_route_dialog = new AddRouteDialog (_session); - add_route_dialog->set_position (WIN_POS_MOUSE); - if (float_window) { - add_route_dialog->set_transient_for (*float_window); - } - } - if (add_route_dialog->is_visible()) { /* we're already doing this */ return; } + if (float_window) { + add_route_dialog->set_transient_for (*float_window); + } + ResponseType r = (ResponseType) add_route_dialog->run (); add_route_dialog->hide(); @@ -3135,10 +3277,20 @@ 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()) { - _session->new_route_from_template (count, template_path); + if (add_route_dialog->name_template_is_default()) { + _session->new_route_from_template (count, template_path, string()); + } else { + _session->new_route_from_template (count, template_path, add_route_dialog->name_template()); + } return; } @@ -3147,7 +3299,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) { @@ -3173,6 +3324,275 @@ 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 */ +} + +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; + } + if (video_server_process) { + if(ask_confirm) { + ArdourDialog confirm (_("Stop Video-Server"), true); + Label m (_("Do you really want to stop the Video Server?")); + confirm.get_vbox()->pack_start (m, true, true); + confirm.add_button (Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL); + confirm.add_button (_("Yes, Stop It"), Gtk::RESPONSE_ACCEPT); + confirm.show_all (); + if (confirm.run() == RESPONSE_CANCEL) { + return; + } + } + delete video_server_process; + video_server_process =0; + } +} + +void +ARDOUR_UI::start_video_server_menu (Gtk::Window* float_window) +{ + ARDOUR_UI::start_video_server( float_window, true); +} + +bool +ARDOUR_UI::start_video_server (Gtk::Window* float_window, bool popup_msg) +{ + if (!_session) { + return false; + } + if (popup_msg) { + if (ARDOUR_UI::instance()->video_timeline->check_server()) { + if (video_server_process) { + popup_error(_("The Video Server is already started.")); + } else { + popup_error(_("An external Video Server is configured and can be reached. Not starting a new instance.")); + } + } + } + + int firsttime = 0; + while (!ARDOUR_UI::instance()->video_timeline->check_server()) { + if (firsttime++) { + warning << _("Could not connect to the Video Server. Start it or configure its access URL in Edit -> Preferences.") << endmsg; + } + VideoServerDialog *video_server_dialog = new VideoServerDialog (_session); + if (float_window) { + video_server_dialog->set_transient_for (*float_window); + } + + if (!Config->get_show_video_server_dialog() && firsttime < 2) { + video_server_dialog->hide(); + } else { + ResponseType r = (ResponseType) video_server_dialog->run (); + video_server_dialog->hide(); + if (r != RESPONSE_ACCEPT) { return false; } + if (video_server_dialog->show_again()) { + Config->set_show_video_server_dialog(false); + } + } + + std::string icsd_exec = video_server_dialog->get_exec_path(); + 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)) { + warning << _("Specified docroot is not an existing directory.") << endmsg; + continue; + } + if ( (!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; + } + + char **argp; + argp=(char**) calloc(9,sizeof(char*)); + argp[0] = strdup(icsd_exec.c_str()); + argp[1] = strdup("-P"); + argp[2] = (char*) calloc(16,sizeof(char)); snprintf(argp[2], 16, "%s", video_server_dialog->get_listenaddr().c_str()); + argp[3] = strdup("-p"); + argp[4] = (char*) calloc(6,sizeof(char)); snprintf(argp[4], 6, "%i", video_server_dialog->get_listenport()); + argp[5] = strdup("-C"); + argp[6] = (char*) calloc(6,sizeof(char)); snprintf(argp[6], 6, "%i", video_server_dialog->get_cachesize()); + argp[7] = strdup(icsd_docroot.c_str()); + argp[8] = 0; + stop_video_server(); + + if (icsd_docroot == X_("/")) { + Config->set_video_advanced_setup(false); + } else { + std::ostringstream osstream; + osstream << "http://localhost:" << video_server_dialog->get_listenport() << "/"; + Config->set_video_server_url(osstream.str()); + Config->set_video_server_docroot(icsd_docroot); + Config->set_video_advanced_setup(true); + } + + if (video_server_process) { + delete video_server_process; + } + + video_server_process = new SystemExec(icsd_exec, argp); + if (video_server_process->start()) { + warning << _("Cannot launch the video-server") << endmsg; + continue; + } + int timeout = 120; // 6 sec + while (!ARDOUR_UI::instance()->video_timeline->check_server()) { + usleep (50000); + if (--timeout <= 0 || !video_server_process->is_running()) break; + } + if (timeout <= 0) { + warning << _("Video-server was started but does not respond to requests...") << endmsg; + } else { + if (!ARDOUR_UI::instance()->video_timeline->check_server_docroot()) { + delete video_server_process; + video_server_process = 0; + } + } + } + return true; +} + +void +ARDOUR_UI::add_video (Gtk::Window* float_window) +{ + if (!_session) { + return; + } + + if (!start_video_server(float_window, false)) { + warning << _("Could not connect to the Video Server. Start it or configure its access URL in Edit -> Preferences.") << endmsg; + return; + } + + if (float_window) { + add_video_dialog->set_transient_for (*float_window); + } + + if (add_video_dialog->is_visible()) { + /* we're already doing this */ + return; + } + + ResponseType r = (ResponseType) add_video_dialog->run (); + add_video_dialog->hide(); + if (r != RESPONSE_ACCEPT) { return; } + + bool local_file, orig_local_file; + std::string path = add_video_dialog->file_name(local_file); + + std::string orig_path = path; + orig_local_file = local_file; + + bool auto_set_session_fps = add_video_dialog->auto_set_session_fps(); + + if (local_file && !Glib::file_test(path, Glib::FILE_TEST_EXISTS)) { + warning << string_compose(_("could not open %1"), path) << endmsg; + return; + } + if (!local_file && path.length() == 0) { + warning << _("no video-file selected") << endmsg; + return; + } + + switch (add_video_dialog->import_option()) { + case VTL_IMPORT_TRANSCODE: + { + TranscodeVideoDialog *transcode_video_dialog; + transcode_video_dialog = new TranscodeVideoDialog (_session, path); + ResponseType r = (ResponseType) transcode_video_dialog->run (); + transcode_video_dialog->hide(); + if (r != RESPONSE_ACCEPT) { + delete transcode_video_dialog; + return; + } + if (!transcode_video_dialog->get_audiofile().empty()) { + editor->embed_audio_from_video(transcode_video_dialog->get_audiofile()); + } + switch (transcode_video_dialog->import_option()) { + case VTL_IMPORT_TRANSCODED: + path = transcode_video_dialog->get_filename(); + local_file = true; + break; + case VTL_IMPORT_REFERENCE: + break; + default: + delete transcode_video_dialog; + return; + } + delete transcode_video_dialog; + } + break; + default: + case VTL_IMPORT_NONE: + break; + } + + /* strip _session->session_directory().video_path() from video file if possible */ + if (local_file && !path.compare(0, _session->session_directory().video_path().size(), _session->session_directory().video_path())) { + path=path.substr(_session->session_directory().video_path().size()); + if (path.at(0) == G_DIR_SEPARATOR) { + path=path.substr(1); + } + } + + video_timeline->set_update_session_fps(auto_set_session_fps); + 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")); + if (orig_local_file) { + node->add_property (X_("OriginalVideoFile"), orig_path); + } else { + node->remove_property (X_("OriginalVideoFile")); + } + _session->add_extra_xml (*node); + _session->set_dirty (); + + _session->maybe_update_session_range( + std::max(video_timeline->get_offset(), (ARDOUR::frameoffset_t) 0), + std::max(video_timeline->get_offset() + video_timeline->get_duration(), (ARDOUR::frameoffset_t) 0)); + + + if (add_video_dialog->launch_xjadeo() && local_file) { + editor->set_xjadeo_sensitive(true); + editor->toggle_xjadeo_proc(1); + } else { + editor->toggle_xjadeo_proc(0); + } + editor->toggle_ruler_video(true); + } +} + +void +ARDOUR_UI::remove_video () +{ + video_timeline->close_session(); + editor->toggle_ruler_video(false); + + /* delete session state */ + XMLNode* node = new XMLNode(X_("Videotimeline")); + _session->add_extra_xml(*node); + node = new XMLNode(X_("Videomonitor")); + _session->add_extra_xml(*node); + stop_video_server(); +} + +void +ARDOUR_UI::flush_videotimeline_cache (bool localcacheonly) +{ + if (localcacheonly) { + video_timeline->vmon_update(); + } else { + video_timeline->flush_cache(); + } + editor->queue_visual_videotimeline_update(); } XMLNode* @@ -3331,8 +3751,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\ @@ -3362,7 +3782,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\ @@ -3381,12 +3801,14 @@ audio may be played at the wrong sample rate.\n"), desired, PROGRAM_NAME, actual image->show(); hbox->show(); - switch (dialog.run ()) { + switch (dialog.run()) { case RESPONSE_ACCEPT: return 0; default: - return 1; + break; } + + return 1; } @@ -3440,12 +3862,12 @@ ARDOUR_UI::update_transport_clocks (framepos_t pos) secondary_clock->set (pos); } - if (big_clock_window->get()) { + if (big_clock_window) { big_clock->set (pos); } + ARDOUR_UI::instance()->video_timeline->manual_seek_video_monitor(pos); } - void ARDOUR_UI::step_edit_status_change (bool yn) { @@ -3466,7 +3888,7 @@ ARDOUR_UI::record_state_changed () { ENSURE_GUI_THREAD (*this, &ARDOUR_UI::record_state_changed); - if (!_session || !big_clock_window->get()) { + if (!_session || !big_clock_window) { /* why bother - the clock isn't visible */ return; } @@ -3605,63 +4027,6 @@ ARDOUR_UI::setup_profile () } } -void -ARDOUR_UI::toggle_translations () -{ - using namespace Glib; - - RefPtr act = ActionManager::get_action (X_("Main"), X_("EnableTranslation")); - if (act) { - RefPtr ract = RefPtr::cast_dynamic (act); - if (ract) { - - string i18n_killer = ARDOUR::translation_kill_path(); - - bool already_enabled = !ARDOUR::translations_are_disabled (); - - if (ract->get_active ()) { - /* we don't care about errors */ - int fd = ::open (i18n_killer.c_str(), O_RDONLY|O_CREAT, 0644); - close (fd); - } else { - /* we don't care about errors */ - unlink (i18n_killer.c_str()); - } - - if (already_enabled != ract->get_active()) { - MessageDialog win (already_enabled ? _("Translations disabled") : _("Translations enabled"), - false, - Gtk::MESSAGE_WARNING, - Gtk::BUTTONS_OK); - win.set_secondary_text (string_compose (_("You must restart %1 for this to take effect."), PROGRAM_NAME)); - win.set_position (Gtk::WIN_POS_CENTER); - win.present (); - win.run (); - } - } - } -} - -/** Add a window proxy to our list, so that its state will be saved. - * This call also causes the window to be created and opened if its - * state was saved as `visible'. - */ -void -ARDOUR_UI::add_window_proxy (WindowProxyBase* p) -{ - _window_proxies.push_back (p); - p->maybe_show (); -} - -/** Remove a window proxy from our list. Must be called if a WindowProxy - * is deleted, to prevent hanging pointers. - */ -void -ARDOUR_UI::remove_window_proxy (WindowProxyBase* p) -{ - _window_proxies.remove (p); -} - int ARDOUR_UI::missing_file (Session*s, std::string str, DataType type) { @@ -3730,3 +4095,21 @@ ARDOUR_UI::midi_panic () _session->midi_panic(); } } + +void +ARDOUR_UI::session_format_mismatch (std::string xml_path, std::string backup_path) +{ + const char* start_big = ""; + const char* end_big = ""; + const char* start_mono = ""; + const char* end_mono = ""; + + MessageDialog msg (string_compose (_("%4This is a session from an older version of %3%5\n\n" + "%3 has copied the old session file\n\n%6%1%7\n\nto\n\n%6%2%7\n\n" + "From now on, use the -2000 version with older versions of %3"), + xml_path, backup_path, PROGRAM_NAME, + start_big, end_big, + start_mono, end_mono), true); + + msg.run (); +}