X-Git-Url: https://main.carlh.net/gitweb/?a=blobdiff_plain;f=gtk2_ardour%2Fardour_ui.cc;h=0d646c8add46e24811c95fec8035b2d42e948632;hb=c912bd61ae49cc79158f3322439c29b27ef51de8;hp=3948b5cc8c3da3d385f43e67c4d2605db31a1aa2;hpb=b64634e32e9962bd0e0d2f8a93bbae3e51b710ed;p=ardour.git diff --git a/gtk2_ardour/ardour_ui.cc b/gtk2_ardour/ardour_ui.cc index 3948b5cc8c..0d646c8add 100644 --- a/gtk2_ardour/ardour_ui.cc +++ b/gtk2_ardour/ardour_ui.cc @@ -19,6 +19,7 @@ #ifdef WAF_BUILD #include "gtk2ardour-config.h" +#include "gtk2ardour-version.h" #endif #include @@ -53,6 +54,7 @@ #include "pbd/stl_delete.h" #include "pbd/file_utils.h" #include "pbd/localtime_r.h" +#include "pbd/pthread_utils.h" #include "gtkmm2ext/application.h" #include "gtkmm2ext/bindings.h" @@ -86,12 +88,16 @@ #ifdef WINDOWS_VST_SUPPORT #include #endif +#ifdef AUDIOUNIT_SUPPORT +#include "ardour/audio_unit.h" +#endif #include "timecode/time.h" typedef uint64_t microseconds_t; #include "about.h" +#include "editing.h" #include "actions.h" #include "add_route_dialog.h" #include "ambiguous_file_dialog.h" @@ -100,6 +106,8 @@ typedef uint64_t microseconds_t; #include "big_clock_window.h" #include "bundle_manager.h" #include "engine_dialog.h" +#include "export_video_dialog.h" +#include "export_video_infobox.h" #include "gain_meter.h" #include "global_port_matrix.h" #include "gui_object.h" @@ -121,6 +129,7 @@ typedef uint64_t microseconds_t; #include "rc_option_editor.h" #include "route_time_axis.h" #include "route_params_ui.h" +#include "save_as_dialog.h" #include "session_dialog.h" #include "session_metadata_dialog.h" #include "session_option_editor.h" @@ -130,6 +139,7 @@ typedef uint64_t microseconds_t; #include "startup.h" #include "theme_manager.h" #include "time_axis_view_item.h" +#include "timers.h" #include "utils.h" #include "video_server_dialog.h" #include "add_video_dialog.h" @@ -143,40 +153,51 @@ using namespace PBD; using namespace Gtkmm2ext; using namespace Gtk; using namespace std; +using namespace Editing; ARDOUR_UI *ARDOUR_UI::theArdourUI = 0; -UIConfiguration *ARDOUR_UI::ui_config = 0; -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[], const char* localedir) +float ARDOUR_UI::ui_scale = 1.0; - : Gtkmm2ext::UI (PROGRAM_NAME, argcp, argvp) - - , gui_object_state (new GUIObjectState) +static bool +ask_about_configuration_copy (string const & old_dir, string const & new_dir, int version) +{ + MessageDialog msg (string_compose (_("%1 %2.x has discovered configuration files from %1 %3.x.\n\n" + "Would you like these files to be copied and used for %1 %2.x?\n\n" + "(This will require you to restart %1.)"), + PROGRAM_NAME, PROGRAM_VERSION, version), + false, /* no markup */ + Gtk::MESSAGE_INFO, + Gtk::BUTTONS_YES_NO, + true /* modal, though it hardly matters since it is the only window */ + ); - , 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)) + msg.set_default_response (Gtk::RESPONSE_YES); + msg.show_all (); - /* big clock */ + return (msg.run() == Gtk::RESPONSE_YES); +} + +ARDOUR_UI::ARDOUR_UI (int *argcp, char **argvp[], const char* localedir, UIConfiguration* uic) + : Gtkmm2ext::UI (PROGRAM_NAME, argcp, argvp) + , ui_config (uic->post_gui_init ()) + , session_loaded (false) + , gui_object_state (new GUIObjectState) + , primary_clock (new MainClock (X_("primary"), X_("transport"), true )) + , secondary_clock (new MainClock (X_("secondary"), X_("secondary"), false)) , big_clock (new AudioClock (X_("bigclock"), false, "big", true, true, false, false)) , video_timeline(0) - - /* start of private members */ - + , ignore_dual_punch (false) + , editor (0) + , mixer (0) , nsm (0) , _was_dirty (false) , _mixer_on_top (false) , first_time_engine_run (true) - , blink_timeout_tag (-1) - - /* transport */ - , roll_controllable (new TransportControllable ("transport roll", *this, TransportControllable::Roll)) , stop_controllable (new TransportControllable ("transport stop", *this, TransportControllable::Stop)) , goto_start_controllable (new TransportControllable ("transport goto start", *this, TransportControllable::GotoStart)) @@ -184,20 +205,23 @@ ARDOUR_UI::ARDOUR_UI (int *argcp, char **argvp[], const char* localedir) , auto_loop_controllable (new TransportControllable ("transport auto loop", *this, TransportControllable::AutoLoop)) , play_selection_controllable (new TransportControllable ("transport play selection", *this, TransportControllable::PlaySelection)) , rec_controllable (new TransportControllable ("transport rec-enable", *this, TransportControllable::RecordEnable)) - , auto_return_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")) - + , auditioning_alert_button (_("Audition")) + , solo_alert_button (_("Solo")) + , feedback_alert_button (_("Feedback")) + , error_alert_button ( ArdourButton::just_led_default_elements ) , editor_meter(0) , editor_meter_peak_display() - + , session_selector_window (0) + , open_session_selector (0) + , _numpad_locate_happening (false) + , _session_is_new (false) + , last_key_press_time (0) + , save_as_dialog (0) + , meterbridge (0) , 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")) @@ -205,48 +229,40 @@ ARDOUR_UI::ARDOUR_UI (int *argcp, char **argvp[], const char* localedir) , location_ui (X_("locations"), _("Locations")) , route_params (X_("inspector"), _("Tracks and Busses")) , audio_midi_setup (X_("audio-midi-setup"), _("Audio/MIDI Setup")) + , export_video_dialog (X_("video-export"), _("Video Export Dialog")) , 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")) - + , video_server_process (0) + , splash (0) + , have_configure_timeout (false) + , last_configure_time (0) + , last_peak_grab (0) + , have_disk_speed_dialog_displayed (false) , _status_bar_visibility (X_("status-bar")) , _feedback_exists (false) + , _log_not_acknowledged (LogLevelNone) { - Gtkmm2ext::init(localedir); - - splash = 0; - - _numpad_locate_happening = false; + Gtkmm2ext::init (localedir); + if (ARDOUR::handle_old_configuration_files (boost::bind (ask_about_configuration_copy, _1, _2, _3))) { + MessageDialog msg (string_compose (_("Your configuration files were copied. You can now restart %1."), PROGRAM_NAME), true); + msg.run (); + /* configuration was modified, exit immediately */ + _exit (0); + } + if (theArdourUI == 0) { theArdourUI = this; } - ui_config = new UIConfiguration(); - ui_config->ParameterChanged.connect (sigc::mem_fun (*this, &ARDOUR_UI::parameter_changed)); boost::function pc (boost::bind (&ARDOUR_UI::parameter_changed, this, _1)); ui_config->map_parameters (pc); - editor = 0; - mixer = 0; - meterbridge = 0; - editor = 0; - _session_is_new = false; - session_selector_window = 0; - last_key_press_time = 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; - roll_button.set_controllable (roll_controllable); stop_button.set_controllable (stop_controllable); goto_start_button.set_controllable (goto_start_controllable); @@ -264,13 +280,6 @@ ARDOUR_UI::ARDOUR_UI (int *argcp, char **argvp[], const char* localedir) rec_button.set_name ("transport recenable button"); midi_panic_button.set_name ("transport button"); - goto_start_button.set_tweaks (ArdourButton::ShowClick); - goto_end_button.set_tweaks (ArdourButton::ShowClick); - midi_panic_button.set_tweaks (ArdourButton::ShowClick); - - last_configure_time= 0; - last_peak_grab = 0; - 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()); @@ -315,6 +324,9 @@ ARDOUR_UI::ARDOUR_UI (int *argcp, char **argvp[], const char* localedir) ARDOUR::GUIIdle.connect (forever_connections, MISSING_INVALIDATOR, boost::bind(&ARDOUR_UI::gui_idle_handler, this), gui_context()); + Config->ParameterChanged.connect ( forever_connections, MISSING_INVALIDATOR, boost::bind(&ARDOUR_UI::set_flat_buttons, this), gui_context() ); + set_flat_buttons(); + /* lets get this party started */ setup_gtk_ardour_enums (); @@ -347,7 +359,6 @@ ARDOUR_UI::ARDOUR_UI (int *argcp, char **argvp[], const char* localedir) 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); @@ -361,9 +372,9 @@ ARDOUR_UI::ARDOUR_UI (int *argcp, char **argvp[], const char* localedir) big_clock_window.set_state (*ui_xml); audio_port_matrix.set_state (*ui_xml); midi_port_matrix.set_state (*ui_xml); + export_video_dialog.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); @@ -373,18 +384,16 @@ ARDOUR_UI::ARDOUR_UI (int *argcp, char **argvp[], const char* localedir) WM::Manager::instance().register_window (&add_video_dialog); WM::Manager::instance().register_window (&route_params); WM::Manager::instance().register_window (&audio_midi_setup); + WM::Manager::instance().register_window (&export_video_dialog); 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); + /* Trigger setting up the color scheme and loading the GTK RC file */ + + ARDOUR_UI::config()->load_rc_file (false); _process_thread = new ProcessThread (); _process_thread->init (); @@ -426,8 +435,12 @@ ARDOUR_UI::engine_running () first_time_engine_run = false; } + if (_session) { + _session->reset_xrun_count (); + } update_disk_space (); update_cpu_load (); + update_xrun_count (); update_sample_rate (AudioEngine::instance()->sample_rate()); update_timecode_format (); } @@ -441,7 +454,7 @@ ARDOUR_UI::engine_halted (const char* reason, bool free_reason) free it later. */ char *copy = strdup (reason); - Gtkmm2ext::UI::instance()->call_slot (invalidator (*this), boost::bind (&ARDOUR_UI::engine_halted, this, copy, true)); + Gtkmm2ext::UI::instance()->call_slot (MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::engine_halted, this, copy, true)); return; } @@ -468,7 +481,6 @@ the audio backend and save the session."), PROGRAM_NAME); MessageDialog msg (*editor, msgstr); pop_back_splash (msg); - msg.set_keep_above (true); msg.run (); if (free_reason) { @@ -481,6 +493,14 @@ ARDOUR_UI::post_engine () { /* Things to be done once (and once ONLY) after we have a backend running in the AudioEngine */ +#ifdef AUDIOUNIT_SUPPORT + std::string au_msg; + if (AUPluginInfo::au_get_crashlog(au_msg)) { + popup_error(_("Audio Unit Plugin Scan Failed. Automatic AU scanning has been disabled. Please see the log window for further details.")); + error << _("Audio Unit Plugin Scan Failed:") << endmsg; + info << au_msg << endmsg; + } +#endif ARDOUR::init_post_engine (); @@ -488,7 +508,9 @@ ARDOUR_UI::post_engine () AudioEngine::instance()->Stopped.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::engine_stopped, this), gui_context()); AudioEngine::instance()->SampleRateChanged.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::update_sample_rate, this, _1), gui_context()); + AudioEngine::instance()->BufferSizeChanged.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::update_sample_rate, this, _1), gui_context()); AudioEngine::instance()->Halted.connect_same_thread (halt_connection, boost::bind (&ARDOUR_UI::engine_halted, this, _1, false)); + AudioEngine::instance()->BecameSilent.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::audioengine_became_silent, this), gui_context()); _tooltips.enable(); @@ -527,8 +549,6 @@ ARDOUR_UI::post_engine () exit (0); } - blink_timeout_tag = -1; - /* this being a GUI and all, we want peakfiles */ AudioFileSource::set_build_peakfiles (true); @@ -552,18 +572,31 @@ ARDOUR_UI::post_engine () Glib::signal_timeout().connect_seconds (sigc::mem_fun(*this, &ARDOUR_UI::update_wall_clock), 1); #endif - 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)); - Config->map_parameters (pc); + { + DisplaySuspender ds; + 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)); + Config->map_parameters (pc); + + ui_config->map_parameters (pc); + } } ARDOUR_UI::~ARDOUR_UI () { - if (ui_config->dirty()) { - ui_config->save_state(); - } + ui_config->save_state(); stop_video_server(); + + if (getenv ("ARDOUR_RUNNING_UNDER_VALGRIND")) { + // don't bother at 'real' exit. the OS cleans up for us. + delete big_clock; + delete primary_clock; + delete secondary_clock; + delete _process_thread; + delete gui_object_state; + FastMeter::flush_pattern_cache (); + } } void @@ -664,6 +697,13 @@ ARDOUR_UI::get_transport_controllable_state () return *node; } +void +ARDOUR_UI::save_session_at_its_request (std::string snapshot_name) +{ + if (_session) { + _session->save_state (snapshot_name); + } +} gint ARDOUR_UI::autosave_session () @@ -742,7 +782,7 @@ ARDOUR_UI::starting () bool brand_new_user = ArdourStartup::required (); app->ShouldQuit.connect (sigc::mem_fun (*this, &ARDOUR_UI::queue_finish)); - app->ShouldLoad.connect (sigc::mem_fun (*this, &ARDOUR_UI::idle_load)); + app->ShouldLoad.connect (sigc::mem_fun (*this, &ARDOUR_UI::load_from_application_api)); if (ARDOUR_COMMAND_LINE::check_announcements) { check_announcements (); @@ -764,7 +804,16 @@ ARDOUR_UI::starting () if ((nsm_url = g_getenv ("NSM_URL")) != 0) { nsm = new NSM_Client; if (!nsm->init (nsm_url)) { - nsm->announce (PROGRAM_NAME, ":dirty:", "ardour3"); + /* the ardour executable may have different names: + * + * waf's obj.target for distro versions: eg ardour4, ardourvst4 + * Ardour4, Mixbus3 for bundled versions + full path on OSX & windows + * argv[0] does not apply since we need the wrapper-script (not the binary itself) + * + * The wrapper startup script should set the environment variable 'ARDOUR_SELF' + */ + const char *process_name = g_getenv ("ARDOUR_SELF"); + nsm->announce (PROGRAM_NAME, ":dirty:", process_name ? process_name : "ardour4"); unsigned int i = 0; // wait for announce reply from nsm server @@ -839,6 +888,50 @@ ARDOUR_UI::starting () } } +#ifdef NO_PLUGIN_STATE + + ARDOUR::RecentSessions rs; + ARDOUR::read_recent_sessions (rs); + + string path = Glib::build_filename (user_config_directory(), ".iknowaboutfreeversion"); + + if (!Glib::file_test (path, Glib::FILE_TEST_EXISTS) && !rs.empty()) { + + /* already used Ardour, have sessions ... warn about plugin state */ + + ArdourDialog d (_("Free/Demo Version Warning"), true); + Label l; + Button b (string_compose (_("Subscribe and support development of %1"), PROGRAM_NAME)); + CheckButton c (_("Don't warn me about this again")); + + l.set_markup (string_compose (_("%1\n\n%2\n\n%3\n\n%4"), + string_compose (_("This is a free/demo version of %1"), PROGRAM_NAME), + _("It will not restore OR save any plugin settings"), + _("If you load an existing session with plugin settings\n" + "they will not be used and will be lost."), + _("To get full access to updates without this limitation\n" + "consider becoming a subscriber for a low cost every month."))); + l.set_justify (JUSTIFY_CENTER); + + b.signal_clicked().connect (mem_fun(*this, &ARDOUR_UI::launch_subscribe)); + + d.get_vbox()->pack_start (l, true, true); + d.get_vbox()->pack_start (b, false, false, 12); + d.get_vbox()->pack_start (c, false, false, 12); + + d.add_button (_("Quit now"), RESPONSE_CANCEL); + d.add_button (string_compose (_("Continue using %1"), PROGRAM_NAME), RESPONSE_OK); + + d.show_all (); + + c.signal_toggled().connect (sigc::hide_return (sigc::bind (sigc::ptr_fun (toggle_file_existence), path))); + + if (d.run () != RESPONSE_OK) { + _exit (0); + } + } +#endif + /* go get a session */ const bool new_session_required = (ARDOUR_COMMAND_LINE::new_session || brand_new_user); @@ -992,6 +1085,7 @@ If you still wish to quit, please use the\n\n\ second_connection.disconnect (); point_one_second_connection.disconnect (); point_zero_something_second_connection.disconnect(); + fps_connection.disconnect(); } delete ARDOUR_UI::instance()->video_timeline; @@ -1007,7 +1101,6 @@ If you still wish to quit, please use the\n\n\ close_all_dialogs (); if (_session) { - // _session->set_deletion_in_progress (); _session->set_clean (); _session->remove_pending_capture_state (); delete _session; @@ -1071,7 +1164,6 @@ ARDOUR_UI::ask_about_saving_session (const vector& actions) prompt_label.show(); dimage->show(); window.show(); - window.set_keep_above (true); window.present (); ResponseType r = (ResponseType) window.run(); @@ -1091,10 +1183,11 @@ ARDOUR_UI::ask_about_saving_session (const vector& actions) } -gint +void ARDOUR_UI::every_second () { update_cpu_load (); + update_xrun_count (); update_buffer_load (); update_disk_space (); update_timecode_format (); @@ -1111,33 +1204,60 @@ ARDOUR_UI::every_second () _was_dirty = false; } } - return TRUE; } -gint +void ARDOUR_UI::every_point_one_seconds () { - shuttle_box->update_speed_display (); - RapidScreenUpdate(); /* EMIT_SIGNAL */ - return TRUE; + // TODO get rid of this.. + // ShuttleControl is updated directly via TransportStateChange signal } -gint +void ARDOUR_UI::every_point_zero_something_seconds () { // august 2007: actual update frequency: 25Hz (40ms), not 100Hz - SuperRapidScreenUpdate(); /* EMIT_SIGNAL */ - if (editor_meter && Config->get_show_editor_meter()) { + if (editor_meter && ARDOUR_UI::config()->get_show_editor_meter()) { float mpeak = editor_meter->update_meters(); if (mpeak > editor_meter_max_peak) { - if (mpeak >= Config->get_meter_peak()) { - editor_meter_peak_display.set_name ("meterbridge peakindicator on"); - editor_meter_peak_display.set_elements((ArdourButton::Element) (ArdourButton::Edge|ArdourButton::Body)); + if (mpeak >= ARDOUR_UI::config()->get_meter_peak()) { + editor_meter_peak_display.set_active_state ( Gtkmm2ext::ExplicitActive ); } } } - return TRUE; +} + +void +ARDOUR_UI::set_fps_timeout_connection () +{ + unsigned int interval = 40; + if (!_session) return; + if (_session->timecode_frames_per_second() != 0) { + /* ideally we'll use a select() to sleep and not accumulate + * idle time to provide a regular periodic signal. + * See linux_vst_gui_support.cc 'elapsed_time_ms'. + * However, that'll require a dedicated thread and cross-thread + * signals to the GUI Thread.. + */ + interval = floor(500. /* update twice per FPS, since Glib::signal_timeout is very irregular */ + * _session->frame_rate() / _session->nominal_frame_rate() + / _session->timecode_frames_per_second() + ); +#ifdef PLATFORM_WINDOWS + // the smallest windows scheduler time-slice is ~15ms. + // periodic GUI timeouts shorter than that will cause + // WaitForSingleObject to spinlock (100% of one CPU Core) + // and gtk never enters idle mode. + // also changing timeBeginPeriod(1) does not affect that in + // any beneficial way, so we just limit the max rate for now. + interval = std::max(30u, interval); // at most ~33Hz. +#else + interval = std::max(8u, interval); // at most 120Hz. +#endif + } + fps_connection.disconnect(); + Timers::set_fps_interval (interval); } void @@ -1149,7 +1269,7 @@ ARDOUR_UI::update_sample_rate (framecnt_t) if (!AudioEngine::instance()->connected()) { - snprintf (buf, sizeof (buf), _("Audio: none")); + snprintf (buf, sizeof (buf), "%s", _("Audio: none")); } else { @@ -1157,7 +1277,7 @@ ARDOUR_UI::update_sample_rate (framecnt_t) if (rate == 0) { /* no sample rate available */ - snprintf (buf, sizeof (buf), _("Audio: none")); + snprintf (buf, sizeof (buf), "%s", _("Audio: none")); } else { if (fmod (rate, 1000.0) != 0.0) { @@ -1228,6 +1348,29 @@ ARDOUR_UI::update_format () format_label.set_markup (s.str ()); } +void +ARDOUR_UI::update_xrun_count () +{ + char buf[64]; + + /* If this text is changed, the set_size_request_to_display_given_text call in ARDOUR_UI::resize_text_widgets + should also be changed. + */ + + if (_session) { + const unsigned int x = _session->get_xrun_count (); + if (x > 9999) { + snprintf (buf, sizeof (buf), _("X: >10K"), X_("red")); + } else { + snprintf (buf, sizeof (buf), _("X: %u"), x > 0 ? X_("red") : X_("green"), x); + } + } else { + snprintf (buf, sizeof (buf), _("X: ?"), X_("yellow")); + } + xrun_label.set_markup (buf); + set_tip (xrun_label, _("Audio dropouts. Shift+click to reset")); +} + void ARDOUR_UI::update_cpu_load () { @@ -1237,7 +1380,7 @@ ARDOUR_UI::update_cpu_load () should also be changed. */ - float const c = AudioEngine::instance()->get_dsp_load (); + double const c = AudioEngine::instance()->get_dsp_load (); snprintf (buf, sizeof (buf), _("DSP: %5.1f%%"), c >= 90 ? X_("red") : X_("green"), c); cpu_load_label.set_markup (buf); } @@ -1303,7 +1446,7 @@ ARDOUR_UI::update_disk_space() snprintf (buf, sizeof (buf), "%s", _("Disk: 24hrs+")); } else { rec_enabled_streams = 0; - _session->foreach_route (this, &ARDOUR_UI::count_recenabled_streams); + _session->foreach_route (this, &ARDOUR_UI::count_recenabled_streams, false); framecnt_t frames = opt_frames.get_value_or (0); @@ -1612,7 +1755,7 @@ ARDOUR_UI::open_session () } FileFilter session_filter; - session_filter.add_pattern ("*.ardour"); + session_filter.add_pattern (string_compose(X_("*%1"), ARDOUR::statefile_suffix)); session_filter.set_name (string_compose (_("%1 sessions"), PROGRAM_NAME)); open_session_selector->add_filter (session_filter); open_session_selector->set_filter (session_filter); @@ -1833,10 +1976,39 @@ ARDOUR_UI::transport_stop () _session->request_stop (false, true); } +/** Check if any tracks are record enabled. If none are, record enable all of them. + * @return true if track record-enabled status was changed, false otherwise. + */ +bool +ARDOUR_UI::trx_record_enable_all_tracks () +{ + if (!_session) { + return false; + } + + boost::shared_ptr rl = _session->get_tracks (); + bool none_record_enabled = true; + + for (RouteList::iterator r = rl->begin(); r != rl->end(); ++r) { + boost::shared_ptr t = boost::dynamic_pointer_cast (*r); + assert (t); + + if (t->record_enabled()) { + none_record_enabled = false; + break; + } + } + + if (none_record_enabled) { + _session->set_record_enabled (rl, true, Session::rt_cleanup); + } + + return none_record_enabled; +} + void ARDOUR_UI::transport_record (bool roll) { - if (_session) { switch (_session->record_status()) { case Session::Disabled: @@ -1845,6 +2017,9 @@ ARDOUR_UI::transport_record (bool roll) msg.run (); return; } + if (Profile->get_trx()) { + roll = trx_record_enable_all_tracks (); + } _session->maybe_enable_record (); if (roll) { transport_roll (); @@ -1929,7 +2104,6 @@ ARDOUR_UI::get_smart_mode() const void ARDOUR_UI::toggle_roll (bool with_abort, bool roll_out_of_bounded_mode) { - if (!_session) { return; } @@ -1976,7 +2150,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_follow_edits() && ( editor->get_selection().time.front().start == _session->transport_frame() ) ) { //if playhead is exactly at the start of a range, we can assume it was placed there by follow_edits + if (ARDOUR_UI::config()->get_follow_edits() && ( editor->get_selection().time.front().start == _session->transport_frame() ) ) { //if playhead is exactly at the start of a range, we can assume it was placed there by follow_edits _session->request_play_range (&editor->get_selection().time, true); _session->set_requested_return_frame( editor->get_selection().time.front().start ); //force an auto-return here } @@ -2153,7 +2327,7 @@ ARDOUR_UI::map_transport_state () auto_loop_button.set_active (false); } - if (Config->get_follow_edits()) { + if (ARDOUR_UI::config()->get_follow_edits()) { /* light up both roll and play-selection if they are joined */ roll_button.set_active (true); play_selection_button.set_active (true); @@ -2175,21 +2349,34 @@ ARDOUR_UI::map_transport_state () } } +void +ARDOUR_UI::blink_handler (bool blink_on) +{ + transport_rec_enable_blink (blink_on); + solo_blink (blink_on); + sync_blink (blink_on); + audition_blink (blink_on); + feedback_blink (blink_on); + error_blink (blink_on); +} + void ARDOUR_UI::update_clocks () { - if (!editor || !editor->dragging_playhead()) { - Clock (_session->audible_frame(), false, editor->get_preferred_edit_position()); /* EMIT_SIGNAL */ + if (!_session) return; + + if (editor && !editor->dragging_playhead()) { + Clock (_session->audible_frame(), false, editor->get_preferred_edit_position (EDIT_IGNORE_PHEAD)); /* EMIT_SIGNAL */ } } void ARDOUR_UI::start_clocking () { - if (Config->get_super_rapid_clock_update()) { - clock_signal_connection = SuperRapidScreenUpdate.connect (sigc::mem_fun(*this, &ARDOUR_UI::update_clocks)); + if (ui_config->get_super_rapid_clock_update()) { + clock_signal_connection = Timers::fps_connect (sigc::mem_fun(*this, &ARDOUR_UI::update_clocks)); } else { - clock_signal_connection = RapidScreenUpdate.connect (sigc::mem_fun(*this, &ARDOUR_UI::update_clocks)); + clock_signal_connection = Timers::rapid_connect (sigc::mem_fun(*this, &ARDOUR_UI::update_clocks)); } } @@ -2199,42 +2386,103 @@ ARDOUR_UI::stop_clocking () clock_signal_connection.disconnect (); } -gint -ARDOUR_UI::_blink (void *arg) +bool +ARDOUR_UI::save_as_progress_update (float fraction, int64_t cnt, int64_t total, Gtk::Label* label, Gtk::ProgressBar* bar) { - ((ARDOUR_UI *) arg)->blink (); - return TRUE; -} + char buf[256]; -void -ARDOUR_UI::blink () -{ - Blink (blink_on = !blink_on); /* EMIT_SIGNAL */ + snprintf (buf, sizeof (buf), _("Copied %" PRId64 " of %" PRId64), cnt, total); + + label->set_text (buf); + bar->set_fraction (fraction); + + /* process events, redraws, etc. */ + + while (gtk_events_pending()) { + gtk_main_iteration (); + } + + return true; /* continue with save-as */ } void -ARDOUR_UI::start_blinking () +ARDOUR_UI::save_session_as () { - /* Start the blink signal. Everybody with a blinking widget - uses Blink to drive the widget's state. + if (!_session) { + return; + } + + if (!save_as_dialog) { + save_as_dialog = new SaveAsDialog; + } else { + save_as_dialog->clear_name (); + } + + int response = save_as_dialog->run (); + + save_as_dialog->hide (); + + switch (response) { + case Gtk::RESPONSE_OK: + break; + default: + return; + } + + + Session::SaveAs sa; + + sa.new_parent_folder = save_as_dialog->new_parent_folder (); + sa.new_name = save_as_dialog->new_name (); + sa.switch_to = save_as_dialog->switch_to(); + sa.copy_media = save_as_dialog->copy_media(); + sa.copy_external = save_as_dialog->copy_external(); + sa.include_media = save_as_dialog->include_media (); + + /* Only bother with a progress dialog if we're going to copy + media into the save-as target. Without that choice, this + will be very fast because we're only talking about a few kB's to + perhaps a couple of MB's of data. */ + + ArdourDialog progress_dialog (_("Save As"), true); - if (blink_timeout_tag < 0) { - blink_on = false; - blink_timeout_tag = g_timeout_add (240, _blink, this); + if (sa.include_media && sa.copy_media) { + + Gtk::Label label; + Gtk::ProgressBar progress_bar; + + progress_dialog.get_vbox()->pack_start (label); + progress_dialog.get_vbox()->pack_start (progress_bar); + label.show (); + progress_bar.show (); + + /* this signal will be emitted from within this, the calling thread, + * after every file is copied. It provides information on percentage + * complete (in terms of total data to copy), the number of files + * copied so far, and the total number to copy. + */ + + ScopedConnection c; + + sa.Progress.connect_same_thread (c, boost::bind (&ARDOUR_UI::save_as_progress_update, this, _1, _2, _3, &label, &progress_bar)); + + progress_dialog.show_all (); + progress_dialog.present (); + } + + if (_session->save_as (sa)) { + /* ERROR MESSAGE */ + MessageDialog msg (string_compose (_("Save As failed: %1"), sa.failure_message)); + msg.run (); } -} -void -ARDOUR_UI::stop_blinking () -{ - if (blink_timeout_tag >= 0) { - g_source_remove (blink_timeout_tag); - blink_timeout_tag = -1; + if (!sa.include_media) { + unload_session (false); + load_session (sa.final_session_folder_name, sa.new_name); } } - /** Ask the user for the name of a new snapshot and then take it. */ @@ -2385,6 +2633,10 @@ ARDOUR_UI::save_state (const string & name, bool switch_to_it) _session->add_extra_xml (*node); + if (export_video_dialog) { + _session->add_extra_xml (export_video_dialog->get_state()); + } + save_state_canfail (name, switch_to_it); } @@ -2449,7 +2701,7 @@ ARDOUR_UI::transport_rec_enable_blink (bool onoff) if (onoff) { rec_button.set_active_state (Gtkmm2ext::ExplicitActive); } else { - rec_button.set_active_state (Gtkmm2ext::ImplicitActive); + rec_button.set_active_state (Gtkmm2ext::Off); } } else if (r == Session::Recording && h) { rec_button.set_active_state (Gtkmm2ext::ExplicitActive); @@ -2493,7 +2745,7 @@ ARDOUR_UI::edit_metadata () { SessionMetadataEditor dialog; dialog.set_session (_session); - editor->ensure_float (dialog); + dialog.grab_focus (); dialog.run (); } @@ -2502,7 +2754,6 @@ ARDOUR_UI::import_metadata () { SessionMetadataImporter dialog; dialog.set_session (_session); - editor->ensure_float (dialog); dialog.run (); } @@ -2521,7 +2772,7 @@ ARDOUR_UI::ask_about_loading_existing_session (const std::string& session_path) msg.set_name (X_("OpenExistingDialog")); msg.set_title (_("Open Existing Session")); msg.set_wmclass (X_("existing_session"), PROGRAM_NAME); - msg.set_position (Gtk::WIN_POS_MOUSE); + msg.set_position (Gtk::WIN_POS_CENTER); pop_back_splash (msg); switch (msg.run()) { @@ -2583,19 +2834,16 @@ ARDOUR_UI::build_session_from_dialog (SessionDialog& sd, const std::string& sess } void -ARDOUR_UI::idle_load (const std::string& path) +ARDOUR_UI::load_from_application_api (const std::string& path) { - if (_session) { - if (Glib::file_test (path, Glib::FILE_TEST_IS_DIR)) { - /* /path/to/foo => /path/to/foo, foo */ - load_session (path, basename_nosuffix (path)); - } else { - /* /path/to/foo/foo.ardour => /path/to/foo, foo */ - load_session (Glib::path_get_dirname (path), basename_nosuffix (path)); - } + ARDOUR_COMMAND_LINE::session_name = path; + if (Glib::file_test (path, Glib::FILE_TEST_IS_DIR)) { + /* /path/to/foo => /path/to/foo, foo */ + load_session (path, basename_nosuffix (path)); } else { - ARDOUR_COMMAND_LINE::session_name = path; + /* /path/to/foo/foo.ardour => /path/to/foo, foo */ + load_session (Glib::path_get_dirname (path), basename_nosuffix (path)); } } @@ -2686,6 +2934,13 @@ ARDOUR_UI::get_session_parameters (bool quit_on_cancel, bool should_be_new, stri break; default: if (quit_on_cancel) { + // JE - Currently (July 2014) this section can only get reached if the + // user quits from the main 'Session Setup' dialog (i.e. reaching this + // point does NOT indicate an abnormal termination). Therefore, let's + // behave gracefully (i.e. let's do some cleanup) before we call exit() + ARDOUR::cleanup (); + pthread_cancel_all (); + exit (1); } else { return ret; @@ -2724,8 +2979,14 @@ ARDOUR_UI::get_session_parameters (bool quit_on_cancel, bool should_be_new, stri } if (session_name[0] == G_DIR_SEPARATOR || +#ifdef PLATFORM_WINDOWS + (session_name.length() > 3 && session_name[1] == ':' && session_name[2] == G_DIR_SEPARATOR) +#else (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)) { + (session_name.length() > 3 && session_name[0] == '.' && session_name[1] == '.' && session_name[2] == G_DIR_SEPARATOR) +#endif + ) + { /* absolute path or cwd-relative path specified for session name: infer session folder from what was given. @@ -2905,7 +3166,6 @@ ARDOUR_UI::load_session (const std::string& path, const std::string& snap_name, Gtk::MESSAGE_INFO, BUTTONS_OK); - msg.set_keep_above (true); msg.set_title (_("Loading Error")); msg.set_position (Gtk::WIN_POS_CENTER); pop_back_splash (msg); @@ -2929,8 +3189,7 @@ ARDOUR_UI::load_session (const std::string& path, const std::string& snap_name, true, Gtk::MESSAGE_INFO, BUTTONS_OK); - - msg.set_keep_above (true); + msg.set_title (_("Read-only Session")); msg.set_position (Gtk::WIN_POS_CENTER); pop_back_splash (msg); @@ -3008,6 +3267,7 @@ ARDOUR_UI::build_session (const std::string& path, const std::string& snap_name, XMLNode* n; n = Config->instant_xml (X_("Editor")); if (n) { + n->remove_nodes_and_delete ("Selection"); // no not apply selection to new sessions. new_session->add_instant_xml (*n, false); } n = Config->instant_xml (X_("Mixer")); @@ -3036,6 +3296,8 @@ ARDOUR_UI::launch_chat () { #ifdef __APPLE__ open_uri("http://webchat.freenode.net/?channels=ardour-osx"); +#elif defined PLATFORM_WINDOWS + open_uri("http://webchat.freenode.net/?channels=ardour-windows"); #else open_uri("http://webchat.freenode.net/?channels=ardour"); #endif @@ -3053,6 +3315,52 @@ ARDOUR_UI::launch_reference () PBD::open_uri (Config->get_reference_manual_url()); } +void +ARDOUR_UI::launch_tracker () +{ + PBD::open_uri ("http://tracker.ardour.org/bug_report_page.php"); +} + +void +ARDOUR_UI::launch_subscribe () +{ + PBD::open_uri ("https://community.ardour.org/s/subscribe"); +} + +void +ARDOUR_UI::launch_cheat_sheet () +{ +#ifdef __APPLE__ + PBD::open_uri ("http://manual.ardour.org/files/a3_mnemonic_cheat_sheet_osx.pdf"); +#else + PBD::open_uri ("http://manual.ardour.org/files/a3_mnemonic_cheatsheet.pdf"); +#endif +} + +void +ARDOUR_UI::launch_website () +{ + PBD::open_uri ("http://ardour.org"); +} + +void +ARDOUR_UI::launch_website_dev () +{ + PBD::open_uri ("http://ardour.org/development.html"); +} + +void +ARDOUR_UI::launch_forums () +{ + PBD::open_uri ("https://community.ardour.org/forums"); +} + +void +ARDOUR_UI::launch_howto_report () +{ + PBD::open_uri ("http://ardour.org/reporting_bugs"); +} + void ARDOUR_UI::loading_message (const std::string& msg) { @@ -3305,46 +3613,50 @@ ARDOUR_UI::flush_trash () } void -ARDOUR_UI::setup_order_hint () +ARDOUR_UI::setup_order_hint (AddRouteDialog::InsertAt place) { - uint32_t order_hint = 0; + uint32_t order_hint = UINT32_MAX; + if (editor->get_selection().tracks.empty()) { + return; + } + /* 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()) { + + if (place == AddRouteDialog::AfterSelection) { + RouteTimeAxisView *rtav = dynamic_cast (editor->get_selection().tracks.back()); + if (rtav) { + order_hint = rtav->route()->order_key(); order_hint++; } - - } else { - for (TrackSelection::iterator s = editor->get_selection().tracks.begin(); s != editor->get_selection().tracks.end(); ++s) { - RouteTimeAxisView* tav = dynamic_cast (*s); - if (tav && tav->route() && tav->route()->order_key() > order_hint) { - order_hint = tav->route()->order_key(); - } + } else if (place == AddRouteDialog::BeforeSelection) { + RouteTimeAxisView *rtav = dynamic_cast (editor->get_selection().tracks.front()); + if (rtav) { + order_hint = rtav->route()->order_key(); } + } else if (place == AddRouteDialog::First) { + order_hint = 0; + } else { + /* leave order_hint at UINT32_MAX */ + } - if (!editor->get_selection().tracks.empty()) { - order_hint++; - } + if (order_hint == UINT32_MAX) { + /** AddRouteDialog::Last or selection with first/last not a RouteTimeAxisView + * not setting an order hint will place new routes last. + */ + return; } _session->set_order_hint (order_hint); /* create a gap in the existing route order keys to accomodate new routes.*/ - boost::shared_ptr rd = _session->get_routes(); for (RouteList::iterator ri = rd->begin(); ri != rd->end(); ++ri) { boost::shared_ptr rt (*ri); - + if (rt->is_monitor()) { continue; } @@ -3356,7 +3668,7 @@ ARDOUR_UI::setup_order_hint () } void -ARDOUR_UI::add_route (Gtk::Window* float_window) +ARDOUR_UI::add_route (Gtk::Window* /* ignored */) { int count; @@ -3369,11 +3681,6 @@ ARDOUR_UI::add_route (Gtk::Window* float_window) return; } - if (float_window) { - add_route_dialog->unset_transient_for (); - add_route_dialog->set_transient_for (*float_window); - } - ResponseType r = (ResponseType) add_route_dialog->run (); add_route_dialog->hide(); @@ -3390,7 +3697,7 @@ ARDOUR_UI::add_route (Gtk::Window* float_window) return; } - setup_order_hint(); + setup_order_hint(add_route_dialog->insert_at()); string template_path = add_route_dialog->track_template(); DisplaySuspender ds; @@ -3484,7 +3791,7 @@ ARDOUR_UI::start_video_server (Gtk::Window* float_window, bool popup_msg) 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; + warning << _("Could not connect to the Video Server. Start it or configure its access URL in Preferences.") << endmsg; } VideoServerDialog *video_server_dialog = new VideoServerDialog (_session); if (float_window) { @@ -3504,21 +3811,27 @@ ARDOUR_UI::start_video_server (Gtk::Window* float_window, bool popup_msg) 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_("/");} + if (icsd_docroot.empty()) { +#ifndef PLATFORM_WINDOWS + icsd_docroot = X_("/"); +#else + icsd_docroot = X_("C:\\"); +#endif + } GStatBuf sb; - if (!g_lstat (icsd_docroot.c_str(), &sb) == 0 || !S_ISDIR(sb.st_mode)) { + if (g_lstat (icsd_docroot.c_str(), &sb) != 0 || !S_ISDIR(sb.st_mode)) { warning << _("Specified docroot is not an existing directory.") << endmsg; continue; } #ifndef PLATFORM_WINDOWS - if ( (!g_lstat (icsd_exec.c_str(), &sb) == 0) + 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) + 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; @@ -3538,7 +3851,7 @@ ARDOUR_UI::start_video_server (Gtk::Window* float_window, bool popup_msg) argp[8] = 0; stop_video_server(); - if (icsd_docroot == X_("/")) { + if (icsd_docroot == X_("/") || icsd_docroot == X_("C:\\")) { Config->set_video_advanced_setup(false); } else { std::ostringstream osstream; @@ -3583,7 +3896,7 @@ ARDOUR_UI::add_video (Gtk::Window* float_window) } 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; + warning << _("Could not connect to the Video Server. Start it or configure its access URL in Preferences.") << endmsg; return; } @@ -3706,6 +4019,8 @@ ARDOUR_UI::remove_video () _session->add_extra_xml(*node); node = new XMLNode(X_("Videomonitor")); _session->add_extra_xml(*node); + node = new XMLNode(X_("Videoexport")); + _session->add_extra_xml(*node); stop_video_server(); } @@ -3720,6 +4035,29 @@ ARDOUR_UI::flush_videotimeline_cache (bool localcacheonly) editor->queue_visual_videotimeline_update(); } +void +ARDOUR_UI::export_video (bool range) +{ + if (ARDOUR::Config->get_show_video_export_info()) { + ExportVideoInfobox infobox (_session); + Gtk::ResponseType rv = (Gtk::ResponseType) infobox.run(); + if (infobox.show_again()) { + ARDOUR::Config->set_show_video_export_info(false); + } + switch (rv) { + case GTK_RESPONSE_YES: + PBD::open_uri (ARDOUR::Config->get_reference_manual_url() + "/video-timeline/operations/#export"); + break; + default: + break; + } + } + export_video_dialog->set_session (_session); + export_video_dialog->apply_state(editor->get_selection().time, range); + export_video_dialog->run (); + export_video_dialog->hide (); +} + XMLNode* ARDOUR_UI::mixer_settings () const { @@ -3779,14 +4117,17 @@ ARDOUR_UI::keyboard_settings () const void ARDOUR_UI::create_xrun_marker (framepos_t where) { - editor->mouse_add_new_marker (where, false, true); + if (_session) { + Location *location = new Location (*_session, where, where, _("xrun"), Location::IsMark); + _session->locations()->add (location); + } } void ARDOUR_UI::halt_on_xrun_message () { - MessageDialog msg (*editor, - _("Recording was stopped because your system could not keep up.")); + cerr << "HALT on xrun\n"; + MessageDialog msg (*editor, _("Recording was stopped because your system could not keep up.")); msg.run (); } @@ -3868,7 +4209,7 @@ ARDOUR_UI::plugin_scan_dialog (std::string type, std::string plugin, bool can_ca } const bool cancelled = PluginManager::instance().cancelled(); - if (type != X_("closeme") && !Config->get_show_plugin_scan_window()) { + if (type != X_("closeme") && !ui_config->get_show_plugin_scan_window()) { if (cancelled && scan_dlg->is_mapped()) { scan_dlg->hide(); gui_idle_handler(); @@ -3912,6 +4253,8 @@ ARDOUR_UI::plugin_scan_dialog (std::string type, std::string plugin, bool can_ca scan_dlg->get_vbox()->pack_start (*scan_tbox, PACK_SHRINK, 4); } + assert(scan_dlg && scan_tbox && cancel_button); + if (type == X_("closeme")) { scan_dlg->hide(); } else { @@ -4071,6 +4414,7 @@ int ARDOUR_UI::reconnect_to_engine () { if (AudioEngine::instance()->start ()) { + // TODO somehow make this the topmost window (above any dialogs currently visible) if (editor) { MessageDialog msg (*editor, _("Could not reconnect to the Audio/MIDI engine")); msg.run (); @@ -4097,14 +4441,14 @@ ARDOUR_UI::use_config () void ARDOUR_UI::update_transport_clocks (framepos_t pos) { - if (Config->get_primary_clock_delta_edit_cursor()) { - primary_clock->set (pos, false, editor->get_preferred_edit_position()); + if (ui_config->get_primary_clock_delta_edit_cursor()) { + primary_clock->set (pos, false, editor->get_preferred_edit_position (EDIT_IGNORE_PHEAD)); } else { primary_clock->set (pos); } - if (Config->get_secondary_clock_delta_edit_cursor()) { - secondary_clock->set (pos, false, editor->get_preferred_edit_position()); + if (ui_config->get_secondary_clock_delta_edit_cursor()) { + secondary_clock->set (pos, false, editor->get_preferred_edit_position (EDIT_IGNORE_PHEAD)); } else { secondary_clock->set (pos); } @@ -4276,6 +4620,10 @@ ARDOUR_UI::setup_profile () if (g_getenv ("TRX")) { Profile->set_trx (); } + + if (g_getenv ("MIXBUS")) { + Profile->set_mixbus (); + } } int @@ -4372,8 +4720,7 @@ ARDOUR_UI::reset_peak_display () if (!_session || !_session->master_out() || !editor_meter) return; editor_meter->clear_meters(); editor_meter_max_peak = -INFINITY; - editor_meter_peak_display.set_name ("meterbridge peakindicator"); - editor_meter_peak_display.set_elements((ArdourButton::Element) (ArdourButton::Edge|ArdourButton::Body)); + editor_meter_peak_display.set_active_state ( Gtkmm2ext::Off ); } void @@ -4446,12 +4793,81 @@ ARDOUR_UI::transport_numpad_event (int num) case 1: transport_rewind(1); break; case 2: transport_forward(1); break; case 3: transport_record(true); break; - case 4: if (_session) _session->request_play_loop(true); break; - case 5: if (_session) _session->request_play_loop(true); transport_record(false); break; - case 6: toggle_punch(); break; + case 4: toggle_session_auto_loop(); break; + case 5: transport_record(false); toggle_session_auto_loop(); break; + case 6: toggle_punch(); break; case 7: toggle_click(); break; case 8: toggle_auto_return(); break; case 9: toggle_follow_edits(); break; } } } + +void +ARDOUR_UI::set_flat_buttons () +{ + CairoWidget::set_flat_buttons( config()->get_flat_buttons() ); +} + +void +ARDOUR_UI::audioengine_became_silent () +{ + MessageDialog msg (string_compose (_("This is a free/demo copy of %1. It has just switched to silent mode."), PROGRAM_NAME), + true, + Gtk::MESSAGE_WARNING, + Gtk::BUTTONS_NONE, + true); + + msg.set_title (string_compose (_("%1 is now silent"), PROGRAM_NAME)); + + Gtk::Label pay_label (string_compose (_("Please consider paying for a copy of %1 - you can pay whatever you want."), PROGRAM_NAME)); + Gtk::Label subscribe_label (_("Better yet become a subscriber - subscriptions start at US$1 per month.")); + Gtk::Button pay_button (_("Pay for a copy (via the web)")); + Gtk::Button subscribe_button (_("Become a subscriber (via the web)")); + Gtk::HBox pay_button_box; + Gtk::HBox subscribe_button_box; + + pay_button_box.pack_start (pay_button, true, false); + subscribe_button_box.pack_start (subscribe_button, true, false); + + bool (*openuri)(const char*) = PBD::open_uri; /* this forces selection of the const char* variant of PBD::open_uri(), which we need to avoid ambiguity below */ + + pay_button.signal_clicked().connect (sigc::hide_return (sigc::bind (sigc::ptr_fun (openuri), (const char*) "https://ardour.org/download"))); + subscribe_button.signal_clicked().connect (sigc::hide_return (sigc::bind (sigc::ptr_fun (openuri), (const char*) "https://community.ardour.org/s/subscribe"))); + + msg.get_vbox()->pack_start (pay_label); + msg.get_vbox()->pack_start (pay_button_box); + msg.get_vbox()->pack_start (subscribe_label); + msg.get_vbox()->pack_start (subscribe_button_box); + + msg.get_vbox()->show_all (); + + msg.add_button (_("Remain silent"), Gtk::RESPONSE_CANCEL); + msg.add_button (_("Save and quit"), Gtk::RESPONSE_NO); + msg.add_button (_("Give me more time"), Gtk::RESPONSE_YES); + + int r = msg.run (); + + switch (r) { + case Gtk::RESPONSE_YES: + AudioEngine::instance()->reset_silence_countdown (); + break; + + case Gtk::RESPONSE_NO: + /* save and quit */ + save_state_canfail (""); + exit (0); + break; + + case Gtk::RESPONSE_CANCEL: + default: + /* don't reset, save session and exit */ + break; + } +} + +void +ARDOUR_UI::hide_application () +{ + Application::instance ()-> hide (); +}