X-Git-Url: https://main.carlh.net/gitweb/?a=blobdiff_plain;f=gtk2_ardour%2Fardour_ui.cc;h=e507370513e6d7f08c4c3bcbd74c508121a21e3e;hb=3a50975c3dae3759d9e7f4fdcf9a39ed4e3e69e7;hp=65b882fe6de1b81b49296dddc70119351fffb066;hpb=653ae4acd639fef149314fe6f8c7a0d862afae40;p=ardour.git diff --git a/gtk2_ardour/ardour_ui.cc b/gtk2_ardour/ardour_ui.cc index 65b882fe6d..e507370513 100644 --- a/gtk2_ardour/ardour_ui.cc +++ b/gtk2_ardour/ardour_ui.cc @@ -33,6 +33,11 @@ #include #endif +#ifdef __FreeBSD__ +#include +#include +#endif + #include #include #include @@ -44,12 +49,14 @@ #include #include +#include #include "pbd/error.h" #include "pbd/basename.h" #include "pbd/compose.h" #include "pbd/convert.h" #include "pbd/failed_constructor.h" +#include "pbd/file_archive.h" #include "pbd/enumwriter.h" #include "pbd/memento_command.h" #include "pbd/openuri.h" @@ -58,6 +65,7 @@ #include "pbd/localtime_r.h" #include "pbd/pthread_utils.h" #include "pbd/replace_all.h" +#include "pbd/scoped_file_descriptor.h" #include "pbd/xml++.h" #include "gtkmm2ext/application.h" @@ -85,6 +93,7 @@ #include "ardour/process_thread.h" #include "ardour/profile.h" #include "ardour/recent_sessions.h" +#include "ardour/record_enable_control.h" #include "ardour/session_directory.h" #include "ardour/session_route.h" #include "ardour/session_state_utils.h" @@ -155,22 +164,23 @@ typedef uint64_t microseconds_t; #include "route_params_ui.h" #include "save_as_dialog.h" #include "script_selector.h" +#include "session_archive_dialog.h" #include "session_dialog.h" #include "session_metadata_dialog.h" #include "session_option_editor.h" -#include "shuttle_control.h" #include "speaker_dialog.h" #include "splash.h" #include "startup.h" -#include "theme_manager.h" #include "time_axis_view_item.h" +#include "time_info_box.h" #include "timers.h" #include "utils.h" +#include "utils_videotl.h" #include "video_server_dialog.h" #include "add_video_dialog.h" #include "transcode_video_dialog.h" -#include "i18n.h" +#include "pbd/i18n.h" using namespace ARDOUR; using namespace ARDOUR_UI_UTILS; @@ -263,16 +273,11 @@ ARDOUR_UI::ARDOUR_UI (int *argcp, char **argvp[], const char* localedir) , _mixer_on_top (false) , _initial_verbose_plugin_scan (false) , first_time_engine_run (true) - , 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)) - , goto_end_controllable (new TransportControllable ("transport goto end", *this, TransportControllable::GotoEnd)) - , 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)) + , secondary_clock_spacer (0) + , auto_input_button (ArdourButton::led_default_elements) + , time_info_box (0) , 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")) @@ -289,7 +294,7 @@ ARDOUR_UI::ARDOUR_UI (int *argcp, char **argvp[], const char* localedir) , speaker_config_window (X_("speaker-config"), _("Speaker Configuration")) , add_route_dialog (X_("add-routes"), _("Add Tracks/Busses")) , about (X_("about"), _("About")) - , location_ui (X_("locations"), _("Locations")) + , location_ui (X_("locations"), S_("Ranges|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")) @@ -300,7 +305,7 @@ ARDOUR_UI::ARDOUR_UI (int *argcp, char **argvp[], const char* localedir) , 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)) - , key_editor (X_("key-editor"), _("Bindings Editor"), boost::bind (&ARDOUR_UI::create_key_editor, this)) + , key_editor (X_("key-editor"), _("Keyboard Shortcuts"), boost::bind (&ARDOUR_UI::create_key_editor, this)) , video_server_process (0) , splash (0) , have_configure_timeout (false) @@ -320,12 +325,24 @@ ARDOUR_UI::ARDOUR_UI (int *argcp, char **argvp[], const char* localedir) UIConfiguration::instance().post_gui_init (); if (ARDOUR::handle_old_configuration_files (boost::bind (ask_about_configuration_copy, _1, _2, _3))) { + { + /* "touch" the been-here-before path now that config has been migrated */ + PBD::ScopedFileDescriptor fout (g_open (been_here_before_path ().c_str(), O_CREAT|O_TRUNC|O_RDWR, 0666)); + } 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 (string (VERSIONSTRING).find (".pre") != string::npos) { + /* check this is not being run from ./ardev etc. */ + if (!running_from_source_tree ()) { + pre_release_dialog (); + } + } + if (theArdourUI == 0) { theArdourUI = this; } @@ -343,13 +360,22 @@ ARDOUR_UI::ARDOUR_UI (int *argcp, char **argvp[], const char* localedir) boost::function pc (boost::bind (&ARDOUR_UI::parameter_changed, this, _1)); UIConfiguration::instance().map_parameters (pc); - roll_button.set_controllable (roll_controllable); - stop_button.set_controllable (stop_controllable); - goto_start_button.set_controllable (goto_start_controllable); - goto_end_button.set_controllable (goto_end_controllable); - auto_loop_button.set_controllable (auto_loop_controllable); - play_selection_button.set_controllable (play_selection_controllable); - rec_button.set_controllable (rec_controllable); + Glib::RefPtr act; + + act = ActionManager::get_action ("Transport/Roll"); + roll_button.set_related_action (act); + act = ActionManager::get_action ("Transport/Stop"); + stop_button.set_related_action (act); + act = ActionManager::get_action ("Transport/GotoStart"); + goto_start_button.set_related_action (act); + act = ActionManager::get_action ("Transport/GotoEnd"); + goto_end_button.set_related_action (act); + act = ActionManager::get_action ("Transport/Loop"); + auto_loop_button.set_related_action (act); + act = ActionManager::get_action ("Transport/PlaySelection"); + play_selection_button.set_related_action (act); + act = ActionManager::get_action ("Transport/Record"); + rec_button.set_related_action (act); roll_button.set_name ("transport button"); stop_button.set_name ("transport button"); @@ -473,6 +499,9 @@ ARDOUR_UI::ARDOUR_UI (int *argcp, char **argvp[], const char* localedir) WM::Manager::instance().register_window (&audio_port_matrix); WM::Manager::instance().register_window (&midi_port_matrix); + /* do not retain position for add route dialog */ + add_route_dialog.set_state_mask (WindowProxy::Size); + /* Trigger setting up the color scheme and loading the GTK RC file */ UIConfiguration::instance().load_rc_file (false); @@ -485,6 +514,40 @@ ARDOUR_UI::ARDOUR_UI (int *argcp, char **argvp[], const char* localedir) attach_to_engine (); } +void +ARDOUR_UI::pre_release_dialog () +{ + ArdourDialog d (_("Pre-Release Warning"), true, false); + d.add_button (Gtk::Stock::OK, Gtk::RESPONSE_OK); + + Label* label = manage (new Label); + label->set_markup (string_compose (_("Welcome to this pre-release build of %1 %2\n\n\ +There are still several issues and bugs to be worked on,\n\ +as well as general workflow improvements, before this can be considered\n\ +release software. So, a few guidelines:\n\ +\n\ +1) Please do NOT use this software with the expectation that it is stable or reliable\n\ + though it may be so, depending on your workflow.\n\ +2) Please wait for a helpful writeup of new features.\n\ +3) Please do NOT use the forums at ardour.org to report issues.\n\ +4) Please DO use the bugtracker at http://tracker.ardour.org/ to report issues\n\ + making sure to note the product version number as 5.0-pre.\n\ +5) Please DO use the ardour-users mailing list to discuss ideas and pass on comments.\n\ +6) Please DO join us on IRC for real time discussions about %1 %2. You\n\ + can get there directly from within the program via the Help->Chat menu option.\n\ +\n\ +Full information on all the above can be found on the support page at\n\ +\n\ + http://ardour.org/support\n\ +"), PROGRAM_NAME, VERSIONSTRING)); + + d.get_vbox()->set_border_width (12); + d.get_vbox()->pack_start (*label, false, false, 12); + d.get_vbox()->show_all (); + + d.run (); +} + GlobalPortMatrixWindow* ARDOUR_UI::create_global_port_matrix (ARDOUR::DataType type) { @@ -685,10 +748,12 @@ ARDOUR_UI::~ARDOUR_UI () delete primary_clock; primary_clock = 0; delete secondary_clock; secondary_clock = 0; delete _process_thread; _process_thread = 0; + delete time_info_box; time_info_box = 0; delete meterbridge; meterbridge = 0; delete luawindow; luawindow = 0; delete editor; editor = 0; delete mixer; mixer = 0; + delete rc_option_editor; rc_option_editor = 0; // failed to wrap object warning delete nsm; nsm = 0; delete gui_object_state; gui_object_state = 0; delete main_window_visibility; @@ -747,63 +812,6 @@ ARDOUR_UI::configure_handler (GdkEventConfigure* /*conf*/) return FALSE; } -void -ARDOUR_UI::set_transport_controllable_state (const XMLNode& node) -{ - XMLProperty const * prop; - - if ((prop = node.property ("roll")) != 0) { - roll_controllable->set_id (prop->value()); - } - if ((prop = node.property ("stop")) != 0) { - stop_controllable->set_id (prop->value()); - } - if ((prop = node.property ("goto-start")) != 0) { - goto_start_controllable->set_id (prop->value()); - } - if ((prop = node.property ("goto-end")) != 0) { - goto_end_controllable->set_id (prop->value()); - } - if ((prop = node.property ("auto-loop")) != 0) { - auto_loop_controllable->set_id (prop->value()); - } - if ((prop = node.property ("play-selection")) != 0) { - play_selection_controllable->set_id (prop->value()); - } - if ((prop = node.property ("rec")) != 0) { - rec_controllable->set_id (prop->value()); - } - if ((prop = node.property ("shuttle")) != 0) { - shuttle_box->controllable()->set_id (prop->value()); - } -} - -XMLNode& -ARDOUR_UI::get_transport_controllable_state () -{ - XMLNode* node = new XMLNode(X_("TransportControllables")); - char buf[64]; - - roll_controllable->id().print (buf, sizeof (buf)); - node->add_property (X_("roll"), buf); - stop_controllable->id().print (buf, sizeof (buf)); - node->add_property (X_("stop"), buf); - goto_start_controllable->id().print (buf, sizeof (buf)); - node->add_property (X_("goto_start"), buf); - goto_end_controllable->id().print (buf, sizeof (buf)); - node->add_property (X_("goto_end"), buf); - auto_loop_controllable->id().print (buf, sizeof (buf)); - node->add_property (X_("auto_loop"), buf); - play_selection_controllable->id().print (buf, sizeof (buf)); - node->add_property (X_("play_selection"), buf); - rec_controllable->id().print (buf, sizeof (buf)); - node->add_property (X_("rec"), buf); - shuttle_box->controllable()->id().print (buf, sizeof (buf)); - node->add_property (X_("shuttle"), buf); - - return *node; -} - void ARDOUR_UI::save_session_at_its_request (std::string snapshot_name) { @@ -1017,6 +1025,45 @@ ARDOUR_UI::starting () } } + // TODO: maybe IFF brand_new_user + if (ARDOUR::Profile->get_mixbus () && Config->get_copy_demo_sessions ()) { + std::string dspd (Config->get_default_session_parent_dir()); + Searchpath ds (ARDOUR::ardour_data_search_path()); + ds.add_subdirectory_to_paths ("sessions"); + vector demos; + find_files_matching_pattern (demos, ds, "*.tar.xz"); + + ARDOUR::RecentSessions rs; + ARDOUR::read_recent_sessions (rs); + + for (vector::iterator i = demos.begin(); i != demos.end (); ++i) { + /* "demo-session" must be inside "demo-session.tar.xz" + * strip ".tar.xz" + */ + std::string name = basename_nosuffix (basename_nosuffix (*i)); + std::string path = Glib::build_filename (dspd, name); + /* skip if session-dir already exists */ + if (Glib::file_test(path.c_str(), Glib::FILE_TEST_IS_DIR)) { + continue; + } + /* skip sessions that are already in 'recent'. + * eg. a new user changed shorly after installation + */ + for (ARDOUR::RecentSessions::iterator r = rs.begin(); r != rs.end(); ++r) { + if ((*r).first == name) { + continue; + } + } + try { + PBD::FileArchive ar (*i); + if (0 == ar.inflate (dspd)) { + store_recent_sessions (name, path); + info << string_compose (_("Copied Demo Session %1."), name) << endmsg; + } + } catch (...) {} + } + } + #ifdef NO_PLUGIN_STATE ARDOUR::RecentSessions rs; @@ -1232,6 +1279,10 @@ If you still wish to quit, please use the\n\n\ */ save_ardour_state (); + if (key_editor.get (false)) { + key_editor->disconnect (); + } + close_all_dialogs (); if (_session) { @@ -1353,7 +1404,7 @@ ARDOUR_UI::every_point_zero_something_seconds () { // august 2007: actual update frequency: 25Hz (40ms), not 100Hz - if (editor_meter && UIConfiguration::instance().get_show_editor_meter()) { + if (editor_meter && UIConfiguration::instance().get_show_editor_meter() && editor_meter_peak_display.is_mapped ()) { float mpeak = editor_meter->update_meters(); if (mpeak > editor_meter_max_peak) { if (mpeak >= UIConfiguration::instance().get_meter_peak()) { @@ -1778,6 +1829,13 @@ ARDOUR_UI::open_session () 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); + + FileFilter archive_filter; + archive_filter.add_pattern (X_("*.tar.xz")); + archive_filter.set_name (_("Session Archives")); + + open_session_selector.add_filter (archive_filter); + open_session_selector.set_filter (session_filter); int response = open_session_selector.run(); @@ -1792,7 +1850,18 @@ ARDOUR_UI::open_session () bool isnew; if (session_path.length() > 0) { - if (ARDOUR::find_session (session_path, path, name, isnew) == 0) { + int rv = ARDOUR::inflate_session (session_path, + Config->get_default_session_parent_dir(), path, name); + if (rv == 0) { + _session_is_new = false; + load_session (path, name); + } + else if (rv < 0) { + MessageDialog msg (_main_window, + string_compose (_("Extracting session-archive failed: %1"), inflate_error (rv))); + msg.run (); + } + else if (ARDOUR::find_session (session_path, path, name, isnew) == 0) { _session_is_new = isnew; load_session (path, name); } @@ -1818,17 +1887,21 @@ ARDOUR_UI::session_add_mixed_track ( const string& name_template, bool strict_io, PluginInfoPtr instrument, - Plugin::PresetRecord* pset) + Plugin::PresetRecord* pset, + ARDOUR::PresentationInfo::order_t order) { - list > tracks; - if (_session == 0) { warning << _("You cannot add a track without a session already loaded.") << endmsg; return; } + if (Profile->get_mixbus ()) { + strict_io = true; + } + try { - tracks = _session->new_midi_track (input, output, instrument, ARDOUR::Normal, route_group, how_many, name_template, pset); + list > tracks; + tracks = _session->new_midi_track (input, output, strict_io, instrument, pset, route_group, how_many, name_template, order, ARDOUR::Normal); if (tracks.size() != how_many) { error << string_compose(P_("could not create %1 new mixed track", "could not create %1 new mixed tracks", how_many), how_many) << endmsg; @@ -1839,12 +1912,6 @@ ARDOUR_UI::session_add_mixed_track ( display_insufficient_ports_message (); return; } - - if (strict_io) { - for (list >::iterator i = tracks.begin(); i != tracks.end(); ++i) { - (*i)->set_strict_io (true); - } - } } void @@ -1854,17 +1921,21 @@ ARDOUR_UI::session_add_midi_bus ( const string& name_template, bool strict_io, PluginInfoPtr instrument, - Plugin::PresetRecord* pset) + Plugin::PresetRecord* pset, + ARDOUR::PresentationInfo::order_t order) { - RouteList routes; - if (_session == 0) { warning << _("You cannot add a track without a session already loaded.") << endmsg; return; } + if (Profile->get_mixbus ()) { + strict_io = true; + } + try { - routes = _session->new_midi_route (route_group, how_many, name_template, instrument, pset); + RouteList routes; + routes = _session->new_midi_route (route_group, how_many, name_template, strict_io, instrument, pset, PresentationInfo::MidiBus, order); if (routes.size() != how_many) { error << string_compose(P_("could not create %1 new Midi Bus", "could not create %1 new Midi Busses", how_many), how_many) << endmsg; } @@ -1874,12 +1945,6 @@ ARDOUR_UI::session_add_midi_bus ( display_insufficient_ports_message (); return; } - - if (strict_io) { - for (RouteList::iterator i = routes.begin(); i != routes.end(); ++i) { - (*i)->set_strict_io (true); - } - } } void @@ -1890,15 +1955,16 @@ ARDOUR_UI::session_add_midi_route ( const string& name_template, bool strict_io, PluginInfoPtr instrument, - Plugin::PresetRecord* pset) + Plugin::PresetRecord* pset, + ARDOUR::PresentationInfo::order_t order) { ChanCount one_midi_channel; one_midi_channel.set (DataType::MIDI, 1); if (disk) { - session_add_mixed_track (one_midi_channel, one_midi_channel, route_group, how_many, name_template, strict_io, instrument, pset); + session_add_mixed_track (one_midi_channel, one_midi_channel, route_group, how_many, name_template, strict_io, instrument, pset, order); } else { - session_add_midi_bus (route_group, how_many, name_template, strict_io, instrument, pset); + session_add_midi_bus (route_group, how_many, name_template, strict_io, instrument, pset, order); } } @@ -1911,8 +1977,8 @@ ARDOUR_UI::session_add_audio_route ( RouteGroup* route_group, uint32_t how_many, string const & name_template, - bool strict_io - ) + bool strict_io, + ARDOUR::PresentationInfo::order_t order) { list > tracks; RouteList routes; @@ -1924,7 +1990,7 @@ ARDOUR_UI::session_add_audio_route ( try { if (track) { - tracks = _session->new_audio_track (input_channels, output_channels, mode, route_group, how_many, name_template); + tracks = _session->new_audio_track (input_channels, output_channels, route_group, how_many, name_template, order, mode); if (tracks.size() != how_many) { error << string_compose (P_("could not create %1 new audio track", "could not create %1 new audio tracks", how_many), how_many) @@ -1933,7 +1999,7 @@ ARDOUR_UI::session_add_audio_route ( } else { - routes = _session->new_audio_route (input_channels, output_channels, route_group, how_many, name_template); + routes = _session->new_audio_route (input_channels, output_channels, route_group, how_many, name_template, PresentationInfo::AudioBus, order); if (routes.size() != how_many) { error << string_compose (P_("could not create %1 new audio bus", "could not create %1 new audio busses", how_many), how_many) @@ -2092,7 +2158,7 @@ ARDOUR_UI::trx_record_enable_all_tracks () } if (none_record_enabled) { - _session->set_controls (route_list_to_control_list (rl, &Track::rec_enable_control), 1.0, Controllable::NoGroup); + _session->set_controls (route_list_to_control_list (rl, &Stripable::rec_enable_control), 1.0, Controllable::NoGroup); } return none_record_enabled; @@ -2250,7 +2316,12 @@ ARDOUR_UI::toggle_roll (bool with_abort, bool roll_out_of_bounded_mode) if (affect_transport) { if (rolling) { _session->request_stop (with_abort, true); - } else { + + } else if (!with_abort) { /* with_abort == true means the + * command was intended to stop + * transport, not start. + */ + /* the only external sync condition we can be in here * would be Engine (JACK) sync, in which case we still * want to do this. @@ -2322,6 +2393,24 @@ ARDOUR_UI::transport_play_preroll () editor->play_with_preroll (); } +void +ARDOUR_UI::transport_rec_preroll () +{ + if (!_session) { + return; + } + editor->rec_with_preroll (); +} + +void +ARDOUR_UI::transport_rec_count_in () +{ + if (!_session) { + return; + } + editor->rec_with_count_in (); +} + void ARDOUR_UI::transport_rewind (int option) { @@ -2377,7 +2466,7 @@ ARDOUR_UI::transport_forward (int option) } void -ARDOUR_UI::toggle_record_enable (uint32_t rid) +ARDOUR_UI::toggle_record_enable (uint16_t rid) { if (!_session) { return; @@ -2385,7 +2474,7 @@ ARDOUR_UI::toggle_record_enable (uint32_t rid) boost::shared_ptr r; - if ((r = _session->route_by_remote_id (rid)) != 0) { + if ((r = _session->get_remote_nth_route (rid)) != 0) { boost::shared_ptr t; @@ -2403,10 +2492,11 @@ ARDOUR_UI::map_transport_state () play_selection_button.unset_active_state (); roll_button.unset_active_state (); stop_button.set_active_state (Gtkmm2ext::ExplicitActive); + layered_button.set_sensitive (false); return; } - shuttle_box->map_transport_state (); + shuttle_box.map_transport_state (); float sp = _session->transport_speed(); @@ -2442,11 +2532,13 @@ ARDOUR_UI::map_transport_state () roll_button.set_active (true); play_selection_button.set_active (true); } + layered_button.set_sensitive (!_session->actively_recording ()); stop_button.set_active (false); } else { + layered_button.set_sensitive (true); stop_button.set_active (true); roll_button.set_active (false); play_selection_button.set_active (false); @@ -2587,9 +2679,44 @@ ARDOUR_UI::save_session_as () msg.run (); } - if (!sa.include_media) { + /* the logic here may seem odd: why isn't the condition sa.switch_to ? + * the trick is this: if the new session was copy with media included, + * then Session::save_as() will have already done a neat trick to avoid + * us having to unload and load the new state. But if the media was not + * included, then this is required (it avoids us having to otherwise + * drop all references to media (sources). + */ + + if (!sa.include_media && sa.switch_to) { unload_session (false); load_session (sa.final_session_folder_name, sa.new_name); + hide_splash (); + } +} + +void +ARDOUR_UI::archive_session () +{ + if (!_session) { + return; + } + + time_t n; + time (&n); + Glib::DateTime gdt (Glib::DateTime::create_now_local (n)); + + SessionArchiveDialog sad; + sad.set_name (_session->name() + gdt.format ("_%F_%H%M%S")); + int response = sad.run (); + + if (response != Gtk::RESPONSE_OK) { + sad.hide (); + return; + } + + if (_session->archive_session (sad.target_folder(), sad.name(), sad.encode_option (), sad.only_used_sources (), &sad)) { + MessageDialog msg (_("Session Archiving failed.")); + msg.run (); } } @@ -2670,14 +2797,8 @@ ARDOUR_UI::snapshot_session (bool switch_to_it) if (switch_to_it) { prompter.set_initial_text (_session->snap_name()); } else { - char timebuf[128]; - time_t n; - struct tm local_time; - - time (&n); - localtime_r (&n, &local_time); - strftime (timebuf, sizeof(timebuf), "%FT%H.%M.%S", &local_time); - prompter.set_initial_text (timebuf); + Glib::DateTime tm (g_date_time_new_now_local ()); + prompter.set_initial_text (tm.format ("%FT%H.%M.%S")); } bool finished = false; @@ -2999,7 +3120,19 @@ ARDOUR_UI::build_session_from_dialog (SessionDialog& sd, const std::string& sess void ARDOUR_UI::load_from_application_api (const std::string& path) { + /* OS X El Capitan (and probably later) now somehow passes the command + line arguments to an app via the openFile delegate protocol. Ardour + already does its own command line processing, and having both + pathways active causes crashes. So, if the command line was already + set, do nothing here. + */ + + if (!ARDOUR_COMMAND_LINE::session_name.empty()) { + return; + } + ARDOUR_COMMAND_LINE::session_name = path; + /* Cancel SessionDialog if it's visible to make OSX delegates work. * * ARDOUR_UI::starting connects app->ShouldLoad signal and then shows a SessionDialog @@ -3161,6 +3294,21 @@ ARDOUR_UI::get_session_parameters (bool quit_on_cancel, bool should_be_new, stri likely_new = true; } + if (!likely_new) { + int rv = ARDOUR::inflate_session (session_name, + Config->get_default_session_parent_dir(), session_path, session_name); + if (rv < 0) { + MessageDialog msg (session_dialog, + string_compose (_("Extracting session-archive failed: %1"), inflate_error (rv))); + msg.run (); + continue; + } + else if (rv == 0) { + session_dialog.set_provided_session (session_name, session_path); + } + } + + // XXX check archive, inflate string::size_type suffix = session_name.find (statefile_suffix); if (suffix != string::npos) { @@ -3424,16 +3572,6 @@ ARDOUR_UI::load_session (const std::string& path, const std::string& snap_name, msg.hide (); } - - /* Now the session been created, add the transport controls */ - new_session->add_controllable(roll_controllable); - new_session->add_controllable(stop_controllable); - new_session->add_controllable(goto_start_controllable); - new_session->add_controllable(goto_end_controllable); - new_session->add_controllable(auto_loop_controllable); - new_session->add_controllable(play_selection_controllable); - new_session->add_controllable(rec_controllable); - set_session (new_session); session_loaded = true; @@ -3448,7 +3586,7 @@ ARDOUR_UI::load_session (const std::string& path, const std::string& snap_name, { Timers::TimerSuspender t; - flush_pending (); + flush_pending (10); } #ifdef WINDOWS_VST_SUPPORT @@ -3482,7 +3620,9 @@ ARDOUR_UI::build_session (const std::string& path, const std::string& snap_name, } catch (SessionException e) { + cerr << "Here are the errors associated with this failed session:\n"; dump_errors (cerr); + cerr << "---------\n"; MessageDialog msg (string_compose(_("Could not create session in \"%1\": %2"), path, e.what())); msg.set_title (_("Loading Error")); msg.set_position (Gtk::WIN_POS_CENTER); @@ -3491,7 +3631,9 @@ ARDOUR_UI::build_session (const std::string& path, const std::string& snap_name, return -1; } catch (...) { + cerr << "Here are the errors associated with this failed session:\n"; dump_errors (cerr); + cerr << "---------\n"; MessageDialog msg (string_compose(_("Could not create session in \"%1\""), path)); msg.set_title (_("Loading Error")); msg.set_position (Gtk::WIN_POS_CENTER); @@ -3513,6 +3655,11 @@ ARDOUR_UI::build_session (const std::string& path, const std::string& snap_name, new_session->add_instant_xml (*n, false); } + n = Config->instant_xml (X_("Preferences")); + if (n) { + new_session->add_instant_xml (*n, false); + } + /* Put the playhead at 0 and scroll fully left */ n = new_session->instant_xml (X_("Editor")); if (n) { @@ -3902,59 +4049,38 @@ ARDOUR_UI::cleanup_peakfiles () } } -void -ARDOUR_UI::setup_order_hint (AddRouteDialog::InsertAt place) +PresentationInfo::order_t +ARDOUR_UI::translate_order (RouteDialogs::InsertAt place) { - uint32_t order_hint = UINT32_MAX; - if (editor->get_selection().tracks.empty()) { - return; + return PresentationInfo::max_order; } + PresentationInfo::order_t order_hint = PresentationInfo::max_order; + /* we want the new routes to have their order keys set starting from the highest order key in the selection + 1 (if available). */ - if (place == AddRouteDialog::AfterSelection) { + if (place == RouteDialogs::AfterSelection) { RouteTimeAxisView *rtav = dynamic_cast (editor->get_selection().tracks.back()); if (rtav) { - order_hint = rtav->route()->order_key(); + order_hint = rtav->route()->presentation_info().order(); order_hint++; } - } else if (place == AddRouteDialog::BeforeSelection) { + } else if (place == RouteDialogs::BeforeSelection) { RouteTimeAxisView *rtav = dynamic_cast (editor->get_selection().tracks.front()); if (rtav) { - order_hint = rtav->route()->order_key(); + order_hint = rtav->route()->presentation_info().order(); } - } else if (place == AddRouteDialog::First) { + } else if (place == RouteDialogs::First) { order_hint = 0; } else { - /* leave order_hint at UINT32_MAX */ + /* leave order_hint at max_order */ } - 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; - } - - if (rt->order_key () >= order_hint) { - rt->set_order_key (rt->order_key () + add_route_dialog->count()); - } - } + return order_hint; } void @@ -3974,7 +4100,9 @@ ARDOUR_UI::start_duplicate_routes () void ARDOUR_UI::add_route () { - int count; + if (!add_route_dialog.get (false)) { + add_route_dialog->signal_response().connect (sigc::mem_fun (*this, &ARDOUR_UI::add_route_dialog_finished)); + } if (!_session) { return; @@ -3985,7 +4113,14 @@ ARDOUR_UI::add_route () return; } - ResponseType r = (ResponseType) add_route_dialog->run (); + add_route_dialog->set_position (WIN_POS_MOUSE); + add_route_dialog->present(); +} + +void +ARDOUR_UI::add_route_dialog_finished (int r) +{ + int count; add_route_dialog->hide(); @@ -4001,15 +4136,15 @@ ARDOUR_UI::add_route () return; } - setup_order_hint(add_route_dialog->insert_at()); + PresentationInfo::order_t order = translate_order (add_route_dialog->insert_at()); string template_path = add_route_dialog->track_template(); DisplaySuspender ds; if (!template_path.empty()) { if (add_route_dialog->name_template_is_default()) { - _session->new_route_from_template (count, template_path, string()); + _session->new_route_from_template (count, order, template_path, string()); } else { - _session->new_route_from_template (count, template_path, add_route_dialog->name_template()); + _session->new_route_from_template (count, order, template_path, add_route_dialog->name_template()); } return; } @@ -4031,21 +4166,23 @@ ARDOUR_UI::add_route () /* XXX do something with name template */ + Session::ProcessorChangeBlocker pcb (_session); + switch (add_route_dialog->type_wanted()) { case AddRouteDialog::AudioTrack: - session_add_audio_track (input_chan.n_audio(), output_chan.n_audio(), add_route_dialog->mode(), route_group, count, name_template, strict_io); + session_add_audio_track (input_chan.n_audio(), output_chan.n_audio(), add_route_dialog->mode(), route_group, count, name_template, strict_io, order); break; case AddRouteDialog::MidiTrack: - session_add_midi_track (route_group, count, name_template, strict_io, instrument); + session_add_midi_track (route_group, count, name_template, strict_io, instrument, 0, order); break; case AddRouteDialog::MixedTrack: - session_add_mixed_track (input_chan, output_chan, route_group, count, name_template, strict_io, instrument, 0); + session_add_mixed_track (input_chan, output_chan, route_group, count, name_template, strict_io, instrument, 0, order); break; case AddRouteDialog::AudioBus: - session_add_audio_bus (input_chan.n_audio(), output_chan.n_audio(), route_group, count, name_template, strict_io); + session_add_audio_bus (input_chan.n_audio(), output_chan.n_audio(), route_group, count, name_template, strict_io, order); break; case AddRouteDialog::MidiBus: - session_add_midi_bus (route_group, count, name_template, strict_io, instrument, 0); + session_add_midi_bus (route_group, count, name_template, strict_io, instrument, 0, order); break; case AddRouteDialog::VCAMaster: session_add_vca (name_template, count); @@ -4053,89 +4190,6 @@ ARDOUR_UI::add_route () } } -void -ARDOUR_UI::add_lua_script () -{ - if (!_session) { - return; - } - - LuaScriptInfoPtr spi; - ScriptSelector ss ("Add Lua Session Script", LuaScriptInfo::Session); - switch (ss.run ()) { - case Gtk::RESPONSE_ACCEPT: - spi = ss.script(); - break; - default: - return; - } - ss.hide(); - - std::string script = ""; - - try { - script = Glib::file_get_contents (spi->path); - } catch (Glib::FileError e) { - string msg = string_compose (_("Cannot read session script '%1': %2"), spi->path, e.what()); - MessageDialog am (msg); - am.run (); - return; - } - - LuaScriptParamList lsp = LuaScriptParams::script_params (spi, "sess_params"); - std::vector reg = _session->registered_lua_functions (); - - ScriptParameterDialog spd (_("Set Script Parameters"), spi, reg, lsp); - switch (spd.run ()) { - case Gtk::RESPONSE_ACCEPT: - break; - default: - return; - } - - try { - _session->register_lua_function (spd.name(), script, lsp); - } catch (luabridge::LuaException const& e) { - string msg = string_compose (_("Session script '%1' instantiation failed: %2"), spd.name(), e.what ()); - MessageDialog am (msg); - am.run (); - } catch (SessionException e) { - string msg = string_compose (_("Loading Session script '%1' failed: %2"), spd.name(), e.what ()); - MessageDialog am (msg); - am.run (); - } -} - -void -ARDOUR_UI::remove_lua_script () -{ - if (!_session) { - return; - } - if (_session->registered_lua_function_count () == 0) { - string msg = _("There are no active Lua session scripts present in this session."); - MessageDialog am (msg); - am.run (); - return; - } - - std::vector reg = _session->registered_lua_functions (); - SessionScriptManager sm ("Remove Lua Session Script", reg); - switch (sm.run ()) { - case Gtk::RESPONSE_ACCEPT: - break; - default: - return; - } - try { - _session->unregister_lua_function (sm.name()); - } catch (luabridge::LuaException const& e) { - string msg = string_compose (_("Session script '%1' removal failed: %2"), sm.name(), e.what ()); - MessageDialog am (msg); - am.run (); - } -} - void ARDOUR_UI::stop_video_server (bool ask_confirm) { @@ -4204,15 +4258,18 @@ 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()) { #ifndef PLATFORM_WINDOWS - icsd_docroot = X_("/"); -#else - icsd_docroot = X_("C:\\"); -#endif + if (icsd_docroot.empty()) { + icsd_docroot = VideoUtils::video_get_docroot (Config); } +#endif GStatBuf sb; +#ifdef PLATFORM_WINDOWS + if (VideoUtils::harvid_version >= 0x000802 && icsd_docroot.empty()) { + /* OK, allow all drive letters */ + } else +#endif if (g_lstat (icsd_docroot.c_str(), &sb) != 0 || !S_ISDIR(sb.st_mode)) { warning << _("Specified docroot is not an existing directory.") << endmsg; continue; @@ -4244,6 +4301,11 @@ ARDOUR_UI::start_video_server (Gtk::Window* float_window, bool popup_msg) argp[8] = 0; stop_video_server(); +#ifdef PLATFORM_WINDOWS + if (VideoUtils::harvid_version >= 0x000802 && icsd_docroot.empty()) { + /* OK, allow all drive letters */ + } else +#endif if (icsd_docroot == X_("/") || icsd_docroot == X_("C:\\")) { Config->set_video_advanced_setup(false); } else { @@ -4495,6 +4557,24 @@ ARDOUR_UI::export_video (bool range) export_video_dialog->hide (); } +XMLNode* +ARDOUR_UI::preferences_settings () const +{ + XMLNode* node = 0; + + if (_session) { + node = _session->instant_xml(X_("Preferences")); + } else { + node = Config->instant_xml(X_("Preferences")); + } + + if (!node) { + node = new XMLNode (X_("Preferences")); + } + + return node; +} + XMLNode* ARDOUR_UI::mixer_settings () const { @@ -4579,7 +4659,7 @@ void ARDOUR_UI::create_xrun_marker (framepos_t where) { if (_session) { - Location *location = new Location (*_session, where, where, _("xrun"), Location::IsMark); + Location *location = new Location (*_session, where, where, _("xrun"), Location::IsMark, 0); _session->locations()->add (location); } } @@ -4867,10 +4947,6 @@ Menu > Window > Audio/Midi Setup"), void ARDOUR_UI::use_config () { - XMLNode* node = Config->extra_xml (X_("TransportControllables")); - if (node) { - set_transport_controllable_state (*node); - } } void @@ -4914,16 +4990,21 @@ ARDOUR_UI::record_state_changed () { ENSURE_GUI_THREAD (*this, &ARDOUR_UI::record_state_changed); - if (!_session || !big_clock_window) { + if (!_session) { /* why bother - the clock isn't visible */ return; } - if (_session->record_status () == Session::Recording && _session->have_rec_enabled_track ()) { - big_clock->set_active (true); - } else { - big_clock->set_active (false); + ActionManager::set_sensitive (ActionManager::rec_sensitive_actions, !_session->actively_recording()); + + if (big_clock_window) { + if (_session->record_status () == Session::Recording && _session->have_rec_enabled_track ()) { + big_clock->set_active (true); + } else { + big_clock->set_active (false); + } } + } bool @@ -4960,86 +5041,6 @@ ARDOUR_UI::store_clock_modes () _session->set_dirty (); } -ARDOUR_UI::TransportControllable::TransportControllable (std::string name, ARDOUR_UI& u, ToggleType tp) - : Controllable (name), ui (u), type(tp) -{ - -} - -void -ARDOUR_UI::TransportControllable::set_value (double val, PBD::Controllable::GroupControlDisposition /*group_override*/) -{ - if (val < 0.5) { - /* do nothing: these are radio-style actions */ - return; - } - - const char *action = 0; - - switch (type) { - case Roll: - action = X_("Roll"); - break; - case Stop: - action = X_("Stop"); - break; - case GotoStart: - action = X_("GotoStart"); - break; - case GotoEnd: - action = X_("GotoEnd"); - break; - case AutoLoop: - action = X_("Loop"); - break; - case PlaySelection: - action = X_("PlaySelection"); - break; - case RecordEnable: - action = X_("Record"); - break; - default: - break; - } - - if (action == 0) { - return; - } - - Glib::RefPtr act = ActionManager::get_action ("Transport", action); - - if (act) { - act->activate (); - } -} - -double -ARDOUR_UI::TransportControllable::get_value (void) const -{ - float val = 0.0; - - switch (type) { - case Roll: - break; - case Stop: - break; - case GotoStart: - break; - case GotoEnd: - break; - case AutoLoop: - break; - case PlaySelection: - break; - case RecordEnable: - break; - default: - break; - } - - return val; -} - void ARDOUR_UI::setup_profile () { @@ -5136,7 +5137,7 @@ ARDOUR_UI::session_format_mismatch (std::string xml_path, std::string backup_pat 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"), + "From now on, use the backup copy with older versions of %3"), xml_path, backup_path, PROGRAM_NAME, start_big, end_big, start_mono, end_mono), true); @@ -5187,16 +5188,16 @@ ARDOUR_UI::do_audio_midi_setup (uint32_t desired_sample_rate) while (true) { int response = audio_midi_setup->run(); + printf("RESPONSE %d\n", response); switch (response) { - case Gtk::RESPONSE_OK: + case Gtk::RESPONSE_DELETE_EVENT: + return -1; + default: if (!AudioEngine::instance()->running()) { continue; - } else { - return 0; } + audio_midi_setup->hide (); return 0; - default: - return -1; } } } @@ -5325,16 +5326,16 @@ ARDOUR_UI::setup_toplevel_window (Gtk::Window& window, const string& name, void* if (window_icons.empty()) { Glib::RefPtr icon; - if ((icon = ::get_icon (PROGRAM_NAME "-icon_16px")) != 0) { + if ((icon = ::get_icon (PROGRAM_NAME "-icon_16px"))) { window_icons.push_back (icon); } - if ((icon = ::get_icon (PROGRAM_NAME "-icon_22px")) != 0) { + if ((icon = ::get_icon (PROGRAM_NAME "-icon_22px"))) { window_icons.push_back (icon); } - if ((icon = ::get_icon (PROGRAM_NAME "-icon_32px")) != 0) { + if ((icon = ::get_icon (PROGRAM_NAME "-icon_32px"))) { window_icons.push_back (icon); } - if ((icon = ::get_icon (PROGRAM_NAME "-icon_48px")) != 0) { + if ((icon = ::get_icon (PROGRAM_NAME "-icon_48px"))) { window_icons.push_back (icon); } } @@ -5350,7 +5351,7 @@ ARDOUR_UI::setup_toplevel_window (Gtk::Window& window, const string& name, void* } window.set_title (title.get_string()); - window.set_wmclass (string_compose (X_("%1_%1"), downcase (PROGRAM_NAME), downcase (name)), PROGRAM_NAME); + window.set_wmclass (string_compose (X_("%1_%1"), downcase (std::string(PROGRAM_NAME)), downcase (name)), PROGRAM_NAME); window.set_flags (CAN_FOCUS); window.add_events (Gdk::KEY_PRESS_MASK|Gdk::KEY_RELEASE_MASK); @@ -5416,15 +5417,15 @@ ARDOUR_UI::key_event_handler (GdkEventKey* ev, Gtk::Window* event_window) } static Gtkmm2ext::Bindings* -get_bindings_from_widget_heirarchy (GtkWidget* w) +get_bindings_from_widget_heirarchy (GtkWidget** w) { void* p = NULL; - while (w) { - if ((p = g_object_get_data (G_OBJECT(w), "ardour-bindings")) != 0) { + while (*w) { + if ((p = g_object_get_data (G_OBJECT(*w), "ardour-bindings")) != 0) { break; } - w = gtk_widget_get_parent (w); + *w = gtk_widget_get_parent (*w); } return reinterpret_cast (p); @@ -5435,6 +5436,7 @@ ARDOUR_UI::key_press_focus_accelerator_handler (Gtk::Window& window, GdkEventKey { GtkWindow* win = window.gobj(); GtkWidget* focus = gtk_window_get_focus (win); + GtkWidget* binding_widget = focus; bool special_handling_of_unmodified_accelerators = false; const guint mask = (Keyboard::RelevantModifierKeyMask & ~(Gdk::SHIFT_MASK|Gdk::LOCK_MASK)); @@ -5453,7 +5455,7 @@ ARDOUR_UI::key_press_focus_accelerator_handler (Gtk::Window& window, GdkEventKey } else { - Gtkmm2ext::Bindings* focus_bindings = get_bindings_from_widget_heirarchy (focus); + Gtkmm2ext::Bindings* focus_bindings = get_bindings_from_widget_heirarchy (&binding_widget); if (focus_bindings) { bindings = focus_bindings; DEBUG_TRACE (DEBUG::Accelerators, string_compose ("Switch bindings based on focus widget, now using %1\n", bindings->name())); @@ -5464,7 +5466,7 @@ ARDOUR_UI::key_press_focus_accelerator_handler (Gtk::Window& window, GdkEventKey DEBUG_TRACE (DEBUG::Accelerators, string_compose ("Win = %1 [title = %9] focus = %7 (%8) Key event: code = %2 state = %3 special handling ? %4 magic widget focus ? %5 focus widget %6 named %7 mods ? %8\n", win, ev->keyval, - show_gdk_event_state (ev->state), + Gtkmm2ext::show_gdk_event_state (ev->state), special_handling_of_unmodified_accelerators, Keyboard::some_magic_widget_has_focus(), focus, @@ -5515,7 +5517,7 @@ ARDOUR_UI::key_press_focus_accelerator_handler (Gtk::Window& window, GdkEventKey DEBUG_TRACE (DEBUG::Accelerators, "\tsending to window\n"); KeyboardKey k (ev->state, ev->keyval); - if (bindings) { + while (bindings) { DEBUG_TRACE (DEBUG::Accelerators, string_compose ("\tusing Ardour bindings %1 @ %2 for this event\n", bindings->name(), bindings)); @@ -5523,6 +5525,17 @@ ARDOUR_UI::key_press_focus_accelerator_handler (Gtk::Window& window, GdkEventKey DEBUG_TRACE (DEBUG::Accelerators, "\t\thandled\n"); return true; } + + if (binding_widget) { + binding_widget = gtk_widget_get_parent (binding_widget); + if (binding_widget) { + bindings = get_bindings_from_widget_heirarchy (&binding_widget); + } else { + bindings = 0; + } + } else { + bindings = 0; + } } DEBUG_TRACE (DEBUG::Accelerators, "\tnot yet handled, try global bindings\n"); @@ -5553,7 +5566,7 @@ ARDOUR_UI::key_press_focus_accelerator_handler (Gtk::Window& window, GdkEventKey DEBUG_TRACE (DEBUG::Accelerators, "\tpropagation didn't handle, so activate\n"); KeyboardKey k (ev->state, ev->keyval); - if (bindings) { + while (bindings) { DEBUG_TRACE (DEBUG::Accelerators, "\tusing Ardour bindings for this window\n"); @@ -5563,6 +5576,16 @@ ARDOUR_UI::key_press_focus_accelerator_handler (Gtk::Window& window, GdkEventKey return true; } + if (binding_widget) { + binding_widget = gtk_widget_get_parent (binding_widget); + if (binding_widget) { + bindings = get_bindings_from_widget_heirarchy (&binding_widget); + } else { + bindings = 0; + } + } else { + bindings = 0; + } } DEBUG_TRACE (DEBUG::Accelerators, "\tnot yet handled, try global bindings\n"); @@ -5589,6 +5612,58 @@ void ARDOUR_UI::cancel_solo () { if (_session) { - _session->clear_all_solo_state (_session->get_routes()); // safeguard, ideally this won't do anything, check the log-window + _session->cancel_all_solo (); + } +} + +void +ARDOUR_UI::reset_focus (Gtk::Widget* w) +{ + /* this resets focus to the first focusable parent of the given widget, + * or, if there is no focusable parent, cancels focus in the toplevel + * window that the given widget is packed into (if there is one). + */ + + if (!w) { + return; + } + + Gtk::Widget* top = w->get_toplevel(); + + if (!top || !top->is_toplevel()) { + return; + } + + w = w->get_parent (); + + while (w) { + + if (w->is_toplevel()) { + /* Setting the focus widget to a Gtk::Window causes all + * subsequent calls to ::has_focus() on the nominal + * focus widget in that window to return + * false. Workaround: never set focus to the toplevel + * itself. + */ + break; + } + + if (w->get_can_focus ()) { + Gtk::Window* win = dynamic_cast (top); + win->set_focus (*w); + return; + } + w = w->get_parent (); + } + + if (top == &_main_window) { + } + + /* no focusable parent found, cancel focus in top level window. + C++ API cannot be used for this. Thanks, references. + */ + + gtk_window_set_focus (GTK_WINDOW(top->gobj()), 0); + }