X-Git-Url: https://main.carlh.net/gitweb/?a=blobdiff_plain;f=gtk2_ardour%2Fardour_ui.cc;h=2ef51d80ecce420f3c6ee322d73ea0c78c1bae60;hb=eab3c57b834c3f4dbaeb5d412cdef3a672276c56;hp=2e0749ca5e6788ef6a31478fc7cd5337e40c18bd;hpb=8774be86f7990b7e27acd6a5f5026b7b81e3c46e;p=ardour.git diff --git a/gtk2_ardour/ardour_ui.cc b/gtk2_ardour/ardour_ui.cc index 2e0749ca5e..2ef51d80ec 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,10 +49,12 @@ #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/enumwriter.h" #include "pbd/memento_command.h" @@ -70,6 +77,7 @@ #include "ardour/ardour.h" #include "ardour/audio_backend.h" +#include "ardour/audio_track.h" #include "ardour/audioengine.h" #include "ardour/audiofilesource.h" #include "ardour/automation_watch.h" @@ -77,11 +85,13 @@ #include "ardour/filename_extensions.h" #include "ardour/filesystem_paths.h" #include "ardour/ltc_file_reader.h" +#include "ardour/midi_track.h" #include "ardour/port.h" #include "ardour/plugin_manager.h" #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" @@ -89,6 +99,11 @@ #include "ardour/source_factory.h" #include "ardour/slave.h" #include "ardour/system_exec.h" +#include "ardour/track.h" +#include "ardour/vca_manager.h" +#include "ardour/utils.h" + +#include "LuaBridge/LuaBridge.h" #ifdef WINDOWS_VST_SUPPORT #include @@ -97,6 +112,11 @@ #include "ardour/audio_unit.h" #endif +// fix for OSX (nsm.h has a check function, AU/Apple defines check) +#ifdef check +#undef check +#endif + #include "timecode/time.h" typedef uint64_t microseconds_t; @@ -112,6 +132,7 @@ typedef uint64_t microseconds_t; #include "big_clock_window.h" #include "bundle_manager.h" #include "duplicate_routes_dialog.h" +#include "debug.h" #include "engine_dialog.h" #include "export_video_dialog.h" #include "export_video_infobox.h" @@ -122,6 +143,8 @@ typedef uint64_t microseconds_t; #include "keyboard.h" #include "keyeditor.h" #include "location_ui.h" +#include "lua_script_manager.h" +#include "luawindow.h" #include "main_clock.h" #include "missing_file_dialog.h" #include "missing_plugin_dialog.h" @@ -138,6 +161,7 @@ typedef uint64_t microseconds_t; #include "route_time_axis.h" #include "route_params_ui.h" #include "save_as_dialog.h" +#include "script_selector.h" #include "session_dialog.h" #include "session_metadata_dialog.h" #include "session_option_editor.h" @@ -212,19 +236,23 @@ libxml_structured_error_func (void* /* parsing_context*/, replace_all (msg, "\n", ""); - if (err->file && err->line) { - error << X_("XML error: ") << msg << " in " << err->file << " at line " << err->line; + if (!msg.empty()) { + if (err->file && err->line) { + error << X_("XML error: ") << msg << " in " << err->file << " at line " << err->line; - if (err->int2) { - error << ':' << err->int2; + if (err->int2) { + error << ':' << err->int2; + } + + error << endmsg; + } else { + error << X_("XML error: ") << msg << endmsg; } } - error << endmsg; } ARDOUR_UI::ARDOUR_UI (int *argcp, char **argvp[], const char* localedir) - : Gtkmm2ext::UI (PROGRAM_NAME, X_("gui"), argcp, argvp) , session_loaded (false) , gui_object_state (new GUIObjectState) @@ -232,7 +260,9 @@ ARDOUR_UI::ARDOUR_UI (int *argcp, char **argvp[], const char* localedir) , secondary_clock (new MainClock (X_("secondary"), X_("secondary"), false)) , big_clock (new AudioClock (X_("bigclock"), false, "big", true, true, false, false)) , video_timeline(0) + , global_actions (X_("global")) , ignore_dual_punch (false) + , main_window_visibility (0) , editor (0) , mixer (0) , nsm (0) @@ -261,27 +291,23 @@ ARDOUR_UI::ARDOUR_UI (int *argcp, char **argvp[], const char* localedir) , last_key_press_time (0) , save_as_dialog (0) , meterbridge (0) + , luawindow (0) , rc_option_editor (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")) - , key_editor (X_("key-editor"), _("Key Bindings")) , 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")) + , lua_script_window (X_("script-manager"), _("Script Manager")) , 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)) + , add_video_dialog (X_("add-video"), _("Add Video"), 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)) + , key_editor (X_("key-editor"), _("Bindings Editor"), boost::bind (&ARDOUR_UI::create_key_editor, this)) , video_server_process (0) , splash (0) , have_configure_timeout (false) @@ -292,6 +318,9 @@ ARDOUR_UI::ARDOUR_UI (int *argcp, char **argvp[], const char* localedir) , _feedback_exists (false) , _log_not_acknowledged (LogLevelNone) , duplicate_routes_dialog (0) + , editor_visibility_button (S_("Window|Editor")) + , mixer_visibility_button (S_("Window|Mixer")) + , prefs_visibility_button (S_("Window|Preferences")) { Gtkmm2ext::init (localedir); @@ -304,10 +333,22 @@ ARDOUR_UI::ARDOUR_UI (int *argcp, char **argvp[], const char* localedir) _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; } + /* track main window visibility */ + + main_window_visibility = new VisibilityTracker (_main_window); + /* stop libxml from spewing to stdout/stderr */ xmlSetGenericErrorFunc (this, libxml_generic_error_func); @@ -355,6 +396,9 @@ ARDOUR_UI::ARDOUR_UI (int *argcp, char **argvp[], const char* localedir) ARDOUR::Session::AskAboutSampleRateMismatch.connect_same_thread (forever_connections, boost::bind (&ARDOUR_UI::sr_mismatch_dialog, this, _1, _2)); + /* handle sr mismatch with a dialog - cross-thread from engine */ + ARDOUR::Session::NotifyAboutSampleRateMismatch.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::sr_mismatch_message, this, _1, _2), gui_context ()); + /* handle requests to quit (coming from JACK session) */ ARDOUR::Session::Quit.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::finish, this), gui_context ()); @@ -397,9 +441,6 @@ ARDOUR_UI::ARDOUR_UI (int *argcp, char **argvp[], const char* localedir) keyboard->set_state (*node, Stateful::loading_state_version); } - /* we don't like certain modifiers */ - Bindings::set_ignored_state (GDK_LOCK_MASK|GDK_MOD2_MASK|GDK_MOD3_MASK); - UIConfiguration::instance().reset_dpi (); TimeAxisViewItem::set_constant_heights (); @@ -413,24 +454,25 @@ ARDOUR_UI::ARDOUR_UI (int *argcp, char **argvp[], const char* localedir) const XMLNode* ui_xml = Config->extra_xml (X_("UI")); if (ui_xml) { - key_editor.set_state (*ui_xml); - // rc_option_editor.set_state (*ui_xml); - session_option_editor.set_state (*ui_xml); - speaker_config_window.set_state (*ui_xml); - about.set_state (*ui_xml); - add_route_dialog.set_state (*ui_xml); - add_video_dialog.set_state (*ui_xml); - route_params.set_state (*ui_xml); - bundle_manager.set_state (*ui_xml); - location_ui.set_state (*ui_xml); - big_clock_window.set_state (*ui_xml); - audio_port_matrix.set_state (*ui_xml); - midi_port_matrix.set_state (*ui_xml); - export_video_dialog.set_state (*ui_xml); - } + key_editor.set_state (*ui_xml, 0); + session_option_editor.set_state (*ui_xml, 0); + speaker_config_window.set_state (*ui_xml, 0); + about.set_state (*ui_xml, 0); + add_route_dialog.set_state (*ui_xml, 0); + add_video_dialog.set_state (*ui_xml, 0); + route_params.set_state (*ui_xml, 0); + bundle_manager.set_state (*ui_xml, 0); + location_ui.set_state (*ui_xml, 0); + big_clock_window.set_state (*ui_xml, 0); + audio_port_matrix.set_state (*ui_xml, 0); + midi_port_matrix.set_state (*ui_xml, 0); + export_video_dialog.set_state (*ui_xml, 0); + lua_script_window.set_state (*ui_xml, 0); + } + + /* Separate windows */ WM::Manager::instance().register_window (&key_editor); - // WM::Manager::instance().register_window (&rc_option_editor); WM::Manager::instance().register_window (&session_option_editor); WM::Manager::instance().register_window (&speaker_config_window); WM::Manager::instance().register_window (&about); @@ -439,12 +481,16 @@ ARDOUR_UI::ARDOUR_UI (int *argcp, char **argvp[], const char* localedir) 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 (&lua_script_window); 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); + /* 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); @@ -457,6 +503,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) { @@ -539,7 +619,7 @@ was not fast enough. Try to restart\n\ the audio backend and save the session."), PROGRAM_NAME); } - MessageDialog msg (*editor, msgstr); + MessageDialog msg (_main_window, msgstr); pop_back_splash (msg); msg.run (); @@ -584,22 +664,32 @@ ARDOUR_UI::post_engine () check_memory_locking(); - /* this is the first point at which all the keybindings are available */ + /* this is the first point at which all the possible actions are + * available, because some of the available actions are dependent on + * aspects of the engine/backend. + */ if (ARDOUR_COMMAND_LINE::show_key_actions) { - vector names; + + vector paths; + vector labels; vector tooltips; vector keys; - vector bindings; + vector > actions; - ActionManager::get_all_actions (names, paths, tooltips, keys, bindings); + Gtkmm2ext::ActionMap::get_all_actions (paths, labels, tooltips, keys, actions); - vector::iterator n; vector::iterator k; vector::iterator p; - for (n = names.begin(), k = keys.begin(), p = paths.begin(); n != names.end(); ++n, ++k, ++p) { - cout << "Action: '" << (*n) << "' bound to '" << (*k) << "' Path: '" << (*p) << "'" << endl; + + for (p = paths.begin(), k = keys.begin(); p != paths.end(); ++k, ++p) { + + if ((*k).empty()) { + cout << *p << endl; + } else { + cout << *p << " => " << *k << endl; + } } halt_connection.disconnect (); @@ -614,17 +704,12 @@ ARDOUR_UI::post_engine () /* set default clock modes */ - if (Profile->get_sae()) { - primary_clock->set_mode (AudioClock::BBT); - secondary_clock->set_mode (AudioClock::MinSec); - } else { - primary_clock->set_mode (AudioClock::Timecode); - secondary_clock->set_mode (AudioClock::BBT); - } + primary_clock->set_mode (AudioClock::Timecode); + secondary_clock->set_mode (AudioClock::BBT); /* start the time-of-day-clock */ -#ifndef GTKOSX +#ifndef __APPLE__ /* OS X provides a nearly-always visible wallclock, so don't be stupid */ update_wall_clock (); Glib::signal_timeout().connect_seconds (sigc::mem_fun(*this, &ARDOUR_UI::update_wall_clock), 1); @@ -648,15 +733,17 @@ ARDOUR_UI::~ARDOUR_UI () 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 meterbridge; - delete editor; - delete mixer; - delete nsm; - delete gui_object_state; + delete big_clock; big_clock = 0; + delete primary_clock; primary_clock = 0; + delete secondary_clock; secondary_clock = 0; + delete _process_thread; _process_thread = 0; + delete meterbridge; meterbridge = 0; + delete luawindow; luawindow = 0; + delete editor; editor = 0; + delete mixer; mixer = 0; + delete nsm; nsm = 0; + delete gui_object_state; gui_object_state = 0; + delete main_window_visibility; FastMeter::flush_pattern_cache (); PixFader::flush_pattern_cache (); } @@ -715,7 +802,7 @@ ARDOUR_UI::configure_handler (GdkEventConfigure* /*conf*/) void ARDOUR_UI::set_transport_controllable_state (const XMLNode& node) { - const XMLProperty* prop; + XMLProperty const * prop; if ((prop = node.property ("roll")) != 0) { roll_controllable->set_id (prop->value()); @@ -800,10 +887,15 @@ ARDOUR_UI::autosave_session () } void -ARDOUR_UI::update_autosave () +ARDOUR_UI::session_dirty_changed () { - ENSURE_GUI_THREAD (*this, &ARDOUR_UI::update_autosave) + update_autosave (); + update_title (); +} +void +ARDOUR_UI::update_autosave () +{ if (_session && _session->dirty()) { if (_autosave_connection.connected()) { _autosave_connection.disconnect(); @@ -854,6 +946,13 @@ ARDOUR_UI::check_announcements () #endif } +static bool +_hide_splash (gpointer arg) +{ + ((ARDOUR_UI*)arg)->hide_splash(); + return false; +} + int ARDOUR_UI::starting () { @@ -1026,8 +1125,6 @@ ARDOUR_UI::starting () use_config (); - goto_editor_window (); - WM::Manager::instance().show_visible (); /* We have to do this here since goto_editor_window() ends up calling show_all() on the @@ -1036,6 +1133,14 @@ ARDOUR_UI::starting () _status_bar_visibility.update (); BootMessage (string_compose (_("%1 is ready for use"), PROGRAM_NAME)); + + if (splash && splash->is_visible()) { + // in 1 second, hide the splash screen + Glib::signal_timeout().connect (sigc::bind (sigc::ptr_fun (_hide_splash), this), 1000); + } + + /* all other dialogs are created conditionally */ + return 0; } @@ -1103,7 +1208,6 @@ ARDOUR_UI::check_memory_locking () pop_back_splash (msg); - editor->ensure_float (msg); msg.run (); if (cb.get_active()) { @@ -1149,7 +1253,7 @@ ARDOUR_UI::finish() /* use the default name */ if (save_state_canfail ("")) { /* failed - don't quit */ - MessageDialog msg (*editor, + MessageDialog msg (_main_window, string_compose (_("\ %1 was unable to save your session.\n\n\ If you still wish to quit, please use the\n\n\ @@ -1520,7 +1624,7 @@ void ARDOUR_UI::count_recenabled_streams (Route& route) { Track* track = dynamic_cast(&route); - if (track && track->record_enabled()) { + if (track && track->rec_enable_control()->get_value()) { rec_enabled_streams += track->n_inputs().n_total(); } } @@ -1671,6 +1775,10 @@ ARDOUR_UI::open_recent_session () can_return = false; } + if (splash && splash->is_visible()) { + // in 1 second, hide the splash screen + Glib::signal_timeout().connect (sigc::bind (sigc::ptr_fun (_hide_splash), this), 1000); + } } bool @@ -1678,8 +1786,8 @@ ARDOUR_UI::check_audioengine (Gtk::Window& parent) { if (!AudioEngine::instance()->connected()) { MessageDialog msg (parent, string_compose ( - _("%1 is not connected to any audio backend.\n" - "You cannot open or close sessions in this condition"), + _("%1 is not connected to any audio backend.\n" + "You cannot open or close sessions in this condition"), PROGRAM_NAME)); pop_back_splash (msg); msg.run (); @@ -1691,7 +1799,7 @@ ARDOUR_UI::check_audioengine (Gtk::Window& parent) void ARDOUR_UI::open_session () { - if (!check_audioengine(*editor)) { + if (!check_audioengine (_main_window)) { return; } @@ -1743,10 +1851,27 @@ ARDOUR_UI::open_session () } } +void +ARDOUR_UI::session_add_vca (const string& name_template, uint32_t n) +{ + if (!_session) { + return; + } + + _session->vca_manager().create_vca (n, name_template); +} void -ARDOUR_UI::session_add_mixed_track (const ChanCount& input, const ChanCount& output, RouteGroup* route_group, - uint32_t how_many, const string& name_template, PluginInfoPtr instrument) +ARDOUR_UI::session_add_mixed_track ( + const ChanCount& input, + const ChanCount& output, + RouteGroup* route_group, + uint32_t how_many, + const string& name_template, + bool strict_io, + PluginInfoPtr instrument, + Plugin::PresetRecord* pset, + ARDOUR::PresentationInfo::order_t order) { list > tracks; @@ -1756,7 +1881,7 @@ ARDOUR_UI::session_add_mixed_track (const ChanCount& input, const ChanCount& out } try { - tracks = _session->new_midi_track (input, output, instrument, ARDOUR::Normal, route_group, how_many, name_template); + tracks = _session->new_midi_track (input, output, 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; @@ -1764,24 +1889,72 @@ ARDOUR_UI::session_add_mixed_track (const ChanCount& input, const ChanCount& out } catch (...) { - MessageDialog msg (*editor, - string_compose (_("There are insufficient ports available\n\ -to create a new track or bus.\n\ -You should save %1, exit and\n\ -restart with more ports."), PROGRAM_NAME)); - msg.run (); + display_insufficient_ports_message (); + return; + } + + if (strict_io) { + for (list >::iterator i = tracks.begin(); i != tracks.end(); ++i) { + (*i)->set_strict_io (true); + } } } +void +ARDOUR_UI::session_add_midi_bus ( + RouteGroup* route_group, + uint32_t how_many, + const string& name_template, + bool strict_io, + PluginInfoPtr instrument, + 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; + } + + try { + + routes = _session->new_midi_route (route_group, how_many, name_template, 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; + } + + } + catch (...) { + display_insufficient_ports_message (); + return; + } + + if (strict_io) { + for (RouteList::iterator i = routes.begin(); i != routes.end(); ++i) { + (*i)->set_strict_io (true); + } + } +} void -ARDOUR_UI::session_add_midi_route (bool disk, RouteGroup* route_group, uint32_t how_many, const string& name_template, PluginInfoPtr instrument) +ARDOUR_UI::session_add_midi_route ( + bool disk, + RouteGroup* route_group, + uint32_t how_many, + const string& name_template, + bool strict_io, + PluginInfoPtr instrument, + 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, instrument); + 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, order); } } @@ -1793,8 +1966,9 @@ ARDOUR_UI::session_add_audio_route ( ARDOUR::TrackMode mode, RouteGroup* route_group, uint32_t how_many, - string const & name_template - ) + string const & name_template, + bool strict_io, + ARDOUR::PresentationInfo::order_t order) { list > tracks; RouteList routes; @@ -1806,7 +1980,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) @@ -1815,7 +1989,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) @@ -1825,14 +1999,30 @@ ARDOUR_UI::session_add_audio_route ( } catch (...) { - MessageDialog msg (*editor, - string_compose (_("There are insufficient ports available\n\ + display_insufficient_ports_message (); + return; + } + + if (strict_io) { + for (list >::iterator i = tracks.begin(); i != tracks.end(); ++i) { + (*i)->set_strict_io (true); + } + for (RouteList::iterator i = routes.begin(); i != routes.end(); ++i) { + (*i)->set_strict_io (true); + } + } +} + +void +ARDOUR_UI::display_insufficient_ports_message () +{ + MessageDialog msg (_main_window, + string_compose (_("There are insufficient ports available\n\ to create a new track or bus.\n\ You should save %1, exit and\n\ restart with more ports."), PROGRAM_NAME)); - pop_back_splash (msg); - msg.run (); - } + pop_back_splash (msg); + msg.run (); } void @@ -1951,14 +2141,14 @@ ARDOUR_UI::trx_record_enable_all_tracks () boost::shared_ptr t = boost::dynamic_pointer_cast (*r); assert (t); - if (t->record_enabled()) { + if (t->rec_enable_control()->get_value()) { none_record_enabled = false; break; } } if (none_record_enabled) { - _session->set_record_enabled (rl, true, Session::rt_cleanup); + _session->set_controls (route_list_to_control_list (rl, &Stripable::rec_enable_control), 1.0, Controllable::NoGroup); } return none_record_enabled; @@ -1971,7 +2161,7 @@ ARDOUR_UI::transport_record (bool roll) switch (_session->record_status()) { case Session::Disabled: if (_session->ntracks() == 0) { - MessageDialog msg (*editor, _("Please create one or more tracks before trying to record.\nYou can do this with the \"Add Track or Bus\" option in the Session menu.")); + MessageDialog msg (_main_window, _("Please create one or more tracks before trying to record.\nYou can do this with the \"Add Track or Bus\" option in the Session menu.")); msg.run (); return; } @@ -2116,7 +2306,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. @@ -2243,7 +2438,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; @@ -2251,12 +2446,12 @@ 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; if ((t = boost::dynamic_pointer_cast(r)) != 0) { - t->set_record_enabled (!t->record_enabled(), Controllable::UseGroup); + t->rec_enable_control()->set_value (!t->rec_enable_control()->get_value(), Controllable::UseGroup); } } } @@ -2526,7 +2721,7 @@ ARDOUR_UI::snapshot_session (bool switch_to_it) prompter.set_name ("Prompter"); prompter.add_button (Gtk::Stock::SAVE, Gtk::RESPONSE_ACCEPT); if (switch_to_it) { - prompter.set_title (_("Save as...")); + prompter.set_title (_("Snapshot and switch")); prompter.set_prompt (_("New session name")); } else { prompter.set_title (_("Take Snapshot")); @@ -2745,7 +2940,7 @@ ARDOUR_UI::save_template () { ArdourPrompter prompter (true); - if (!check_audioengine(*editor)) { + if (!check_audioengine (_main_window)) { return; } @@ -2817,7 +3012,7 @@ ARDOUR_UI::build_session_from_dialog (SessionDialog& sd, const std::string& sess { BusProfile bus_profile; - if (nsm || Profile->get_sae()) { + if (nsm) { bus_profile.master_out_channels = 2; bus_profile.input_ac = AutoConnectPhysical; @@ -2905,8 +3100,6 @@ ARDOUR_UI::load_from_application_api (const std::string& path) if (get_session_parameters (true, false)) { exit (1); } - - goto_editor_window (); } } @@ -3153,7 +3346,7 @@ ARDOUR_UI::get_session_parameters (bool quit_on_cancel, bool should_be_new, stri void ARDOUR_UI::close_session() { - if (!check_audioengine(*editor)) { + if (!check_audioengine (_main_window)) { return; } @@ -3166,8 +3359,10 @@ ARDOUR_UI::close_session() if (get_session_parameters (true, false)) { exit (1); } - - goto_editor_window (); + if (splash && splash->is_visible()) { + // in 1 second, hide the splash screen + Glib::signal_timeout().connect (sigc::bind (sigc::ptr_fun (_hide_splash), this), 1000); + } } /** @param snap_name Snapshot name (without .ardour suffix). @@ -3304,8 +3499,6 @@ ARDOUR_UI::load_session (const std::string& path, const std::string& snap_name, session_loaded = true; - goto_editor_window (); - if (_session) { _session->set_clean (); } @@ -3521,7 +3714,7 @@ ARDOUR_UI::display_cleanup_results (ARDOUR::CleanupReport& rep, const gchar* lis removed = rep.paths.size(); if (removed == 0) { - MessageDialog msgd (*editor, + MessageDialog msgd (_main_window, _("No files were ready for clean-up"), true, Gtk::MESSAGE_INFO, @@ -3770,15 +3963,15 @@ ARDOUR_UI::cleanup_peakfiles () } } -void -ARDOUR_UI::setup_order_hint (AddRouteDialog::InsertAt place) +PresentationInfo::order_t +ARDOUR_UI::translate_order (AddRouteDialog::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). @@ -3787,42 +3980,21 @@ ARDOUR_UI::setup_order_hint (AddRouteDialog::InsertAt place) if (place == AddRouteDialog::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) { 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) { order_hint = 0; } else { - /* leave order_hint at UINT32_MAX */ - } - - 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; + /* leave order_hint at max_order */ } - _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 @@ -3840,9 +4012,11 @@ ARDOUR_UI::start_duplicate_routes () } void -ARDOUR_UI::add_route (Gtk::Window* /* ignored */) +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; @@ -3853,7 +4027,14 @@ ARDOUR_UI::add_route (Gtk::Window* /* ignored */) 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(); @@ -3869,8 +4050,7 @@ ARDOUR_UI::add_route (Gtk::Window* /* ignored */) 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; @@ -3889,6 +4069,7 @@ ARDOUR_UI::add_route (Gtk::Window* /* ignored */) PluginInfoPtr instrument = add_route_dialog->requested_instrument (); RouteGroup* route_group = add_route_dialog->route_group (); AutoConnectOption oac = Config->get_output_auto_connect(); + bool strict_io = add_route_dialog->use_strict_io (); if (oac & AutoConnectMaster) { output_chan.set (DataType::AUDIO, (_session->master_out() ? _session->master_out()->n_inputs().n_audio() : input_chan.n_audio())); @@ -3901,17 +4082,106 @@ ARDOUR_UI::add_route (Gtk::Window* /* ignored */) 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); + 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, 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, instrument); + 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); + 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, order); break; + case AddRouteDialog::VCAMaster: + session_add_vca (name_template, count); + break; + } +} + +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 (); } } @@ -4292,6 +4562,30 @@ ARDOUR_UI::mixer_settings () const return node; } +XMLNode* +ARDOUR_UI::main_window_settings () const +{ + XMLNode* node = 0; + + if (_session) { + node = _session->instant_xml(X_("Main")); + } else { + node = Config->instant_xml(X_("Main")); + } + + if (!node) { + if (getenv("ARDOUR_INSTANT_XML_PATH")) { + node = Config->instant_xml(getenv("ARDOUR_INSTANT_XML_PATH")); + } + } + + if (!node) { + node = new XMLNode (X_("Main")); + } + + return node; +} + XMLNode* ARDOUR_UI::editor_settings () const { @@ -4343,7 +4637,7 @@ void ARDOUR_UI::halt_on_xrun_message () { cerr << "HALT on xrun\n"; - MessageDialog msg (*editor, _("Recording was stopped because your system could not keep up.")); + MessageDialog msg (_main_window, _("Recording was stopped because your system could not keep up.")); msg.run (); } @@ -4372,7 +4666,7 @@ ARDOUR_UI::disk_overrun_handler () if (!have_disk_speed_dialog_displayed) { have_disk_speed_dialog_displayed = true; - MessageDialog* msg = new MessageDialog (*editor, string_compose (_("\ + MessageDialog* msg = new MessageDialog (_main_window, string_compose (_("\ The disk system on your computer\n\ was not able to keep up with %1.\n\ \n\ @@ -4507,7 +4801,7 @@ ARDOUR_UI::disk_underrun_handler () if (!have_disk_speed_dialog_displayed) { have_disk_speed_dialog_displayed = true; MessageDialog* msg = new MessageDialog ( - *editor, string_compose (_("The disk system on your computer\n\ + _main_window, string_compose (_("The disk system on your computer\n\ was not able to keep up with %1.\n\ \n\ Specifically, it failed to read data from disk\n\ @@ -4531,12 +4825,7 @@ ARDOUR_UI::session_dialog (std::string msg) MessageDialog* d; - if (editor) { - d = new MessageDialog (*editor, msg, false, MESSAGE_INFO, BUTTONS_OK, true); - } else { - d = new MessageDialog (msg, false, MESSAGE_INFO, BUTTONS_OK, true); - } - + d = new MessageDialog (msg, false, MESSAGE_INFO, BUTTONS_OK, true); d->show_all (); d->run (); delete d; @@ -4609,6 +4898,21 @@ audio may be played at the wrong sample rate.\n"), desired, PROGRAM_NAME, actual return 1; } +void +ARDOUR_UI::sr_mismatch_message (framecnt_t desired, framecnt_t actual) +{ + MessageDialog msg (string_compose (_("\ +This session was created with a sample rate of %1 Hz, but\n\ +%2 is currently running at %3 Hz.\n\ +Audio will be recorded and played at the wrong sample rate.\n\ +Re-Configure the Audio Engine in\n\ +Menu > Window > Audio/Midi Setup"), + desired, PROGRAM_NAME, actual), + true, + Gtk::MESSAGE_WARNING); + msg.run (); +} + void ARDOUR_UI::use_config () { @@ -4792,11 +5096,6 @@ ARDOUR_UI::setup_profile () Profile->set_small_screen (); } - if (g_getenv ("ARDOUR_SAE")) { - Profile->set_sae (); - Profile->set_single_package (); - } - if (g_getenv ("TRX")) { Profile->set_trx (); } @@ -4886,7 +5185,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); @@ -4928,10 +5227,15 @@ ARDOUR_UI::do_audio_midi_setup (uint32_t desired_sample_rate) audio_midi_setup->set_desired_sample_rate (desired_sample_rate); audio_midi_setup->set_position (WIN_POS_CENTER); - int response; + if (Config->get_try_autostart_engine () || getenv ("TRY_AUTOSTART_ENGINE")) { + audio_midi_setup->try_autostart (); + if (ARDOUR::AudioEngine::instance()->running()) { + return 0; + } + } while (true) { - response = audio_midi_setup->run(); + int response = audio_midi_setup->run(); switch (response) { case Gtk::RESPONSE_OK: if (!AudioEngine::instance()->running()) { @@ -5062,15 +5366,279 @@ ARDOUR_UI::hide_application () } void -ARDOUR_UI::cancel_solo () +ARDOUR_UI::setup_toplevel_window (Gtk::Window& window, const string& name, void* owner) { - if (_session) { - if (_session->soloing()) { - _session->set_solo (_session->get_routes(), false); - } else if (_session->listening()) { - _session->set_listen (_session->get_routes(), false); + /* icons, titles, WM stuff */ + + static list > window_icons; + + if (window_icons.empty()) { + Glib::RefPtr icon; + if ((icon = ::get_icon (PROGRAM_NAME "-icon_16px")) != 0) { + window_icons.push_back (icon); + } + if ((icon = ::get_icon (PROGRAM_NAME "-icon_22px")) != 0) { + window_icons.push_back (icon); + } + if ((icon = ::get_icon (PROGRAM_NAME "-icon_32px")) != 0) { + window_icons.push_back (icon); + } + if ((icon = ::get_icon (PROGRAM_NAME "-icon_48px")) != 0) { + window_icons.push_back (icon); + } + } + + if (!window_icons.empty()) { + window.set_default_icon_list (window_icons); + } + + Gtkmm2ext::WindowTitle title (Glib::get_application_name()); + + if (!name.empty()) { + title += name; + } + + window.set_title (title.get_string()); + window.set_wmclass (string_compose (X_("%1_%1"), downcase (PROGRAM_NAME), downcase (name)), PROGRAM_NAME); + + window.set_flags (CAN_FOCUS); + window.add_events (Gdk::KEY_PRESS_MASK|Gdk::KEY_RELEASE_MASK); + + /* This is a hack to ensure that GTK-accelerators continue to + * work. Once we switch over to entirely native bindings, this will be + * unnecessary and should be removed + */ + window.add_accel_group (ActionManager::ui_manager->get_accel_group()); + + window.signal_configure_event().connect (sigc::mem_fun (*this, &ARDOUR_UI::configure_handler)); + window.signal_window_state_event().connect (sigc::bind (sigc::mem_fun (*this, &ARDOUR_UI::tabbed_window_state_event_handler), owner)); + window.signal_key_press_event().connect (sigc::bind (sigc::mem_fun (*this, &ARDOUR_UI::key_event_handler), &window), false); + window.signal_key_release_event().connect (sigc::bind (sigc::mem_fun (*this, &ARDOUR_UI::key_event_handler), &window), false); +} + +bool +ARDOUR_UI::key_event_handler (GdkEventKey* ev, Gtk::Window* event_window) +{ + Gtkmm2ext::Bindings* bindings = 0; + Gtk::Window* window = 0; + + /* until we get ardour bindings working, we are not handling key + * releases yet. + */ + + if (ev->type != GDK_KEY_PRESS) { + return false; + } + + if (event_window == &_main_window) { + + window = event_window; + + /* find current tab contents */ + + Gtk::Widget* w = _tabs.get_nth_page (_tabs.get_current_page()); + + /* see if it uses the ardour binding system */ + + if (w) { + bindings = reinterpret_cast(w->get_data ("ardour-bindings")); + } + + DEBUG_TRACE (DEBUG::Accelerators, string_compose ("main window key event, bindings = %1, global = %2\n", bindings, &global_bindings)); + + } else { + + window = event_window; + + /* see if window uses ardour binding system */ + + bindings = reinterpret_cast(window->get_data ("ardour-bindings")); + } + + /* An empty binding set is treated as if it doesn't exist */ + + if (bindings && bindings->empty()) { + bindings = 0; + } + + return key_press_focus_accelerator_handler (*window, ev, bindings); +} + +static Gtkmm2ext::Bindings* +get_bindings_from_widget_heirarchy (GtkWidget* w) +{ + void* p = NULL; + + while (w) { + if ((p = g_object_get_data (G_OBJECT(w), "ardour-bindings")) != 0) { + break; + } + w = gtk_widget_get_parent (w); + } + + return reinterpret_cast (p); +} + +bool +ARDOUR_UI::key_press_focus_accelerator_handler (Gtk::Window& window, GdkEventKey* ev, Gtkmm2ext::Bindings* bindings) +{ + GtkWindow* win = window.gobj(); + GtkWidget* focus = gtk_window_get_focus (win); + bool special_handling_of_unmodified_accelerators = false; + const guint mask = (Keyboard::RelevantModifierKeyMask & ~(Gdk::SHIFT_MASK|Gdk::LOCK_MASK)); + + if (focus) { + + /* some widget has keyboard focus */ + + if (GTK_IS_ENTRY(focus) || Keyboard::some_magic_widget_has_focus()) { + + /* A particular kind of focusable widget currently has keyboard + * focus. All unmodified key events should go to that widget + * first and not be used as an accelerator by default + */ + + special_handling_of_unmodified_accelerators = true; + + } else { + + Gtkmm2ext::Bindings* focus_bindings = get_bindings_from_widget_heirarchy (focus); + if (focus_bindings) { + bindings = focus_bindings; + DEBUG_TRACE (DEBUG::Accelerators, string_compose ("Switch bindings based on focus widget, now using %1\n", bindings->name())); + } + } + } + + 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), + special_handling_of_unmodified_accelerators, + Keyboard::some_magic_widget_has_focus(), + focus, + (focus ? gtk_widget_get_name (focus) : "no focus widget"), + ((ev->state & mask) ? "yes" : "no"), + window.get_title())); + + /* This exists to allow us to override the way GTK handles + key events. The normal sequence is: + + a) event is delivered to a GtkWindow + b) accelerators/mnemonics are activated + c) if (b) didn't handle the event, propagate to + the focus widget and/or focus chain + + The problem with this is that if the accelerators include + keys without modifiers, such as the space bar or the + letter "e", then pressing the key while typing into + a text entry widget results in the accelerator being + activated, instead of the desired letter appearing + in the text entry. + + There is no good way of fixing this, but this + represents a compromise. The idea is that + key events involving modifiers (not Shift) + get routed into the activation pathway first, then + get propagated to the focus widget if necessary. + + If the key event doesn't involve modifiers, + we deliver to the focus widget first, thus allowing + it to get "normal text" without interference + from acceleration. + + Of course, this can also be problematic: if there + is a widget with focus, then it will swallow + all "normal text" accelerators. + */ + + + if (!special_handling_of_unmodified_accelerators || (ev->state & mask)) { + + /* no special handling or there are modifiers in effect: accelerate first */ + + DEBUG_TRACE (DEBUG::Accelerators, "\tactivate, then propagate\n"); + DEBUG_TRACE (DEBUG::Accelerators, string_compose ("\tevent send-event:%1 time:%2 length:%3 name %7 string:%4 hardware_keycode:%5 group:%6\n", + ev->send_event, ev->time, ev->length, ev->string, ev->hardware_keycode, ev->group, gdk_keyval_name (ev->keyval))); + + DEBUG_TRACE (DEBUG::Accelerators, "\tsending to window\n"); + KeyboardKey k (ev->state, ev->keyval); + + if (bindings) { + + DEBUG_TRACE (DEBUG::Accelerators, string_compose ("\tusing Ardour bindings %1 @ %2 for this event\n", bindings->name(), bindings)); + + if (bindings->activate (k, Bindings::Press)) { + DEBUG_TRACE (DEBUG::Accelerators, "\t\thandled\n"); + return true; + } + } + + DEBUG_TRACE (DEBUG::Accelerators, "\tnot yet handled, try global bindings\n"); + + if (global_bindings && global_bindings->activate (k, Bindings::Press)) { + DEBUG_TRACE (DEBUG::Accelerators, "\t\thandled\n"); + return true; + } + + DEBUG_TRACE (DEBUG::Accelerators, "\tnot accelerated, now propagate\n"); + + if (gtk_window_propagate_key_event (win, ev)) { + DEBUG_TRACE (DEBUG::Accelerators, "\tpropagate handled\n"); + return true; + } + + } else { + + /* no modifiers, propagate first */ + + DEBUG_TRACE (DEBUG::Accelerators, "\tpropagate, then activate\n"); + + if (gtk_window_propagate_key_event (win, ev)) { + DEBUG_TRACE (DEBUG::Accelerators, "\thandled by propagate\n"); + return true; + } + + DEBUG_TRACE (DEBUG::Accelerators, "\tpropagation didn't handle, so activate\n"); + KeyboardKey k (ev->state, ev->keyval); + + if (bindings) { + + DEBUG_TRACE (DEBUG::Accelerators, "\tusing Ardour bindings for this window\n"); + + + if (bindings->activate (k, Bindings::Press)) { + DEBUG_TRACE (DEBUG::Accelerators, "\t\thandled\n"); + return true; + } + } + DEBUG_TRACE (DEBUG::Accelerators, "\tnot yet handled, try global bindings\n"); + + if (global_bindings && global_bindings->activate (k, Bindings::Press)) { + DEBUG_TRACE (DEBUG::Accelerators, "\t\thandled\n"); + return true; + } + } + + DEBUG_TRACE (DEBUG::Accelerators, "\tnot handled\n"); + return true; +} + +void +ARDOUR_UI::load_bindings () +{ + if ((global_bindings = Bindings::get_bindings (X_("Global"), global_actions)) == 0) { + error << _("Global keybindings are missing") << endmsg; + } +} + +void +ARDOUR_UI::cancel_solo () +{ + if (_session) { + _session->set_controls (route_list_to_control_list (_session->get_routes(), &Stripable::solo_control), 0.0, Controllable::NoGroup); _session->clear_all_solo_state (_session->get_routes()); // safeguard, ideally this won't do anything, check the log-window } }