OSC: Changed gainVCA to gainfader as VCA is already used.
[ardour.git] / gtk2_ardour / ardour_ui.cc
index 1754abb80899a15311f83e1d3307d16d930ce4d2..fe9a5c3713ee85b9aa4d8f8f9b574e9387146ad2 100644 (file)
@@ -71,6 +71,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"
@@ -78,6 +79,7 @@
 #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"
@@ -91,6 +93,8 @@
 #include "ardour/slave.h"
 #include "ardour/system_exec.h"
 
+#include "LuaBridge/LuaBridge.h"
+
 #ifdef WINDOWS_VST_SUPPORT
 #include <fst.h>
 #endif
 #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;
@@ -124,6 +133,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"
@@ -140,6 +151,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"
@@ -226,18 +238,14 @@ libxml_structured_error_func (void* /* parsing_context*/,
 
 
 ARDOUR_UI::ARDOUR_UI (int *argcp, char **argvp[], const char* localedir)
-<<<<<<< HEAD
-
        : Gtkmm2ext::UI (PROGRAM_NAME, X_("gui"), argcp, argvp)
-=======
-       : Gtkmm2ext::UI (PROGRAM_NAME, argcp, argvp)
->>>>>>> first compilable version of tabbable design.
        , session_loaded (false)
        , gui_object_state (new GUIObjectState)
        , primary_clock   (new MainClock (X_("primary"),   X_("transport"), true ))
        , secondary_clock (new MainClock (X_("secondary"), X_("secondary"), false))
        , big_clock (new AudioClock (X_("bigclock"), false, "big", true, true, false, false))
        , video_timeline(0)
+       , global_actions (X_("global"))
        , ignore_dual_punch (false)
        , editor (0)
        , mixer (0)
@@ -267,21 +275,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)
        , 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"))
        , 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 +302,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);
 
@@ -397,9 +410,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 ();
@@ -426,10 +436,11 @@ ARDOUR_UI::ARDOUR_UI (int *argcp, char **argvp[], const char* localedir)
                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 (&session_option_editor);
        WM::Manager::instance().register_window (&speaker_config_window);
@@ -439,6 +450,7 @@ 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);
@@ -584,22 +596,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<string> names;
+
+
                vector<string> paths;
+               vector<string> labels;
                vector<string> tooltips;
                vector<string> keys;
-               vector<AccelKey> bindings;
+               vector<Glib::RefPtr<Gtk::Action> > actions;
 
-               ActionManager::get_all_actions (names, paths, tooltips, keys, bindings);
+               Gtkmm2ext::ActionMap::get_all_actions (paths, labels, tooltips, keys, actions);
 
-               vector<string>::iterator n;
                vector<string>::iterator k;
                vector<string>::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 +636,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 +665,16 @@ 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;
                FastMeter::flush_pattern_cache ();
                PixFader::flush_pattern_cache ();
        }
@@ -859,6 +877,13 @@ ARDOUR_UI::check_announcements ()
 #endif
 }
 
+static bool
+_hide_splash (gpointer arg)
+{
+       ((ARDOUR_UI*)arg)->hide_splash();
+       return false;
+}
+
 int
 ARDOUR_UI::starting ()
 {
@@ -1031,8 +1056,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
@@ -1041,6 +1064,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;
 }
 
@@ -1682,8 +1713,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 ();
@@ -1695,7 +1726,7 @@ ARDOUR_UI::check_audioengine (Gtk::Window& parent)
 void
 ARDOUR_UI::open_session ()
 {
-       if (!check_audioengine(*editor)) {
+       if (!check_audioengine (_main_window)) {
                return;
        }
 
@@ -1747,10 +1778,15 @@ ARDOUR_UI::open_session ()
        }
 }
 
-
 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)
 {
        list<boost::shared_ptr<MidiTrack> > tracks;
 
@@ -1768,24 +1804,67 @@ ARDOUR_UI::session_add_mixed_track (const ChanCount& input, const ChanCount& out
        }
 
        catch (...) {
-               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));
-               msg.run ();
+               display_insufficient_ports_message ();
+               return;
+       }
+
+       if (strict_io) {
+               for (list<boost::shared_ptr<MidiTrack> >::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)
+{
+       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);
+               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)
 {
        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);
+       } else {
+               session_add_midi_bus (route_group, how_many, name_template, strict_io, instrument);
        }
 }
 
@@ -1797,7 +1876,8 @@ 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
        )
 {
        list<boost::shared_ptr<AudioTrack> > tracks;
@@ -1829,14 +1909,30 @@ ARDOUR_UI::session_add_audio_route (
        }
 
        catch (...) {
-               MessageDialog msg (_main_window,
-                                  string_compose (_("There are insufficient ports available\n\
+               display_insufficient_ports_message ();
+               return;
+       }
+
+       if (strict_io) {
+               for (list<boost::shared_ptr<AudioTrack> >::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
@@ -2749,7 +2845,7 @@ ARDOUR_UI::save_template ()
 {
        ArdourPrompter prompter (true);
 
-       if (!check_audioengine(*editor)) {
+       if (!check_audioengine (_main_window)) {
                return;
        }
 
@@ -2821,7 +2917,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;
@@ -2909,8 +3005,6 @@ ARDOUR_UI::load_from_application_api (const std::string& path)
                if (get_session_parameters (true, false)) {
                        exit (1);
                }
-
-               goto_editor_window ();
        }
 }
 
@@ -3157,7 +3251,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;
        }
 
@@ -3170,8 +3264,6 @@ ARDOUR_UI::close_session()
        if (get_session_parameters (true, false)) {
                exit (1);
        }
-
-       goto_editor_window ();
 }
 
 /** @param snap_name Snapshot name (without .ardour suffix).
@@ -3308,8 +3400,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 ();
        }
@@ -3874,7 +3964,6 @@ ARDOUR_UI::add_route (Gtk::Window* /* ignored */)
        }
 
        setup_order_hint(add_route_dialog->insert_at());
-
        string template_path = add_route_dialog->track_template();
        DisplaySuspender ds;
 
@@ -3893,6 +3982,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()));
@@ -3905,20 +3995,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);
                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);
                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);
                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);
+               break;
+       case AddRouteDialog::MidiBus:
+               session_add_midi_bus (route_group, count, name_template, strict_io, instrument);
                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<std::string> 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<std::string> 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)
 {
@@ -4815,11 +4991,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 ();
        }
@@ -5110,7 +5281,7 @@ ARDOUR_UI::setup_toplevel_window (Gtk::Window& window, const string& name, void*
        if (!window_icons.empty()) {
                window.set_default_icon_list (window_icons);
        }
-       
+
        Gtkmm2ext::WindowTitle title (Glib::get_application_name());
 
        if (!name.empty()) {
@@ -5123,6 +5294,10 @@ ARDOUR_UI::setup_toplevel_window (Gtk::Window& window, const string& name, void*
        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));
@@ -5140,15 +5315,15 @@ ARDOUR_UI::key_event_handler (GdkEventKey* ev, Gtk::Window* event_window)
        /* 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());
@@ -5157,65 +5332,83 @@ ARDOUR_UI::key_event_handler (GdkEventKey* ev, Gtk::Window* event_window)
 
                if (w) {
                        bindings = reinterpret_cast<Gtkmm2ext::Bindings*>(w->get_data ("ardour-bindings"));
-               } else {
-                       bindings = &_global_bindings;
                }
 
-       } else if (event_window != 0) {
+               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<Gtkmm2ext::Bindings*>(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;
+
+       while (w) {
+               if ((p = g_object_get_data (G_OBJECT(w), "ardour-bindings")) != 0) {
+                       break;
+               }
+               w = gtk_widget_get_parent (w);
+       }
+
+       return reinterpret_cast<Gtkmm2ext::Bindings*> (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;
-       /* consider all relevant modifiers but not LOCK or SHIFT */
        const guint mask = (Keyboard::RelevantModifierKeyMask & ~(Gdk::SHIFT_MASK|Gdk::LOCK_MASK));
 
-       GdkModifierType modifier = GdkModifierType (ev->state);
-        modifier = GdkModifierType (modifier & gtk_accelerator_get_default_mod_mask());
-        Gtkmm2ext::possibly_translate_mod_to_make_legal_accelerator(modifier);
-
         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 
+                        * 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 focus = %7 (%8) Key event: code = %2  state = %3 special handling ? %4 magic widget focus ? %5 focus widget %6 named %7\n",
+        DEBUG_TRACE (DEBUG::Accelerators, string_compose ("Win = %1 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")));
+                                                          (focus ? gtk_widget_get_name (focus) : "no focus widget"),
+                                                          ((ev->state & mask) ? "yes" : "no")));
 
        /* This exists to allow us to override the way GTK handles
           key events. The normal sequence is:
@@ -5248,9 +5441,9 @@ ARDOUR_UI::key_press_focus_accelerator_handler (Gtk::Window& window, GdkEventKey
           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");
@@ -5258,99 +5451,88 @@ ARDOUR_UI::key_press_focus_accelerator_handler (Gtk::Window& window, GdkEventKey
                                                                  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, "\tusing Ardour bindings for this window\n");
-                       KeyboardKey k (ev->state, ev->keyval);
-                       
+                       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;
                        }
                }
 
-               if (try_gtk_accel_binding (win, ev, !special_handling_of_unmodified_accelerators, modifier)) {
+               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");
-                       KeyboardKey k (ev->state, ev->keyval);
-                       
+
+
                        if (bindings->activate (k, Bindings::Press)) {
                                DEBUG_TRACE (DEBUG::Accelerators, "\t\thandled\n");
                                return true;
                        }
-                       
-               } 
-               
-               DEBUG_TRACE (DEBUG::Accelerators, "\tnot yet handled, try GTK bindings\n");
-               
-               if (try_gtk_accel_binding (win, ev, !special_handling_of_unmodified_accelerators, modifier)) {
+
+               }
+
+               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 yet handled, try global bindings\n");
-       
-       KeyboardKey k (ev->state, ev->keyval);
-       
-       if (_global_bindings.activate (k, Bindings::Press)) {
-               DEBUG_TRACE (DEBUG::Accelerators, "\t\thandled\n");
-               return true;
-       }
-
        DEBUG_TRACE (DEBUG::Accelerators, "\tnot handled\n");
        return true;
 }
 
-bool
-ARDOUR_UI::try_gtk_accel_binding (GtkWindow* win, GdkEventKey* ev, bool translate, GdkModifierType modifier)
+void
+ARDOUR_UI::load_bindings ()
 {
-       uint32_t fakekey = ev->keyval;
-
-       if (translate) {
-               
-               /* pretend that certain key events that GTK does not allow
-                  to be used as accelerators are actually something that
-                  it does allow. but only where there are no modifiers.
-               */
+       if ((global_bindings = Bindings::get_bindings (X_("Global"), global_actions)) == 0) {
+               error << _("Global keybindings are missing") << endmsg;
+       }
+}
 
-               if (Gtkmm2ext::possibly_translate_keyval_to_make_legal_accelerator (fakekey)) {
-                       DEBUG_TRACE (DEBUG::Accelerators, string_compose ("\tactivate (was %1 now %2) without special hanlding of unmodified accels, modifier was %3\n",
-                                                                         ev->keyval, fakekey, show_gdk_event_state (modifier)));
+void
+ARDOUR_UI::cancel_solo ()
+{
+       if (_session) {
+               if (_session->soloing()) {
+                       _session->set_solo (_session->get_routes(), false);
+               } else if (_session->listening()) {
+                       _session->set_listen (_session->get_routes(), false);
                }
-       }
-                       
-       if (gtk_accel_groups_activate (G_OBJECT(win), fakekey, modifier)) {
-               DEBUG_TRACE (DEBUG::Accelerators, "\tGTK accel group activated\n");
-               return true;
-       }
 
-       return false;
+               _session->clear_all_solo_state (_session->get_routes()); // safeguard, ideally this won't do anything, check the log-window
+       }
 }